Reputation: 5846
When I try to crop transparant area of an image, its get to keep it original size, and the transparant areas are turned black.
If i run this code:
<?php
// Create a 300x300px transparant image with a 100px wide red circle in the middle
$i = imagecreatetruecolor(300, 300);
imagealphablending($i, FALSE);
imagesavealpha($i, TRUE);
$transparant = imagecolorallocatealpha($i, 0xDD, 0xDD, 0xDD, 0x7F);
imagefill($i, 0, 0, $transparant);
$red = imagecolorallocate($i, 0xFF, 0x0, 0x0);
imagefilledellipse($i, 150, 150, 100, 100, $red);
imagepng($i, "red_300.png");
// Crop away transparant parts and save
$i2 = imagecropauto($i, IMG_CROP_TRANSPARENT);
imagepng($i2, "red_crop_trans.png");
imagedestroy($i2);
// Crop away bg-color parts and save
$i2 = imagecropauto($i, IMG_CROP_SIDES);
imagepng($i2, "red_crop_sides.png");
imagedestroy($i2);
// clean up org image
imagedestroy($i);
I end up with a red_crop_trans.png
image that is a 300x300px
black image with an 100x100px
red circle in it.
And a red_crop_sides.png that is a 100x100px
black image with a 100x100px
red circle in it.
Why is red_crop_trans.png not croped to 100x100px
? and why is the background of both images black? And how do I crop them while keeping the transparace?
Upvotes: 8
Views: 3856
Reputation: 715
Here is a more detailed explanation to this IMG_CROP_TRANSPARENT flag and why it works and why it doesn't. It is actually related to the function imagecrop which has a very strange line of code if you look at the php source code, and is doing something like this
gdImagePtr gdImageCrop(gdImagePtr src, const gdRectPtr crop)
{
gdImagePtr dst;
int alphaBlendingFlag;
if (gdImageTrueColor(src)) {
dst = gdImageCreateTrueColor(crop->width, crop->height);
} else {
dst = gdImageCreate(crop->width, crop->height);
}
if (!dst) return NULL;
alphaBlendingFlag = dst->alphaBlendingFlag;
gdImageAlphaBlending(dst, gdEffectReplace);
gdImageCopy(dst, src, 0, 0, crop->x, crop->y, crop->width, crop->height);
gdImageAlphaBlending(dst, alphaBlendingFlag);
return dst;
}
imagecrop is called by imagecropauto after finding the edges to crop. And as you can see before calling the gdImageCopy, for some unknwon reason !!!, the developer called gdImageAlphaBlending(dst, gdEffectReplace);. What it does, it is replacing the alpha color to black. The alpha color is the one that you define when using imagecolortransparent function.
So now, if you want to use the flag IMG_CROP_TRANSPARENT, you need to set the alpha color since initially it is "-1", even if you created the image from PNG. Then the function will correctly crop the image, but will replace the transparent background with black, because of that line of code from C source code. So you cannot set the alpha color and so you cannot use IMG_CROP_TRANSPARENT in same time.
Instead, what is working, is by using the flag IMG_CROP_SIDES which in the C source code is calling the function gdGuessBackgroundColorFromCorners, which I guess is trying to find a transparent color on the edge of the image, but will not set the alpha color.
The mystery now remains, why the developer decided to replace the alpha color before copying the image while cropping.
Upvotes: 0
Reputation: 8773
It took me a while to figure out what exactly was going on. It turned out $i2 = imagecropauto($i, IMG_CROP_TRANSPARENT);
was returning false instead of true. According to the docs:
imagecropauto() returns FALSE when there is either nothing to crop or the whole image would be cropped.
So instead of IMG_CROP_TRANSPARENT
I used IMG_CROP_DEFAULT
:
Attempts to use IMG_CROP_TRANSPARENT and if it fails it falls back to IMG_CROP_SIDES.
This gave me the expected result. Now I didn't get any black backgrounds myself. But it's a known issue so the solution was quite easily found:
imagecolortransparent($i, $transparant); // Set background transparent
And that brings me to the final completed code:
<?php
// Create a 300x300px transparant image with a 100px wide red circle in the middle
$i = imagecreatetruecolor(300, 300);
imagealphablending($i, FALSE);
imagesavealpha($i, TRUE);
$transparant = imagecolorallocatealpha($i, 0xDD, 0xDD, 0xDD, 0x7F);
imagecolortransparent($i, $transparant); // Set background transparent
imagefill($i, 0, 0, $transparant);
$red = imagecolorallocate($i, 0xFF, 0x0, 0x0);
imagefilledellipse($i, 150, 150, 100, 100, $red);
imagepng($i, "red_300.png");
// Crop away transparant parts and save
$i2 = imagecropauto($i, IMG_CROP_DEFAULT); //Attempts to use IMG_CROP_TRANSPARENT and if it fails it falls back to IMG_CROP_SIDES.
imagepng($i2, "red_crop_trans.png");
imagedestroy($i2);
// Crop away bg-color parts and save
$i2 = imagecropauto($i, IMG_CROP_SIDES);
imagepng($i2, "red_crop_sides.png");
imagedestroy($i2);
// clean up org image
imagedestroy($i);
?>
Upvotes: 3