PHP中图像拼贴的虚拟网格化/调整大小

问题描述 投票:12回答:4

我正在寻找最终的解决方案,或者可能需要一些数学/算法来从较小的产品图片中创建大图像拼贴?我知道如何用gd / imagemagick用相同大小的图片以方形方式进行此操作,但我希望内置一些变化。

例如,有些图片可能会更高一些,如果所有图片的大小和正方形都相同-我可能希望其中一张占据更多空间,只是为了混合设计。保持有趣。

我考虑的越多,公式似乎越难。具有预定义的“模板”以用于所有可能的场景将无法正常工作,因为图片的数量可能会从仅1张(无需工作)到10张以上不等。

我不是在寻找任何旋转或特殊效果,只是在网格中的图像之间可能有一些间距并且没有重叠。

关于实现此目标的任何想法,真的没有准备好去那里了吗?

php image imagemagick gd
4个回答
27
投票

我建议您创建网格和权重方法。

此答案分为三部分:

  1. Working with a virtual grid
  2. Randomly dispose image into that grid
  3. Implement transparency

23
投票

使用虚拟网格

[创建一个新图像,并使用实际的宽度/高度(例如:600x800),以及网格的宽度/高度(例如:10x10)。然后,您可以为图像指定虚拟尺寸和虚拟位置。我会逐步尝试使您理解我的意思。

首先,我们需要一个环境。

class imageGrid
{

    private $realWidth;
    private $realHeight;
    private $gridWidth;
    private $gridHeight;
    private $image;

    public function __construct($realWidth, $realHeight, $gridWidth, $gridHeight)
    {
        $this->realWidth = $realWidth;
        $this->realHeight = $realHeight;
        $this->gridWidth = $gridWidth;
        $this->gridHeight = $gridHeight;

        // create destination image
        $this->image = imagecreatetruecolor($realWidth, $realHeight);

        // set image default background
        $white = imagecolorallocate($this->image, 255, 255, 255);
        imagefill($this->image, 0, 0, $white);
    }

    public function __destruct()
    {
        imagedestroy($this->image);
    }

    public function display()
    {
        header("Content-type: image/png");
        imagepng($this->image);
    }

}

$imageGrid = new imageGrid(800, 600, 10, 10);
$imageGrid->display();

这会给我们一个美丽的白色正方形。然后,我们需要一个网格来显示图像。因为这也许很难想象,所以让我们展示一下。

public function demoGrid()
{
    $black = imagecolorallocate($this->image, 0, 0, 0);
    imagesetthickness($this->image, 3);
    $cellWidth = ($this->realWidth - 1) / $this->gridWidth;   // note: -1 to avoid writting
    $cellHeight = ($this->realHeight - 1) / $this->gridHeight; // a pixel outside the image
    for ($x = 0; ($x <= $this->gridWidth); $x++)
    {
        for ($y = 0; ($y <= $this->gridHeight); $y++)
        {
            imageline($this->image, ($x * $cellWidth), 0, ($x * $cellWidth), $this->realHeight, $black);
            imageline($this->image, 0, ($y * $cellHeight), $this->realWidth, ($y * $cellHeight), $black);
        }
    }
}

通过致电:

$imageGrid = new imageGrid(800, 600, 10, 10);
$imageGrid->demoGrid();
$imageGrid->display();

我们可以看到:

<< img src =“ https://image.soinside.com/eyJ1cmwiOiAiaHR0cHM6Ly9pLnN0YWNrLmltZ3VyLmNvbS9MeGU1Uy5wbmcifQ==” alt =“在此处输入图像描述”>

现在,我们想知道如何编写一个3x4的矩形,并将其粘贴到我们的虚拟度量中的(2,5)上。我们需要搜索如何获取矩形的实际大小和位置。

public function demoPutSquare($sizeW, $sizeH, $posX, $posY)
{
    // Cell width
    $cellWidth = $this->realWidth / $this->gridWidth;
    $cellHeight = $this->realHeight / $this->gridHeight;

    // Conversion of our virtual sizes/positions to real ones
    $realSizeW = ($cellWidth * $sizeW);
    $realSizeH = ($cellHeight * $sizeH);
    $realPosX = ($cellWidth * $posX);
    $realPosY = ($cellHeight * $posY);

    // Getting top left and bottom right of our rectangle
    $topLeftX = $realPosX;
    $topLeftY = $realPosY;
    $bottomRightX = $realPosX + $realSizeW;
    $bottomRightY = $realPosY + $realSizeH;

    // Displaying rectangle
    $red = imagecolorallocate($this->image, 100, 0, 0);
    imagefilledrectangle($this->image, $topLeftX, $topLeftY, $bottomRightX, $bottomRightY, $red);
}

通过致电:

$imageGrid = new imageGrid(800, 600, 10, 10);
$imageGrid->demoGrid();
$imageGrid->demoPutSquare(3, 4, 2, 5);
$imageGrid->display();

我们在网格中得到一个3x4的正方形,位于(2,5)处:

“在此处输入图像描述”

现在让我们更加认真地进行说明,我们已经采取了很好的措施,因此我们可以粘贴图像。

public function putImage($img, $sizeW, $sizeH, $posX, $posY)
{
    // Cell width
    $cellWidth = $this->realWidth / $this->gridWidth;
    $cellHeight = $this->realHeight / $this->gridHeight;

    // Conversion of our virtual sizes/positions to real ones
    $realSizeW = ceil($cellWidth * $sizeW);
    $realSizeH = ceil($cellHeight * $sizeH);
    $realPosX = ($cellWidth * $posX);
    $realPosY = ($cellHeight * $posY);

    // Copying the image
    imagecopyresampled($this->image, $img, $realPosX, $realPosY, 0, 0, $realSizeW, $realSizeH, imagesx($img), imagesy($img));
}

通过致电:

$imageGrid = new imageGrid(800, 600, 10, 10);
$imageGrid->demoGrid();
$img = imagecreatefromjpeg("ninsuo.jpg");
$imageGrid->putImage($img, 3, 4, 2, 5);
$imageGrid->display();

我们得到:

“在此处输入图像描述”

这样,我们可以在合适的位置拍摄照片,但是我们失去了宽高比。让我们添加一种方法来正确调整图像的大小。

public function resizePreservingAspectRatio($img, $targetWidth, $targetHeight)
{
    $srcWidth = imagesx($img);
    $srcHeight = imagesy($img);

    $srcRatio = $srcWidth / $srcHeight;
    $targetRatio = $targetWidth / $targetHeight;
    if (($srcWidth <= $targetWidth) && ($srcHeight <= $targetHeight))
    {
        $imgTargetWidth = $srcWidth;
        $imgTargetHeight = $srcHeight;
    }
    else if ($targetRatio > $srcRatio)
    {
        $imgTargetWidth = (int) ($targetHeight * $srcRatio);
        $imgTargetHeight = $targetHeight;
    }
    else
    {
        $imgTargetWidth = $targetWidth;
        $imgTargetHeight = (int) ($targetWidth / $srcRatio);
    }

    $targetImg = imagecreatetruecolor($targetWidth, $targetHeight);

    imagecopyresampled(
       $targetImg,
       $img,
       ($targetWidth - $imgTargetWidth) / 2, // centered
       ($targetHeight - $imgTargetHeight) / 2, // centered
       0,
       0,
       $imgTargetWidth,
       $imgTargetHeight,
       $srcWidth,
       $srcHeight
    );

    return $targetImg;
}

就在之前:

    imagecopyresampled($this->image, $img, $realPosX, $realPosY, 0, 0, $realSizeW, $realSizeH, imagesx($img), imagesy($img));

我们放入:

    $img = $this->resizePreservingAspectRatio($img, $realSizeW, $realSizeH);

看起来像这样:

<< img src =“ https://image.soinside.com/eyJ1cmwiOiAiaHR0cHM6Ly9pLnN0YWNrLmltZ3VyLmNvbS9EZWxpZy5wbmcifQ==” alt =“在此处输入图像描述”>

我们现在有一个功能齐全的班级来完成您的工作。

class imageGrid
{

    private $realWidth;
    private $realHeight;
    private $gridWidth;
    private $gridHeight;
    private $image;

    public function __construct($realWidth, $realHeight, $gridWidth, $gridHeight)
    {
        $this->realWidth = $realWidth;
        $this->realHeight = $realHeight;
        $this->gridWidth = $gridWidth;
        $this->gridHeight = $gridHeight;

        // create destination image
        $this->image = imagecreatetruecolor($realWidth, $realHeight);
        $black = imagecolorallocate($this->image, 0, 0, 0);
        imagecolortransparent($this->image, $black);
    }

    public function __destruct()
    {
        imagedestroy($this->image);
    }

    public function display()
    {
        header("Content-type: image/png");
        imagepng($this->image);
    }

    public function putImage($img, $sizeW, $sizeH, $posX, $posY)
    {
        // Cell width
        $cellWidth = $this->realWidth / $this->gridWidth;
        $cellHeight = $this->realHeight / $this->gridHeight;

        // Conversion of our virtual sizes/positions to real ones
        $realSizeW = ceil($cellWidth * $sizeW);
        $realSizeH = ceil($cellHeight * $sizeH);
        $realPosX = ($cellWidth * $posX);
        $realPosY = ($cellHeight * $posY);

        $img = $this->resizePreservingAspectRatio($img, $realSizeW, $realSizeH);

        // Copying the image
        imagecopyresampled($this->image, $img, $realPosX, $realPosY, 0, 0, $realSizeW, $realSizeH, imagesx($img), imagesy($img));
    }

    public function resizePreservingAspectRatio($img, $targetWidth, $targetHeight)
    {
        $srcWidth = imagesx($img);
        $srcHeight = imagesy($img);

        $srcRatio = $srcWidth / $srcHeight;
        $targetRatio = $targetWidth / $targetHeight;
        if (($srcWidth <= $targetWidth) && ($srcHeight <= $targetHeight))
        {
            $imgTargetWidth = $srcWidth;
            $imgTargetHeight = $srcHeight;
        }
        else if ($targetRatio > $srcRatio)
        {
            $imgTargetWidth = (int) ($targetHeight * $srcRatio);
            $imgTargetHeight = $targetHeight;
        }
        else
        {
            $imgTargetWidth = $targetWidth;
            $imgTargetHeight = (int) ($targetWidth / $srcRatio);
        }

        $targetImg = imagecreatetruecolor($targetWidth, $targetHeight);

        imagecopyresampled(
           $targetImg,
           $img,
           ($targetWidth - $imgTargetWidth) / 2, // centered
           ($targetHeight - $imgTargetHeight) / 2, // centered
           0,
           0,
           $imgTargetWidth,
           $imgTargetHeight,
           $srcWidth,
           $srcHeight
        );

        return $targetImg;
    }

}

我们现在可以使用它来查看它是否有效:

$imageGrid = new imageGrid(800, 400, 12, 2);

$blue = imagecreatefrompng("cheers_blue.png");
$imageGrid->putImage($blue, 6, 2, 0, 0);
imagedestroy($blue);

$green = imagecreatefrompng("cheers_green.png");
$imageGrid->putImage($green, 2, 1, 6, 0);
imagedestroy($green);

$red = imagecreatefrompng("cheers_red.png");
$imageGrid->putImage($red, 2, 1, 8, 0);
imagedestroy($red);

$yellow = imagecreatefrompng("cheers_yellow.png");
$imageGrid->putImage($yellow, 2, 1, 10, 0);
imagedestroy($yellow);

$purple = imagecreatefrompng("cheers_purple.png");
$imageGrid->putImage($purple, 3, 1, 6, 1);
imagedestroy($purple);

$cyan = imagecreatefrompng("cheers_cyan.png");
$imageGrid->putImage($cyan, 3, 1, 9, 1);
imagedestroy($cyan);

$imageGrid->display();

<< img src =“ https://image.soinside.com/eyJ1cmwiOiAiaHR0cHM6Ly9pLnN0YWNrLmltZ3VyLmNvbS9NSDRmYy5wbmcifQ==” alt =“在此处输入图像描述”>“ >>

就我个人而言,我更喜欢不保留宽高比的:-)

“在此处输入图像描述”

干杯! (嗯,很高兴我会说!)


6
投票

实施透明度


5
投票

将图像随机放置到该网格中

© www.soinside.com 2019 - 2024. All rights reserved.