Skip to content

Commit eb6c9eb

Browse files
morssssscmb69
authored andcommitted
Lossless conversion for webp
Propagating lossless conversion from libgd to our bundled gd. Changing "quantization" to "quality" as in libgd. Adding test. IMG_WEBP_LOSSLESS is only defined, if lossless WebP encoding is supported by the libgd used. Closes GH-7348.
1 parent b80767e commit eb6c9eb

File tree

6 files changed

+48
-11
lines changed

6 files changed

+48
-11
lines changed

UPGRADING

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,11 @@ PHP 8.1 UPGRADE NOTES
562562
9. Other Changes to Extensions
563563
========================================
564564

565+
- GD:
566+
imagewebp() can do lossless WebP encoding by passing IMG_WEBP_LOSSLESS as
567+
quality. This constant is only defined, if a libgd is used which supports
568+
lossless WebP encoding.
569+
565570
- MySQLi:
566571
. The mysqli_stmt::next_result() and mysqli::fetch_all() methods are now
567572
available when linking against libmysqlclient.

ext/gd/config.m4

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ AC_DEFUN([PHP_GD_AVIF],[
9292

9393
AC_DEFUN([PHP_GD_WEBP],[
9494
if test "$PHP_WEBP" != "no"; then
95-
PKG_CHECK_MODULES([WEBP], [libwebp])
95+
PKG_CHECK_MODULES([WEBP], [libwebp >= 0.2.0])
9696
PHP_EVAL_LIBLINE($WEBP_LIBS, GD_SHARED_LIBADD)
9797
PHP_EVAL_INCLINE($WEBP_CFLAGS)
9898
AC_DEFINE(HAVE_LIBWEBP, 1, [ ])

ext/gd/gd.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,11 @@ PHP_MINIT_FUNCTION(gd)
378378
REGISTER_LONG_CONSTANT("IMG_BMP", PHP_IMG_BMP, CONST_CS | CONST_PERSISTENT);
379379
REGISTER_LONG_CONSTANT("IMG_TGA", PHP_IMG_TGA, CONST_CS | CONST_PERSISTENT);
380380

381+
#ifdef gdWebpLossless
382+
/* constant for webp encoding */
383+
REGISTER_LONG_CONSTANT("IMG_WEBP_LOSSLESS", gdWebpLossless, CONST_CS | CONST_PERSISTENT);
384+
#endif
385+
381386
/* special colours for gd */
382387
REGISTER_LONG_CONSTANT("IMG_COLOR_TILED", gdTiled, CONST_CS | CONST_PERSISTENT);
383388
REGISTER_LONG_CONSTANT("IMG_COLOR_STYLED", gdStyled, CONST_CS | CONST_PERSISTENT);

ext/gd/libgd/gd.h

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -619,7 +619,20 @@ void *gdImageWBMPPtr(gdImagePtr im, int *size, int fg);
619619
void gdImageJpeg(gdImagePtr im, FILE *out, int quality);
620620
void gdImageJpegCtx(gdImagePtr im, gdIOCtx *out, int quality);
621621

622-
void gdImageWebpCtx (gdImagePtr im, gdIOCtx * outfile, int quantization);
622+
/**
623+
* Group: WebP
624+
*
625+
* Constant: gdWebpLossless
626+
*
627+
* Lossless quality threshold. When image quality is greater than or equal to
628+
* <gdWebpLossless>, the image will be written in the lossless WebP format.
629+
*
630+
* See also:
631+
* - <gdImageWebpCtx>
632+
*/
633+
#define gdWebpLossless 101
634+
635+
void gdImageWebpCtx (gdImagePtr im, gdIOCtx * outfile, int quality);
623636

624637
/* Best to free this memory with gdFree(), not free() */
625638
void *gdImageJpegPtr(gdImagePtr im, int *size, int quality);

ext/gd/libgd/gd_webp.c

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ gdImagePtr gdImageCreateFromWebpCtx (gdIOCtx * infile)
100100
return im;
101101
}
102102

103-
void gdImageWebpCtx (gdImagePtr im, gdIOCtx * outfile, int quantization)
103+
void gdImageWebpCtx (gdImagePtr im, gdIOCtx * outfile, int quality)
104104
{
105105
uint8_t *argb;
106106
int x, y;
@@ -117,8 +117,8 @@ void gdImageWebpCtx (gdImagePtr im, gdIOCtx * outfile, int quantization)
117117
return;
118118
}
119119

120-
if (quantization == -1) {
121-
quantization = 80;
120+
if (quality == -1) {
121+
quality = 80;
122122
}
123123

124124
if (overflow2(gdImageSX(im), 4)) {
@@ -151,7 +151,13 @@ void gdImageWebpCtx (gdImagePtr im, gdIOCtx * outfile, int quantization)
151151
*(p++) = a;
152152
}
153153
}
154-
out_size = WebPEncodeRGBA(argb, gdImageSX(im), gdImageSY(im), gdImageSX(im) * 4, quantization, &out);
154+
155+
if (quality >= gdWebpLossless) {
156+
out_size = WebPEncodeLosslessRGBA(argb, gdImageSX(im), gdImageSY(im), gdImageSX(im) * 4, &out);
157+
} else {
158+
out_size = WebPEncodeRGBA(argb, gdImageSX(im), gdImageSY(im), gdImageSX(im) * 4, quality, &out);
159+
}
160+
155161
if (out_size == 0) {
156162
zend_error(E_ERROR, "gd-webp encoding failed");
157163
goto freeargb;
@@ -163,10 +169,10 @@ void gdImageWebpCtx (gdImagePtr im, gdIOCtx * outfile, int quantization)
163169
gdFree(argb);
164170
}
165171

166-
void gdImageWebpEx (gdImagePtr im, FILE * outFile, int quantization)
172+
void gdImageWebpEx (gdImagePtr im, FILE * outFile, int quality)
167173
{
168174
gdIOCtx *out = gdNewFileCtx(outFile);
169-
gdImageWebpCtx(im, out, quantization);
175+
gdImageWebpCtx(im, out, quality);
170176
out->gd_free(out);
171177
}
172178

@@ -188,11 +194,11 @@ void * gdImageWebpPtr (gdImagePtr im, int *size)
188194
return rv;
189195
}
190196

191-
void * gdImageWebpPtrEx (gdImagePtr im, int *size, int quantization)
197+
void * gdImageWebpPtrEx (gdImagePtr im, int *size, int quality)
192198
{
193199
void *rv;
194200
gdIOCtx *out = gdNewDynamicCtx(2048, NULL);
195-
gdImageWebpCtx(im, out, quantization);
201+
gdImageWebpCtx(im, out, quality);
196202
rv = gdDPExtractData(out, size);
197203
out->gd_free(out);
198204
return rv;

ext/gd/tests/webp_basic.phpt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,19 @@ imagewebp($im1, $filename);
2929

3030
$im2 = imagecreatefromwebp($filename);
3131
imagewebp($im2, $filename);
32+
echo 'Is lossy conversion close enough? ';
3233
var_dump(calc_image_dissimilarity($im1, $im2) < 10e5);
34+
35+
imagewebp($im1, $filename, IMG_WEBP_LOSSLESS);
36+
$im_lossless = imagecreatefromwebp($filename);
37+
echo 'Does lossless conversion work? ';
38+
var_dump(calc_image_dissimilarity($im1, $im_lossless) == 0);
39+
3340
?>
3441
--CLEAN--
3542
<?php
3643
@unlink(__DIR__ . '/webp_basic.webp');
3744
?>
3845
--EXPECT--
39-
bool(true)
46+
Is lossy conversion close enough? bool(true)
47+
Does lossless conversion work? bool(true)

0 commit comments

Comments
 (0)