Problems with GD: Solved
Tuesday, October 11th, 2005In a recent project, I had the joy (make that pain) of using GD a lot. The project was an update to the a facial composite tool for Identikit. The new code isn’t live yet, its still in final testing, but its all done for me except for a bit of final bug fixing.
Anyway the app is written in Flash and integrates with PHP for things like saving files to the database or creating a jpeg for the user to save. So what I have is a bunch of transparent pngs that I composite together to make the final sketch. Just like you would do by hand if you had an old school version of this from little paper cutouts.
The problem I ran into with GD is it doesn’t repect an images transparency. So my basic test of this is, open an transparent Image and resize then output the image.
You take the starting Image (shown on and off a colored background so you can see the transparency)
|
|
Next we resize it, some code for this is shown below:
<?php
// load in the source image
$im = imagecreatefrompng('sample1.png');
imagesavealpha($target,true);
// get its width and height
$imageWidth = imagesx($im);
$imageHeight = imagesy($im);
// were doubling in size
$targetWidth = $imageWidth*2;
$targetHeight = $imageHeight*2;
// create a target im
$target = imagecreatetruecolor($targetWidth,$targetHeight);
imagesavealpha($target,true);
// fill the image with transparency
$trans = imagecolorallocatealpha($target,255,255,255,127);
imagefill($target,0,0,$trans);
// copy with resize to the target
if (isset($_GET['resample'])) {
imagecopyresampled($target,$im,0,0,0,0,$targetWidth,$targetHeight,$imageWidth,$imageHeight);
}
else {
imagecopyresized($target,$im,0,0,0,0,$targetWidth,$targetHeight,$imageWidth,$imageHeight);
}
// output the image as a png
header('Content-Type: image/png');
imagepng($target);
?>
Output from this is shown below, first using resize then using resample
As you can see the background is still alpha transparent but the lenses are now black. I hope im just missing some flag, but in that case someone should really add a makeBrokenGDWorkLikeIWouldExpect flag so I don’t have to find the right combination of them to make things work. After all if I shelled out to ImageMagick convert to do the resize it would just do the right thing.
The next step would be to do some compositing, but you wouldn’t see it anyway since the eyes go below the glasses and they are black.
Anyhow feedback on what im doing wrong here would be nice, or if this just doesn’t work what I need to make this a good bug report.
Any how this example doesn’t have the problems I had before, that just had a simple bug in it from me filling in the wrong order.
Anyhow I did have similar problems when working with the compositing code for this app, im guessing it was caused by a similar mistake, but i’d have to read through commit logs to be sure, and that doesn’t sound like much fun. Suffice it too say, the equivalent code using Imagemagick on the command line is a lot easier to understand though not much easier to debug.
Anyhow the second part item after resizing an image is adjusting its properties. Shading the image, playing with gamma works pretty well, flipping it if needed (this would be nice to have as part of the GD api but its quite easy to write, This manual comment has one), and then adjusting the transparency of the image (Imagecopymerge works well for that).
A sample output would be:
And for a quality comparison, the same thing done shelling out to composite
The main things I would take out of this is that the API for GD is way to low of a level for normal use, so you’ll want to look into a wrapper (there are some options in PEAR but none with a stable release). There are also quality issues with GD when making images larger, but I don’t want to see new features like cubic interpolation added until the api to use them is reasonable.
Code for GD Compositing
<?php
// create a target im
$target = imagecreatetruecolor(500,200);
imagesavealpha($target,true);
imagealphablending($target,true);
// fill the image with transparency
$trans = imagecolorallocatealpha($target,255,255,255,127);
imagefill($target,0,0,$trans);
// copy the eyes in place first
// load in the source image
$im = imagecreatefrompng('sample2.png');
imagesavealpha($im,true);
imagealphablending($im,true);
// get its width and height
$imageWidth = imagesx($im);
$imageHeight = imagesy($im);
// were doubling in size
$targetWidth = $imageWidth*2;
$targetHeight = $imageHeight*2;
imagecopyresampled($target,$im,2,26,0,0,$targetWidth,$targetHeight,$imageWidth,$imageHeight);
imagedestroy($im);
// copy the glasses on top of that
// load in the source image
$im = imagecreatefrompng('sample1.png');
imagesavealpha($im,true);
imagealphablending($im,true);
// get its width and height
$imageWidth = imagesx($im);
$imageHeight = imagesy($im);
// were doubling in size
$targetWidth = $imageWidth*2.2;
$targetHeight = $imageHeight*2.2;
imagecopyresampled($target,$im,0,0,0,0,$targetWidth,$targetHeight,$imageWidth,$imageHeight);
imagedestroy($im);
// output the image as a png
header('Content-Type: image/png');
imagepng($target);
?>
Code for ImageMagick compositing
<?php
header('Content-type: image/png');
passthru('composite -geometry +2+26 sample2.png -resize 200% back.png - | composite sample1.png -resize 220% - - ');
?>








