PHP-GD: Resize Transparent Image PNG & GIF

Written on July 10, 2008 – 10:21 pm | by vandai |

By default, you will get black background if you resize a transparent image. To fix it, you need set alpha channel imagecolorallocatealpha to 127.
With imagecolorallocatealpha, it will allocate a color for an image.

Usage:
int imagecolorallocatealpha ( resource image, int red, int green, int blue, int alpha)

From PHP manual:
imagecolorallocatealpha() behaves identically to imagecolorallocate() with the addition of the transparency parameter alpha which may have a value between 0 and 127. 0 indicates completely opaque while 127 indicates completely transparent.
Returns FALSE if the allocation failed.

Before using it, you must set to false the blending mode for an image and set true the flag to save full alpha channel information.

Example:

  1. <?
  2. $newImg = imagecreatetruecolor($nWidth, $nHeight);
  3. imagealphablending($newImg, false);
  4. imagesavealpha($newImg,true);
  5. $transparent = imagecolorallocatealpha($newImg, 255, 255, 255, 127);
  6. imagefilledrectangle($newImg, 0, 0, $nWidth, $nHeight, $transparent);
  7. imagecopyresampled($newImg, $im, 0, 0, 0, 0, $nWidth, $nHeight, $imgInfo[0], $imgInfo[1]);
  8. ?>


Full source code for resizing image:

filename: imageresize.php
  1. <?
  2. function resize($img, $w, $h, $newfilename) {
  3.  
  4.  //Check if GD extension is loaded
  5.  if (!extension_loaded('gd') && !extension_loaded('gd2')) {
  6.   trigger_error("GD is not loaded", E_USER_WARNING);
  7.   return false;
  8.  }
  9.  
  10.  //Get Image size info
  11.  $imgInfo = getimagesize($img);
  12.  switch ($imgInfo[2]) {
  13.   case 1: $im = imagecreatefromgif($img); break;
  14.   case 2: $im = imagecreatefromjpeg($img);  break;
  15.   case 3: $im = imagecreatefrompng($img); break;
  16.   default:  trigger_error('Unsupported filetype!', E_USER_WARNING);  break;
  17.  }
  18.  
  19.  //If image dimension is smaller, do not resize
  20.  if ($imgInfo[0] <= $w && $imgInfo[1] <= $h) {
  21.   $nHeight = $imgInfo[1];
  22.   $nWidth = $imgInfo[0];
  23.  }else{
  24.                 //yeah, resize it, but keep it proportional
  25.   if ($w/$imgInfo[0] > $h/$imgInfo[1]) {
  26.    $nWidth = $w;
  27.    $nHeight = $imgInfo[1]*($w/$imgInfo[0]);
  28.   }else{
  29.    $nWidth = $imgInfo[0]*($h/$imgInfo[1]);
  30.    $nHeight = $h;
  31.   }
  32.  }
  33.  $nWidth = round($nWidth);
  34.  $nHeight = round($nHeight);
  35.  
  36.  $newImg = imagecreatetruecolor($nWidth, $nHeight);
  37.  
  38.  /* Check if this image is PNG or GIF, then set if Transparent*/  
  39.  if(($imgInfo[2] == 1) OR ($imgInfo[2]==3)){
  40.   imagealphablending($newImg, false);
  41.   imagesavealpha($newImg,true);
  42.   $transparent = imagecolorallocatealpha($newImg, 255, 255, 255, 127);
  43.   imagefilledrectangle($newImg, 0, 0, $nWidth, $nHeight, $transparent);
  44.  }
  45.  imagecopyresampled($newImg, $im, 0, 0, 0, 0, $nWidth, $nHeight, $imgInfo[0], $imgInfo[1]);
  46.  
  47.  //Generate the file, and rename it to $newfilename
  48.  switch ($imgInfo[2]) {
  49.   case 1: imagegif($newImg,$newfilename); break;
  50.   case 2: imagejpeg($newImg,$newfilename);  break;
  51.   case 3: imagepng($newImg,$newfilename); break;
  52.   default:  trigger_error('Failed resize image!', E_USER_WARNING);  break;
  53.  }
  54.    
  55.    return $newfilename;
  56. }
  57. ?>

Script usage:

filename showimage.php
  1. <?
  2. include_once("resizeimage.php");
  3. $image = "some/dir/image.png"; // File image location
  4. $newfilename = "thumb_image.png"; // New file name for thumb
  5. $w = 100;
  6. $h = 100;
  7.  
  8. $thumbnail = resize($img, $w, $h, $newfilename);
  9.  
  10. echo "<img src='".$thumbnail."'>";
  11. ?>

No, i’m not provide any downloadable source-code.
Just copy-paste this code, and use it well.

  1. 42 Responses to “PHP-GD: Resize Transparent Image PNG & GIF”

  2. Avatar

    By hendry on Jul 19, 2008 | Reply

    wow just simple, it’s work !!! thanks

  3. Avatar

    By joy on Jul 24, 2008 | Reply

    wow nice!!!

  4. Avatar

    By rivaldo on Jul 25, 2008 | Reply

    Fantastic job!

  5. Avatar

    By kurroman on Jul 31, 2008 | Reply

    First, my english is a little… :)

    I have a problem. Im trying to open a png file with a transparent object inside (not all, just the border). Then i write some text and save the file as another .png file.

    The problem is that de quality of the object border is too bad (¿pixeled?). How can i fix that?

  6. Avatar

    By vandai on Jul 31, 2008 | Reply

    have u tried this code?
    i have the same problem with you before.
    the image quality is sooo bad.

    but this code has fix it.

  7. Avatar

    By Christopher on Aug 8, 2008 | Reply

    Many thanks! Just the help I needed.

  8. Avatar

    By TAF on Aug 23, 2008 | Reply

    The script gets hinkey if you have a file that is smaller in height than the minimum, but longer in width… you end up resizing huge in width to get the right height.

    It needs to resize down by which ever length is too long, or both if they are both too long.

    I HAVE AN IMPROVEMENT THAT FIXES THIS:

    //If image dimension is smaller, do not resize
    if ($imgInfo[0] <= $w && $imgInfo[1] = $w && $imgInfo[1] <= $h) {
    $nWidth = $w;
    $nHeight = $imgInfo[1]*($w/$imgInfo[0]);
    }else{
    //if h larger but not w, resize it, but keep it proportional
    if ($imgInfo[0] = $h) {
    $nWidth = $imgInfo[0]*($h/$imgInfo[1]);
    $nHeight = $h;
    }else{
    //if both w and h are larger, resize it, but keep it proportional
    if ($w/$imgInfo[0] > $h/$imgInfo[1]) {
    $nWidth = $w;
    $nHeight = $imgInfo[1]*($w/$imgInfo[0]);
    }else{
    $nWidth = $imgInfo[0]*($h/$imgInfo[1]);
    $nHeight = $h;
    }
    }
    }
    }
    $nWidth = round($nWidth);
    $nHeight = round($nHeight);

  9. Avatar

    By ghprod on Aug 29, 2008 | Reply

    this is one i’m looking for :)

    Thnx for this great code!

  10. Avatar

    By TAF on Aug 29, 2008 | Reply

    Ahhh… just realised through lotsa testing that the line:

    if ($w/$imgInfo[0] > $h/$imgInfo[1]) {

    Should be

    if ($w/$imgInfo[0] < $h/$imgInfo[1]) {

  11. Avatar

    By infi on Sep 16, 2008 | Reply

    Gif -> Png transparent conversion failed.

    From gif files it is not working.. It is making a gif file, even if I selected PNG. And it is not transparent.

  12. Avatar

    By infi on Sep 16, 2008 | Reply

    Sorry, just had to removed the switches and directly let it to open as gif and save as png. It worked really fine. Just removed some if-s. :)

  13. Avatar

    By femReikeSkic on Sep 23, 2008 | Reply

    thats for sure, bro

  14. Avatar

    By injeliunfonge on Oct 6, 2008 | Reply

    thats it, man

  15. Avatar

    By Oliver on Oct 10, 2008 | Reply

    Is anyone having a problem with transparent gifs background coming through black?

    Specifically, this:
    http://upload.wikimedia.org/wikipedia/commons/8/8d/Klocka_transparent.GIF

  16. Avatar

    By vandai on Oct 10, 2008 | Reply

    @oliver:
    i’m having that problem too before.
    but after using this code, the problem has gone.

    try using this code without any modifying first.

  17. Avatar

    By Oliver on Oct 10, 2008 | Reply

    Good Day,

    I tried copying the code, without any changes, and uploading it, but it’s still black in the background. Can you try locally with that image:

    http://upload.wikimedia.org/wikipedia/commons/8/8d/Klocka_transparent.GIF

  18. Avatar

    By Stefan on Oct 10, 2008 | Reply

    Hi Oliver,
    I have the same problem as you. I copied the code, didn’t make changes and it’s still black in the background. No idea what to do. Does anyone have an idea?
    Stefan

  19. Avatar

    By TAF on Oct 10, 2008 | Reply

    I had the same issue, so (since I really don’t need it to be transparent) I forced it not to be transparent and just preserve whatever color the trasparent area was started as. Like transparent green shows green without transparency.

    I believe the acctual issue is the fact that the transparent color is mandatorily white in this code, and none of my gifs ever end up with pure white as the transparent color after I optimize them. (Just my guess on the reason though.)

  20. Avatar

    By Oliver on Oct 10, 2008 | Reply

    It has to do with the imagecreatetruecolor call. This call does not work with gifs, as a gif only has 256 colors. I tried to convert the gif to png, then resize it, and then re-convert back to gif, but that didn’t work. Anyone have any thoughts?

  21. Avatar

    By Oliver on Oct 10, 2008 | Reply

    Hmmm, can you go into more detail though? My prob is I have a cms where users are uploading pics. Most of the time they’re non-transparent jpegs, gifs, or pngs, in which case it’s fine (even though the resizing/resampling of gifs loses alot of the quality).
    If you use imagecreate instead of imagecreatetruecolor, you’ll get the transparent background, but like I said, the quality is awful.

    If you’ve got image magick installed, you can use this:

    $image = new Imagick($source);
    $image->resizeImage($nWidth,$nHeight,imagick::FILTER_LANCZOS,1);
    $image->writeImage($destination);

    It makes it so the quality is slightly better, and still transparent. Only run that code if it’s a gif though; the qaulity goes down if it’s a png or jpeg.

    I’m still looking for a specific function which will improve gif quality when it gets resized. I believe the route I need to go is to convert it to a png, resize, resample, get rid of opacity for the images, and the resave as gif.

    Thoughts?

  22. Avatar

    By TAF on Oct 10, 2008 | Reply

    Here is the code section that doesn’t do transparent on the gif… it splits the IF PNG and the IF GIF into two sections:

    /* Check if this image is PNG , then set if Transparent*/
    if($imgInfo[2] == 3){
    imagealphablending($newImg, false);
    imagesavealpha($newImg,true);
    $transparent = imagecolorallocatealpha($newImg, 255, 255, 255, 127);
    imagefilledrectangle($newImg, 0, 0, $nWidth, $nHeight, $transparent);
    }
    /* Check if this image is GIF , then DONT transparent */
    if($imgInfo[2] == 1){
    imagealphablending($newImg, true);
    imagesavealpha($newImg,false);
    $transparent = imagecolorallocatealpha($newImg, 255, 255, 255, 127);
    imagefilledrectangle($newImg, 0, 0, $nWidth, $nHeight, $transparent);
    }
    imagecopyresampled($newImg, $im, 0, 0, 0, 0, $nWidth, $nHeight, $imgInfo[0], $imgInfo[1]);

  23. Avatar

    By TAF on Oct 10, 2008 | Reply

    Oh! You probably will need this alteration too:

    //Get Image size info
    $imgInfo = getimagesize($img);
    switch ($imgInfo[2]) {
    case 1: $im = imagecreatefromgif($img); break;
    case 2: $im = imagecreatefromjpeg($img); break;
    case 3: $im = imagecreatefrompng($img); break;
    default: $im = imagecreatefrombmp($img); break; // If it doesn’t fit a previous type, try it as a BMP
    }

    The BMP section is some custom function as below:
    <? // Accept BMP FILES
    function ConvertBMP2GD($src, $dest = false) {
    if(!($src_f = fopen($src, “rb”))) {
    trigger_error(”Can’t open $src”, E_WARNING);
    return false;
    }
    if(!($dest_f = fopen($dest, “wb”))) {
    trigger_error(”Can’t open $dest”, E_WARNING);
    return false;
    }
    $header = unpack(”vtype/Vsize/v2reserved/Voffset”, fread($src_f, 14));
    $info =
    unpack(”Vsize/Vwidth/Vheight/vplanes/vbits/Vcompression/Vimagesize/Vxres/Vy­r
    es/Vncolor/Vimportant”, fread($src_f, 40));

    extract($info);
    extract($header);

    if($type != 0×4D42) { // signature “BM”
    return false;
    }

    $palette_size = $offset - 54;
    $ncolor = $palette_size / 4;
    $gd_header = “”;
    // true-color vs. palette
    $gd_header .= ($palette_size == 0) ? “\xFF\xFE” : “\xFF\xFF”;
    $gd_header .= pack(”n2″, $width, $height);
    $gd_header .= ($palette_size == 0) ? “\x01″ : “\x00″;
    if($palette_size) {
    $gd_header .= pack(”n”, $ncolor);
    }
    // no transparency
    $gd_header .= “\xFF\xFF\xFF\xFF”;

    fwrite($dest_f, $gd_header);

    if($palette_size) {
    $palette = fread($src_f, $palette_size);
    $gd_palette = “”;
    $j = 0;
    while($j > 3;
    $scan_line_align = ($scan_line_size & 0×03) ? 4 - ($scan_line_size & 0×03)
    : 0;

    if($bits == 24) {
    $j = 0;
    $k = 1;
    $m = 2;
    $function = ‘return “‘;
    while($j < $scan_line_size) {
    $function .= “\\{\$s\{$m}}\{\$s\{$k}}\{\$s\{$j}}”;
    $j += 3;
    $k += 3;
    $m += 3;
    }
    $function .= ‘”;’;
    }
    else if($bits == 32) {
    $function = ‘return “‘;
    $j = 0;
    $k = 1;
    $m = 2;
    $n = 3;
    while($j < $scan_line_size) {
    $function .= “\\{\$s\{$m}}\{\$s\{$k}}\{\$s\{$j}}”;
    $j += 4;
    $k += 4;
    $m += 4;
    $n += 4;
    }
    $function .= ‘”;’;
    }
    else if($bits == 8) {
    $function = ‘return $s;’;
    }
    else if($bits == 4) {
    $j = 0;
    $function = ”;
    while($j >4);”;
    $function .= “\$a[]=chr(\$b&0×0F);”;
    $j++;
    }
    $function .= “return substr(implode(\$a), 0, \$width);”;
    }
    else if($bits == 1) {
    $j = 0;
    $function = ”;
    while($j < $scan_line_size) {
    $function .= “\$b=ord(\$s\{$j});”;
    $function .= “\$a[]=chr((int)((\$b&0×80)!=0));”;
    $function .= “\$a[]=chr((int)((\$b&0×40)!=0));”;
    $function .= “\$a[]=chr((int)((\$b&0×20)!=0));”;
    $function .= “\$a[]=chr((int)((\$b&0×10)!=0));”;
    $function .= “\$a[]=chr((int)((\$b&0×08)!=0));”;
    $function .= “\$a[]=chr((int)((\$b&0×04)!=0));”;
    $function .= “\$a[]=chr((int)((\$b&0×02)!=0));”;
    $function .= “\$a[]=chr((int)((\$b&0×01)!=0));\n”;
    $j++;
    }
    $function .= “return substr(implode(\$a), 0, \$width);”;
    }

    $f = create_function(’$s, $width’, $function);

    for($i = 0, $l = $height - 1; $i varname = $url["host"];
    $this->position = 0;
    $this->buffer = @$GLOBALS[$this->varname];
    return true;
    }

    function stream_close()
    {
    $GLOBALS[$this->varname] = $this->buffer;
    }

    function stream_read($count)
    {
    $ret = substr($this->buffer, $this->position, $count);
    $this->position += strlen($ret);
    return $ret;
    }

    function stream_write($data)
    {
    $this->buffer .= $data;
    $this->position += strlen($data);
    return strlen($data);
    }

    function stream_tell()
    {
    return $this->position;
    }

    function stream_eof()
    {
    return $this->position >= strlen($this->buffer);
    }

    function stream_stat() {
    return array( ’size’ => strlen($this->buffer) );
    }

    }

    function imagecreatefrombmp($filename) {
    // use a memory stream instead of a temp file
    // where possible
    if(function_exists(’stream_wrapper_register’)
    && stream_wrapper_register(”mem”, “MemoryStream”)) {
    $tmp_name = “mem://GD_TMP_FILE”;
    $del_tmp = false;
    }
    else {
    $tmp_name = tempnam(”/tmp”, “GD”);
    $del_tmp = true;
    }
    if(ConvertBMP2GD($filename, $tmp_name)) {
    $img = imagecreatefromgd($tmp_name);
    if($del_tmp) {
    unlink($tmp_name);
    }
    return $img;
    } return false;

    }
    ?>

    and the Save section to handle the BMP looks like this:

    $temp_array1 = explode(”.”, $img);
    if (($temp_array1[1] != “bmp”)&&($temp_array1[1] != “BMP”)){
    //Generate the file, and rename it to $newfilename
    switch ($imgInfo[2]) {
    case 1: imagegif($newImg,$newfilename); break;
    case 2: imagejpeg($newImg,$newfilename); break;
    case 3: imagepng($newImg,$newfilename); break;
    default: trigger_error(’Failed resize image!’, E_USER_WARNING); break;
    }
    }else{
    imagepng($newImg,$newfilename); // Force it to save as a png type if it was a bmp but leave the .bmp extention
    }

  24. Avatar

    By TAF on Oct 10, 2008 | Reply

    Err… it stuck in a smile where it is supposed to be ‘8 )’

  25. Avatar

    By TAF on Oct 10, 2008 | Reply

    Here also is a sweet function that may be of use:

    <? // Rotate
    function rotateit($img, $angle) {
    //Set the new file name the same as the old file name
    $newfilename = $img;

    //Get Image size info
    $imgInfo = getimagesize($img);
    switch ($imgInfo[2]) {
    case 1: $im = imagecreatefromgif($img); break;
    case 2: $im = imagecreatefromjpeg($img); break;
    case 3: $im = imagecreatefrompng($img); break;
    default: trigger_error(’Unsupported filetype!’, E_USER_WARNING); break;
    }

    // .. what colour will the uncovered bits be?
    $bgColour = 0xFFFFFF; // red
    // rotate the image by $angle degrees
    $newImg = imagerotate($im, $angle, $bgColour);

    //Generate the file, and rename it to $newfilename
    switch ($imgInfo[2]) {
    case 1: imagegif($newImg,$newfilename); break;
    case 2: imagejpeg($newImg,$newfilename); break;
    case 3: imagepng($newImg,$newfilename); break; // This will rotate any that are BMP but are loaded up into PNG Type
    default: trigger_error(’Failed to rotate image!’, E_USER_WARNING); break;
    }

    echo “Image Rotated: ” . $newfilename . ” “;
    return $newfilename;
    }
    ?>

  26. Avatar

    By Oliver on Oct 10, 2008 | Reply

    So you’re not using the transparent gif?
    So for example, if someone uploaded this file, what would your code do?

    http://upload.wikimedia.org/wikipedia/commons/8/8d/Klocka_transparent.GIF

  27. Avatar

    By TAF on Oct 11, 2008 | Reply

    the transparent part would be gray like it looks if you open it in an editor program.

    See the slight gray in the resize here:
    http://cecolts.com/ofiles/Klocka_transparent_S.gif

  28. Avatar

    By Oliver on Oct 11, 2008 | Reply

    hmmmm
    there’s no way around that i guess eh?

  29. Avatar

    By TAF on Oct 11, 2008 | Reply

    Not that I see unless you use the orrigional code and make sure all your transparent areas are pure white.

  30. Avatar

    By Oliver on Oct 11, 2008 | Reply

    That sucks.
    What I don’t get, is I can accomplish the task in photoshop. I take the 300×300 gif, turn it into a png, resize it to 72×72, then turn it back to a gif, and save it.

    Transparency is preserved, resize quality is perfect. There must be a way somehow in php. I’ve been looking around with image magick, but can’t seem to find it (nor is this documented anywhere online, oddly enough; gif resizing is, but not the kind of quality maintenance you get from photoshop)

  31. Avatar

    By Oliver on Oct 12, 2008 | Reply

    I’m still stuck on trying to get gifs to resize perfectly. Thats wsweet about the bmp’s though. I’ll test that out and see how they resize :)

  32. Avatar

    By Dan on Oct 25, 2008 | Reply

    Finally, someone who has got this right. This code can resize a png with aphablending properly. I’ve been looking for this for so long, and have tried around 6 examples. Well done and thank you!

  33. Avatar

    By Dan on Oct 25, 2008 | Reply

    The only thing I would like is to be able to select a max width (trying to add this myself). If you select 120,120 in the function you get an image which might be 120×147 for example, too big for my purposes.

  34. Avatar

    By TAF on Oct 25, 2008 | Reply

    As Posted Above (with later correction), reposted for Dan.
    This section does what you need.

    //If image dimension is smaller, do not resize
    if ($imgInfo[0] <= $w && $imgInfo[1] = $w && $imgInfo[1] <= $h) {
    $nWidth = $w;
    $nHeight = $imgInfo[1]*($w/$imgInfo[0]);
    }else{
    //if h larger but not w, resize it, but keep it proportional
    if ($imgInfo[0] = $h) {
    $nWidth = $imgInfo[0]*($h/$imgInfo[1]);
    $nHeight = $h;
    }else{
    //if both w and h are larger, resize it, but keep it proportional
    if ($w/$imgInfo[0] < $h/$imgInfo[1]) {
    $nWidth = $w;
    $nHeight = $imgInfo[1]*($w/$imgInfo[0]);
    }else{
    $nWidth = $imgInfo[0]*($h/$imgInfo[1]);
    $nHeight = $h;
    }
    }
    }
    }
    $nWidth = round($nWidth);
    $nHeight = round($nHeight);

  35. Avatar

    By willowdan on Dec 12, 2008 | Reply

    Hi,

    Many thanks for the function … I’ll be using it later in ePinoyBiz.com/directory …

  36. Avatar

    By siapa_aku on Dec 24, 2008 | Reply

    Finally i found it….tahnk mate :)

  37. Avatar

    By darwin on Jan 5, 2009 | Reply

    thanks for your tutorial :)

  38. Avatar

    By daniel on Jan 12, 2009 | Reply

    yes! just what i was looking for. many thanks.

  39. Avatar

    By Mares on Feb 26, 2009 | Reply

    Man you rock!!!! Thank you very very much for your script!!!

  40. Avatar

    By Adrian Mummey on Mar 16, 2009 | Reply

    One thing about the transparent gifs, I am pretty sure you cannot preserve transparency AND use imagecopyresampled. I am having the same problem with black background, however changing imagecopyresampled to imagecopyresized fixes transparency, but gives a crappy resize. Am investigating this further to see if there is a good solution.

  41. Avatar

    By meme on Mar 27, 2009 | Reply

    I currently have all my functions setup to resize whatever size I need - jpg mime type is cool - but I get jagged edges - this is wher IM HOPING this nifty lil script can save my ass - but for the life of me I can’t seem to figure how to implemant it - I copied and pasted and got tons of warnings.

    [php]
    Warning: Unsupported filetype! in C:\wamp\www\cool\functions\fns_photo.php on line 228

    Warning: imagecreatetruecolor() [function.imagecreatetruecolor]: Invalid image dimensions in C:\wamp\www\cool\functions\fns_photo.php on line 268

    Warning: imagecopyresampled(): supplied argument is not a valid Image resource in C:\wamp\www\cool\functions\fns_photo.php on line 286

    Warning: Failed resize image! in C:\wamp\www\cool\functions\fns_photo.php on line 300
    [/php]

    it seems It;s not getting the image I need to set - but how do I do that…

    Greatly appreciated if anyone can help

    thanks :)

  42. Avatar

    By meme on Mar 27, 2009 | Reply

    sorry jagged edges with png and gif

  43. Avatar

    By KattyBlackyard on Jun 15, 2009 | Reply

    The best information i have found exactly here. Keep going Thank you

Post a Comment

About Me

Here I'll share my knowledge, discovery and experience related to my hobby and work. Most articles on this site are related to daily life, hobbies, programming, and linux. More

Want to subscribe?

 Subscribe in a reader
Find entries :