RSS

Transparent GIFs with PHP and GD

During development of my cSprites application I ran across an interesting problem when generating my sprites with GD. When dealling with transparent GIFs, GD does not take care of processing by default you must enable some specific settings to get it done correctly. The default behavior is that imagecreatefromgif adds a black background to the transparent gif. The way I solved this was a lot of trial, error and research.


Original Image

Here is the original Image I used. Initially I thought I could just use the basic image copy functions in GD and it would take care of the rest. Well this isn’t the case. This is the code I initially tried. Essentially creating a true color image and just using imagecopy to copy the gifs into the sprite.



 protected static function handleGif($spriteImages, $imgSize, $filePath){
    $sprite = imagecreatetruecolor($imgSize->right, $imgSize->bottom);

    foreach($spriteImages as $spriteImage){
      $tempImage = imagecreatefromgif($spriteImage->getPath());
      $position = $spriteImage->getPosition();
      imagecopy($sprite, $tempImage, $position->left, $position->top, 0, 0, $spriteImage->getWidth(), $spriteImage->getHeight());
      imagedestroy($tempImage);
    }

    ob_start();
    imagegif($sprite);
    $spriteOutput = ob_get_clean();
    imagedestroy($sprite);
    SpriteImageWriter::writeImageFile($spriteOutput, $filePath);
  }

First Try
Here is the output from the above code. You will notice that GD scrapped the transparency and opted for a black background. Back to the drawing board I guess. The next chunk of code shows the next iteration. Basically allocating the “black” color (which most gifs use as transparent) and setting the newly created image to use that as the transparent color.


protected static function handleGif($spriteImages, $imgSize, $filePath){
    $sprite = imagecreatetruecolor($imgSize->right, $imgSize->bottom);
    $trans_color = imagecolorallocatealpha($sprite, 0, 0, 0, 127);
    imagecolortransparent  ( $sprite, $transparent);

    foreach($spriteImages as $spriteImage){
      $tempImage = imagecreatefromgif($spriteImage->getPath());
      $position = $spriteImage->getPosition();
      imagecopy($sprite, $tempImage, $position->left, $position->top, 0, 0, $spriteImage->getWidth(), $spriteImage->getHeight());
      imagedestroy($tempImage);
    }

    ob_start();
    imagegif($sprite);
    $spriteOutput = ob_get_clean();
    imagedestroy($sprite);
    SpriteImageWriter::writeImageFile($spriteOutput, $filePath);
  }

Second TryAnd this is the output from the above code. As you can see we now have some transparency, however big chunks of the image have been made transparent. Specifically where the color in the image matched “black”, it was replaced by a transparent color. So last try now. Here is the final code, which first involves setting some flags that tell it to maintain the transparency. Then create a transparent rectangle over the whole image and next set the image color to transparent. So a little more overhead however the results are great.


protected static function handleGif($spriteImages, $imgSize, $filePath){
    $sprite = imagecreatetruecolor($imgSize->right, $imgSize->bottom);
    imagealphablending($sprite, false);
    imagesavealpha($sprite,true);
    $transparent = imagecolorallocatealpha($sprite, 255, 255, 255, 127);
    imagefilledrectangle($sprite, 0, 0, $imgSize->right, $imgSize->bottom, $transparent);
    imagecolortransparent  ( $sprite, $transparent);

    foreach($spriteImages as $spriteImage){
      $tempImage = imagecreatefromgif($spriteImage->getPath());
      $position = $spriteImage->getPosition();
      imagecopy($sprite, $tempImage, $position->left, $position->top, 0, 0, $spriteImage->getWidth(), $spriteImage->getHeight());
      imagedestroy($tempImage);
    }

    ob_start();
    imagegif($sprite);
    $spriteOutput = ob_get_clean();
    imagedestroy($sprite);
    SpriteImageWriter::writeImageFile($spriteOutput, $filePath);
  }

The above code will do the job of copying the transparent GIFs for my sprite generation. However one issue I ran into when generating my sprites is that when I had a lot of different GIFs in one sprite there was some small but noticeable dithering. I assume this is because while each individual GIF can use its own color pallete, when you combine a lot of them they can all only grab from the generated pallete.

  • Share/Bookmark

Related posts:

  1. YAML – My Favorite Non-Markup Language I have been using YAML for awhile and decided I’d...



6 Responses to “Transparent GIFs with PHP and GD”

  1. drifter says:

    thanks a lot for this solution, it works. but.. what about resizing? after using imageCopyResampled i got some dirts, like here:

    http://drifter.flexx.pl/gif_resampled.gif

    i don’t know GD well enough to guess why..

  2. Thanks for doing the work of trial/error. I hate doing something like that. ;)

    I am actually using some of your ideas in a symfony plugin of mine, called sfFilebasePlugin, for image processing.

    Greetings to mongolia
    joshi

  3. This worked awesome. One thing was that the browser printed a bunch of gobbly gook while it executed the script:

    ���x�+��%A>�”H”��)���c����G(�й4Ё&x>��7 R(��r�X�!H �;B���( I(�)Ȁ/h�*�Z� 9��S��`��B��Gx�$T�� i��&X�3�X�\

    any idea why it would have done that??

  4. turns out that the imagegif($sprite1); function just needed its second argument.

  5. Thanks alot, saved my day!

    You can use the imagecopyresampled function, though, if you do not need to output as gif file, but (as I do) as PNG with transparency.

    Best Regards,
    Dave

Leave a Reply