Bug #55034 [Opn]: ImageCopyResampled doesn't calculate colours properly with alpha
| From: | php at mrphlip dot com | Date: | Sat, 11 Jun 2011 13:53:32 +0000 |
| Subject: | Bug #55034 [Opn]: ImageCopyResampled doesn't calculate colours properly with alpha | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-161306@lists.php.net to get a copy of this message | ||
Edit report at http://bugs.php.net/bug.php?id=55034&edit=1
ID: 55034
User updated by: php at mrphlip dot com
Reported by: php at mrphlip dot com
-Summary: ImageCopyResampled doesn't calculate alpha properly
+Summary: ImageCopyResampled doesn't calculate colours
properly with alpha
Status: Open
Type: Bug
Package: GD related
Operating System: Ubuntu Natty
PHP Version: 5.3.6
Block user comment: N
Private report: N
New Comment:
Changed summary to be more accurate... it calculates the alpha fine, it's the colours it
doesn't calculate correctly in the presence of an alpha channel.
Previous Comments:
------------------------------------------------------------------------
[2011-06-11 15:48:17] php at mrphlip dot com
Description:
------------
It appears that ImageCopyResampled uses a naive averaging, which isn't correct when there is an
alpha channel involved. It should instead use a weighted average for the colour channel, weighting
each input pixel according to its opacity (so a more opaque input pixel has more weight in the
average).
This comes up particularly if you have eg a solid white shape against a solid black-but-transparent
background. The original image, every pixel is either white or transparent. But shrink it down, and
the object will have a thin dark halo around the edge, because of averaging those black pixels into
the result. The expected result would fade from full opacity white, to half opacity white, to
transparent any-colour... but the actual result fades from full opacity white, to half opacity
*grey*, to transparent black.
Test script:
---------------
# create an image with an almost-transparent white pixel and an almost-opaque black pixel
$img1 = ImageCreateTrueColor(2, 1);
ImageAlphaBlending($img1, FALSE);
ImageSetPixel($img1, 0, 0, ImageColorAllocateAlpha($img1, 255, 255, 255, 0x70));
ImageSetPixel($img1, 1, 0, ImageColorAllocateAlpha($img1, 0, 0, 0, 0x10));
# scale the image down to a single pixel - make it mix the two together
$img2 = ImageCreateTrueColor(1, 1);
ImageAlphaBlending($img2, FALSE);
ImageCopyResampled($img2, $img1, 0, 0, 0, 0, 1, 1, 2, 1);
# find out what colour the resulting pixel is
$col = ImageColorAt($img2, 0, 0);
print "R: " . (($col >> 16) & 0xFF) . "<br>";
print "G: " . (($col >> 8) & 0xFF) . "<br>";
print "B: " . ($col & 0xFF) . "<br>";
print "A: " . (($col >> 24) & 0xFF) . "<br>";
# clean up
ImageDestroy($img1);
ImageDestroy($img2);
Expected result:
----------------
R: 30
G: 30
B: 30
A: 64
Each of the colour channels has been weighted in the average... the almost-transparent white pixel
with a weight of 0xF (0x7F - 0x70), and the almost-opaque black pixel with a weight of 0x6F (0x7F -
0x10), giving a weighted average of (255 * 0xF + 0 * 0x6F) / (0xF + 0x6F) == 30. The alpha channel
is averaged in the normal way.
Actual result:
--------------
R: 127
G: 127
B: 127
A: 64
Each channel has been averaged separately, with no regard for the alpha channel.
------------------------------------------------------------------------
--
Edit this bug report at http://bugs.php.net/bug.php?id=55034&edit=1