Edit report at http://bugs.php.net/bug.php?id=23815&edit=1
ID: 23815 Comment by: setvik at gmail dot com Reported by: bjorn at smokingmedia dot com Summary: imagecopymerge doesn't respect alpha-channel in PNG-24 file Status: Assigned Type: Feature/Change Request Package: Feature/Change Request Operating System: Linux pluto 2.4.18lvm-r1 PHP Version: 5.2.9 Assigned To: pajoye New Comment: I have the same need to merge alpha images with the opacity of the top one reduced, and like the others in this thread, I assumed imagecopymerge would respect the alpha settings in the image. Based on comments here and in the docs ( http://php.net/manual/en/function.imagecopymerge.php), others are making the same assumption. @pajoye - The inclusion of alpha support whether in imagecopymerge or an additional function would be very valuable for working with images, especially watermarks with complex transparency. Any chance imagecopymerge can be patched to support this? Or should an additional function be written and the documentation for imagecopymerge updated? What's your take? Previous Comments: ------------------------------------------------------------------------ [2009-12-10 18:35:56] andre at webkr dot de Ah, I see. It's imagecopy() which implements alpha transparency while imagecopymerge() does not. ------------------------------------------------------------------------ [2009-12-10 18:23:20] andre at webkr dot de So what does the "it implements alpha transparency for true colour images" in "When pct = 0, no action is taken, when 100 this function behaves identically to imagecopy() for pallete images, while it implements alpha transparency for true colour images." mean anyway? ------------------------------------------------------------------------ [2009-07-20 12:10:43] steve at redmonkey dot org Thanks, understood. Although, I do think it would be a useful feature, perhaps there's scope for an 'imagecopymergealpha' type function in the future? ------------------------------------------------------------------------ [2009-07-20 08:43:04] paj...@php.net imagecopymerge was not meant to support the alpha channel but to emulate it via pct. It was also not meant to use both the alpha or the pct value to blend an image over another. ------------------------------------------------------------------------ [2009-07-20 05:44:49] steve at redmonkey dot org To make life a little easier I've put the notes and examples together on a simple web page at http://www.redmonkey.org/php-bug-23815/ After investigating the code base a little further I've realised my patch solution can be made more efficient as there is no need to make a copy of the source or pass the image over to gdImageCopy once the new alpha level has been set as we've already done the all the work and can simply set the pixels RGBA index within the second image scan. The revised patch (which is also available from a link on the web page) 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-20 05:54:21.709936176 +0100 @@ -2255,6 +2255,67 @@ 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. + */ + int ca, cr, cg, cb; + float na; + float ac; + + /* 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 (src, srcX + x, srcY + y); + ca = gdImageAlpha(src, 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 (src, srcX + x, srcY + y); + ca = gdImageAlpha(src, c); + cr = gdImageRed(src, c); + cg = gdImageGreen(src, c); + cb = gdImageBlue(src, c); + + na = (ca + gdAlphaMax - (gdAlphaMax * ((float)pct / 100))) * ac; + na = (na > gdAlphaMax)? gdAlphaMax : ((na < gdAlphaOpaque)? gdAlphaOpaque: na); + + int nc = gdImageColorAllocateAlpha(src, cr, cg, cb, (int)na); + if (nc == -1) { + gdImageColorClosestAlpha(src, cr, cg, cb, (int)na); + } + + gdImageSetPixel (dst, dstX + x, dstY + y, nc); + } + } + + return; + } + for (y = srcY; y < (srcY + h); y++) { tox = dstX; for (x = srcX; x < (srcX + w); x++) { ------------------------------------------------------------------------ The remainder of the comments for this report are too long. To view the rest of the comments, please view the bug report online at http://bugs.php.net/bug.php?id=23815 -- Edit this bug report at http://bugs.php.net/bug.php?id=23815&edit=1