9

I'm looking for cloning an image in PHP created with imagecreatetruecolor or some other image creation function..

As it was said in the comment, no you can't do a simple affection like :

$copy = $original;

This because ressources are reference and could not be copied like scalar values.

Example :

$a = imagecreatetruecolor(10,10);
$b = $a;

var_dump($a, $b);

// resource(2, gd)

// resource(2, gd)
Leto
  • 2,594
  • 3
  • 24
  • 37
  • 3
    I didn't know `$img1 = $img2` didn't work? – Zathrus Writer Sep 26 '12 at 15:59
  • 2
    @ZathrusWriter `imagecreatetruecolor` returns a [resource](http://php.net/manual/en/language.types.resource.php). So, no, you can't just use a simple assignment as both `$img1` and `$img2` will point to the same resource. –  Sep 26 '12 at 16:02
  • @rdlowrey interesting, I honestly didn't know this... gotta try it out, as it basically goes against PHP's [variables and references](http://php.net/manual/en/language.variables.basics.php) in my view – Zathrus Writer Sep 26 '12 at 16:03
  • Thank you for improving your question -- I've changed my downvote to a +1. Incidentally you'll probably want [`imagecopy`](http://us.php.net/manual/en/function.imagecopy.php) –  Sep 26 '12 at 16:11
  • how about using [imagecopy](http://php.net/manual/en/function.imagecopy.php)? its source and destination parameters are both resources, you may only need to know dimensions to copy one to the other? – Zathrus Writer Sep 26 '12 at 16:12
  • ok, i thought there were a proper way to do that. Thanks (maybe someone could answer to select it for other people) – Leto Sep 26 '12 at 16:20
  • [http://stackoverflow.com/questions/3047852/duplicate-a-image-varible-gd-library](http://stackoverflow.com/questions/3047852/duplicate-a-image-varible-gd-library) – air4x Sep 26 '12 at 16:52
  • This has something worth a look.. https://stackoverflow.com/questions/279236/how-do-i-resize-pngs-with-transparency-in-php#:~:text=%24this%2D%3Eimage%20%3D%20imagecreatefrompng,%2C%20127)%3B%20imagecolortransparent(%24newImage – JSG Jun 18 '20 at 04:32

4 Answers4

7

This little function will clone an image resource while retaining the alpha channel (transparency).

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;
}
DrupalFever
  • 4,302
  • 1
  • 17
  • 10
  • 1
    `+1` I think that it is better answer. Have no idea why OP didn't choose it. – Flash Thunder Mar 09 '14 at 14:15
  • 1
    It didn't work for me. My image resource lost its transparency when I passed it through this function. – ban-geoengineering Dec 12 '14 at 12:32
  • H, ban-geoengineering! I am sorry to hear that. This function works fine for me. Have you been able to troubleshoot your problem? – DrupalFever Mar 02 '15 at 17:08
  • Hi, Flash Thunder! This answer is better if you need to use images with transparency. If you are OK with JPG only, the first answer is the simplest. What I am trying to say is that both answers are good. It only depends on your needs. Thanks for the vote, though! – DrupalFever Mar 02 '15 at 17:11
  • This (or the same flow anyway) is causing problems with transparency for me too. Just trying to narrow down the circumstances - my app can load indexed or truecolor images in different situations. – AnotherHowie May 30 '16 at 16:52
  • This does NOT properly handle transparency. Mine turned black. – Ryan Feb 22 '20 at 18:04
  • No you need to set the transparency of the background. – JSG Jun 18 '20 at 04:47
6

So, the solution found was in the comment, and this is an implementation of it in a Image management class :

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;
}
Leto
  • 2,594
  • 3
  • 24
  • 37
  • 2
    This actually doesn't clone an image resource, just copies bitmap-canvas to another new resource-object and ignores all other settings from original resource such as alpha-transparency, blending, some color settings, etc. When you try it with transparent PNG (or GIF) layer you'll more likely get black background instead of transparent color. With non-transparent images, this still works well. – Wh1T3h4Ck5 Sep 04 '15 at 14:14
1

Much simpler code, one line, handle transparency:

function clone_img_resource($img) {
    return imagecrop($img, array('x'=>0,'y'=>0,'width'=>imagesx($img),'height'=>imagesy($img)));
}
  • This does NOT properly handle transparency. Mine turned black. – Ryan Feb 22 '20 at 18:02
  • Ryan it always will until you set the transparency of the image made from imagecreatetruecolor. See my answer. – JSG Jun 18 '20 at 05:14
0

Ok so I needed to resize with transparency and I see how this question's answer and my question's answer are similar but not exactly the same so I shall post my answer.

I want to point out that I modified the answer from HERE to answer my personal need and the OP's question. (Which was about keeping transparency of the 1 and only image that will be copied/cloned/or resized)

In Addition: The transparency color will stay with that resource and apply it to other transparent images copied onto it. The workaround I used was that I used imagecopy() to copy the cloned file in my example to clear the allocated transparency color.

$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...

So for the function, it would go:

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

So use it as:

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

The original $image will be intact.

JSG
  • 390
  • 1
  • 4
  • 13