php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #39353 more imagecopyresized() alpha problems
Submitted: 2006-11-03 00:23 UTC Modified: 2006-11-04 20:11 UTC
From: seth at pricepages dot org Assigned: pajoye (profile)
Status: Not a bug Package: GD related
PHP Version: 5CVS-2006-11-02 (snap) OS: Mac 10.4
Private report: No CVE-ID: None
 [2006-11-03 00:23 UTC] seth at pricepages dot org
Description:
------------
I'm not sure how many bugs are hidden here, but I thought 
this should be submitted.

imagecopyresized() is ignoring alpha the blending mode. 
Specifically, in ext/gd/libgd/gd.c line 2376 or so, there is 
this code that skips processing transparent pixels:
  tmp = gdImageGetPixel (src, x, y);
  if (gdImageGetTransparent (src) == tmp) {
      tox += stx[x - srcX];
      continue;
  }

But if the alpha blending is set to false, you want to copy 
the transparent pixels. So commenting out this if statement 
removes one bug. There is other similar code in this loop, 
so maybe it should all be removed?

Unfortunately, all result pixels still opaque, when the 
source image pixels are partially transparent. So this code 
does not fix the problem.

Reproduce code:
---------------
<?php
$small = imagecreatefrompng(
           'http://pricepages.org/temp/partialTrans.png');

$width = 300;
$height = 300;
$srcW = imagesx($small);
$srcH = imagesy($small);

$img = imagecreatetruecolor($width, $height);
$red = imagecolorresolve($img,255,0,0);
imagefill($img, 0,0, $red);
imagealphablending($img, false);

imagecopyresized($img, $small, 0,0, 0,0, $width, $height, $srcW, $srcH);

header('Content-Type: image/png');
imagepng($img);
?>

Expected result:
----------------
The image is filled with red, and a partially transparent 
black-and-white image is composited on top of it. Because 
alpha blending is set to false, there should be no red showing 
in the final image. (bug#1, squashed above)

Also, because the greyscale image should have partial 
transparency, there should be a gradient between black and 
red, but there is none. It is only black or only red. (bug#2)



Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2006-11-04 00:17 UTC] pajoye@php.net
"But if the alpha blending is set to false, you want to copy 
the transparent pixels."

No, you do not want. Alpha channel and transparent color are two different things. Alpha blending works with the alpha channel not with the transparent color.

I closed this bug (bogus), reopen it if you think that I misunderstood your problem.
 [2006-11-04 00:28 UTC] seth at pricepages dot org
Well, you can tell me what I'm doing wrong then. I have a 
source image with fully transparent pixels. I would like to 
copy it over another image, so the final image has fully 
transparent pixels.

To do this, I set imagealphablending() to false, and I copy 
via imagecopyresized(). But no fully transparent pixels are 
copied.

Your statement does not address the second bug that I 
mentioned.
 [2006-11-04 15:52 UTC] pajoye@php.net
"imagecopyresized() is ignoring alpha the blending mode. 
Specifically, in ext/gd/libgd/gd.c line 2376 or so, there is 
this code that skips processing transparent pixels:"

My statement covers this part of your report, which is wrong. It is the expected behavior to do not copy the transparent color.

The transparent color has nothing to do with the *alpha* channel of any other pixels.

The alpha blending mode affects *only* pixels with alpha channels, not the transparent color.

Which second bug are you talking about? The link bug#1 and bug#2 does not work, maybe you are refering to them?

As a sidenote, it makes no sense to call colorresolve for truecolor images, just use imagecolorallocate or imagecolorallocatealpha.

Here is your example, with a check for truecolor or indexed image, and showing which color is the *transparent* color (imagecolortransparent):
$small = imagecreatefrompng('bug39353.png');
if (imageistruecolor($small)) {
    echo "truecolor image\n"; 
} else {
    $c = imagecolortransparent($small);
    echo "transparent index: " . $c . "\n";
    print_r( imagecolorsforindex($small,$c));
}

$width = 300;
$height = 300;
$srcW = imagesx($small);
$srcH = imagesy($small);

$img = imagecreatetruecolor($width, $height);
$red = imagecolorallocate($img,255,0,0);
imagefill($img, 0,0, $red);
imagecopyresized($img, $small, 0,0, 0,0, $width, $height, $srcW,$srcH);
imagepng($img, 'a.png');
?>
and the result image:
http://blog.thepimp.net/misc/bug39353_out.png

Please note that the transparent color is the index 0 and has these values:
transparent index: 0
Array
(
    [red] => 246
    [green] => 246
    [blue] => 246
    [alpha] => 127
)

Is it more clear now?


 [2006-11-04 17:01 UTC] seth at pricepages dot org
I thought that a color with alpha = 127 will produce the 
same results as a color marked as transparent. I want the 
contents of $small to overwrite everything in $img. This is 
not correct?

The "bug#1" and "bug#2" that I wrote were not intended to be 
links, they were just supposed to show that I believe there 
are two bugs at work here. This web site turned them into 
links.

To reproduce the second bug without changing the first, 
alter my code to look like this:

...
$img = imagecreatetruecolor($width, $height);
$red = imagecolorallocate($img, 255,0,0);
imagecolortransparent($img, $red);
imagefill($img, 0,0, $red);

imagecopyresized($img, $small, 0,0, 0,0, $width, $height, 
$srcW, $srcH);
...

The background is supposed to be transparent, but where 
$small has partial transparency, $img becomes fully opaque. 
The final image should have partial transparency around the 
object, but it does not.
 [2006-11-04 17:11 UTC] seth at pricepages dot org
Also, if you alter the transparency of a color to be 64, and 
you fill the image with that color, shouldn't the final 
image have a transparency of 64?

imagecolorsforindex() gives the correct alpha value, but the 
"true color" PNG produced in my browser has no partial 
transparency. (it is all opaque)

The code that I am using looks like this:
...
$img = imagecreatetruecolor($width, $height);
$red = imagecolorallocatealpha($img, 255,0,0, 64);
imagefill($img, 0,0, $red);
imagealphablending($img, false);

/*
var_dump(imagecolorsforindex($img, imagecolorat($img, 
0,0)));
exit;
//*/

header('Content-Type: image/png');
...
 [2006-11-04 17:26 UTC] pajoye@php.net
"I thought that a color with alpha = 127 will produce the 
same results as a color marked as transparent. I want the 
contents of $small to overwrite everything in $img. This is 
not correct?"

But this color (imagecolortransparent($small)) *IS* the transparent color and is ignored on copy.

http://blog.thepimp.net/misc/bug39353_out.png is it not what you expect?

If not, provide an image to show what you expect.
 [2006-11-04 17:42 UTC] pajoye@php.net
Another thing you may not know is how to preserve the alpha channel information on save:

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

you have to use imagesavealpha($img,true); before calling imagepng.


 [2006-11-04 17:45 UTC] seth at pricepages dot org
I am simply trying to enlarge the original image. I can't find 
a work-around in PHP, but I can create the image in Adobe 
Photoshop.

This is what I'm attempting to create:
http://pricepages.org/temp/partialTrans2.png

By the way, this image is the outline of Bermuda. :)
 [2006-11-04 17:48 UTC] seth at pricepages dot org
Oh! No, I didn't realize imagesavealpha() existed. Why is 
saving the alpha a separate function? Shouldn't it be default?
 [2006-11-04 17:50 UTC] pajoye@php.net
"Shouldn't it be default?"

Backward compatibility... GD is an old library. But things are getting better.

No bug > bogus.
 [2006-11-04 18:10 UTC] seth at pricepages dot org
But I *still* can't produce the image that I want. I simply 
want to enlarge $small. How can I do this?
 [2006-11-04 18:59 UTC] pajoye@php.net
$img = imagecreatetruecolor($width, $height);
$bgdalpha = imagecolorallocatealpha($img,0,0,0, 127);
imagefill($img, 0,0, $bgdalpha);
imagecopyresized($img, $small, 0,0, 0,0, $width, $height, $srcW,$srcH);
imagesavealpha($img, 1);
imagepng($img, 'a.png');

 [2006-11-04 19:16 UTC] seth at pricepages dot org
That is a workaround. imagecopyresized() isn't working as 
defined in the manual, so you've changed the destination 
image to compensate.

I suppose it's fine if you don't want to fix it, I think I 
can use this workaround for now.

There is a waste of pixel processing, though. You need to 
process the entire final image twice. But I've seen worse 
code in the GD library...
 [2006-11-04 19:21 UTC] pajoye@php.net
"That is a workaround. imagecopyresized() isn't working as 
defined in the manual, so you've changed the destination 
image to compensate."

Now you've reached my patience limit.

http://blog.thepimp.net/misc/bug39353_with_alpha.png
is exactly what you expect.

Now if you do not understand the different between the TRANSPARENT COLOR and the alpha channel of each independent pixel, I cannot help you further.

But you keep considering other apps behaviors as what should happen in gd. It is not the case for various reasons (backward compatibility is one of them).

"But I've seen worse code in the GD library..."

For example?

 [2006-11-04 19:32 UTC] pajoye@php.net
A last comment is this free support session, you certainly do not know that the default contents of an image create by imagecreatetruecolor is black and not transparent/NULL.
 [2006-11-04 19:53 UTC] seth at pricepages dot org
> For example?

gdImageCopyResized() in our example (palette -> true color, 
no alpha blending) requires 11+ branches and 3 function 
calls per input pixel. There is another function call and 4+ 
branches per output pixel. I'm skipping a good number of 
branches created by the short-circuiting in each of those 15 
if statements. Those create bubbles in your processor 
pipeline which are going to kill your performance much 
faster than initializing each pixel 3 times.

It's a good thing we are working with small images on fast 
computers. :)

No reply requested.
 [2006-11-04 20:11 UTC] pajoye@php.net
It is in there since a long times and all the new functions (that I added for example) do not have this obvious problem and access the right buffer directly.

As I agree about the lack of performance of the GD library in some areas, I do not see the points to criticize it as you did in this report. Especially not when you get help and support. It is also very easy to spot problems in other codes without actually taking care about the reasoning or the history.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Wed May 29 11:01:32 2024 UTC