Skip to content

imagesavealpha(…, false) should not save alpha channel #10055

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion ext/gd/libgd/gd_avif.c
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,9 @@ void gdImageAvifCtx(gdImagePtr im, gdIOCtx *outfile, int quality, int speed)
avifIm->matrixCoefficients = lossless ? AVIF_MATRIX_COEFFICIENTS_IDENTITY : AVIF_MATRIX_COEFFICIENTS_BT709;

avifRGBImageSetDefaults(&rgb, avifIm);
if (!im->saveAlphaFlag) {
rgb.format = AVIF_RGB_FORMAT_RGB;
}
// this allocates memory, and sets rgb.rowBytes and rgb.pixels.
avifRGBImageAllocatePixels(&rgb);

Expand All @@ -542,7 +545,9 @@ void gdImageAvifCtx(gdImagePtr im, gdIOCtx *outfile, int quality, int speed)
*(p++) = gdTrueColorGetRed(val);
*(p++) = gdTrueColorGetGreen(val);
*(p++) = gdTrueColorGetBlue(val);
*(p++) = alpha7BitTo8Bit(gdTrueColorGetAlpha(val));
if (im->saveAlphaFlag) {
*(p++) = alpha7BitTo8Bit(gdTrueColorGetAlpha(val));
}
}
}

Expand Down
39 changes: 28 additions & 11 deletions ext/gd/libgd/gd_webp.c
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@ void gdImageWebpCtx (gdImagePtr im, gdIOCtx * outfile, int quality)
uint8_t *p;
uint8_t *out;
size_t out_size;
uint8_t bpp;
size_t (*encode)(const uint8_t*, int, int, int, float, uint8_t**);
size_t (*encode_lossless)(const uint8_t*, int, int, int, uint8_t**);

if (im == NULL) {
return;
Expand All @@ -121,15 +124,25 @@ void gdImageWebpCtx (gdImagePtr im, gdIOCtx * outfile, int quality)
quality = 80;
}

if (overflow2(gdImageSX(im), 4)) {
if (im->saveAlphaFlag) {
bpp = 4;
encode = WebPEncodeRGBA;
encode_lossless = WebPEncodeLosslessRGBA;
} else {
bpp = 3;
encode = WebPEncodeRGB;
encode_lossless = WebPEncodeLosslessRGB;
}

if (overflow2(gdImageSX(im), bpp)) {
return;
}

if (overflow2(gdImageSX(im) * 4, gdImageSY(im))) {
if (overflow2(gdImageSX(im) * bpp, gdImageSY(im))) {
return;
}

argb = (uint8_t *)gdMalloc(gdImageSX(im) * 4 * gdImageSY(im));
argb = (uint8_t *)gdMalloc(gdImageSX(im) * bpp * gdImageSY(im));
if (!argb) {
return;
}
Expand All @@ -139,23 +152,27 @@ void gdImageWebpCtx (gdImagePtr im, gdIOCtx * outfile, int quality)
register int c;
register char a;
c = im->tpixels[y][x];
a = gdTrueColorGetAlpha(c);
if (a == 127) {
a = 0;
} else {
a = 255 - ((a << 1) + (a >> 6));
if (bpp == 4) {
a = gdTrueColorGetAlpha(c);
if (a == 127) {
a = 0;
} else {
a = 255 - ((a << 1) + (a >> 6));
}
}
*(p++) = gdTrueColorGetRed(c);
*(p++) = gdTrueColorGetGreen(c);
*(p++) = gdTrueColorGetBlue(c);
*(p++) = a;
if (bpp == 4) {
*(p++) = a;
}
}
}

if (quality >= gdWebpLossless) {
out_size = WebPEncodeLosslessRGBA(argb, gdImageSX(im), gdImageSY(im), gdImageSX(im) * 4, &out);
out_size = encode_lossless(argb, gdImageSX(im), gdImageSY(im), gdImageSX(im) * bpp, &out);
} else {
out_size = WebPEncodeRGBA(argb, gdImageSX(im), gdImageSY(im), gdImageSX(im) * 4, quality, &out);
out_size = encode(argb, gdImageSX(im), gdImageSY(im), gdImageSX(im) * bpp, quality, &out);
}

if (out_size == 0) {
Expand Down
50 changes: 50 additions & 0 deletions ext/gd/tests/imagesavealpha_avif.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
--TEST--
Testing imagesavealpha() with AVIF
--EXTENSIONS--
gd
--SKIPIF--
<?php
$support = gd_info();
if (!isset($support['AVIF Support']) || $support['AVIF Support'] === false) {
die("skip AVIF support not available");
}
?>
--FILE--
<?php
$filename = __DIR__ . "/imagesavealpha_avif.avif";
$im = imagecreatetruecolor(8, 8);
imagealphablending($im, false);
imagefilledrectangle($im, 0, 0, 7, 7, 0x7f000000);

echo "without alpha\n";
imagesavealpha($im, false);
imageavif($im, $filename, 100); // lossless
$im1 = imagecreatefromavif($filename);
checkColors($im1, 0x000000);
imagedestroy($im1);

echo "with alpha\n";
imagesavealpha($im, true);
imageavif($im, $filename, 100); // lossless
$im1 = imagecreatefromavif($filename);
checkColors($im1, 0x7f000000);
imagedestroy($im1);

function checkColors(GdImage $im, int $expected) {
for ($i = 0; $i < 8; $i++) {
for ($j = 0; $j < 8; $j++) {
$actual = imagecolorat($im, $i, $j);
if ($actual !== $expected) {
echo "($i, $j) is $actual, but $expected expected\n";
}
}
}
}
?>
--CLEAN--
<?php
@unlink(__DIR__ . "/imagesavealpha_avif.avif");
?>
--EXPECT--
without alpha
with alpha
50 changes: 50 additions & 0 deletions ext/gd/tests/imagesavealpha_png.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
--TEST--
Testing imagesavealpha() with PNG
--EXTENSIONS--
gd
--SKIPIF--
<?php
$support = gd_info();
if (!isset($support['PNG Support']) || $support['PNG Support'] === false) {
die("skip PNG support not available");
}
?>
--FILE--
<?php
$filename = __DIR__ . "/imagesavealpha_png.png";
$im = imagecreatetruecolor(8, 8);
imagealphablending($im, false);
imagefilledrectangle($im, 0, 0, 7, 7, 0x7f000000);

echo "without alpha\n";
imagesavealpha($im, false);
imagepng($im, $filename);
$im1 = imagecreatefrompng($filename);
checkColors($im1, 0x000000);
imagedestroy($im1);

echo "with alpha\n";
imagesavealpha($im, true);
imagepng($im, $filename);
$im1 = imagecreatefrompng($filename);
checkColors($im1, 0x7f000000);
imagedestroy($im1);

function checkColors(GdImage $im, int $expected) {
for ($i = 0; $i < 8; $i++) {
for ($j = 0; $j < 8; $j++) {
$actual = imagecolorat($im, $i, $j);
if ($actual !== $expected) {
echo "($i, $j) is $actual, but $expected expected\n";
}
}
}
}
?>
--CLEAN--
<?php
@unlink(__DIR__ . "/imagesavealpha_png.png");
?>
--EXPECT--
without alpha
with alpha
50 changes: 50 additions & 0 deletions ext/gd/tests/imagesavealpha_webp.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
--TEST--
Testing imagesavealpha() with WebP
--EXTENSIONS--
gd
--SKIPIF--
<?php
$support = gd_info();
if (!isset($support['WebP Support']) || $support['WebP Support'] === false) {
die("skip WebP support not available");
}
?>
--FILE--
<?php
$filename = __DIR__ . "/imagesavealpha_webp.webp";
$im = imagecreatetruecolor(8, 8);
imagealphablending($im, false);
imagefilledrectangle($im, 0, 0, 7, 7, 0x7f000000);

echo "without alpha\n";
imagesavealpha($im, false);
imagewebp($im, $filename, 101); // lossless
$im1 = imagecreatefromwebp($filename);
checkColors($im1, 0x000000);
imagedestroy($im1);

echo "with alpha\n";
imagesavealpha($im, true);
imagewebp($im, $filename, 101); // lossless
$im1 = imagecreatefromwebp($filename);
checkColors($im1, 0x7f000000);
imagedestroy($im1);

function checkColors(GdImage $im, int $expected) {
for ($i = 0; $i < 8; $i++) {
for ($j = 0; $j < 8; $j++) {
$actual = imagecolorat($im, $i, $j);
if ($actual !== $expected) {
echo "($i, $j) is $actual, but $expected expected\n";
}
}
}
}
?>
--CLEAN--
<?php
@unlink(__DIR__ . "/imagesavealpha_webp.webp");
?>
--EXPECT--
without alpha
with alpha