php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #40158 Artifact left on transparent pngs using image filters
Submitted: 2007-01-18 10:40 UTC Modified: 2017-01-22 15:06 UTC
Votes:3
Avg. Score:4.0 ± 0.8
Reproduced:2 of 2 (100.0%)
Same Version:2 (100.0%)
Same OS:0 (0.0%)
From: henus at mail dot ru Assigned: pajoye (profile)
Status: Closed Package: GD related
PHP Version: 5CVS-2008-11-03 OS: *
Private report: No CVE-ID: None
 [2007-01-18 10:40 UTC] henus at mail dot ru
Description:
------------
After using imagefilter (IMG_FILTER_COLORIZE) on transparent png image the result color of translucent pixels is wrong.

I.e. the edge of non-transparent part of image, which contain translucent antialiasing area - wrong colored.



Reproduce code:
---------------
<?
$mask=imagecreatefrompng("mask.png"); // http://fort-ross.ru/henus/gd/mask.png (mask for colorize, contain translucent)
$imagewidth=imagesx($mask);
$imageheight=imagesy($mask);
$imagemain=imagecreatetruecolor($imagewidth,$imageheight);
imagealphablending($mask, TRUE);
imagealphablending($imagemain, TRUE);
$color=imagecolorallocate($imagemain, 0, 0, 0);
imagefill($imagemain, 0, 0, $color);
imagefilter($mask, IMG_FILTER_COLORIZE, -255, -255, 0);
imagecopy($imagemain, $mask, 0, 0, 0, 0, $imagewidth, $imageheight);
imagepng($imagemain,"result_incorrect.png"); // http://www.fort-ross.ru/henus/gd/result_incorrect.png 
imagedestroy($mask);
imagedestroy($imagemain);
?>

Expected result:
----------------
The result image - absolutely black square

Actual result:
--------------
The result image - black square with gray line (on the edge of mask image)

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2007-01-18 11:03 UTC] henus at mail dot ru
My mistake...

correct 12 line in Reproduce code:

imagefilter($mask, IMG_FILTER_COLORIZE, -255, -255, -255);
 [2007-01-18 14:23 UTC] henus at mail dot ru
php-5.2.0\ext\gd\libgd\gd.c

Lines 3682-3685:

new_pxl = gdImageColorAllocateAlpha(src, (int)r, (int)g, (int)b, a);
if (new_pxl == -1) {
	new_pxl = gdImageColorClosestAlpha(src, (int)r, (int)g, (int)b, a);
}

....should be without alpha...
 [2007-01-18 14:26 UTC] tony2001@php.net
>...should be without alpha...
Could you plz elaborate?
A unified diff would explain it much better, btw.
 [2007-01-18 15:22 UTC] pajoye@php.net
Can you provide an image to show what you expect?

I did not check your script but having an image will help to really understand what you are trying to achieve.

By the way, filters work only with truecolor images, allocate will never fail.
 [2007-01-18 17:56 UTC] henus at mail dot ru
i create black image and overlay it by colorized white-truecolor-png24-image ( http://fort-ross.ru/henus/gd/mask.png )
 
the result of colorize like:
imagefilter($mask, IMG_FILTER_COLORIZE, -255, -255, -255);
is image:
http://www.fort-ross.ru/henus/gd/result_incorrect.png 
which contain artefacts...



also, the result of such script ( http://fort-ross.ru/henus/gd/demo2.phps )
is:

is truecolor - 1
before - Array ( [red] => 255 [green] => 255 [blue] => 255 [alpha] => 63 ) 
wrong result, using filter - Array ( [red] => 126 [green] => 126 [blue] => 126 [alpha] => 31 ) 
wrong result, using imagecolorallocatealpha and imagesetpixel - Array ( [red] => 126 [green] => 126 [blue] => 126 [alpha] => 31 ) 
correct result, using imagefill, imagecolorallocatealpha and imagesetpixel - Array ( [red] => 0 [green] => 0 [blue] => 0 [alpha] => 63 )

I.e.
colorizing pixel ( [red] => 255 [green] => 255 [blue] => 255 [alpha] => 63 ) to black 
should be with ( [red] => 0 [green] => 0 [blue] => 0 [alpha] => 63 ), 
not  ( [red] => 126 [green] => 126 [blue] => 126 [alpha] => 31 )
 [2007-01-18 18:09 UTC] pajoye@php.net
Please provide an *image* showing what you expect.
 [2007-01-18 18:11 UTC] henus at mail dot ru
correction fo my previous post about
php-5.2.0\ext\gd\libgd\gd.c 



Lines 3682-3688:
new_pxl = gdImageColorAllocateAlpha(src, (int)r, (int)g, (int)b, a);
if (new_pxl == -1) {
	new_pxl = gdImageColorClosestAlpha(src, (int)r, (int)g, (int)b, a);
}
if ((y >= 0) && (y < src->sy)) {
	gdImageSetPixel (src, x, y, new_pxl);


in gdImageSetPixel src should be absolutely transparent, with  alpha=127
differently it mix colors.
 [2007-01-18 18:32 UTC] henus at mail dot ru
i expect absolutely black image like
http://www.fort-ross.ru/henus/gd/result_correct.png
instead of 
http://www.fort-ross.ru/henus/gd/result_incorrect.png

i use colorizing by black for clearness.
 [2007-01-18 18:51 UTC] pajoye@php.net
An absolute black image is not what you should expect.

imagefilter($mask, IMG_FILTER_COLORIZE, -255, -255, 0); will replace the white color with blue (you remove all components but the blue):

http://blog.thepimp.net/misc/bug40158_filtered_mask.png

imagecopy($imagemain, $mask, 0, 0, 0, 0, $imagewidth, $imageheight); will copy it over the $imagemain, the border of the quadrant will be blended over black:

http://blog.thepimp.net/misc/bug40158_result.png

Each pixel in your circle are rgb(255,255,255) with some alpha value in the edges (and only in the edges). You are substracting 255 to the R and G component, the result is blue.


Now, take a look at this image:
http://blog.thepimp.net/misc/bug40158_correct_filtered_mask.png

It is what you are expecting (if I understand correctly your problem). The edges of the circle have a blue color with various alpha values (rgba(255,0,0,xxx)). You can reproduce it by disabling the alpha blending mode in the mask image (imagealphablending($mask, false); ). The alpha component will be kept and stored in the image instead of being used as a blending value.

Let me know if that solves your problem.

By the way, COLORIZE uses gdImageColor. The lines you are referring to are in the contrast function.


 [2007-01-18 18:51 UTC] pajoye@php.net
(rgba(255,0,0,xxx)) should have been (rgba(0,0,255,xxx)) but you noticed it :)
 [2007-01-18 19:37 UTC] henus at mail dot ru
it`s not solve my problem.... :(
first - 
about blue color - look at my submission from 
[18 Jan 11:03am UTC]

if use 
imagefilter($mask, IMG_FILTER_COLORIZE, -255, -255, -255);
the result is
http://www.fort-ross.ru/henus/gd/result_incorrect.png
with legibly visible artefacts.

second - 
image
http://blog.thepimp.net/misc/bug40158_result.png
also has artefacts at the adges...
pixel from edge with coord (95,11) have wrong color
red-98
green-98
blue-164
(why is red>0  and green>0 ????????? after substracting 255???) 

(should be
red-0
green-0
blue-102)

third - 
look at my submission from [18 Jan 5:56pm UTC]
why is 255-255=126????????????????



one more demo - 
using
imagefilter($mask, IMG_FILTER_COLORIZE, -255, -255, 0);

mask - http://fort-ross.ru/henus/gd/mask3.png
incorrect image - http://fort-ross.ru/henus/gd/result_incorrect3.png
correct image - http://fort-ross.ru/henus/gd/result_correct3.png
 [2007-01-18 19:54 UTC] pajoye@php.net
"pixel from edge with coord (95,11) have wrong color.
red-98 green-98 blue-164 (why is red>0  and green>0 ????????? after substracting 255???)  (should be red-0 green-0 blue-102)"

It is blended over the destination pixel. You have to disable alpha blending *before* the imagefilter call.

This image:

http://blog.thepimp.net/misc/bug40158_black_filtered_mask.png

shows exactly what you are trying to do (blue, black or purple, it really does not matter), the script being:

$mask=imagecreatefrompng("40158.png");
imagealphablending($mask, false); //<<< Important!
imagefilter($mask, IMG_FILTER_COLORIZE, -255, -255, -255);
//<<< save alpha, so we see its value
imagesavealpha($mask, true);
imagepng($mask,"mask1.png");

Using your last example, the resulting image is like your "result_correct3.png".

 [2007-01-19 11:53 UTC] henus at mail dot ru
Yes, the is global problem with alphablending in libgd\gd.c

but about "imagealphablending($mask, false); //<<< Important!":
i absolutely should not care about ebabling\disabling imagealphablending before imagefilter, 
because of function shoud colorize image by new values of red,gree,blue 
(!!!there is no alpha in parameters)

if IMG_FILTER_COLORIZE will have in parameters alpha,
if alphablending enable, value of alpha should allow for calculation of new color values
(in gdImageColor it will before new_pxl = gdImageColorAllocateAlpha(src, (int)r, (int)g, (int)b, a);)
and gdImageSetPixel shoul with disabled alphablending.


otherwise function work like merging of two images with alphablending.
where:
first image - source image from function parameters.
second image - correct colorized copy of source image.

it is not logically. it is incorrect.


another bug in imagefill:
this function not only fill image, it is also disable alphablending.
php example:

<?
/* first colorizing */
$im1=imagecreatetruecolor(1,1);
imagealphablending($im1, TRUE);
$c01=imagecolorallocatealpha($im1,255,0,0,63);
imagefill($im1,0,0,$c01);
$c01=imagecolorsforindex($im1,imagecolorat($im1,0,0));
imagefilter($im1, IMG_FILTER_COLORIZE, -255, 255, 0);
$c1=imagecolorsforindex($im1,imagecolorat($im1,0,0));

/* second colorizing */
$im2=imagecreatetruecolor(1,1);
imagealphablending($im2, TRUE);
$c02=imagecolorallocatealpha($im2,255,0,0,63);
imagefill($im2,0,0,$c02);
$c02=imagecolorsforindex($im1,imagecolorat($im1,0,0));
/* att!!! after imagefill another enabling alphablending */
imagealphablending($im2, TRUE);
imagefilter($im2, IMG_FILTER_COLORIZE, -255, 255, 0);
$c2=imagecolorsforindex($im2,imagecolorat($im2,0,0));

print"<br>before 1 - ";
print_r($c01);
print"<br>after  1 - ";
print_r($c1);
print"<br><br>before 2 - ";
print_r($c02);
print"<br>after  2 - ";
print_r($c2);
?>

results:
before 1- Array ( [red] => 255 [green] => 0 [blue] => 0 [alpha] => 63 ) 
after  1 - Array ( [red] => 0 [green] => 255 [blue] => 0 [alpha] => 63 ) 

before 2- Array ( [red] => 0 [green] => 255 [blue] => 0 [alpha] => 63 ) 
after  2 - Array ( [red] => 126 [green] => 128 [blue] => 0 [alpha] => 31 )

where:
after 1 - correct result of IMG_FILTER_COLORIZE, because of imagefill disable alphablending
after 2 - incorrect result of IMG_FILTER_COLORIZE, because of after imagefill i manually enable alphablending


disabling alphablending in code it is good solutions for gdImageColor, but after it is necessary to restore old value of alphaBlendingFlag.
 [2007-01-19 12:02 UTC] pajoye@php.net
Can you *PLEASE* confirm that it works when you disable alpha blending? Answer should be Yes or No, I got the details already. I really do not have the time to explain/ask again and again the same thing.

About imagefill, yes, that's a bug. Please open a new one if you like. I will fix it as soon as possible.
 [2007-01-19 12:11 UTC] henus at mail dot ru
Yes, it work
 [2007-01-19 12:14 UTC] pajoye@php.net
Ok, good, thanks for the test. I will disable alpha blending and restore it on exit in imagefilter.

About the imagefill bug, it happens only with small images (< 4 pixels large), thanks for the notice.
 [2007-01-19 16:08 UTC] pajoye@php.net
For the record, the imagefill bug is fixed in cvs, it will be in 5.2.1 .
 [2008-11-03 09:09 UTC] pajoye@php.net
not fixed, imagefill was opened in another bug report.
 [2017-01-22 15:06 UTC] cmb@php.net
-Status: Assigned +Status: Closed
 [2017-01-22 15:06 UTC] cmb@php.net
I'm closing this ticket, because the originally reported issue was
not a bug, and the imagefill() issue should have its own ticket
(preferably filed against libgd) – if there is an issue at all.
 
PHP Copyright © 2001-2021 The PHP Group
All rights reserved.
Last updated: Fri Jul 30 13:01:24 2021 UTC