Skip to content

Move GD binary transparency handling from Cloner to GifEncoder - #1547

Closed
olivervogel wants to merge 16 commits into
developfrom
fix/cloner-transparency
Closed

olivervogel wants to merge 16 commits into
developfrom
fix/cloner-transparency

Conversation

@olivervogel

Copy link
Copy Markdown
Member

No description provided.

@guillaume-sainthillier

Copy link
Copy Markdown
Contributor

Found it: it isn't the GD version but how libgd is built. setup-php installs PHP 8.3–8.5 from the ondrej PPA, whose libgd3 (2.3.3-13+deb.sury.org) is built with libimagequant. PHP 8.6 runs against Ubuntu's own libgd3 (2.3.3-9ubuntu5), which isn't. With libimagequant, imagegif() turns truecolor images into a palette based on each pixel's alpha and ignores an opaque transparent color:

$gd = imagecreatetruecolor(2, 1);
imagesetpixel($gd, 0, 0, 0x000000FF);
imagecolortransparent($gd, 0x000000FF);
// after imagegif(): transparent index 1 with Ubuntu's libgd, -1 with the PPA build

A fully transparent color (alpha 127) survives with both, which is why the current Cloner approach (0x7FFFFFFF) passes. So the pixels that should become transparent need alpha 127 when imagegif() runs. This can be done natively, without iterating over pixels: flatten as in #1547, then restore alpha 127 where the source was fully transparent:

$mask = Cloner::clone($native); // copy incl. alpha
imagealphablending($mask, false); // the filters must not blend
imagefilter($mask, IMG_FILTER_BRIGHTNESS, 255); // rgb -> white, alpha kept
imagefilter($mask, IMG_FILTER_COLORIZE, 0, 0, 0, -126); // alpha 127 -> 1, others -> 0
imagefilter($mask, IMG_FILTER_COLORIZE, 0, 0, 0, 126); // -> 127 (transparent) or 126 (keep)
imagecolortransparent($mask, 0x7EFFFFFF); // imagecopy() skips the pixels to keep
imagealphablending($gd, false);
imagecopy($gd, $mask, 0, 0, 0, 0, imagesx($gd), imagesy($gd));
imagecolortransparent($gd, 0x7FFFFFFF);

I tested this with Ubuntu's libgd, the PPA build and PHP's bundled GD. Fully transparent pixels and sources with a transparent color (e.g. tile.png) stay transparent, and semi-transparent pixels blend with the background. Opaque pixels that equal the background color also stay opaque, which an opaque background key can't guarantee.

@olivervogel

Copy link
Copy Markdown
Member Author

Thanks. This helps.

@olivervogel olivervogel closed this Oct 4, 2026
@olivervogel
olivervogel deleted the fix/cloner-transparency branch October 5, 2026 12:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants