【问题标题】:Virtual gridding/resizing of image collage in PHPPHP中图像拼贴的虚拟网格化/调整大小
【发布时间】:2012-10-06 12:11:57
【问题描述】:

我正在寻找一个已完成的解决方案,或者可能是一些数学/算法,以便从较小的产品图片中创建一个大图像拼贴画? 我知道如何使用 gd/imagemagick 从相同大小的图片中以方形方式进行操作,但我想内置一些变化。

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

我想得越多,它似乎就越难用公式。为所有可能的场景预定义“模板”是行不通的,因为图片的数量可能从 1(无需工作)到 10+ 不等。

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

任何想法如何实现这一点,真的没有什么准备好出去吗?

【问题讨论】:

    标签: php image imagemagick gd


    【解决方案1】:

    我建议你创建一个网格和权重方法。

    这个答案分为三部分:

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

    【讨论】:

    • 哇。可能是有史以来最广泛的答案。非常非常非常感谢!这肯定会为我节省大量时间来开始做一些基础工作!我现在的主要问题是计算图像将如何放置在网格中。我需要尝试跟踪不同的图像大小并动态计算如何使用 "$imageGrid->putImage 放置它们的最优化布局($蓝色, 6, 2, 0, 0);" - 有什么想法吗?
    • 很高兴看到这个答案对您有所帮助。是的,您可以通过这种方式动态确定权重:1)计算所有图像宽度/高度的总和,2)使用该总和获得每个图像宽度/高度的百分比,3)创建 100x100 的网格并使用这些百分比。我现在在工作不能帮助你,所以如果你需要一个例子,请告诉我,我今晚可以写(gmt+2)。
    • 您好,谢谢!我不确定我是否理解这将如何帮助动态确定定位 - 所以一个例子会很棒。也许我只需要再考虑一下,然后重新阅读您写的所有内容。但是在你刚刚写给我的那本小说之后,我有点羞于问你更多,哈哈。不用担心,我不着急!
    • 如果我随机选择一张图片并简单地将其放大一倍?否则,当大多数图像尺寸相同或最多有 2-3 个不同尺寸(主要是高度)时,计算百分比不会引入任何布局错觉。嗯..我会继续考虑它,也许当你有空的时候你可以帮助我:)
    • +1 只是为了花时间写下所有内容!我只能说哇!
    【解决方案2】:

    实现透明度

    首先在__construct方法上,替换:

        $white = imagecolorallocate($this->image, 255, 255, 255);
        imagefill($this->image, 0, 0, $white);
    

    作者:

        $transparent = imagecolorallocate($this->image, 255, 0, 255);
        imagefill($this->image, 0, 0, $transparent);
        imagecolortransparent($this->image, $transparent);
    

    然后,在 resizePreservingAspectRatio 方法上,在后面添加:

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

    以下几行:

        $targetTransparent = imagecolorallocate($targetImg, 255, 0, 255);
        imagefill($targetImg, 0, 0, $targetTransparent);
        imagecolortransparent($targetImg, $targetTransparent);
    

    我们开始吧。

    【讨论】:

      【解决方案3】:

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

      方法是:我们将摇动所有图像以获得一个随机数组,并将它们随机排列在行上:每行 1 到 4 个图像(您可以更改此值),并将使用较高的图像在每一行中确定每一行的高度。因此,如果一张图片比另一张高 50%,如果它们不在同一行,您将保持比例。

      这有点难,所以我决定在这部分的开发过程中从不使用图形。这就是为什么有很多步骤和调试的原因,但这对逐步获得最终结果有很大帮助。

      我们得到所有图像的高度和它们的总和:

      $images = array ();
      $totalHeight = 0;
      foreach (glob("images/*.jpg") as $jpg)
      {
          $img = imagecreatefromjpeg($jpg);
          $images[$jpg] = imagesy($img);
          $totalHeight += $images[$jpg];
          imagedestroy($img);
      }
      
      echo "image list with heights:\n";
      var_dump($images);
      echo "total heights: {$totalHeight}\n";
      

      给我们:

      image list with heights:
      array(12) {
        ["images/image1.jpg"]=>
        int(392)
        ["images/image10.jpg"]=>
        int(640)
        ["images/image11.jpg"]=>
        int(364)
        ["images/image12.jpg"]=>
        int(324)
        ["images/image2.jpg"]=>
        int(533)
        ["images/image3.jpg"]=>
        int(360)
        ["images/image4.jpg"]=>
        int(768)
        ["images/image5.jpg"]=>
        int(330)
        ["images/image6.jpg"]=>
        int(360)
        ["images/image7.jpg"]=>
        int(338)
        ["images/image8.jpg"]=>
        int(600)
        ["images/image9.jpg"]=>
        int(391)
      }
      total heights: 5400
      

      然后我们打乱图像数组以获得图像的随机排列。我们需要保留密钥,而 shffle 不需要,所以我们需要一点技巧。

      // Shuffle image array of files preserving keys to get random image disposition
      $keys = array_keys($images);
      shuffle($keys);
      $images = array_merge(array_flip($keys), $images);
      
      // Separate image names and heights, will simplify our future work
      $heights = array_values($images);
      $images = array_keys($images);
      
      echo "image list:\n";
      var_dump($images);
      
      echo "image heights:\n";
      var_dump($heights);
      

      给我们:

      image list:
      array(12) {
        [0]=>
        string(17) "images/image6.jpg"
        [1]=>
        string(17) "images/image5.jpg"
        [2]=>
        string(18) "images/image10.jpg"
        [3]=>
        string(17) "images/image2.jpg"
        [4]=>
        string(18) "images/image12.jpg"
        [5]=>
        string(17) "images/image3.jpg"
        [6]=>
        string(17) "images/image4.jpg"
        [7]=>
        string(17) "images/image1.jpg"
        [8]=>
        string(17) "images/image8.jpg"
        [9]=>
        string(17) "images/image9.jpg"
        [10]=>
        string(18) "images/image11.jpg"
        [11]=>
        string(17) "images/image7.jpg"
      }
      image heights:
      array(12) {
        [0]=>
        int(360)
        [1]=>
        int(330)
        [2]=>
        int(640)
        [3]=>
        int(533)
        [4]=>
        int(324)
        [5]=>
        int(360)
        [6]=>
        int(768)
        [7]=>
        int(392)
        [8]=>
        int(600)
        [9]=>
        int(391)
        [10]=>
        int(364)
        [11]=>
        int(338)
      }
      

      这里重要的是检查我们是否保留了图像/高度关联。

      现在,我们需要将图片高度转换为百分比:因此,如果您有 2 张图片,其中一张比第二张高 50%,因此您将拥有第一张图片总高度的 66% 和 33%对于第二个。这个虚拟高度将用作我们网格上的高度。

      $count = count($heights);
      for ($i = 0; ($i < $count); $i++)
      {
          $heights[$i] = ($heights[$i] * 100) / $totalHeight
      }
      
      echo "image heights in percents\n";
      var_dump($heights);
      echo "check : " . array_sum($heights) . " = 100\n";
      

      结果:

      Image heights in percents
      array(12) {
        [0]=>
        float(6.6666666666667)
        [1]=>
        float(6.1111111111111)
        [2]=>
        float(11.851851851852)
        [3]=>
        float(9.8703703703704)
        [4]=>
        int(6)
        [5]=>
        float(6.6666666666667)
        [6]=>
        float(14.222222222222)
        [7]=>
        float(7.2592592592593)
        [8]=>
        float(11.111111111111)
        [9]=>
        float(7.2407407407407)
        [10]=>
        float(6.7407407407407)
        [11]=>
        float(6.2592592592593)
      }
      check : 100 = 100
      

      我们现在生成一个行数组,以查看每行将放置多少张图像。对于此示例,我们希望每行 1 到 4 个图像。在此处更改rand() % 4 + 1,按您想要的每行获得尽可能多的图像。示例:rand() % 3 + 2 将为您提供 2 到 5 张图片。

      $lines = array ();
      while ($count > 0)
      {
          $nbImages = rand() % 4 + 1;
          if (($count - $nbImages) < 0)
          {
              $nbImages = $count;
          }
      
          $lines[] = $nbImages;
          $count -= $nbImages;
      }
      
      echo "Number of lines : " . count($lines) . "\n";
      echo "images per line disposition :\n";
      var_dump($lines);
      

      结果:

      Number of lines : 5
      images per line disposition :
      array(5) {
        [0]=>
        int(3)
        [1]=>
        int(1)
        [2]=>
        int(1)
        [3]=>
        int(4)
        [4]=>
        int(3)
      }
      

      我们需要将图像与一条线以及一条线中的位置相关联。这将帮助我们获得图像在网格中的位置。

      $imageLines = array();
      foreach ($lines as $key => $numberImg)
      {
          while ($numberImg--)
          {
              $imageLines[] = $key;
          }
      }
      
      echo "image / line association:\n";
      var_dump($imageLines);
      
      $imagePositions = array();
      foreach ($lines as $numberImg)
      {
          for ($i = 0; ($i < $numberImg); $i++)
          {
              $imagePositions[] = $i;
          }
      }
      
      echo "image / position in a line association:\n";
      var_dump($imagePositions);
      

      结果:

      image / line association:
      array(12) {
        [0]=>
        int(0)
        [1]=>
        int(0)
        [2]=>
        int(0)
        [3]=>
        int(1)
        [4]=>
        int(2)
        [5]=>
        int(3)
        [6]=>
        int(3)
        [7]=>
        int(3)
        [8]=>
        int(3)
        [9]=>
        int(4)
        [10]=>
        int(4)
        [11]=>
        int(4)
      }
      image / position in a line association:
      array(12) {
        [0]=>
        int(0)
        [1]=>
        int(1)
        [2]=>
        int(2)
        [3]=>
        int(0)
        [4]=>
        int(0)
        [5]=>
        int(0)
        [6]=>
        int(1)
        [7]=>
        int(2)
        [8]=>
        int(3)
        [9]=>
        int(0)
        [10]=>
        int(1)
        [11]=>
        int(2)
      }
      

      现在,我们需要获取图像的总宽度。我们有 1 到 4 个图像,因此无论每行有多少图像,为了获得每个图像的整数大小,我们将 4(最大值)乘以从 4 到 1 的所有值。在这种情况下:4 * 3 * 2 * 1 = 24,所以如果我们有 1 幅图像/行,它的宽度将为 24,2 幅图像/行:24/2 = 12,3 幅图像/行:24/3=8,4 幅图像/行:24 /4=6。都是有效的整数。

      $i = 4;
      $virtualWidth = 1;
      while ($i)
      {
          $virtualWidth *= $i--;
      }
      
      echo "virtual width: {$virtualWidth}\n";
      

      这里没什么难的,结果是:

      virtual width: 24
      

      我们现在需要根据每行的最高图像来确定每行的高度。我们也可以在这个计算中推导出我们的网格高度。

      // Determine the virtual height needed for each line and for the whole grid
      $imageHeights = array();
      $index = 0;
      foreach ($lines as $key => $numberImages)
      {
          $slice = array_slice($heights, $index, $numberImages);
      
          echo "at line {$key}, images heights are:\n";
          var_dump($slice);
      
          $imageHeights[] = max($slice);
          $index += $numberImages;
      }
      $virtualHeight = array_sum($imageHeights);
      
      echo "heights for each line:\n";
      var_dump($imageHeights);
      echo "total height = {$virtualHeight}\n";
      

      这会导致:

      at line 0, images heights are:
      array(3) {
        [0]=>
        float(6.6666666666667)
        [1]=>
        float(6.1111111111111)
        [2]=>
        float(11.851851851852)
      }
      at line 1, images heights are:
      array(1) {
        [0]=>
        float(9.8703703703704)
      }
      at line 2, images heights are:
      array(1) {
        [0]=>
        int(6)
      }
      at line 3, images heights are:
      array(4) {
        [0]=>
        float(6.6666666666667)
        [1]=>
        float(14.222222222222)
        [2]=>
        float(7.2592592592593)
        [3]=>
        float(11.111111111111)
      }
      at line 4, images heights are:
      array(3) {
        [0]=>
        float(7.2407407407407)
        [1]=>
        float(6.7407407407407)
        [2]=>
        float(6.2592592592593)
      }
      heights for each line:
      array(5) {
        [0]=>
        float(11.851851851852)
        [1]=>
        float(9.8703703703704)
        [2]=>
        int(6)
        [3]=>
        float(14.222222222222)
        [4]=>
        float(7.2407407407407)
      }
      total height = 49.185185185185
      

      我们检查这个结果是否我们有每行的最高值,并且总和是否有效。

      我们终于有了显示随机定位图像网格所需的所有信息。

      $imageGrid = new imageGrid(800, 800, $virtualWidth, $virtualHeight);
      foreach (glob("images/*.jpg") as $jpg)
      {
          $img = imagecreatefromjpeg($jpg);
      
          $index = array_search($jpg, $images);
          echo "image {$index}:\n";
      
          $line = $imageLines[$index];
          echo "image is at line {$line}\n";
      
          $sizeW = ($virtualWidth / $lines[$line]);
          echo "width = {$virtualWidth} / {$lines[$line]} = {$sizeW}\n";
      
          $sizeH = $imageHeights[$line];
          echo "height = {$imageHeights[$line]}\n";
      
          $posX = $imagePositions[$index] * ($virtualWidth / $lines[$line]);
          echo "pos X = {$imagePositions[$index]} * ({$virtualWidth} / {$lines[$line]}) = {$posX}\n";
      
          $slice = array_slice($imageHeights, 0, $line);
          echo "Slice to calc Y:\n";
          var_dump($slice);
      
          $posY = array_sum($slice);
          echo "pos Y = {$posY}\n";
      
          echo "\n";
      
          $imageGrid->putImage($img, $sizeW, $sizeH, $posX, $posY);
          imagedestroy($img);
      }
      

      这会导致:

      image 7:
      image is at line 3
      width = 24 / 4 = 6
      height = 14.222222222222
      pos X = 2 * (24 / 4) = 12
      Slice to calc Y:
      array(3) {
        [0]=>
        float(11.851851851852)
        [1]=>
        float(9.8703703703704)
        [2]=>
        int(6)
      }
      pos Y = 27.722222222222
      
      image 2:
      image is at line 0
      width = 24 / 3 = 8
      height = 11.851851851852
      pos X = 2 * (24 / 3) = 16
      Slice to calc Y:
      array(0) {
      }
      pos Y = 0
      
      image 10:
      image is at line 4
      width = 24 / 3 = 8
      height = 7.2407407407407
      pos X = 1 * (24 / 3) = 8
      Slice to calc Y:
      array(4) {
        [0]=>
        float(11.851851851852)
        [1]=>
        float(9.8703703703704)
        [2]=>
        int(6)
        [3]=>
        float(14.222222222222)
      }
      pos Y = 41.944444444444
      
      image 4:
      image is at line 2
      width = 24 / 1 = 24
      height = 6
      pos X = 0 * (24 / 1) = 0
      Slice to calc Y:
      array(2) {
        [0]=>
        float(11.851851851852)
        [1]=>
        float(9.8703703703704)
      }
      pos Y = 21.722222222222
      
      image 3:
      image is at line 1
      width = 24 / 1 = 24
      height = 9.8703703703704
      pos X = 0 * (24 / 1) = 0
      Slice to calc Y:
      array(1) {
        [0]=>
        float(11.851851851852)
      }
      pos Y = 11.851851851852
      
      image 5:
      image is at line 3
      width = 24 / 4 = 6
      height = 14.222222222222
      pos X = 0 * (24 / 4) = 0
      Slice to calc Y:
      array(3) {
        [0]=>
        float(11.851851851852)
        [1]=>
        float(9.8703703703704)
        [2]=>
        int(6)
      }
      pos Y = 27.722222222222
      
      image 6:
      image is at line 3
      width = 24 / 4 = 6
      height = 14.222222222222
      pos X = 1 * (24 / 4) = 6
      Slice to calc Y:
      array(3) {
        [0]=>
        float(11.851851851852)
        [1]=>
        float(9.8703703703704)
        [2]=>
        int(6)
      }
      pos Y = 27.722222222222
      
      image 1:
      image is at line 0
      width = 24 / 3 = 8
      height = 11.851851851852
      pos X = 1 * (24 / 3) = 8
      Slice to calc Y:
      array(0) {
      }
      pos Y = 0
      
      image 0:
      image is at line 0
      width = 24 / 3 = 8
      height = 11.851851851852
      pos X = 0 * (24 / 3) = 0
      Slice to calc Y:
      array(0) {
      }
      pos Y = 0
      
      image 11:
      image is at line 4
      width = 24 / 3 = 8
      height = 7.2407407407407
      pos X = 2 * (24 / 3) = 16
      Slice to calc Y:
      array(4) {
        [0]=>
        float(11.851851851852)
        [1]=>
        float(9.8703703703704)
        [2]=>
        int(6)
        [3]=>
        float(14.222222222222)
      }
      pos Y = 41.944444444444
      
      image 8:
      image is at line 3
      width = 24 / 4 = 6
      height = 14.222222222222
      pos X = 3 * (24 / 4) = 18
      Slice to calc Y:
      array(3) {
        [0]=>
        float(11.851851851852)
        [1]=>
        float(9.8703703703704)
        [2]=>
        int(6)
      }
      pos Y = 27.722222222222
      
      image 9:
      image is at line 4
      width = 24 / 3 = 8
      height = 7.2407407407407
      pos X = 0 * (24 / 3) = 0
      Slice to calc Y:
      array(4) {
        [0]=>
        float(11.851851851852)
        [1]=>
        float(9.8703703703704)
        [2]=>
        int(6)
        [3]=>
        float(14.222222222222)
      }
      pos Y = 41.944444444444
      

      为了调试我们的代码,我们以 :

      结尾
      $debug = true;
      if ($debug)
      {
          echo ob_get_clean();
      }
      else
      {
          ob_clean();
          $imageGrid->display();
      }
      

      好的,您已经完成了所有步骤。结果呢?

      F5...

      F5...

      最终代码:

      ob_start();
      
      echo '<pre>';
      
      // Get height of all images
      $images = array ();
      $totalHeight = 0;
      foreach (glob("images/*.jpg") as $jpg)
      {
          $img = imagecreatefromjpeg($jpg);
          $images[$jpg] = imagesy($img);
          $totalHeight += $images[$jpg];
          imagedestroy($img);
      }
      
      echo "image list with heights:\n";
      var_dump($images);
      
      // Shuffle image array of files preserving keys to get random image disposition
      $keys = array_keys($images);
      shuffle($keys);
      $images = array_merge(array_flip($keys), $images);
      
      // Separate image names and heights, will simplify our future work
      $heights = array_values($images);
      $images = array_keys($images);
      
      echo "image list:\n";
      var_dump($images);
      
      echo "total heights: {$totalHeight}\n";
      
      echo "image heights:\n";
      var_dump($heights);
      
      // Get percentage of image height compared to the total height
      $count = count($heights);
      for ($i = 0; ($i < $count); $i++)
      {
          $heights[$i] = ($heights[$i] * 100) / $totalHeight; // becomes virtual height in a x100 grid
      }
      
      echo "image heights in percents\n";
      var_dump($heights);
      echo "check : " . array_sum($heights) . " = 100\n";
      
      // Get random number of images per line and number of lines
      // Between 1 to 4 images/line until there is no more image.
      $lines = array ();
      while ($count > 0)
      {
          $nbImages = rand() % 4 + 1;
          if (($count - $nbImages) < 0)
          {
              $nbImages = $count;
          }
      
          $lines[] = $nbImages;
          $count -= $nbImages;
      }
      
      echo "Number of lines : " . count($lines) . "\n";
      echo "images per line disposition :\n";
      var_dump($lines);
      
      // Associate an image with a line
      $imageLines = array();
      foreach ($lines as $key => $numberImg)
      {
          while ($numberImg--)
          {
              $imageLines[] = $key;
          }
      }
      
      echo "image / line association:\n";
      var_dump($imageLines);
      
      // Associate an image with a position in a line
      $imagePositions = array();
      foreach ($lines as $numberImg)
      {
          for ($i = 0; ($i < $numberImg); $i++)
          {
              $imagePositions[] = $i;
          }
      }
      
      echo "image / position in a line association:\n";
      var_dump($imagePositions);
      
      // We have from 1 to 4 images/line so we create a grid with a virtual width of 1*2*3*4.
      // In this case, 1 image/line = 24, 2/line =24/2=12, 3/line=24/3=8, all are valid integers.
      $i = 4;
      $virtualWidth = 1;
      while ($i)
      {
          $virtualWidth *= $i--;
      }
      
      echo "virtual width: {$virtualWidth}\n";
      
      // Determine the virtual height needed for each line and for the whole grid
      $imageHeights = array();
      $index = 0;
      foreach ($lines as $key => $numberImages)
      {
          $slice = array_slice($heights, $index, $numberImages);
      
          echo "at line {$key}, images heights are:\n";
          var_dump($slice);
      
          $imageHeights[] = max($slice);
          $index += $numberImages;
      }
      $virtualHeight = array_sum($imageHeights);
      
      echo "heights for each line:\n";
      var_dump($imageHeights);
      echo "total height = {$virtualHeight}\n";
      
      
      // Create a grid and place logically all images in the virtual area
      $imageGrid = new imageGrid(800, 800, $virtualWidth, $virtualHeight);
      foreach (glob("images/*.jpg") as $jpg)
      {
          $img = imagecreatefromjpeg($jpg);
      
          // Determine position
          $index = array_search($jpg, $images);
          echo "image {$index}:\n";
      
          $line = $imageLines[$index];
          echo "image is at line {$line}\n";
      
          $sizeW = ($virtualWidth / $lines[$line]);
          echo "width = {$virtualWidth} / {$lines[$line]} = {$sizeW}\n";
      
          $sizeH = $imageHeights[$line];
          echo "height = {$imageHeights[$line]}\n";
      
          $posX = $imagePositions[$index] * ($virtualWidth / $lines[$line]);
          echo "pos X = {$imagePositions[$index]} * ({$virtualWidth} / {$lines[$line]}) = {$posX}\n";
      
          $slice = array_slice($imageHeights, 0, $line);
          echo "Slice to calc Y:\n";
          var_dump($slice);
      
          $posY = array_sum($slice);
          echo "pos Y = {$posY}\n";
      
          echo "\n";
      
          $imageGrid->putImage($img, $sizeW, $sizeH, $posX, $posY);
          imagedestroy($img);
      }
      
      $debug = false;
      if ($debug)
      {
          echo ob_get_clean();
      }
      else
      {
          ob_clean();
          $imageGrid->display();
      }
      

      我的方法可能不是最好的,但至少,它可以将图像随机定位到保留图像权重的网格中。这个主题很难处理,所以我希望这对你的情况来说足够了。

      【讨论】:

      • 这超出了我的预期,简直太棒了!谢谢。
      【解决方案4】:

      使用虚拟网格

      创建具有实际宽度/高度(例如: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();
      

      我们可以看到:

      现在,我们想知道如何写一个 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();
      

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

      现在让我们更认真一点,我们有很好的措施,所以我们可以粘贴图像。

      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);
      

      看起来像这样:

      我们现在有一个完整的函数类来完成你的工作。

      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();
      

      就个人而言,我更喜欢不保留纵横比的那个:-)

      干杯! (嗯,我会说享受!)

      【讨论】:

      • 谢谢!有没有办法将拼贴图像保存到具有不同名称的目录中? @Alain Tiemblo
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-27
      • 2011-11-25
      • 2012-01-09
      • 2016-11-28
      • 1970-01-01
      • 2013-01-16
      相关资源
      最近更新 更多