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

Reply via email to