From 924c41a59df6dcb49c3486694ea4beccfa5e80e2 Mon Sep 17 00:00:00 2001 From: Ben Morss Date: Fri, 6 Aug 2021 18:46:50 -0400 Subject: [PATCH 1/3] Lossless conversion for webp Propagating lossless conversion from libgd to our bundled gd. Changing "quantization" to "quality" as in libgd. Adding test. --- ext/gd/config.m4 | 2 +- ext/gd/libgd/gd.h | 15 ++++++++++++++- ext/gd/libgd/gd_webp.c | 22 ++++++++++++++-------- ext/gd/tests/webp_basic.phpt | 12 +++++++++++- 4 files changed, 40 insertions(+), 11 deletions(-) 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/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..9af58ea6bf1e7 100644 --- a/ext/gd/tests/webp_basic.phpt +++ b/ext/gd/tests/webp_basic.phpt @@ -14,6 +14,8 @@ if (!function_exists('imagewebp') || !function_exists('imagecreatefromwebp')) --CLEAN-- --EXPECT-- -bool(true) +Is lossy conversion close enough? bool(true) +Does lossless conversion work? bool(true) From 337afb4894b97f79d02873b0857e816c11f1d398 Mon Sep 17 00:00:00 2001 From: Ben Morss Date: Wed, 11 Aug 2021 18:53:33 -0400 Subject: [PATCH 2/3] Created IMG_WEBP_LOSSLESS constant --- ext/gd/gd.c | 3 +++ ext/gd/php_gd.h | 3 +++ ext/gd/tests/webp_basic.phpt | 4 +--- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/ext/gd/gd.c b/ext/gd/gd.c index 0ecee9445ed4c..626c3c4e2b20c 100644 --- a/ext/gd/gd.c +++ b/ext/gd/gd.c @@ -378,6 +378,9 @@ 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); + /* constant for webp encoding */ + REGISTER_LONG_CONSTANT("IMG_WEBP_LOSSLESS", PHP_IMG_WEBP_LOSSLESS, CONST_CS | CONST_PERSISTENT); + /* 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/php_gd.h b/ext/gd/php_gd.h index f063f30e3e075..4e94ac83b5526 100644 --- a/ext/gd/php_gd.h +++ b/ext/gd/php_gd.h @@ -55,6 +55,9 @@ #define PHP_IMG_TGA 128 #define PHP_IMG_AVIF 256 +/* constant for webp encoding. Matches gdWebpLossless in gd.h */ +#define PHP_IMG_WEBP_LOSSLESS 101 + #ifdef PHP_WIN32 # ifdef PHP_GD_EXPORTS # define PHP_GD_API __declspec(dllexport) diff --git a/ext/gd/tests/webp_basic.phpt b/ext/gd/tests/webp_basic.phpt index 9af58ea6bf1e7..65d933dcc3fda 100644 --- a/ext/gd/tests/webp_basic.phpt +++ b/ext/gd/tests/webp_basic.phpt @@ -14,8 +14,6 @@ if (!function_exists('imagewebp') || !function_exists('imagecreatefromwebp')) Date: Thu, 12 Aug 2021 11:43:32 -0400 Subject: [PATCH 3/3] Guard against older versions of gd that lack gdWebpLossless --- ext/gd/gd.c | 4 +++- ext/gd/php_gd.h | 3 --- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/ext/gd/gd.c b/ext/gd/gd.c index 626c3c4e2b20c..287cb2f712f8b 100644 --- a/ext/gd/gd.c +++ b/ext/gd/gd.c @@ -378,8 +378,10 @@ 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", PHP_IMG_WEBP_LOSSLESS, CONST_CS | CONST_PERSISTENT); + 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); diff --git a/ext/gd/php_gd.h b/ext/gd/php_gd.h index 4e94ac83b5526..f063f30e3e075 100644 --- a/ext/gd/php_gd.h +++ b/ext/gd/php_gd.h @@ -55,9 +55,6 @@ #define PHP_IMG_TGA 128 #define PHP_IMG_AVIF 256 -/* constant for webp encoding. Matches gdWebpLossless in gd.h */ -#define PHP_IMG_WEBP_LOSSLESS 101 - #ifdef PHP_WIN32 # ifdef PHP_GD_EXPORTS # define PHP_GD_API __declspec(dllexport)