如何在PHP中克隆gd资源

9

我希望能够在PHP中克隆使用imagecreatetruecolor或其他图像创建函数创建的图像。

正如评论中所述,不,你不能简单地进行克隆操作,例如:

$copy = $original;

这是因为资源是引用类型,不能像标量值一样进行复制。
例如:
$a = imagecreatetruecolor(10,10);
$b = $a;

var_dump($a, $b);

// resource(2, gd)

// resource(2, gd)

3
我不知道“$img1 = $img2”不能起作用? - Zathrus Writer
2
@ZathrusWriter imagecreatetruecolor 返回一个resource。因此,不能只使用简单的赋值,因为 $img1$img2 都将指向相同的资源。 - user895378
感谢您改进您的问题 - 我已经将我的负投票改为正投票。顺便说一下,您可能需要 imagecopy - user895378
使用imagecopy怎么样?它的源和目标参数都是资源,你可能只需要知道尺寸就可以将一个复制到另一个上了。 - Zathrus Writer
好的,我以为有一个正确的方法来做到这一点。谢谢(也许有人可以回答并选择它供其他人使用)。 - Leto
显示剩余3条评论
4个回答

7

这个小函数可以克隆一个图像资源并保留 alpha 通道(透明度)。

function _clone_img_resource($img) {

  //Get width from image.
  $w = imagesx($img);
  //Get height from image.
  $h = imagesy($img);
  //Get the transparent color from a 256 palette image.
  $trans = imagecolortransparent($img);

  //If this is a true color image...
  if (imageistruecolor($img)) {

    $clone = imagecreatetruecolor($w, $h);
    imagealphablending($clone, false);
    imagesavealpha($clone, true);
  }
  //If this is a 256 color palette image...
  else {

    $clone = imagecreate($w, $h);

    //If the image has transparency...
    if($trans >= 0) {

      $rgb = imagecolorsforindex($img, $trans);

      imagesavealpha($clone, true);
      $trans_index = imagecolorallocatealpha($clone, $rgb['red'], $rgb['green'], $rgb['blue'], $rgb['alpha']);
      imagefill($clone, 0, 0, $trans_index);
    }
  }

  //Create the Clone!!
  imagecopy($clone, $img, 0, 0, 0, 0, $w, $h);

  return $clone;
}

1
+1 我认为这是更好的答案。不知道为什么 OP 没选择它。 - Flash Thunder
1
这个对我没用。当我通过这个函数传递我的图像资源时,它失去了透明度。 - ban-geoengineering
H,禁止地球工程!很抱歉听到这个消息。这个函数在我的电脑上运行良好。你能解决问题吗? - DrupalFever
嗨,Flash Thunder!如果您需要使用带有透明度的图像,则此答案更好。如果您只接受JPG格式,那么第一个答案是最简单的。我的意思是说,两个答案都很好。这只取决于您的需求。不过还是感谢您的投票! - DrupalFever
这个流程(或者说同样的流程)也给我带来了透明度方面的问题。我只是试图缩小情况范围——我的应用程序可以在不同的情况下加载索引或真彩色图像。 - AnotherHowie
显示剩余2条评论

6
因此,找到的解决方案在评论中,以下是图像管理类的实现:
public function __clone() {
    $original = $this->_img;
    $copy = imagecreatetruecolor($this->_width, $this->_height);

    imagecopy($copy, $original, 0, 0, 0, 0, $this->_width, $this->_height);

    $this->_img = $copy;
}

2
实际上,这并不是克隆图像资源,而只是将位图画布复制到另一个新的资源对象中,并忽略原始资源中的所有其他设置,例如alpha透明度、混合、某些颜色设置等。当您尝试使用透明PNG(或GIF)层时,您更有可能得到黑色背景而不是透明颜色。对于非透明图像,这仍然有效。 - Wh1T3h4Ck5

1
更简单的代码,只有一行,处理透明度:
function clone_img_resource($img) {
    return imagecrop($img, array('x'=>0,'y'=>0,'width'=>imagesx($img),'height'=>imagesy($img)));
}

这个并没有正确处理透明度,我的变成了黑色。 - Ryan
Ryan,除非您设置了使用imagecreatetruecolor创建的图像的透明度,否则它将始终存在。请参阅我的答案。 - JSG

0

好的,所以我需要带透明度调整大小,我看到这个问题的答案和我的问题的答案相似但不完全相同,所以我将发布我的答案。

我想指出,我修改了此处的答案来回答我的个人需求和OP的问题。(这是关于保持将被复制/克隆/或调整大小的唯一图像的透明度)

此外:透明颜色将保留该资源,并将其应用于其他透明图像复制到它上面。我使用的解决方法是,我在我的示例中使用imagecopy()复制克隆文件以清除分配的透明颜色。

$im = imagecreatefromstring(file_get_contents('I/image.png')); //
$imw = imagesx($im); /*w*/                          $imh = imagesy($im); /*h*/

$tmpIm = imagecreatetruecolor($imw, $imh); // This is black by default
imagealphablending($tmpIm, false);                  imagesavealpha($tmpIm, true); // Set these as usual
$wht = imagecolorallocatealpha($tmpIm, 255, 255, 255, 127); // white
imagecolortransparent($tmpIm, $wht); // Setting this seems to be unsettable and will make this color transparent on all images later coppied to it
imagealphablending($tmpIm, false);                  imagesavealpha($tmpIm, true); // Set these as usual
// That is it... As long as you set the transparency of the background before you copy it should work. That means now at least some of the other answers can work now.
imagecopyresampled($tmpIm, $im, 0, 0, 0, 0, $imw, $imh, $imw, $imh); // Copy or resize whatever floats your boat. The above process is what does the trick.

$newIm = imagecreatetruecolor($imw, $imh); // Begin Clone
imagealphablending($newIm, false);                  imagesavealpha($newIm, true); // Set these as usual
imagecopyresampled($newIm, $tmpIm, 0, 0, 0, 0, $imw, $imh, $imw, $imh); // Clearing the tranparent color previously set (Workaround)
imagedestroy($tmpIm);

header('Content-Type: image/png');
imagepng($newIm); // see I told you.. Or he did... Whatever, it works...

所以对于这个函数,它将会是:

function F_img_clone($im,$trgt,$id){
                            $imw = imagesx($im);                            $imh = imagesy($im);    // Height and Width of Original
    if(empty($trgt) === true){
                            $rsiw = $imw;                                   $rsih = $imh;   // if there are no H or W changes
    }else{  // if there are H or W changes
        if( $imw > $imh ) {
                            $pcntg = ( ($trgt??1920) / $imw );
        }else{
                            $pcntg = ( ($trgt??1920) / $imh );
        }
                            $rsiw = round($imw * $pcntg);                   $rsih = round($imh * $pcntg);
    }
                            
                            $ni = imagecreatetruecolor($rsiw, $rsih);// Begin the background
                            imagealphablending($ni, false);             imagesavealpha($ni, true); // To keep the alpha channel
                            $wht = imagecolorallocatealpha($ni, 255, 255, 255, 127); // white
                            imagecolortransparent($ni, $wht); // Setting this seems to be unsettable and will make this color transparent on all images later coppied to it
                            imagealphablending($ni, false);             imagesavealpha($ni, true);
                            imagecopyresampled($ni, $im, 0, 0, 0, 0, $rsiw, $rsih, $imw, $imh);
                            imagealphablending($ni, true);              imagesavealpha($ni, false);
                            imagedestroy($im);
                            $imw = imagesx($ni); /*h*/                  $imh = imagesy($ni); /*w*/
                            ${$id} = imagecreatetruecolor($imw, $imh); // Begin Clone
                            imagealphablending(${$id}, false);              imagesavealpha(${$id}, true); // Set these as usual
                            imagecopyresampled(${$id}, $ni, 0, 0, 0, 0, $imw, $imh, $imw, $imh); // Clearing the tranparent color previously set (Workaround)
                            
                            imagedestroy($ni);
                            return ${$id};
}

所以使用它的方式是:

$image = imagecreatefromstring(file_get_contents('I/image.png')); //
$clone = F_img_clone($image,'','clone');

原始的$image将保持不变。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接