diff --git a/ext/gd/config.m4 b/ext/gd/config.m4 index 4c24e1f5842f5..e93eb703d299d 100644 --- a/ext/gd/config.m4 +++ b/ext/gd/config.m4 @@ -92,7 +92,7 @@ AC_DEFUN([PHP_GD_AVIF],[ AC_DEFUN([PHP_GD_WEBP],[ if test "$PHP_WEBP" != "no"; then - PKG_CHECK_MODULES([WEBP], [libwebp]) + PKG_CHECK_MODULES([WEBP], [libwebp >= 0.2.0]) PHP_EVAL_LIBLINE($WEBP_LIBS, GD_SHARED_LIBADD) PHP_EVAL_INCLINE($WEBP_CFLAGS) AC_DEFINE(HAVE_LIBWEBP, 1, [ ]) diff --git a/ext/gd/gd.c b/ext/gd/gd.c index 0ecee9445ed4c..287cb2f712f8b 100644 --- a/ext/gd/gd.c +++ b/ext/gd/gd.c @@ -378,6 +378,11 @@ PHP_MINIT_FUNCTION(gd) REGISTER_LONG_CONSTANT("IMG_BMP", PHP_IMG_BMP, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("IMG_TGA", PHP_IMG_TGA, CONST_CS | CONST_PERSISTENT); +#ifdef gdWebpLossless + /* constant for webp encoding */ + REGISTER_LONG_CONSTANT("IMG_WEBP_LOSSLESS", gdWebpLossless, CONST_CS | CONST_PERSISTENT); +#endif + /* special colours for gd */ REGISTER_LONG_CONSTANT("IMG_COLOR_TILED", gdTiled, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("IMG_COLOR_STYLED", gdStyled, CONST_CS | CONST_PERSISTENT); diff --git a/ext/gd/libgd/gd.h b/ext/gd/libgd/gd.h index 51235c7c1d6dd..51e7fa7a6e1b0 100644 --- a/ext/gd/libgd/gd.h +++ b/ext/gd/libgd/gd.h @@ -619,7 +619,20 @@ void *gdImageWBMPPtr(gdImagePtr im, int *size, int fg); void gdImageJpeg(gdImagePtr im, FILE *out, int quality); void gdImageJpegCtx(gdImagePtr im, gdIOCtx *out, int quality); -void gdImageWebpCtx (gdImagePtr im, gdIOCtx * outfile, int quantization); +/** + * Group: WebP + * + * Constant: gdWebpLossless + * + * Lossless quality threshold. When image quality is greater than or equal to + * , the image will be written in the lossless WebP format. + * + * See also: + * - + */ +#define gdWebpLossless 101 + +void gdImageWebpCtx (gdImagePtr im, gdIOCtx * outfile, int quality); /* Best to free this memory with gdFree(), not free() */ void *gdImageJpegPtr(gdImagePtr im, int *size, int quality); diff --git a/ext/gd/libgd/gd_webp.c b/ext/gd/libgd/gd_webp.c index bcd8008eab0d0..a27398f1e491b 100644 --- a/ext/gd/libgd/gd_webp.c +++ b/ext/gd/libgd/gd_webp.c @@ -100,7 +100,7 @@ gdImagePtr gdImageCreateFromWebpCtx (gdIOCtx * infile) return im; } -void gdImageWebpCtx (gdImagePtr im, gdIOCtx * outfile, int quantization) +void gdImageWebpCtx (gdImagePtr im, gdIOCtx * outfile, int quality) { uint8_t *argb; int x, y; @@ -117,8 +117,8 @@ void gdImageWebpCtx (gdImagePtr im, gdIOCtx * outfile, int quantization) return; } - if (quantization == -1) { - quantization = 80; + if (quality == -1) { + quality = 80; } if (overflow2(gdImageSX(im), 4)) { @@ -151,7 +151,13 @@ void gdImageWebpCtx (gdImagePtr im, gdIOCtx * outfile, int quantization) *(p++) = a; } } - out_size = WebPEncodeRGBA(argb, gdImageSX(im), gdImageSY(im), gdImageSX(im) * 4, quantization, &out); + + if (quality >= gdWebpLossless) { + out_size = WebPEncodeLosslessRGBA(argb, gdImageSX(im), gdImageSY(im), gdImageSX(im) * 4, &out); + } else { + out_size = WebPEncodeRGBA(argb, gdImageSX(im), gdImageSY(im), gdImageSX(im) * 4, quality, &out); + } + if (out_size == 0) { zend_error(E_ERROR, "gd-webp encoding failed"); goto freeargb; @@ -163,10 +169,10 @@ void gdImageWebpCtx (gdImagePtr im, gdIOCtx * outfile, int quantization) gdFree(argb); } -void gdImageWebpEx (gdImagePtr im, FILE * outFile, int quantization) +void gdImageWebpEx (gdImagePtr im, FILE * outFile, int quality) { gdIOCtx *out = gdNewFileCtx(outFile); - gdImageWebpCtx(im, out, quantization); + gdImageWebpCtx(im, out, quality); out->gd_free(out); } @@ -188,11 +194,11 @@ void * gdImageWebpPtr (gdImagePtr im, int *size) return rv; } -void * gdImageWebpPtrEx (gdImagePtr im, int *size, int quantization) +void * gdImageWebpPtrEx (gdImagePtr im, int *size, int quality) { void *rv; gdIOCtx *out = gdNewDynamicCtx(2048, NULL); - gdImageWebpCtx(im, out, quantization); + gdImageWebpCtx(im, out, quality); rv = gdDPExtractData(out, size); out->gd_free(out); return rv; diff --git a/ext/gd/tests/webp_basic.phpt b/ext/gd/tests/webp_basic.phpt index 1432d157e2939..65d933dcc3fda 100644 --- a/ext/gd/tests/webp_basic.phpt +++ b/ext/gd/tests/webp_basic.phpt @@ -29,11 +29,19 @@ imagewebp($im1, $filename); $im2 = imagecreatefromwebp($filename); imagewebp($im2, $filename); +echo 'Is lossy conversion close enough? '; var_dump(calc_image_dissimilarity($im1, $im2) < 10e5); + +imagewebp($im1, $filename, IMG_WEBP_LOSSLESS); +$im_lossless = imagecreatefromwebp($filename); +echo 'Does lossless conversion work? '; +var_dump(calc_image_dissimilarity($im1, $im_lossless) == 0); + ?> --CLEAN-- --EXPECT-- -bool(true) +Is lossy conversion close enough? bool(true) +Does lossless conversion work? bool(true)