ID: 23815
Comment by: steve dot denim at redmonkey dot org
Reported By: bjorn at smokingmedia dot com
Status: Assigned
Bug Type: GD related
Operating System: Linux pluto 2.4.18lvm-r1
PHP Version: 5.2.9
Assigned To: pajoye
New Comment:
I have run into the same problem and can reproduce the example from
checat at yandex dot ru.
I have also provided additional examples and a patch for the solution I
have come with.
For the examples I've used two image files 'tux.png' for the background
(destination) image and 'ff-logo-sm.png' for the overlay (source) image,
these can be found at www.redmonkey.org/php-bug-23815/tux.png and
www.redmonkey.org/php-bug-23815/ff-logo-sm.png respectively.
If I run these images through imagecopy() with the following code..
$bg = imagecreatefrompng('tux.png');
$over = imagecreatefrompng('ff-logo-sm.png');
imagealphablending($bg, true);
imagesavealpha($bg, true);
imagecopy($bg, $over, 276, 300, 0, 0, 123, 119);
imagepng($bg, 'tux-fox-imagecopy.png');
The alpha channels of both images seem to be handleed and
merged/blended in a way that I think most users would expect, the
resulting image can be found at
www.redmonkey.org/php-bug-23815/tux-fox-imagecopy.png
However, if I run the two images through imagecopymerge with the
following code..
$bg = imagecreatefrompng('tux.png');
$over = imagecreatefrompng('ff-logo-sm.png');
imagealphablending($bg, true);
imagesavealpha($bg, true);
imagecopymerge($bg, $over, 276, 300, 0, 0, 123, 119, 100);
imagepng($bg, 'tux-fox-imagecopymerge-100-without-patch.png');
The resulting image is not what I would expect, in this case, it seems
that the alpha channel of the destination image is maintained but the
alpha channel of the source image is completely ignored, the resulting
image can be found at
www.redmonkey.org/php-bug-23815/tux-fox-imagecopymerge-100-without-patch.png
Applying a 50% reduction in opacity..
$bg = imagecreatefrompng('tux.png');
$over = imagecreatefrompng('ff-logo-sm.png');
imagealphablending($bg, true);
imagesavealpha($bg, true);
imagecopymerge($bg, $over, 276, 300, 0, 0, 123, 119, 50);
imagepng($bg, 'tux-fox-imagecopymerge-50-without-patch.png');
Also has the same issue, the resulting image can be found at
www.redmonkey.org/php-bug-23815/tux-fox-imagecopymerge-50-without-patch.png
After applying my patch the results from imagcopymerge are more inline
with what I persoanlly would expect in that the alpha channels of both
images are maintained during the copy/merge process.
With the following code..
$bg = imagecreatefrompng('tux.png');
$over = imagecreatefrompng('ff-logo-sm.png');
imagealphablending($bg, true);
imagesavealpha($bg, true);
imagecopymerge($bg, $over, 276, 300, 0, 0, 123, 119, 100);
imagepng($bg, 'tux-fox-imagecopymerge-100-with-patch.png');
The resulting image can be viewed at
www.redmonkey.org/php-bug-23815/tux-fox-imagecopymerge-100-with-patch.png
And with the following code..
$bg = imagecreatefrompng('tux.png');
$over = imagecreatefrompng('ff-logo-sm.png');
imagealphablending($bg, true);
imagesavealpha($bg, true);
imagecopymerge($bg, $over, 276, 300, 0, 0, 123, 119, 50);
imagepng($bg, 'tux-fox-imagecopymerge-50-with-patch.png');
The resulting image can be viewed at
www.redmonkey.org/php-bug-23815/tux-fox-imagecopymerge-50-with-patch.png
The patch as applied to ext/gd/libgd/gd.c is as follows.....
--- php-5.3.0/ext/gd/libgd/gd.c 2009-05-27 08:17:54.000000000 +0100
+++ php-5.3.0-build/ext/gd/libgd/gd.c 2009-07-19 22:28:37.312702552
+0100
@@ -2255,6 +2255,83 @@
int ncR, ncG, ncB;
toy = dstY;
+ if (pct == 100) {
+ /* no opacity adjustment required pass through to gdImageCopy()
*/
+ gdImageCopy(dst, src, dstX, dstY, srcX, srcY, w, h);
+ return;
+ }
+
+ if (pct == 0) {
+ /* 0% opacity? nothing needs to be done */
+ return;
+ }
+
+ if (src->trueColor && dst->trueColor) {
+ /* support for maintaining the alpha (transparency) of both
source
and
+ * destination images (assuming they are true colour) while
opacity
blending.
+ */
+ gdImagePtr srcback;
+ int ca, cr, cg, cb;
+ float na;
+ float ac;
+
+ /* we adjust the alpha levels on a copy of the source image, the
copy
+ * only needs to be as large as the crop area if there is one
+ */
+ srcback = gdImageCreateTrueColor (w, h);
+ if (srcback==NULL) {
+ return;
+ }
+
+ gdImageAlphaBlending(srcback, 0);
+ gdImageSaveAlpha(srcback, 1);
+ gdImageCopy(srcback, src, 0, 0, srcX, srcY, w, h);
+
+ /* we need to loop through the src image to get the max
transparency
level */
+ int mt = 0;
+
+ for (y = 0; y < h; y++) {
+ for (x = 0; x < w; x++) {
+ c = gdImageGetTrueColorPixel (srcback, x, y);
+ ca = gdImageAlpha(srcback, c);
+
+ mt = ca > mt ? ca : mt;
+ }
+ }
+
+ /* src has no transparency? set to use full alpha range */
+ mt = mt == gdAlphaOpaque ? gdAlphaMax : mt;
+
+ /* alpha correction factor */
+ ac = (float)mt / gdAlphaMax;
+
+ /* loop through the image again and set/adjust alpha channel
level
*/
+ for (y = 0; y < h; y++) {
+ for (x = 0; x < w; x++) {
+ c = gdImageGetTrueColorPixel (srcback, x, y);
+ ca = gdImageAlpha(srcback, c);
+ cr = gdImageRed(srcback, c);
+ cg = gdImageGreen(srcback, c);
+ cb = gdImageBlue(srcback, c);
+
+ na = (ca + gdAlphaMax - (gdAlphaMax *
((float)pct / 100))) * ac;
+ na = (na > 127.0f)? 127.0f : ((na < 0.0f)?
0.0f: na);
+
+ int nc = gdImageColorAllocateAlpha(srcback, cr,
cg, cb, (int)na);
+ if (nc == -1) {
+ gdImageColorClosestAlpha(srcback, cr,
cg, cb, (int)na);
+ }
+
+ gdImageSetPixel (srcback, x, y, nc);
+ }
+ }
+
+ /* finally dispatch to gdImageCopy to do the actual copying */
+ gdImageCopy(dst, srcback, dstX, dstY, 0, 0, w, h);
+ gdImageDestroy(srcback);
+ return;
+ }
+
for (y = srcY; y < (srcY + h); y++) {
tox = dstX;
for (x = srcX; x < (srcX + w); x++) {
Previous Comments:
------------------------------------------------------------------------
[2009-05-04 12:14:15] checat at yandex dot ru
Please try again: site with images is up and running.
I've also uploaded files to alternate location, get them from
http://checat.narod.ru/php-bug-23815/
------------------------------------------------------------------------
[2009-04-23 18:08:41] [email protected]
Site not accessible (timeout)
------------------------------------------------------------------------
[2009-04-23 17:52:32] checat at yandex dot ru
PHP version: 5.2.9
CentOS 4
Reproduce code:
<?php
$bg =
imagecreatefrompng('http://guppi.spb.ru/php-bug-23815/bg.png');
$over =
imagecreatefrompng('http://guppi.spb.ru/php-bug-23815/over.png');
imagecopymerge($bg, $over, 0,0,0,0,32,32,100);
imagecopymerge($bg, $over, 16,0,0,0,32,32,50);
imagepng($bg, 'imagecopymerge.png');
?>
Expected result:
Proper image:
http://guppi.spb.ru/php-bug-23815/proper.png
Actual result:
Wrong image:
http://guppi.spb.ru/php-bug-23815/imagecopymerge.png
------------------------------------------------------------------------
[2003-05-26 11:43:05] bjorn at smokingmedia dot com
[[There are similar bugs in the system, but they are either closed or
said to be fixed... i think it's still not fixed..]]
i wanted to do the following. Use a transparent PNG-24(24 bits) file,
with an alpha-channel (with a drop-shadow) and merge it to a background
color. (see sample code).
this works:
imagecopy($backgroundimage, $image_id, 0, 0, 0, 0, $im_X, $im_Y);
this doesn't work:
imagecopymerge($backgroundimage, $image_id, 0, 0, 0, 0, $im_X, $im_Y,
99);
-> with any number instead of 99
sample link:
[change the hex color code to change backgroundcolor]
this is Okay
http://www.smokingmedia.com/test_gd_fb/test?bg=ffee22
this is not okay:
http://www.smokingmedia.com/test_gd_fb/test_nk?bg=ffee22
sample code:
<?php
if(!isset($_GET[bg]) || $_GET[bg] == ""){
$bg = "eeeeee";
}
else{
$bg = $_GET[bg];
}
$im = "test01.png";
//
// function to convert hex colorcode to decimal
//
function colordecode($hex){
$code[r] = hexdec(substr($hex, 0 ,2));
$code[g] = hexdec(substr($hex, 2 ,2));
$code[b] = hexdec(substr($hex, 4 ,2));
return $code;
} // end func colordecode
// create the resource id
$image_id = imageCreateFromPNG($im);
// get image size
$im_X = ImageSX($image_id);
$im_Y = ImageSY($image_id);
// create a truecolor background image of the right size
$backgroundimage = imagecreatetruecolor($im_X, $im_Y);
// get the desired backgroundcolor:
$code = colordecode($bg);
$backgroundcolor = ImageColorAllocate($backgroundimage, $code[r],
$code[g], $code[b]);
ImageFilledRectangle($backgroundimage, 0, 0, $im_X, $im_Y,
$backgroundcolor);
// merge the two together with alphablending on!
ImageAlphaBlending($backgroundimage, true);
// this works:
imagecopy($backgroundimage, $image_id, 0, 0, 0, 0, $im_X, $im_Y);
// this is where things go wrong:
//imagecopymerge($backgroundimage, $image_id, 0, 0, 0, 0, $im_X, $im_Y,
99);
// output the image:
Header( "Content-type: image/png");
ImagePNG($backgroundimage);
// destroy the memory
ImageDestroy($backgroundimage);
ImageDestroy($image_id);
?>
------------------------------------------------------------------------
--
Edit this bug report at http://bugs.php.net/?id=23815&edit=1