Skip to content

Preserve transparency in the Imagick grayscale effect#880

Merged
mlocati merged 2 commits into
php-imagine:developfrom
nlemoine:fix/imagick-grayscale-alpha
Jun 4, 2026
Merged

Preserve transparency in the Imagick grayscale effect#880
mlocati merged 2 commits into
php-imagine:developfrom
nlemoine:fix/imagick-grayscale-alpha

Conversation

@nlemoine

@nlemoine nlemoine commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

$image->effects()->grayscale() on the Imagick driver turns transparent pixels into opaque gray. Imagick::IMGTYPE_GRAYSCALE is one of ImageMagick's alpha-less image types, and switching to it deactivates the image's alpha channel (getImageAlphaChannel() flips from true to false). The pixels keep their stored alpha values in memory — only the encoders ignore them — so the breakage only surfaces in the saved file, whatever the format. That's also why the test asserts through an encode/decode roundtrip instead of reading pixels in place.

The driver already solves this exact problem in Image::setColorspace(), where usePalette() with a grayscale palette deliberately lands on IMGTYPE_GRAYSCALEALPHA to keep alpha; effects()->grayscale() just never got the same treatment. It now picks its type through the same fallback chain (IMGTYPE_GRAYSCALEALPHA on ImageMagick 7 / Imagick 3.4.3+, IMGTYPE_GRAYSCALEMATTE before, hard-coded 3 when neither constant exists). The gray rendition is unchanged — both types go through the same colorspace transform, only the alpha trait differs — so the existing testGrayscale expectations still hold.

GD is unaffected (IMG_FILTER_GRAYSCALE preserves alpha), and Gmagick doesn't support transparency at all, so the shared test skips there.

nlemoine added 2 commits June 4, 2026 11:22
effects()->grayscale() on the Imagick driver switches the image to
IMGTYPE_GRAYSCALE, an alpha-less type: ImageMagick deactivates the
alpha channel as part of the type switch, so every transparent pixel
is encoded as opaque gray. The test saves and reloads the image
because the defect only shows at encode time: in-memory pixel reads
still expose the stored alpha values.
effects()->grayscale() switched the image to IMGTYPE_GRAYSCALE, an
alpha-less image type: ImageMagick deactivates the alpha channel as
part of the type switch, so transparent pixels were encoded as opaque
gray in the saved file, whatever the output format.

Switch to the alpha-preserving grayscale type instead, picked through
the same constant fallback chain the driver already uses in
Image::setColorspace() (IMGTYPE_GRAYSCALEALPHA since ImageMagick 7 /
Imagick 3.4.3, previously IMGTYPE_GRAYSCALEMATTE, hard-coded 3 when
neither is defined). The gray rendition is unchanged: both types go
through the same colorspace transform, only the alpha trait differs.

The GD driver is unaffected (IMG_FILTER_GRAYSCALE keeps alpha); the
Gmagick driver does not support transparency at all, so the shared
test is skipped there.
@nlemoine nlemoine closed this Jun 4, 2026
@nlemoine nlemoine reopened this Jun 4, 2026
@nlemoine nlemoine marked this pull request as ready for review June 4, 2026 09:29
@mlocati mlocati merged commit d15f3e9 into php-imagine:develop Jun 4, 2026
42 checks passed
@mlocati

mlocati commented Jun 4, 2026

Copy link
Copy Markdown
Collaborator

Thanks!

@nlemoine

nlemoine commented Jun 4, 2026

Copy link
Copy Markdown
Contributor Author

Thanks @mlocati :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants