From 592ac3aa218c4553e8f16609211e4e35ad23bddf Mon Sep 17 00:00:00 2001 From: Ben Morss Date: Wed, 5 May 2021 18:47:22 -0400 Subject: [PATCH 01/37] Initial commit before rebase --- azure/i386/job.yml | 1 + azure/macos/job.yml | 1 + ext/gd/config.m4 | 23 ++++++++++++++++++++++- ext/gd/gd.stub.php | 4 ++++ ext/gd/gd_arginfo.h | 6 ++++++ ext/gd/php_gd.h | 3 +++ 6 files changed, 37 insertions(+), 1 deletion(-) diff --git a/azure/i386/job.yml b/azure/i386/job.yml index 94d234e5fbe9d..fce9517290616 100644 --- a/azure/i386/job.yml +++ b/azure/i386/job.yml @@ -30,6 +30,7 @@ jobs: --with-pdo-sqlite \ --without-pear \ --enable-gd \ + --with-avif \ --with-jpeg \ --with-webp \ --with-freetype \ diff --git a/azure/macos/job.yml b/azure/macos/job.yml index ed2e8d9d223e1..60205a719c907 100644 --- a/azure/macos/job.yml +++ b/azure/macos/job.yml @@ -29,6 +29,7 @@ jobs: --with-pdo-sqlite \ --without-pear \ --enable-gd \ + --with-avif \ --with-jpeg \ --with-webp \ --with-freetype \ diff --git a/ext/gd/config.m4 b/ext/gd/config.m4 index 03c61032aa2d0..4c24e1f5842f5 100644 --- a/ext/gd/config.m4 +++ b/ext/gd/config.m4 @@ -13,6 +13,15 @@ PHP_ARG_WITH([external-gd], [no], [no]) +if test -z "$PHP_AVIF"; then + PHP_ARG_WITH([avif], + [for libavif], + [AS_HELP_STRING([--with-avif], + [GD: Enable AVIF support (only for bundled libgd)])], + [no], + [no]) +fi + if test -z "$PHP_WEBP"; then PHP_ARG_WITH([webp], [for libwebp], @@ -71,6 +80,16 @@ AC_DEFUN([PHP_GD_PNG],[ AC_DEFINE(HAVE_LIBPNG, 1, [ ]) ]) +AC_DEFUN([PHP_GD_AVIF],[ + if test "$PHP_AVIF" != "no"; then + PKG_CHECK_MODULES([AVIF], [libavif]) + PHP_EVAL_LIBLINE($AVIF_LIBS, GD_SHARED_LIBADD) + PHP_EVAL_INCLINE($AVIF_CFLAGS) + AC_DEFINE(HAVE_LIBAVIF, 1, [ ]) + AC_DEFINE(HAVE_GD_AVIF, 1, [ ]) + fi +]) + AC_DEFUN([PHP_GD_WEBP],[ if test "$PHP_WEBP" != "no"; then PKG_CHECK_MODULES([WEBP], [libwebp]) @@ -121,6 +140,7 @@ AC_DEFUN([PHP_GD_JISX0208],[ AC_DEFUN([PHP_GD_CHECK_VERSION],[ PHP_CHECK_LIBRARY(gd, gdImageCreateFromPng, [AC_DEFINE(HAVE_GD_PNG, 1, [ ])], [], [ $GD_SHARED_LIBADD ]) + PHP_CHECK_LIBRARY(gd, gdImageCreateFromAvif, [AC_DEFINE(HAVE_GD_AVIF, 1, [ ])], [], [ $GD_SHARED_LIBADD ]) PHP_CHECK_LIBRARY(gd, gdImageCreateFromWebp, [AC_DEFINE(HAVE_GD_WEBP, 1, [ ])], [], [ $GD_SHARED_LIBADD ]) PHP_CHECK_LIBRARY(gd, gdImageCreateFromJpeg, [AC_DEFINE(HAVE_GD_JPG, 1, [ ])], [], [ $GD_SHARED_LIBADD ]) PHP_CHECK_LIBRARY(gd, gdImageCreateFromXpm, [AC_DEFINE(HAVE_GD_XPM, 1, [ ])], [], [ $GD_SHARED_LIBADD ]) @@ -141,7 +161,7 @@ if test "$PHP_GD" != "no"; then dnl Disable strict prototypes as GD takes advantages of variadic function signatures for function pointers. GD_CFLAGS="-Wno-strict-prototypes" extra_sources="libgd/gd.c libgd/gd_gd.c libgd/gd_gd2.c libgd/gd_io.c libgd/gd_io_dp.c \ - libgd/gd_io_file.c libgd/gd_ss.c libgd/gd_io_ss.c libgd/gd_webp.c \ + libgd/gd_io_file.c libgd/gd_ss.c libgd/gd_io_ss.c libgd/gd_webp.c libgd/gd_avif.c \ libgd/gd_png.c libgd/gd_jpeg.c libgd/gdxpm.c libgd/gdfontt.c libgd/gdfonts.c \ libgd/gdfontmb.c libgd/gdfontl.c libgd/gdfontg.c libgd/gdtables.c libgd/gdft.c \ libgd/gdcache.c libgd/gdkanji.c libgd/wbmp.c libgd/gd_wbmp.c libgd/gdhelpers.c \ @@ -162,6 +182,7 @@ dnl These are always available with bundled library dnl Various checks for GD features PHP_GD_ZLIB PHP_GD_PNG + PHP_GD_AVIF PHP_GD_WEBP PHP_GD_JPEG PHP_GD_XPM diff --git a/ext/gd/gd.stub.php b/ext/gd/gd.stub.php index 068cc8797ed53..44ad27c7d8218 100644 --- a/ext/gd/gd.stub.php +++ b/ext/gd/gd.stub.php @@ -68,6 +68,10 @@ function imagecreatefromstring(string $data): GdImage|false {} function imagecreatefromgif(string $filename): GdImage|false {} +#ifdef HAVE_GD_AVIF +function imagecreatefromavif(string $filename): GdImage|false {} +#endif + #ifdef HAVE_GD_JPG function imagecreatefromjpeg(string $filename): GdImage|false {} #endif diff --git a/ext/gd/gd_arginfo.h b/ext/gd/gd_arginfo.h index 83b72fbdee1c9..a379c0656a16d 100644 --- a/ext/gd/gd_arginfo.h +++ b/ext/gd/gd_arginfo.h @@ -148,6 +148,12 @@ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_imagecreatefromgif, 0, 1, Gd ZEND_ARG_TYPE_INFO(0, filename, IS_STRING, 0) ZEND_END_ARG_INFO() +#if defined(HAVE_GD_AVIF) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_imagecreatefromavif, 0, 1, GdImage, MAY_BE_FALSE) + ZEND_ARG_TYPE_INFO(0, filename, IS_STRING, 0) +ZEND_END_ARG_INFO() +#endif + #if defined(HAVE_GD_JPG) ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_imagecreatefromjpeg, 0, 1, GdImage, MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, filename, IS_STRING, 0) diff --git a/ext/gd/php_gd.h b/ext/gd/php_gd.h index 1c09bc33d8950..e804e748d2e88 100644 --- a/ext/gd/php_gd.h +++ b/ext/gd/php_gd.h @@ -39,6 +39,7 @@ #define PHP_GDIMG_TYPE_WEBP 11 #define PHP_GDIMG_TYPE_BMP 12 #define PHP_GDIMG_TYPE_TGA 13 +#define PHP_GDIMG_TYPE_AVIF 14 #define PHP_IMG_GIF 1 #define PHP_IMG_JPG 2 @@ -49,6 +50,7 @@ #define PHP_IMG_WEBP 32 #define PHP_IMG_BMP 64 #define PHP_IMG_TGA 128 +#define PHP_IMG_AVIF 256 #ifdef PHP_WIN32 # ifdef PHP_GD_EXPORTS @@ -68,6 +70,7 @@ PHPAPI extern const char php_sig_png[8]; PHPAPI extern const char php_sig_bmp[2]; PHPAPI extern const char php_sig_riff[4]; PHPAPI extern const char php_sig_webp[4]; +PHPAPI extern const char php_sig_avif[4]; extern zend_module_entry gd_module_entry; #define phpext_gd_ptr &gd_module_entry From 86a5eb0b6d84d127bbf3bdb1985b7d3f88a0d738 Mon Sep 17 00:00:00 2001 From: Ben Morss Date: Fri, 7 May 2021 16:27:12 -0400 Subject: [PATCH 02/37] Incremental commit --- .travis.yml | 1 + azure/apt.yml | 1 + azure/configure.yml | 1 + azure/i386/apt.yml | 1 + ext/gd/gd.c | 46 +++++++++++++++++++++++++++++++++++++++- ext/gd/gd.stub.php | 9 ++++++-- ext/gd/libgd/gd.h | 11 ++++++++++ ext/standard/image.c | 8 +++++++ ext/standard/php_image.h | 3 ++- 9 files changed, 77 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 59ee5ebb21943..366c393dead78 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,6 +12,7 @@ addons: - re2c - ccache - mysql-server + - libavif-dev - libaspell-dev - libbz2-dev - libcurl4-gnutls-dev diff --git a/azure/apt.yml b/azure/apt.yml index 9166509dccae7..aa29b6ab11458 100644 --- a/azure/apt.yml +++ b/azure/apt.yml @@ -12,6 +12,7 @@ steps: slapd \ language-pack-de \ re2c \ + libavif-dev \ libgmp-dev \ libicu-dev \ libtidy-dev \ diff --git a/azure/configure.yml b/azure/configure.yml index 9869de514e82c..b65ac0dedc034 100644 --- a/azure/configure.yml +++ b/azure/configure.yml @@ -17,6 +17,7 @@ steps: --enable-intl \ --without-pear \ --enable-gd \ + --with-avif \ --with-jpeg \ --with-webp \ --with-freetype \ diff --git a/azure/i386/apt.yml b/azure/i386/apt.yml index 9ae39443755d8..4671c4fe5bcc0 100644 --- a/azure/i386/apt.yml +++ b/azure/i386/apt.yml @@ -44,5 +44,6 @@ steps: libffi-dev:i386 \ libfreetype6-dev:i386 \ libsodium-dev:i386 \ + libavif-dev:i386 \ ${{ parameters.packages }} displayName: 'APT' diff --git a/ext/gd/gd.c b/ext/gd/gd.c index 39fea969f0385..cd37af634b81a 100644 --- a/ext/gd/gd.c +++ b/ext/gd/gd.c @@ -371,6 +371,7 @@ PHP_MINIT_FUNCTION(gd) REGISTER_INI_ENTRIES(); + REGISTER_LONG_CONSTANT("IMG_AVIF", PHP_IMG_AVIF, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("IMG_GIF", PHP_IMG_GIF, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("IMG_JPG", PHP_IMG_JPG, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("IMG_JPEG", PHP_IMG_JPEG, CONST_CS | CONST_PERSISTENT); @@ -601,6 +602,9 @@ PHP_MINFO_FUNCTION(gd) #ifdef HAVE_GD_BMP php_info_print_table_row(2, "BMP Support", "enabled"); #endif +#ifdef HAVE_GD_AVIF + php_info_print_table_row(2, "AVIF Support", "enabled"); +#endif #ifdef HAVE_GD_TGA php_info_print_table_row(2, "TGA Read Support", "enabled"); #endif @@ -655,6 +659,11 @@ PHP_FUNCTION(gd_info) #else add_assoc_bool(return_value, "BMP Support", 0); #endif +#ifdef HAVE_GD_AVIF + add_assoc_bool(return_value, "AVIF Support", 1); +#else + add_assoc_bool(return_value, "AVIF Support", 0); +#endif #ifdef HAVE_GD_TGA add_assoc_bool(return_value, "TGA Read Support", 1); #else @@ -1407,7 +1416,7 @@ PHP_FUNCTION(imagecreate) } /* }}} */ -/* {{{ Return the types of images supported in a bitfield - 1=GIF, 2=JPEG, 4=PNG, 8=WBMP, 16=XPM */ +/* {{{ Return the types of images supported in a bitfield - 1=GIF, 2=JPEG, 4=PNG, 8=WBMP, 16=XPM, etc */ PHP_FUNCTION(imagetypes) { int ret = 0; @@ -1431,6 +1440,9 @@ PHP_FUNCTION(imagetypes) #ifdef HAVE_GD_TGA ret |= PHP_IMG_TGA; #endif +#ifdef HAVE_GD_AVIF + ret |= PHP_IMG_AVIF; +#endif if (zend_parse_parameters_none() == FAILURE) { RETURN_THROWS(); @@ -1589,6 +1601,14 @@ PHP_FUNCTION(imagecreatefromstring) RETURN_FALSE; #endif +#ifdef HAVE_GD_AVIF + im = _php_image_create_from_string(data, "AVIF", gdImageCreateFromAvifCtx); + break; +#else + php_error_docref(NULL, E_WARNING, "No AVIF support in this PHP build"); + RETURN_FALSE; +#endif + default: php_error_docref(NULL, E_WARNING, "Data is not in a recognized format"); RETURN_FALSE; @@ -1769,6 +1789,15 @@ PHP_FUNCTION(imagecreatefromxbm) } /* }}} */ +#ifdef HAVE_GD_AVIF +/* {{{ Create a new image from AVIF file or URL */ +PHP_FUNCTION(imagecreatefromavif) +{ + _php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_AVIF, "AVIF", gdImageCreateFromAvif, gdImageCreateFromAvifCtx); +} +/* }}} */ +#endif /* HAVE_GD_AVIF */ + #ifdef HAVE_GD_XPM /* {{{ Create a new image from XPM file or URL */ PHP_FUNCTION(imagecreatefromxpm) @@ -1996,6 +2025,15 @@ PHP_FUNCTION(imagewebp) /* }}} */ #endif /* HAVE_GD_WEBP */ +#ifdef HAVE_GD_AVIF +/* {{{ Output AVIF image to browser or file */ +PHP_FUNCTION(imageavif) +{ + _php_image_output_ctx(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_AVIF, "AVIF", gdImageAvifCtx); +} +/* }}} */ +#endif /* HAVE_GD_AVIF */ + #ifdef HAVE_GD_JPG /* {{{ Output JPEG image to browser or file */ PHP_FUNCTION(imagejpeg) @@ -4218,6 +4256,12 @@ static void _php_image_output_ctx(INTERNAL_FUNCTION_PARAMETERS, int image_type, } (*func_p)(im, ctx, (int) quality); break; + case PHP_GDIMG_TYPE_AVIF: + if (speed == -1) { + speed = 6; + } + (*func_p)(im, ctx, (int) quality, (int) speed); + break; case PHP_GDIMG_TYPE_PNG: (*func_p)(im, ctx, (int) quality, (int) basefilter); break; diff --git a/ext/gd/gd.stub.php b/ext/gd/gd.stub.php index 44ad27c7d8218..5e39ef83cd571 100644 --- a/ext/gd/gd.stub.php +++ b/ext/gd/gd.stub.php @@ -66,12 +66,12 @@ function imagetypes(): int {} function imagecreatefromstring(string $data): GdImage|false {} -function imagecreatefromgif(string $filename): GdImage|false {} - #ifdef HAVE_GD_AVIF function imagecreatefromavif(string $filename): GdImage|false {} #endif +function imagecreatefromgif(string $filename): GdImage|false {} + #ifdef HAVE_GD_JPG function imagecreatefromjpeg(string $filename): GdImage|false {} #endif @@ -108,6 +108,11 @@ function imagecreatefromtga(string $filename): GdImage|false {} function imagexbm(GdImage $image, ?string $filename, ?int $foreground_color = null): bool {} +#ifdef HAVE_GD_AVIF +/** @param resource|string|null $file */ +function imageavif(GdImage $image, $file = null, int $quality = -1, int $speed = -1): bool {} +#endif + /** @param resource|string|null $file */ function imagegif(GdImage $image, $file = null): bool {} diff --git a/ext/gd/libgd/gd.h b/ext/gd/libgd/gd.h index f274b3aebad73..163254f75f379 100644 --- a/ext/gd/libgd/gd.h +++ b/ext/gd/libgd/gd.h @@ -364,6 +364,10 @@ gdImagePtr gdImageCreateFromWebp(FILE *fd); gdImagePtr gdImageCreateFromWebpCtx(gdIOCtxPtr in); gdImagePtr gdImageCreateFromWebpPtr (int size, void *data); +gdImagePtr gdImageCreateFromAvif(FILE *infile); +gdImagePtr gdImageCreateFromAvifPtr(int size, void *data); +gdImagePtr gdImageCreateFromAvifCtx(gdIOCtx *infile); + gdImagePtr gdImageCreateFromTga( FILE * fp ); gdImagePtr gdImageCreateFromTgaCtx(gdIOCtx* ctx); gdImagePtr gdImageCreateFromTgaPtr(int size, void *data); @@ -624,6 +628,13 @@ gdImagePtr gdImageCreateFromGif(FILE *fd); gdImagePtr gdImageCreateFromGifCtx(gdIOCtxPtr in); gdImagePtr gdImageCreateFromGifSource(gdSourcePtr in); +//TODO: we may not need all of these +void gdImageAvif(gdImagePtr im, FILE *outfile); +void gdImageAvifEx(gdImagePtr im, FILE *outfile, int quality, int speed); +void *gdImageAvifPtr(gdImagePtr im, int *size); +void *gdImageAvifPtrEx(gdImagePtr im, int *size, int quality, int speed); +void gdImageAvifCtx(gdImagePtr im, gdIOCtx *outfile, int quality, int speed); + /* A custom data sink. For backwards compatibility. Use gdIOCtx instead. */ /* The sink function must return -1 on error, otherwise the number diff --git a/ext/standard/image.c b/ext/standard/image.c index ed180b7bca6df..25b9aa2e5d110 100644 --- a/ext/standard/image.c +++ b/ext/standard/image.c @@ -90,6 +90,7 @@ PHP_MINIT_FUNCTION(imagetypes) REGISTER_LONG_CONSTANT("IMAGETYPE_WEBP", IMAGE_FILETYPE_WEBP, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("IMAGETYPE_UNKNOWN", IMAGE_FILETYPE_UNKNOWN, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("IMAGETYPE_COUNT", IMAGE_FILETYPE_COUNT, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IMAGETYPE_AVIF", IMAGE_FILETYPE_AVIF, CONST_CS | CONST_PERSISTENT); return SUCCESS; } /* }}} */ @@ -1183,6 +1184,8 @@ PHPAPI char * php_image_type_to_mime_type(int image_type) return "image/vnd.microsoft.icon"; case IMAGE_FILETYPE_WEBP: return "image/webp"; + case IMAGE_FILETYPE_AVIF: + return "image/avif"; default: case IMAGE_FILETYPE_UNKNOWN: return "application/octet-stream"; /* suppose binary format */ @@ -1264,6 +1267,8 @@ PHP_FUNCTION(image_type_to_extension) break; case IMAGE_FILETYPE_WEBP: imgext = ".webp"; + case IMAGE_FILETYPE_AVIF: + imgext = ".avif"; break; } @@ -1431,6 +1436,9 @@ static void php_getimagesize_from_stream(php_stream *stream, char *input, zval * case IMAGE_FILETYPE_WEBP: result = php_handle_webp(stream); break; + case IMAGE_FILETYPE_AVIF: + result = php_handle_avif(stream); + break; default: case IMAGE_FILETYPE_UNKNOWN: break; diff --git a/ext/standard/php_image.h b/ext/standard/php_image.h index 8311f4b2ab8fb..3d00cec171156 100644 --- a/ext/standard/php_image.h +++ b/ext/standard/php_image.h @@ -44,7 +44,8 @@ typedef enum IMAGE_FILETYPE_ICO, IMAGE_FILETYPE_WEBP, /* WHEN EXTENDING: PLEASE ALSO REGISTER IN image.c:PHP_MINIT_FUNCTION(imagetypes) */ - IMAGE_FILETYPE_COUNT + IMAGE_FILETYPE_COUNT, + IMAGE_FILETYPE_AVIF } image_filetype; /* }}} */ From f1b3dd1ccc40cc85758646d010acd3287740b9b1 Mon Sep 17 00:00:00 2001 From: Ben Morss Date: Mon, 10 May 2021 13:14:14 -0400 Subject: [PATCH 03/37] Incremental commit --- ext/gd/gd_arginfo.h | 31 ++- ext/gd/libgd/gd_avif.c | 607 +++++++++++++++++++++++++++++++++++++++++ ext/standard/image.c | 7 + 3 files changed, 640 insertions(+), 5 deletions(-) create mode 100644 ext/gd/libgd/gd_avif.c diff --git a/ext/gd/gd_arginfo.h b/ext/gd/gd_arginfo.h index a379c0656a16d..dad8f3a3eac03 100644 --- a/ext/gd/gd_arginfo.h +++ b/ext/gd/gd_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 4db5a04f57436fffff4d34f4e44db7b7fdc39874 */ + * Stub hash: 6c091ec5dc43771d26c3dac479ede7b38aa6e574 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_gd_info, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() @@ -144,16 +144,16 @@ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_imagecreatefromstring, 0, 1, ZEND_ARG_TYPE_INFO(0, data, IS_STRING, 0) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_imagecreatefromgif, 0, 1, GdImage, MAY_BE_FALSE) - ZEND_ARG_TYPE_INFO(0, filename, IS_STRING, 0) -ZEND_END_ARG_INFO() - #if defined(HAVE_GD_AVIF) ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_imagecreatefromavif, 0, 1, GdImage, MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, filename, IS_STRING, 0) ZEND_END_ARG_INFO() #endif +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_imagecreatefromgif, 0, 1, GdImage, MAY_BE_FALSE) + ZEND_ARG_TYPE_INFO(0, filename, IS_STRING, 0) +ZEND_END_ARG_INFO() + #if defined(HAVE_GD_JPG) ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_imagecreatefromjpeg, 0, 1, GdImage, MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, filename, IS_STRING, 0) @@ -212,6 +212,15 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imagexbm, 0, 2, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, foreground_color, IS_LONG, 1, "null") ZEND_END_ARG_INFO() +#if defined(HAVE_GD_AVIF) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imageavif, 0, 1, _IS_BOOL, 0) + ZEND_ARG_OBJ_INFO(0, image, GdImage, 0) + ZEND_ARG_INFO_WITH_DEFAULT_VALUE(0, file, "null") + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, quality, IS_LONG, 0, "-1") + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, speed, IS_LONG, 0, "-1") +ZEND_END_ARG_INFO() +#endif + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imagegif, 0, 1, _IS_BOOL, 0) ZEND_ARG_OBJ_INFO(0, image, GdImage, 0) ZEND_ARG_INFO_WITH_DEFAULT_VALUE(0, file, "null") @@ -599,6 +608,9 @@ ZEND_FUNCTION(imagesetbrush); ZEND_FUNCTION(imagecreate); ZEND_FUNCTION(imagetypes); ZEND_FUNCTION(imagecreatefromstring); +#if defined(HAVE_GD_AVIF) +ZEND_FUNCTION(imagecreatefromavif); +#endif ZEND_FUNCTION(imagecreatefromgif); #if defined(HAVE_GD_JPG) ZEND_FUNCTION(imagecreatefromjpeg); @@ -624,6 +636,9 @@ ZEND_FUNCTION(imagecreatefrombmp); ZEND_FUNCTION(imagecreatefromtga); #endif ZEND_FUNCTION(imagexbm); +#if defined(HAVE_GD_AVIF) +ZEND_FUNCTION(imageavif); +#endif ZEND_FUNCTION(imagegif); #if defined(HAVE_GD_PNG) ZEND_FUNCTION(imagepng); @@ -734,6 +749,9 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(imagecreate, arginfo_imagecreate) ZEND_FE(imagetypes, arginfo_imagetypes) ZEND_FE(imagecreatefromstring, arginfo_imagecreatefromstring) +#if defined(HAVE_GD_AVIF) + ZEND_FE(imagecreatefromavif, arginfo_imagecreatefromavif) +#endif ZEND_FE(imagecreatefromgif, arginfo_imagecreatefromgif) #if defined(HAVE_GD_JPG) ZEND_FE(imagecreatefromjpeg, arginfo_imagecreatefromjpeg) @@ -759,6 +777,9 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(imagecreatefromtga, arginfo_imagecreatefromtga) #endif ZEND_FE(imagexbm, arginfo_imagexbm) +#if defined(HAVE_GD_AVIF) + ZEND_FE(imageavif, arginfo_imageavif) +#endif ZEND_FE(imagegif, arginfo_imagegif) #if defined(HAVE_GD_PNG) ZEND_FE(imagepng, arginfo_imagepng) diff --git a/ext/gd/libgd/gd_avif.c b/ext/gd/libgd/gd_avif.c new file mode 100644 index 0000000000000..1e77b0b97d64c --- /dev/null +++ b/ext/gd/libgd/gd_avif.c @@ -0,0 +1,607 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include + +#include "gd.h" +#include "gdhelpers.h" +#include "gd_intern.h" + +#ifdef HAVE_LIBAVIF +#include + +/* + Define defaults for encoding images: + CHROMA_SUBSAMPLING_DEFAULT: 4:2:0 is commonly used for Chroma subsampling. + CHROMA_SUBAMPLING_HIGH_QUALITY: Use 4:4:4, or no subsampling, when a sufficient high quality is requested. + SUBAMPLING_HIGH_QUALITY_THRESHOLD: At or above this value, use CHROMA_SUBAMPLING_HIGH_QUALITY + QUANTIZER_DEFAULT: + We need more testing to really know what quantizer settings are optimal, + but teams at Google have been using maximum=30 as a starting point. + QUALITY_DEFAULT: following gd conventions, -1 indicates the default. + SPEED_DEFAULT: + AVIF_SPEED_DEFAULT is simply the default encoding speed of the AV1 codec. + This could be as slow as 0. So we use 6, which is currently considered to be a fine default. + +*/ + +#define CHROMA_SUBSAMPLING_DEFAULT AVIF_PIXEL_FORMAT_YUV420 +#define CHROMA_SUBAMPLING_HIGH_QUALITY AVIF_PIXEL_FORMAT_YUV444 +#define HIGH_QUALITY_SUBSAMPLING_THRESHOLD 90 +#define QUANTIZER_DEFAULT 30 +#define QUALITY_DEFAULT -1 +#define SPEED_DEFAULT 6 + +// This initial size for the gdIOCtx is standard among GD image conversion functions. +#define NEW_DYNAMIC_CTX_SIZE 2048 + +// Our quality param ranges from 0 to 100. +// To calculate quality, we convert from AVIF's quantizer scale, which runs from 63 to 0. +#define MAX_QUALITY 100 + +// These constants are for computing the number of tiles and threads to use during encoding. +// Maximum threads are from libavif/contrib/gkd-pixbuf/loader.c. +#define MIN_TILE_AREA (512 * 512) +#define MAX_TILES 8 +#define MAX_THREADS 64 + +/*** Macros ***/ + +/* + From gd_png.c: + convert the 7-bit alpha channel to an 8-bit alpha channel. + We do a little bit-flipping magic, repeating the MSB + as the LSB, to ensure that 0 maps to 0 and + 127 maps to 255. We also have to invert to match + PNG's convention in which 255 is opaque. +*/ +#define alpha7BitTo8Bit(alpha7Bit) \ + (alpha7Bit == 127 ? \ + 0 : \ + 255 - ((alpha7Bit << 1) + (alpha7Bit >> 6))) + +#define alpha8BitTo7Bit(alpha8Bit) (gdAlphaMax - (alpha8Bit >> 1)) + + +/*** Helper functions ***/ + +/* Convert the quality param we expose to the quantity params used by libavif. + The *Quantizer* params values can range from 0 to 63, with 0 = highest quality and 63 = worst. + We make the scale 0-100, and we reverse this, so that 0 = worst quality and 100 = highest. + + Values below 0 are set to 0, and values below MAX_QUALITY are set to MAX_QUALITY. +*/ +static int quality2Quantizer(int quality) { + int clampedQuality = CLAMP(quality, 0, MAX_QUALITY); + + float scaleFactor = (float) AVIF_QUANTIZER_WORST_QUALITY / (float) MAX_QUALITY; + + return round(scaleFactor * (MAX_QUALITY - clampedQuality)); +} + +/* + As of February 2021, this algorithm reflects the latest research on how many tiles + and threads to include for a given image size. + This is subject to change as research continues. + + Returns false if there was an error, true if all was well. + */ +static avifBool setEncoderTilesAndThreads(avifEncoder *encoder, avifRGBImage *rgb) { + int imageArea, tiles, tilesLog2, encoderTiles; + + // _gdImageAvifCtx(), the calling function, checks this operation for overflow + imageArea = rgb->width * rgb->height; + + tiles = (int) ceil((double) imageArea / MIN_TILE_AREA); + tiles = MIN(tiles, MAX_TILES); + tiles = MIN(tiles, MAX_THREADS); + + // The number of tiles in any dimension will always be a power of 2. We can only specify log(2)tiles. + + tilesLog2 = floor(log2(tiles)); + + // If the image's width is greater than the height, use more tile columns + // than tile rows to make the tile size close to a square. + + if (rgb->width >= rgb->height) { + encoder->tileRowsLog2 = tilesLog2 / 2; + encoder->tileColsLog2 = tilesLog2 - encoder->tileRowsLog2; + } else { + encoder->tileColsLog2 = tilesLog2 / 2; + encoder->tileRowsLog2 = tilesLog2 - encoder->tileColsLog2; + } + + // It's good to have one thread per tile. + encoderTiles = (1 << encoder->tileRowsLog2) * (1 << encoder->tileColsLog2); + encoder->maxThreads = encoderTiles; + + return AVIF_TRUE; +} + +/* + We can handle AVIF images whose color profile is sRGB, or whose color profile isn't set. +*/ +static avifBool isAvifSrgbImage(avifImage *avifIm) { + return + (avifIm->colorPrimaries == AVIF_COLOR_PRIMARIES_BT709 || + avifIm->colorPrimaries == AVIF_COLOR_PRIMARIES_UNSPECIFIED) && + (avifIm->transferCharacteristics == AVIF_TRANSFER_CHARACTERISTICS_SRGB || + avifIm->transferCharacteristics == AVIF_TRANSFER_CHARACTERISTICS_UNSPECIFIED) + ; +} + +/* + Check the result from an Avif function to see if it's an error. + If so, decode the error and output it, and return true. + Otherwise, return false. +*/ +static avifBool isAvifError(avifResult result, const char *msg) { + if (result != AVIF_RESULT_OK) { + zend_error(E_ERROR, "avif error - %s: %s", msg, avifResultToString(result)); + return AVIF_TRUE; + } + + return AVIF_FALSE; +} + + +/* + implements the avifIOReadFunc interface by calling the relevant functions + in the gdIOCtx. Our logic is inspired by avifIOMemoryReaderRead() and avifIOFileReaderRead(). + We don't know whether we're reading from a file or from memory. We don't have to know, + since we rely on the helper functions in the gdIOCtx. + We assume we've stashed the gdIOCtx in io->data, as we do in createAvifIOFromCtx(). + + We ignore readFlags, just as the avifIO*ReaderRead() functions do. + + If there's a problem, this returns an avifResult error. + If things go well, return AVIF_RESULT_OK. + Of course these AVIF codes shouldn't be returned by any top-level GD function. +*/ +static avifResult readFromCtx(avifIO *io, uint32_t readFlags, uint64_t offset, size_t size, avifROData *out) +{ + void *dataBuf = NULL; + gdIOCtx *ctx = (gdIOCtx *) io->data; + + // TODO: if we set sizeHint, this will be more efficient. + + if (offset > LONG_MAX || size < 0) + return AVIF_RESULT_IO_ERROR; + + // Try to seek offset bytes forward. If we pass the end of the buffer, throw an error. + if (!ctx->seek(ctx, offset)) + return AVIF_RESULT_IO_ERROR; + + dataBuf = gdMalloc(size); + if (!dataBuf) { + zend_error(E_ERROR, "avif error - couldn't allocate memory"); + return AVIF_RESULT_UNKNOWN_ERROR; + } + + // Read the number of bytes requested. + // If getBuf() returns a negative value, that means there was an error. + int charsRead = ctx->getBuf(ctx, dataBuf, size); + if (charsRead < 0) { + gdFree(dataBuf); + return AVIF_RESULT_IO_ERROR; + } + + out->data = dataBuf; + out->size = charsRead; + return charsRead == size ? AVIF_RESULT_OK : AVIF_RESULT_TRUNCATED_DATA; +} + +// avif.h says this is optional, but it seemed easy to implement. +static void destroyAvifIO(struct avifIO *io) { + avifFree(io); +} + +/* Set up an avifIO object. + The functions in the gdIOCtx struct may point either to a file or a memory buffer. + To us, that's immaterial. + Our task is simply to assign avifIO functions to the proper functions from gdIOCtx. + The destroy function needs to destroy the avifIO object and anything else it uses. + + Returns NULL if memory for the object can't be allocated. +*/ + +// TODO: can we get sizeHint somehow? +static avifIO *createAvifIOFromCtx(gdIOCtx *ctx) { + avifIO *io; + + io = gdMalloc(sizeof(*io)); + if (io == NULL) + return NULL; + + // TODO: setting persistent=FALSE is safe, but it's less efficient. Is it necessary? + io->persistent = AVIF_FALSE; + io->read = readFromCtx; + io->write = NULL; // this function is currently unused; see avif.h + io->destroy = destroyAvifIO; + io->sizeHint = 0; // sadly, we don't get this information from the gdIOCtx. + io->data = ctx; + + return io; +} + + +/*** Decoding functions ***/ + +/* + Function: gdImageCreateFromAvif + + is called to load truecolor images from + AVIF format files. Invoke with an + already opened pointer to a file containing the desired + image. returns a to the new + truecolor image, or NULL if unable to load the image (most often + because the file is corrupt or does not contain a AVIF + image). does not close the file. + + This function creates a gdIOCtx struct from the file pointer it's passed. + And then it relies on to do the real decoding work. + If the file contains an image sequence, we simply read the first one, discarding the rest. + + Variants: + + creates an image from AVIF data + already in memory. + + reads data from the function + pointers in a structure. + + Parameters: + + infile - pointer to the input file + + Returns: + + A pointer to the new truecolor image. This will need to be + destroyed with once it is no longer needed. + + On error, returns 0. +*/ +gdImagePtr gdImageCreateFromAvif(FILE *infile) +{ + gdImagePtr im; + gdIOCtx *ctx = gdNewFileCtx(infile); + + if (!ctx) + return NULL; + + im = gdImageCreateFromAvifCtx(ctx); + ctx->gd_free(ctx); + + return im; +} + +/* + Function: gdImageCreateFromAvifPtr + + See . + + Parameters: + + size - size of Avif data in bytes. + data - pointer to Avif data. +*/ +gdImagePtr gdImageCreateFromAvifPtr(int size, void *data) +{ + gdImagePtr im; + gdIOCtx *ctx = gdNewDynamicCtxEx(size, data, 0); + + if (!ctx) + return 0; + + im = gdImageCreateFromAvifCtx(ctx); + ctx->gd_free(ctx); + + return im; +} + +/* + Function: gdImageCreateFromAvifCtx + + See . + + Additional details: the AVIF library comes with functions to create an IO object from + a file and from a memory pointer. Of course, it doesn't have a way to create an IO object + from a gdIOCtx. So, here, we use our own helper function, . + + Otherwise, we create the image by calling AVIF library functions in order: + * avifDecoderCreate(), to create the decoder + * avifDecoderSetIO(), to tell libavif how to read from our data structure + * avifDecoderParse(), to parse the image + * avifDecoderNextImage(), to read the first image from the decoder + * avifRGBImageSetDefaults(), to create the avifRGBImage + * avifRGBImageAllocatePixels(), to allocate memory for the pixels + * avifImageYUVToRGB(), to convert YUV to RGB + + Finally, we create a new gd image and copy over the pixel data. + + Parameters: + + ctx - a gdIOCtx struct +*/ +gdImagePtr gdImageCreateFromAvifCtx (gdIOCtx *ctx) +{ + int x, y; + gdImage *im = NULL; + avifResult result; + avifIO *io; + avifDecoder *decoder; + avifRGBImage rgb; + + // this lets us know that memory hasn't been allocated yet for the pixels + rgb.pixels = NULL; + + decoder = avifDecoderCreate(); + + io = createAvifIOFromCtx(ctx); + if (!io) { + zend_error(E_ERROR, "avif error - Could not allocate memory"); + goto cleanup; + } + + avifDecoderSetIO(decoder, io); + + result = avifDecoderParse(decoder); + if (isAvifError(result, "Could not parse image")) + goto cleanup; + + // Note again that, for an image sequence, we read only the first image, ignoring the rest. + result = avifDecoderNextImage(decoder); + if (isAvifError(result, "Could not decode image")) + goto cleanup; + + if (!isAvifSrgbImage(decoder->image)) + gd_error_ex(LOG_WARNING, "Image's color profile is not sRGB"); + + // Set up the avifRGBImage, and convert it from YUV to an 8-bit RGB image. + // (While AVIF image pixel depth can be 8, 10, or 12 bits, GD truecolor images are 8-bit.) + avifRGBImageSetDefaults(&rgb, decoder->image); + rgb.depth = 8; + avifRGBImageAllocatePixels(&rgb); + + result = avifImageYUVToRGB(decoder->image, &rgb); + if (isAvifError(result, "Conversion from YUV to RGB failed")) + goto cleanup; + + im = gdImageCreateTrueColor(decoder->image->width, decoder->image->height); + if (!im) { + zend_error(E_ERROR, "avif error - Could not create GD truecolor image"); + goto cleanup; + } + + im->saveAlphaFlag = 1; + + // Read the pixels from the AVIF image and copy them into the GD image. + + uint8_t *p = rgb.pixels; + + for (y = 0; y < decoder->image->height; y++) { + for (x = 0; x < decoder->image->width; x++) { + uint8_t r = *(p++); + uint8_t g = *(p++); + uint8_t b = *(p++); + uint8_t a = alpha8BitTo7Bit(*(p++)); + im->tpixels[y][x] = gdTrueColorAlpha(r, g, b, a); + } + } + +cleanup: + // if io has been allocated, this frees it + avifDecoderDestroy(decoder); + + if (rgb.pixels) + avifRGBImageFreePixels(&rgb); + + return im; +} + + +/*** Encoding functions ***/ + +/* + Function: gdImageAvifEx + + outputs the specified image to the specified file in + AVIF format. The file must be open for writing. Under MSDOS and + all versions of Windows, it is important to use "wb" as opposed to + simply "w" as the mode when opening the file, and under Unix there + is no penalty for doing so. does not close the file; + your code must do so. + + Variants: + + writes the image to a file, encoding with the default quality and speed. + + stores the image in RAM. + + stores the image in RAM, encoding with the default quality and speed. + + stores the image using a struct. + + Parameters: + + im - The image to save. + outFile - The FILE pointer to write to. + quality - Compression quality (0-100). 0 is lowest-quality, 100 is highest. + speed - The speed of compression (0-10). 0 is slowest, 10 is fastest. + + Notes on parameters: + quality - If quality = -1, we use a default quality as defined in QUALITY_DEFAULT. + For information on how we convert this quality to libavif's quantity param, see . + + speed - At slower speeds, encoding may be quite slow. Use judiciously. + + Qualities or speeds that are lower than the minimum value get clamped to the minimum value, + and qualities or speeds that are lower than the maximum value get clamped to the maxmum value. + Note that AVIF_SPEED_DEFAULT is -1. If we ever set SPEED_DEFAULT = AVIF_SPEED_DEFAULT, + we'd want to add a conditional to ensure that value doesn't get clamped. + + + Returns: + + * for , , and , nothing. + * for and , a pointer to the image in memory. +*/ + +/* + If we're passed the QUALITY_DEFAULT of -1, set the quantizer params to QUANTIZER_DEFAULT. +*/ +void gdImageAvifCtx(gdImagePtr im, gdIOCtx *outfile, int quality, int speed) +{ + avifResult result; + avifRGBImage rgb; + avifRWData avifOutput = AVIF_DATA_EMPTY; + avifBool failed = AVIF_FALSE; + avifBool lossless = quality == 100; + avifEncoder *encoder = NULL; + + uint32_t val; + uint8_t *p; + int x, y; + + if (im == NULL) + return; + + if (!gdImageTrueColor(im)) { + zend_error(E_ERROR, "avif doesn't support palette images"); + return; + } + + if (!gdImageSX(im) || !gdImageSY(im)) { + zend_error(E_ERROR, "image dimensions must not be zero"); + return; + } + + if (overflow2(gdImageSX(im), gdImageSY(im))) { + zend_error(E_ERROR, "image dimensions are too large"); + return; + } + + speed = CLAMP(speed, AVIF_SPEED_SLOWEST, AVIF_SPEED_FASTEST); + + avifPixelFormat subsampling = quality >= HIGH_QUALITY_SUBSAMPLING_THRESHOLD ? + CHROMA_SUBAMPLING_HIGH_QUALITY : CHROMA_SUBSAMPLING_DEFAULT; + + // Create the AVIF image. + // Set the ICC to sRGB, as that's what gd supports right now. + // Note that MATRIX_COEFFICIENTS_IDENTITY enables lossless conversion from RGB to YUV. + + avifImage *avifIm = avifImageCreate(gdImageSX(im), gdImageSY(im), 8, subsampling); + + avifIm->colorPrimaries = AVIF_COLOR_PRIMARIES_BT709; + avifIm->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_SRGB; + avifIm->matrixCoefficients = lossless ? AVIF_MATRIX_COEFFICIENTS_IDENTITY : AVIF_MATRIX_COEFFICIENTS_BT709; + + avifRGBImageSetDefaults(&rgb, avifIm); + // this allocates memory, and sets rgb.rowBytes and rgb.pixels. + avifRGBImageAllocatePixels(&rgb); + + // Parse RGB data from the GD image, and copy it into the AVIF RGB image. + // Convert 7-bit GD alpha channel values to 8-bit AVIF values. + + p = rgb.pixels; + for (y = 0; y < rgb.height; y++) { + for (x = 0; x < rgb.width; x++) { + val = im->tpixels[y][x]; + + *(p++) = gdTrueColorGetRed(val); + *(p++) = gdTrueColorGetGreen(val); + *(p++) = gdTrueColorGetBlue(val); + *(p++) = alpha7BitTo8Bit(gdTrueColorGetAlpha(val)); + } + } + + // Convert the RGB image to YUV. + + result = avifImageRGBToYUV(avifIm, &rgb); + if (isAvifError(result, "Could not convert image to YUV")) + goto cleanup; + + // Encode the image in AVIF format. + + encoder = avifEncoderCreate(); + int quantizerQuality = quality == QUALITY_DEFAULT ? + QUANTIZER_DEFAULT : quality2Quantizer(quality); + + encoder->minQuantizer = quantizerQuality; + encoder->maxQuantizer = quantizerQuality; + encoder->minQuantizerAlpha = quantizerQuality; + encoder->maxQuantizerAlpha = quantizerQuality; + encoder->speed = speed; + + if (!setEncoderTilesAndThreads(encoder, &rgb)) + goto cleanup; + + //TODO: is there a reason to use timeSscales != 1? + result = avifEncoderAddImage(encoder, avifIm, 1, AVIF_ADD_IMAGE_FLAG_SINGLE); + if (isAvifError(result, "Could not encode image")) + goto cleanup; + + result = avifEncoderFinish(encoder, &avifOutput); + if (isAvifError(result, "Could not finish encoding")) + goto cleanup; + + // Write the AVIF image bytes to the GD ctx. + + gdPutBuf(avifOutput.data, avifOutput.size, outfile); + +cleanup: + if (rgb.pixels) + avifRGBImageFreePixels(&rgb); + + if (encoder) + avifEncoderDestroy(encoder); + + if (avifOutput.data) + avifRWDataFree(&avifOutput); +} + +void gdImageAvifEx(gdImagePtr im, FILE *outFile, int quality, int speed) +{ + gdIOCtx *out = gdNewFileCtx(outFile); + + if (out == NULL) + return; + + gdImageAvifCtx(im, out, quality, speed); + out->gd_free(out); +} + +void gdImageAvif(gdImagePtr im, FILE *outFile) +{ + gdImageAvifEx(im, outFile, QUALITY_DEFAULT, SPEED_DEFAULT); +} + +void * gdImageAvifPtrEx(gdImagePtr im, int *size, int quality, int speed) +{ + void *rv; + gdIOCtx *out = gdNewDynamicCtx(NEW_DYNAMIC_CTX_SIZE, NULL); + + if (out == NULL) { + return NULL; + } + + if (gdImageAvifCtx(im, out, quality, speed)) + rv = NULL; + else + rv = gdDPExtractData(out, size); + + out->gd_free(out); + return rv; +} + +void * gdImageAvifPtr(gdImagePtr im, int *size) +{ + return gdImageAvifPtrEx(im, size, QUALITY_DEFAULT, AVIF_SPEED_DEFAULT); +} + +#endif /* HAVE_LIBAVIF */ diff --git a/ext/standard/image.c b/ext/standard/image.c index 25b9aa2e5d110..60d4759661748 100644 --- a/ext/standard/image.c +++ b/ext/standard/image.c @@ -1149,6 +1149,13 @@ static struct gfxinfo *php_handle_webp(php_stream * stream) } /* }}} */ +/* {{{ php_handle_avif }}} */ +/* TODO: This is just a stub */ +static struct gfxinfo *php_handle_avif(php_stream * stream) { + return NULL; +} + + /* {{{ php_image_type_to_mime_type * Convert internal image_type to mime type */ PHPAPI char * php_image_type_to_mime_type(int image_type) From acc40b9f077482da11e5bf81e25a2d094e77de42 Mon Sep 17 00:00:00 2001 From: Ben Morss Date: Mon, 10 May 2021 18:31:20 -0400 Subject: [PATCH 04/37] Include logic to extract speed param in _php_image_output_ctx() --- ext/gd/gd.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ext/gd/gd.c b/ext/gd/gd.c index cd37af634b81a..9045867e77d17 100644 --- a/ext/gd/gd.c +++ b/ext/gd/gd.c @@ -4216,7 +4216,7 @@ static gdIOCtx *create_output_context() { static void _php_image_output_ctx(INTERNAL_FUNCTION_PARAMETERS, int image_type, char *tn, void (*func_p)()) { zval *imgind; - zend_long quality = -1, basefilter = -1; + zend_long quality = -1, basefilter = -1, speed = -1; gdImagePtr im; gdIOCtx *ctx = NULL; zval *to_zval = NULL; @@ -4229,6 +4229,10 @@ static void _php_image_output_ctx(INTERNAL_FUNCTION_PARAMETERS, int image_type, if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|z!ll", &imgind, gd_image_ce, &to_zval, &quality, &basefilter) == FAILURE) { RETURN_THROWS(); } + } else if (image_type == PHP_GDIMG_TYPE_AVIF) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|z!ll", &imgind, gd_image_ce, &to_zval, &quality, &speed) == FAILURE) { + RETURN_THROWS(); + } } else { if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|z!l", &imgind, gd_image_ce, &to_zval, &quality) == FAILURE) { RETURN_THROWS(); From e613ec3ea2e0a7a0e339ed366cdfbddad4a4964c Mon Sep 17 00:00:00 2001 From: Ben Morss Date: Tue, 11 May 2021 19:08:23 -0400 Subject: [PATCH 05/37] Change gd includes to quotes instead of angle brackets To avoid possible collision with the original libgd header files, which may be installed somewhere common like /usr/local/include --- ext/gd/gd.c | 10 +++++++++- ext/gd/libgd/gd_avif.c | 18 +++++++----------- ext/gd/libgd/gd_intern.h | 1 + ext/gd/libgd/gd_interpolation.c | 3 +-- 4 files changed, 18 insertions(+), 14 deletions(-) diff --git a/ext/gd/gd.c b/ext/gd/gd.c index 9045867e77d17..f67aafb97beca 100644 --- a/ext/gd/gd.c +++ b/ext/gd/gd.c @@ -30,12 +30,20 @@ #include "ext/standard/head.h" #include #include "SAPI.h" -#include "php_gd.h" #include "ext/standard/info.h" #include "php_open_temporary_file.h" #include "zend_object_handlers.h" #include "zend_interfaces.h" +#include "libgd/gd.h" +#include "php_gd.h" +#include "libgd/gdfontt.h" /* 1 Tiny font */ +#include "libgd/gdfonts.h" /* 2 Small font */ +#include "libgd/gdfontmb.h" /* 3 Medium bold font */ +#include "libgd/gdfontl.h" /* 4 Large font */ +#include "libgd/gdfontg.h" /* 5 Giant font */ + + #ifdef HAVE_SYS_WAIT_H # include #endif diff --git a/ext/gd/libgd/gd_avif.c b/ext/gd/libgd/gd_avif.c index 1e77b0b97d64c..6db6939d7b8f5 100644 --- a/ext/gd/libgd/gd_avif.c +++ b/ext/gd/libgd/gd_avif.c @@ -360,7 +360,7 @@ gdImagePtr gdImageCreateFromAvifCtx (gdIOCtx *ctx) goto cleanup; if (!isAvifSrgbImage(decoder->image)) - gd_error_ex(LOG_WARNING, "Image's color profile is not sRGB"); + zend_error(E_WARNING, "Image's color profile is not sRGB"); // Set up the avifRGBImage, and convert it from YUV to an 8-bit RGB image. // (While AVIF image pixel depth can be 8, 10, or 12 bits, GD truecolor images are 8-bit.) @@ -460,7 +460,6 @@ void gdImageAvifCtx(gdImagePtr im, gdIOCtx *outfile, int quality, int speed) avifResult result; avifRGBImage rgb; avifRWData avifOutput = AVIF_DATA_EMPTY; - avifBool failed = AVIF_FALSE; avifBool lossless = quality == 100; avifEncoder *encoder = NULL; @@ -569,11 +568,10 @@ void gdImageAvifEx(gdImagePtr im, FILE *outFile, int quality, int speed) { gdIOCtx *out = gdNewFileCtx(outFile); - if (out == NULL) - return; - - gdImageAvifCtx(im, out, quality, speed); - out->gd_free(out); + if (out != NULL) { + gdImageAvifCtx(im, out, quality, speed); + out->gd_free(out); + } } void gdImageAvif(gdImagePtr im, FILE *outFile) @@ -590,10 +588,8 @@ void * gdImageAvifPtrEx(gdImagePtr im, int *size, int quality, int speed) return NULL; } - if (gdImageAvifCtx(im, out, quality, speed)) - rv = NULL; - else - rv = gdDPExtractData(out, size); + gdImageAvifCtx(im, out, quality, speed); + rv = gdDPExtractData(out, size); out->gd_free(out); return rv; diff --git a/ext/gd/libgd/gd_intern.h b/ext/gd/libgd/gd_intern.h index 27f3d10badfdd..ce72bf1cc1f93 100644 --- a/ext/gd/libgd/gd_intern.h +++ b/ext/gd/libgd/gd_intern.h @@ -8,6 +8,7 @@ #define MAX(a,b) ((a)<(b)?(b):(a)) #endif #define MAX3(a,b,c) ((a)<(b)?(MAX(b,c)):(MAX(a,c))) +#define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x))) #endif diff --git a/ext/gd/libgd/gd_interpolation.c b/ext/gd/libgd/gd_interpolation.c index 3fce0100e8d94..cf8821372d923 100644 --- a/ext/gd/libgd/gd_interpolation.c +++ b/ext/gd/libgd/gd_interpolation.c @@ -60,6 +60,7 @@ #include "gd.h" #include "gdhelpers.h" +#include "gd_intern.h" #ifdef _MSC_VER # pragma optimize("t", on) @@ -85,8 +86,6 @@ #endif #define MAX3(a,b,c) ((a)<(b)?(MAX(b,c)):(MAX(a,c))) -#define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x))) - /* only used here, let do a generic fixed point integers later if required by other part of GD */ typedef long gdFixed; From 1fad3c42440da2f284141c1ccebbd86ab8987c10 Mon Sep 17 00:00:00 2001 From: Ben Morss Date: Wed, 12 May 2021 12:47:21 -0400 Subject: [PATCH 06/37] Change one avifFree() to gdFree() --- ext/gd/libgd/gd_avif.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/gd/libgd/gd_avif.c b/ext/gd/libgd/gd_avif.c index 6db6939d7b8f5..f2ded7fcddead 100644 --- a/ext/gd/libgd/gd_avif.c +++ b/ext/gd/libgd/gd_avif.c @@ -198,7 +198,7 @@ static avifResult readFromCtx(avifIO *io, uint32_t readFlags, uint64_t offset, s // avif.h says this is optional, but it seemed easy to implement. static void destroyAvifIO(struct avifIO *io) { - avifFree(io); + gdFree(io); } /* Set up an avifIO object. From a077c1a162802b4f865506de4d4a4893a6e3d41f Mon Sep 17 00:00:00 2001 From: Ben Morss Date: Fri, 21 May 2021 18:02:42 -0400 Subject: [PATCH 07/37] Fix includes --- ext/gd/gd.c | 25 ++++++++++++++++++------- ext/gd/libgd/gd_avif.c | 1 - 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/ext/gd/gd.c b/ext/gd/gd.c index f67aafb97beca..460e504e3700f 100644 --- a/ext/gd/gd.c +++ b/ext/gd/gd.c @@ -30,18 +30,29 @@ #include "ext/standard/head.h" #include #include "SAPI.h" +#include "php_gd.h" #include "ext/standard/info.h" #include "php_open_temporary_file.h" #include "zend_object_handlers.h" #include "zend_interfaces.h" -#include "libgd/gd.h" -#include "php_gd.h" -#include "libgd/gdfontt.h" /* 1 Tiny font */ -#include "libgd/gdfonts.h" /* 2 Small font */ -#include "libgd/gdfontmb.h" /* 3 Medium bold font */ -#include "libgd/gdfontl.h" /* 4 Large font */ -#include "libgd/gdfontg.h" /* 5 Giant font */ +#ifdef HAVE_GD_BUNDLED +# include "libgd/gd.h" +# include "libgd/gd_errors.h" +# include "libgd/gdfontt.h" /* 1 Tiny font */ +# include "libgd/gdfonts.h" /* 2 Small font */ +# include "libgd/gdfontmb.h" /* 3 Medium bold font */ +# include "libgd/gdfontl.h" /* 4 Large font */ +# include "libgd/gdfontg.h" /* 5 Giant font */ +#else +# include +# include +# include /* 1 Tiny font */ +# include /* 2 Small font */ +# include /* 3 Medium bold font */ +# include /* 4 Large font */ +# include /* 5 Giant font */ +#endif #ifdef HAVE_SYS_WAIT_H diff --git a/ext/gd/libgd/gd_avif.c b/ext/gd/libgd/gd_avif.c index f2ded7fcddead..8d9d65708e12d 100644 --- a/ext/gd/libgd/gd_avif.c +++ b/ext/gd/libgd/gd_avif.c @@ -27,7 +27,6 @@ SPEED_DEFAULT: AVIF_SPEED_DEFAULT is simply the default encoding speed of the AV1 codec. This could be as slow as 0. So we use 6, which is currently considered to be a fine default. - */ #define CHROMA_SUBSAMPLING_DEFAULT AVIF_PIXEL_FORMAT_YUV420 From 4c8790f7cf8d8526c14473164a01f50ad19c6dfc Mon Sep 17 00:00:00 2001 From: Ben Morss Date: Fri, 21 May 2021 19:18:57 -0400 Subject: [PATCH 08/37] Add test script and test image --- ext/gd/tests/avif_decode_encode.phpt | 57 +++++++++++++++++++++++++++ ext/gd/tests/girl.avif | Bin 0 -> 5421 bytes 2 files changed, 57 insertions(+) create mode 100644 ext/gd/tests/avif_decode_encode.phpt create mode 100644 ext/gd/tests/girl.avif diff --git a/ext/gd/tests/avif_decode_encode.phpt b/ext/gd/tests/avif_decode_encode.phpt new file mode 100644 index 0000000000000..d97f1dcef1acb --- /dev/null +++ b/ext/gd/tests/avif_decode_encode.phpt @@ -0,0 +1,57 @@ +--TEST-- +avif decoding/encoding tests +--SKIPIF-- + +--FILE-- + +--EXPECT-- +Decoding AVIF image: ok +Default AVIF encoding: ok +Encoding AVIF at quality 70: ok +Encoding AVIF at quality 70 with speed 5: ok +Encoding AVIF with default quality: ok +Encoding AVIF with illegal quality: ok +Encoding AVIF with illegal speed: ok diff --git a/ext/gd/tests/girl.avif b/ext/gd/tests/girl.avif new file mode 100644 index 0000000000000000000000000000000000000000..761e1fa19a94c044b262ca808cca6fe0758e8735 GIT binary patch literal 5421 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 Date: Sat, 22 May 2021 17:11:04 -0400 Subject: [PATCH 09/37] Use new --EXTENSIONS-- to ensure gd is available --- ext/gd/tests/avif_decode_encode.phpt | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/ext/gd/tests/avif_decode_encode.phpt b/ext/gd/tests/avif_decode_encode.phpt index d97f1dcef1acb..2e4f021a8473e 100644 --- a/ext/gd/tests/avif_decode_encode.phpt +++ b/ext/gd/tests/avif_decode_encode.phpt @@ -1,11 +1,9 @@ --TEST-- avif decoding/encoding tests +--EXTENSIONS-- +gd --SKIPIF-- Date: Sat, 22 May 2021 12:56:03 +0200 Subject: [PATCH 10/37] Fix IMAGETYPE_AVIF support We fix an accidental fall through, and the order of enum values (COUNT has to be last). We also fix the respective test case. --- ext/standard/image.c | 6 +++--- ext/standard/php_image.h | 4 ++-- ext/standard/tests/image/image_type_to_extension.phpt | 6 +++++- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/ext/standard/image.c b/ext/standard/image.c index 60d4759661748..f7a3a4b4b58c3 100644 --- a/ext/standard/image.c +++ b/ext/standard/image.c @@ -87,10 +87,10 @@ PHP_MINIT_FUNCTION(imagetypes) REGISTER_LONG_CONSTANT("IMAGETYPE_JPEG2000",IMAGE_FILETYPE_JPC, CONST_CS | CONST_PERSISTENT); /* keep alias */ REGISTER_LONG_CONSTANT("IMAGETYPE_XBM", IMAGE_FILETYPE_XBM, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("IMAGETYPE_ICO", IMAGE_FILETYPE_ICO, CONST_CS | CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("IMAGETYPE_WEBP", IMAGE_FILETYPE_WEBP, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IMAGETYPE_WEBP", IMAGE_FILETYPE_WEBP, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IMAGETYPE_AVIF", IMAGE_FILETYPE_AVIF, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("IMAGETYPE_UNKNOWN", IMAGE_FILETYPE_UNKNOWN, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("IMAGETYPE_COUNT", IMAGE_FILETYPE_COUNT, CONST_CS | CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("IMAGETYPE_AVIF", IMAGE_FILETYPE_AVIF, CONST_CS | CONST_PERSISTENT); return SUCCESS; } /* }}} */ @@ -1274,9 +1274,9 @@ PHP_FUNCTION(image_type_to_extension) break; case IMAGE_FILETYPE_WEBP: imgext = ".webp"; + break; case IMAGE_FILETYPE_AVIF: imgext = ".avif"; - break; } if (imgext) { diff --git a/ext/standard/php_image.h b/ext/standard/php_image.h index 3d00cec171156..9b0c33d7738bd 100644 --- a/ext/standard/php_image.h +++ b/ext/standard/php_image.h @@ -43,9 +43,9 @@ typedef enum IMAGE_FILETYPE_XBM, IMAGE_FILETYPE_ICO, IMAGE_FILETYPE_WEBP, + IMAGE_FILETYPE_AVIF, /* WHEN EXTENDING: PLEASE ALSO REGISTER IN image.c:PHP_MINIT_FUNCTION(imagetypes) */ - IMAGE_FILETYPE_COUNT, - IMAGE_FILETYPE_AVIF + IMAGE_FILETYPE_COUNT } image_filetype; /* }}} */ diff --git a/ext/standard/tests/image/image_type_to_extension.phpt b/ext/standard/tests/image/image_type_to_extension.phpt index fd60fc454e10b..1685bea8e15c0 100644 --- a/ext/standard/tests/image/image_type_to_extension.phpt +++ b/ext/standard/tests/image/image_type_to_extension.phpt @@ -23,7 +23,8 @@ image_type_to_extension() "IMAGETYPE_WBMP" => IMAGETYPE_WBMP, "IMAGETYPE_JPEG2000" => IMAGETYPE_JPEG2000, "IMAGETYPE_XBM" => IMAGETYPE_XBM, - "IMAGETYPE_WEBP" => IMAGETYPE_WEBP + "IMAGETYPE_WEBP" => IMAGETYPE_WEBP, + "IMAGETYPE_AVIF" => IMAGETYPE_AVIF, ); foreach($constants as $name => $constant) { printf("Constant: %s\n\tWith dot: %s\n\tWithout dot: %s\n", $name, image_type_to_extension($constant), image_type_to_extension($constant, false)); @@ -85,6 +86,9 @@ Constant: IMAGETYPE_XBM Constant: IMAGETYPE_WEBP With dot: .webp Without dot: webp +Constant: IMAGETYPE_AVIF + With dot: .avif + Without dot: avif bool(false) bool(false) Done From 14d6d2f1793b3349892a5041694f6df8241e72ff Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Sat, 22 May 2021 13:39:23 +0200 Subject: [PATCH 11/37] Fix failing test case --- .../tests/image/image_type_to_mime_type_variation3.phpt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ext/standard/tests/image/image_type_to_mime_type_variation3.phpt b/ext/standard/tests/image/image_type_to_mime_type_variation3.phpt index 49a53c468b1d3..fc17cb5ecd947 100644 --- a/ext/standard/tests/image/image_type_to_mime_type_variation3.phpt +++ b/ext/standard/tests/image/image_type_to_mime_type_variation3.phpt @@ -72,4 +72,7 @@ string\(24\) "image\/vnd.microsoft.icon" string\(10\) "image\/webp" -- Iteration 19 -- +string\(10\) "image\/avif" + +-- Iteration 20 -- string\(24\) "application\/octet-stream" From b9d8de846d265b526be8c2e0e7a1a7a7c8ebd7fe Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Sat, 22 May 2021 13:44:15 +0200 Subject: [PATCH 12/37] Add AVIF support for bundled GD on Windows --- ext/gd/config.w32 | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/ext/gd/config.w32 b/ext/gd/config.w32 index 541d5f51e0e2b..8ed0205287069 100644 --- a/ext/gd/config.w32 +++ b/ext/gd/config.w32 @@ -2,6 +2,7 @@ ARG_WITH("gd", "Bundled GD support", "yes,shared"); ARG_WITH("libwebp", "webp support", "yes"); +ARG_WITH("libavif", "avif support", "yes"); if (PHP_GD != "no") { if ( @@ -30,6 +31,14 @@ if (PHP_GD != "no") { WARNING("libwebp not enabled; libraries and headers not found"); } } + if (PHP_LIBAVIF != "no") { + if (CHECK_LIB("avif.lib", "gd", PHP_GD) && + CHECK_HEADER_ADD_INCLUDE("avif.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\avif")) { + ADD_FLAG("CFLAGS_GD", "/D HAVE_LIBAVIF /D HAVE_GD_AVIF"); + } else { + WARNING("libavif not enabled; libraries and headers not found"); + } + } CHECK_LIB("User32.lib", "gd", PHP_GD); CHECK_LIB("Gdi32.lib", "gd", PHP_GD); @@ -39,7 +48,7 @@ if (PHP_GD != "no") { gdft.c gd_gd2.c gd_gd.c gd_gif_in.c gd_gif_out.c gdhelpers.c gd_io.c gd_io_dp.c \ gd_io_file.c gd_io_ss.c gd_jpeg.c gdkanji.c gd_png.c gd_ss.c \ gdtables.c gd_topal.c gd_wbmp.c gdxpm.c wbmp.c gd_xbm.c gd_security.c gd_transform.c \ - gd_filter.c gd_pixelate.c gd_rotate.c gd_color_match.c gd_webp.c \ + gd_filter.c gd_pixelate.c gd_rotate.c gd_color_match.c gd_webp.c gd_avif.c \ gd_crop.c gd_interpolation.c gd_matrix.c gd_bmp.c gd_tga.c", "gd"); AC_DEFINE('HAVE_LIBGD', 1, 'GD support'); ADD_FLAG("CFLAGS_GD", " \ From 9aa1b367bde8a20f7c857568e3e6119b2aa49d67 Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Sat, 22 May 2021 14:35:14 +0200 Subject: [PATCH 13/37] Build GD with libavif on AppVeyor This is only needed as long as libavif is not part of the official dependencies. This commit should be reverted before the PR is merged. --- appveyor/build_task.bat | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/appveyor/build_task.bat b/appveyor/build_task.bat index 91fedae855374..e0191740050d8 100644 --- a/appveyor/build_task.bat +++ b/appveyor/build_task.bat @@ -45,6 +45,15 @@ if not exist "%DEPS_DIR%" ( ) if %errorlevel% neq 0 exit /b 3 +rem install libavif into dependency directory +rem temporary workaround for libavif not being part of the official dependencies +if not exist "%DEPS_DIR%\libavif-0.9.0-%PHP_SDK_VS%-%PHP_SDK_ARCH%.zip" ( + curl -fsSL -o %DEPS_DIR%\libavif-0.9.0-%PHP_SDK_VS%-%PHP_SDK_ARCH%.zip https://windows.php.net/downloads/pecl/deps/libavif-0.9.0-%PHP_SDK_VS%-%PHP_SDK_ARCH%.zip +) +if not exist "%DEPS_DIR%\lib\avif.lib" ( + 7z x %DEPS_DIR%\libavif-0.9.0-%PHP_SDK_VS%-%PHP_SDK_ARCH%.zip -o%DEPS_DIR% +) + cmd /c buildconf.bat --force if %errorlevel% neq 0 exit /b 3 From 0585c082492abd5f1b479b75b0e02fdc06e52022 Mon Sep 17 00:00:00 2001 From: Ben Morss Date: Wed, 5 May 2021 18:47:22 -0400 Subject: [PATCH 14/37] Initial commit before rebase --- ext/gd/gd.stub.php | 4 ++++ ext/gd/gd_arginfo.h | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/ext/gd/gd.stub.php b/ext/gd/gd.stub.php index 5e39ef83cd571..10f514a21bf4e 100644 --- a/ext/gd/gd.stub.php +++ b/ext/gd/gd.stub.php @@ -72,6 +72,10 @@ function imagecreatefromavif(string $filename): GdImage|false {} function imagecreatefromgif(string $filename): GdImage|false {} +#ifdef HAVE_GD_AVIF +function imagecreatefromavif(string $filename): GdImage|false {} +#endif + #ifdef HAVE_GD_JPG function imagecreatefromjpeg(string $filename): GdImage|false {} #endif diff --git a/ext/gd/gd_arginfo.h b/ext/gd/gd_arginfo.h index dad8f3a3eac03..ec9f893370493 100644 --- a/ext/gd/gd_arginfo.h +++ b/ext/gd/gd_arginfo.h @@ -154,6 +154,12 @@ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_imagecreatefromgif, 0, 1, Gd ZEND_ARG_TYPE_INFO(0, filename, IS_STRING, 0) ZEND_END_ARG_INFO() +#if defined(HAVE_GD_AVIF) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_imagecreatefromavif, 0, 1, GdImage, MAY_BE_FALSE) + ZEND_ARG_TYPE_INFO(0, filename, IS_STRING, 0) +ZEND_END_ARG_INFO() +#endif + #if defined(HAVE_GD_JPG) ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_imagecreatefromjpeg, 0, 1, GdImage, MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, filename, IS_STRING, 0) From 5a73a4028ee1d947f5bfcbfb0e8f23099ba72f9d Mon Sep 17 00:00:00 2001 From: Ben Morss Date: Fri, 7 May 2021 16:27:12 -0400 Subject: [PATCH 15/37] Incremental commit --- ext/gd/gd.stub.php | 4 ---- ext/standard/image.c | 3 +++ ext/standard/php_image.h | 3 ++- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ext/gd/gd.stub.php b/ext/gd/gd.stub.php index 10f514a21bf4e..5e39ef83cd571 100644 --- a/ext/gd/gd.stub.php +++ b/ext/gd/gd.stub.php @@ -72,10 +72,6 @@ function imagecreatefromavif(string $filename): GdImage|false {} function imagecreatefromgif(string $filename): GdImage|false {} -#ifdef HAVE_GD_AVIF -function imagecreatefromavif(string $filename): GdImage|false {} -#endif - #ifdef HAVE_GD_JPG function imagecreatefromjpeg(string $filename): GdImage|false {} #endif diff --git a/ext/standard/image.c b/ext/standard/image.c index f7a3a4b4b58c3..2c4a30fad06d9 100644 --- a/ext/standard/image.c +++ b/ext/standard/image.c @@ -91,6 +91,7 @@ PHP_MINIT_FUNCTION(imagetypes) REGISTER_LONG_CONSTANT("IMAGETYPE_AVIF", IMAGE_FILETYPE_AVIF, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("IMAGETYPE_UNKNOWN", IMAGE_FILETYPE_UNKNOWN, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("IMAGETYPE_COUNT", IMAGE_FILETYPE_COUNT, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IMAGETYPE_AVIF", IMAGE_FILETYPE_AVIF, CONST_CS | CONST_PERSISTENT); return SUCCESS; } /* }}} */ @@ -1274,6 +1275,8 @@ PHP_FUNCTION(image_type_to_extension) break; case IMAGE_FILETYPE_WEBP: imgext = ".webp"; + case IMAGE_FILETYPE_AVIF: + imgext = ".avif"; break; case IMAGE_FILETYPE_AVIF: imgext = ".avif"; diff --git a/ext/standard/php_image.h b/ext/standard/php_image.h index 9b0c33d7738bd..95025a80b0416 100644 --- a/ext/standard/php_image.h +++ b/ext/standard/php_image.h @@ -45,7 +45,8 @@ typedef enum IMAGE_FILETYPE_WEBP, IMAGE_FILETYPE_AVIF, /* WHEN EXTENDING: PLEASE ALSO REGISTER IN image.c:PHP_MINIT_FUNCTION(imagetypes) */ - IMAGE_FILETYPE_COUNT + IMAGE_FILETYPE_COUNT, + IMAGE_FILETYPE_AVIF } image_filetype; /* }}} */ From a1cb830910f929bd7dab7a5c735f182816889d94 Mon Sep 17 00:00:00 2001 From: Ben Morss Date: Mon, 10 May 2021 13:14:14 -0400 Subject: [PATCH 16/37] Incremental commit --- ext/gd/gd_arginfo.h | 6 ------ ext/gd/libgd/gd_avif.c | 27 +++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/ext/gd/gd_arginfo.h b/ext/gd/gd_arginfo.h index ec9f893370493..dad8f3a3eac03 100644 --- a/ext/gd/gd_arginfo.h +++ b/ext/gd/gd_arginfo.h @@ -154,12 +154,6 @@ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_imagecreatefromgif, 0, 1, Gd ZEND_ARG_TYPE_INFO(0, filename, IS_STRING, 0) ZEND_END_ARG_INFO() -#if defined(HAVE_GD_AVIF) -ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_imagecreatefromavif, 0, 1, GdImage, MAY_BE_FALSE) - ZEND_ARG_TYPE_INFO(0, filename, IS_STRING, 0) -ZEND_END_ARG_INFO() -#endif - #if defined(HAVE_GD_JPG) ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_imagecreatefromjpeg, 0, 1, GdImage, MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, filename, IS_STRING, 0) diff --git a/ext/gd/libgd/gd_avif.c b/ext/gd/libgd/gd_avif.c index 8d9d65708e12d..330446f948901 100644 --- a/ext/gd/libgd/gd_avif.c +++ b/ext/gd/libgd/gd_avif.c @@ -197,7 +197,11 @@ static avifResult readFromCtx(avifIO *io, uint32_t readFlags, uint64_t offset, s // avif.h says this is optional, but it seemed easy to implement. static void destroyAvifIO(struct avifIO *io) { +<<<<<<< HEAD gdFree(io); +======= + avifFree(io); +>>>>>>> d6dfd6b992 (Incremental commit) } /* Set up an avifIO object. @@ -359,7 +363,11 @@ gdImagePtr gdImageCreateFromAvifCtx (gdIOCtx *ctx) goto cleanup; if (!isAvifSrgbImage(decoder->image)) +<<<<<<< HEAD zend_error(E_WARNING, "Image's color profile is not sRGB"); +======= + gd_error_ex(LOG_WARNING, "Image's color profile is not sRGB"); +>>>>>>> d6dfd6b992 (Incremental commit) // Set up the avifRGBImage, and convert it from YUV to an 8-bit RGB image. // (While AVIF image pixel depth can be 8, 10, or 12 bits, GD truecolor images are 8-bit.) @@ -459,6 +467,10 @@ void gdImageAvifCtx(gdImagePtr im, gdIOCtx *outfile, int quality, int speed) avifResult result; avifRGBImage rgb; avifRWData avifOutput = AVIF_DATA_EMPTY; +<<<<<<< HEAD +======= + avifBool failed = AVIF_FALSE; +>>>>>>> d6dfd6b992 (Incremental commit) avifBool lossless = quality == 100; avifEncoder *encoder = NULL; @@ -567,10 +579,18 @@ void gdImageAvifEx(gdImagePtr im, FILE *outFile, int quality, int speed) { gdIOCtx *out = gdNewFileCtx(outFile); +<<<<<<< HEAD if (out != NULL) { gdImageAvifCtx(im, out, quality, speed); out->gd_free(out); } +======= + if (out == NULL) + return; + + gdImageAvifCtx(im, out, quality, speed); + out->gd_free(out); +>>>>>>> d6dfd6b992 (Incremental commit) } void gdImageAvif(gdImagePtr im, FILE *outFile) @@ -587,8 +607,15 @@ void * gdImageAvifPtrEx(gdImagePtr im, int *size, int quality, int speed) return NULL; } +<<<<<<< HEAD gdImageAvifCtx(im, out, quality, speed); rv = gdDPExtractData(out, size); +======= + if (gdImageAvifCtx(im, out, quality, speed)) + rv = NULL; + else + rv = gdDPExtractData(out, size); +>>>>>>> d6dfd6b992 (Incremental commit) out->gd_free(out); return rv; From e98f2cae9b81a5af5ea8f5d8f5e83c6abf521e98 Mon Sep 17 00:00:00 2001 From: Ben Morss Date: Tue, 11 May 2021 19:08:23 -0400 Subject: [PATCH 17/37] Change gd includes to quotes instead of angle brackets To avoid possible collision with the original libgd header files, which may be installed somewhere common like /usr/local/include --- ext/gd/gd.c | 21 --------------------- ext/gd/libgd/gd_avif.c | 22 ++++++++++++++++++---- 2 files changed, 18 insertions(+), 25 deletions(-) diff --git a/ext/gd/gd.c b/ext/gd/gd.c index 460e504e3700f..044fc2745d4c2 100644 --- a/ext/gd/gd.c +++ b/ext/gd/gd.c @@ -30,31 +30,11 @@ #include "ext/standard/head.h" #include #include "SAPI.h" -#include "php_gd.h" #include "ext/standard/info.h" #include "php_open_temporary_file.h" #include "zend_object_handlers.h" #include "zend_interfaces.h" -#ifdef HAVE_GD_BUNDLED -# include "libgd/gd.h" -# include "libgd/gd_errors.h" -# include "libgd/gdfontt.h" /* 1 Tiny font */ -# include "libgd/gdfonts.h" /* 2 Small font */ -# include "libgd/gdfontmb.h" /* 3 Medium bold font */ -# include "libgd/gdfontl.h" /* 4 Large font */ -# include "libgd/gdfontg.h" /* 5 Giant font */ -#else -# include -# include -# include /* 1 Tiny font */ -# include /* 2 Small font */ -# include /* 3 Medium bold font */ -# include /* 4 Large font */ -# include /* 5 Giant font */ -#endif - - #ifdef HAVE_SYS_WAIT_H # include #endif @@ -73,7 +53,6 @@ # include #endif - #include "gd_compat.h" #ifdef HAVE_GD_BUNDLED diff --git a/ext/gd/libgd/gd_avif.c b/ext/gd/libgd/gd_avif.c index 330446f948901..c2f024a6b32ca 100644 --- a/ext/gd/libgd/gd_avif.c +++ b/ext/gd/libgd/gd_avif.c @@ -197,11 +197,7 @@ static avifResult readFromCtx(avifIO *io, uint32_t readFlags, uint64_t offset, s // avif.h says this is optional, but it seemed easy to implement. static void destroyAvifIO(struct avifIO *io) { -<<<<<<< HEAD gdFree(io); -======= - avifFree(io); ->>>>>>> d6dfd6b992 (Incremental commit) } /* Set up an avifIO object. @@ -363,11 +359,15 @@ gdImagePtr gdImageCreateFromAvifCtx (gdIOCtx *ctx) goto cleanup; if (!isAvifSrgbImage(decoder->image)) +<<<<<<< HEAD <<<<<<< HEAD zend_error(E_WARNING, "Image's color profile is not sRGB"); ======= gd_error_ex(LOG_WARNING, "Image's color profile is not sRGB"); >>>>>>> d6dfd6b992 (Incremental commit) +======= + zend_error(E_WARNING, "Image's color profile is not sRGB"); +>>>>>>> bc3489e29b (Change gd includes to quotes instead of angle brackets) // Set up the avifRGBImage, and convert it from YUV to an 8-bit RGB image. // (While AVIF image pixel depth can be 8, 10, or 12 bits, GD truecolor images are 8-bit.) @@ -468,9 +468,12 @@ void gdImageAvifCtx(gdImagePtr im, gdIOCtx *outfile, int quality, int speed) avifRGBImage rgb; avifRWData avifOutput = AVIF_DATA_EMPTY; <<<<<<< HEAD +<<<<<<< HEAD ======= avifBool failed = AVIF_FALSE; >>>>>>> d6dfd6b992 (Incremental commit) +======= +>>>>>>> bc3489e29b (Change gd includes to quotes instead of angle brackets) avifBool lossless = quality == 100; avifEncoder *encoder = NULL; @@ -580,10 +583,14 @@ void gdImageAvifEx(gdImagePtr im, FILE *outFile, int quality, int speed) gdIOCtx *out = gdNewFileCtx(outFile); <<<<<<< HEAD +<<<<<<< HEAD +======= +>>>>>>> bc3489e29b (Change gd includes to quotes instead of angle brackets) if (out != NULL) { gdImageAvifCtx(im, out, quality, speed); out->gd_free(out); } +<<<<<<< HEAD ======= if (out == NULL) return; @@ -591,6 +598,8 @@ void gdImageAvifEx(gdImagePtr im, FILE *outFile, int quality, int speed) gdImageAvifCtx(im, out, quality, speed); out->gd_free(out); >>>>>>> d6dfd6b992 (Incremental commit) +======= +>>>>>>> bc3489e29b (Change gd includes to quotes instead of angle brackets) } void gdImageAvif(gdImagePtr im, FILE *outFile) @@ -607,6 +616,7 @@ void * gdImageAvifPtrEx(gdImagePtr im, int *size, int quality, int speed) return NULL; } +<<<<<<< HEAD <<<<<<< HEAD gdImageAvifCtx(im, out, quality, speed); rv = gdDPExtractData(out, size); @@ -616,6 +626,10 @@ void * gdImageAvifPtrEx(gdImagePtr im, int *size, int quality, int speed) else rv = gdDPExtractData(out, size); >>>>>>> d6dfd6b992 (Incremental commit) +======= + gdImageAvifCtx(im, out, quality, speed); + rv = gdDPExtractData(out, size); +>>>>>>> bc3489e29b (Change gd includes to quotes instead of angle brackets) out->gd_free(out); return rv; From a6a161f3a417d0b676b25313342fab19b898a617 Mon Sep 17 00:00:00 2001 From: Ben Morss Date: Fri, 21 May 2021 18:02:42 -0400 Subject: [PATCH 18/37] Fix includes --- ext/gd/gd.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ext/gd/gd.c b/ext/gd/gd.c index 044fc2745d4c2..2b52bf2067399 100644 --- a/ext/gd/gd.c +++ b/ext/gd/gd.c @@ -30,6 +30,7 @@ #include "ext/standard/head.h" #include #include "SAPI.h" +#include "php_gd.h" #include "ext/standard/info.h" #include "php_open_temporary_file.h" #include "zend_object_handlers.h" From 5e45a76ae09a27a802e77ca8109e0664eac950fd Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Sat, 22 May 2021 12:56:03 +0200 Subject: [PATCH 19/37] Fix IMAGETYPE_AVIF support We fix an accidental fall through, and the order of enum values (COUNT has to be last). We also fix the respective test case. --- ext/standard/image.c | 3 --- ext/standard/php_image.h | 3 +-- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/ext/standard/image.c b/ext/standard/image.c index 2c4a30fad06d9..f7a3a4b4b58c3 100644 --- a/ext/standard/image.c +++ b/ext/standard/image.c @@ -91,7 +91,6 @@ PHP_MINIT_FUNCTION(imagetypes) REGISTER_LONG_CONSTANT("IMAGETYPE_AVIF", IMAGE_FILETYPE_AVIF, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("IMAGETYPE_UNKNOWN", IMAGE_FILETYPE_UNKNOWN, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("IMAGETYPE_COUNT", IMAGE_FILETYPE_COUNT, CONST_CS | CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("IMAGETYPE_AVIF", IMAGE_FILETYPE_AVIF, CONST_CS | CONST_PERSISTENT); return SUCCESS; } /* }}} */ @@ -1275,8 +1274,6 @@ PHP_FUNCTION(image_type_to_extension) break; case IMAGE_FILETYPE_WEBP: imgext = ".webp"; - case IMAGE_FILETYPE_AVIF: - imgext = ".avif"; break; case IMAGE_FILETYPE_AVIF: imgext = ".avif"; diff --git a/ext/standard/php_image.h b/ext/standard/php_image.h index 95025a80b0416..9b0c33d7738bd 100644 --- a/ext/standard/php_image.h +++ b/ext/standard/php_image.h @@ -45,8 +45,7 @@ typedef enum IMAGE_FILETYPE_WEBP, IMAGE_FILETYPE_AVIF, /* WHEN EXTENDING: PLEASE ALSO REGISTER IN image.c:PHP_MINIT_FUNCTION(imagetypes) */ - IMAGE_FILETYPE_COUNT, - IMAGE_FILETYPE_AVIF + IMAGE_FILETYPE_COUNT } image_filetype; /* }}} */ From 270c6afca0b8afa18ccbdd0d5006685f7ad506d8 Mon Sep 17 00:00:00 2001 From: Ben Morss Date: Mon, 24 May 2021 12:18:11 -0400 Subject: [PATCH 20/37] Remove AVIF tests from travis and azure; add to cirrus --- .cirrus.yml | 2 +- .travis.yml | 1 - azure/i386/job.yml | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index 79ee37e1781e6..83661eee0e059 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -13,7 +13,7 @@ task: - pkg install -y autoconf bison gmake re2c icu libiconv png freetype2 enchant2 bzip2 krb5 t1lib gmp tidyp libsodium libzip libxml2 libxslt openssl oniguruma pkgconf webp script: - ./buildconf -f - - ./configure --prefix=/usr/local --enable-debug --enable-option-checking=fatal --enable-fpm --with-pdo-sqlite --without-pear --with-bz2 --with-jpeg --with-webp --with-freetype --enable-gd --enable-exif --with-zip --with-zlib --enable-soap --enable-xmlreader --with-xsl --with-libxml --enable-shmop --enable-pcntl --enable-mbstring --with-curl --enable-sockets --with-openssl --with-iconv=/usr/local --enable-bcmath --enable-calendar --enable-ftp --with-kerberos --with-ffi --enable-zend-test --enable-intl --with-mhash --with-sodium --enable-werror --with-config-file-path=/etc --with-config-file-scan-dir=/etc/php.d + - ./configure --prefix=/usr/local --enable-debug --enable-option-checking=fatal --enable-fpm --with-pdo-sqlite --without-pear --with-bz2 --with-avif --with-jpeg --with-webp --with-freetype --enable-gd --enable-exif --with-zip --with-zlib --enable-soap --enable-xmlreader --with-xsl --with-libxml --enable-shmop --enable-pcntl --enable-mbstring --with-curl --enable-sockets --with-openssl --with-iconv=/usr/local --enable-bcmath --enable-calendar --enable-ftp --with-kerberos --with-ffi --enable-zend-test --enable-intl --with-mhash --with-sodium --enable-werror --with-config-file-path=/etc --with-config-file-scan-dir=/etc/php.d - gmake -j2 - mkdir /etc/php.d - gmake install diff --git a/.travis.yml b/.travis.yml index 366c393dead78..59ee5ebb21943 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,7 +12,6 @@ addons: - re2c - ccache - mysql-server - - libavif-dev - libaspell-dev - libbz2-dev - libcurl4-gnutls-dev diff --git a/azure/i386/job.yml b/azure/i386/job.yml index fce9517290616..94d234e5fbe9d 100644 --- a/azure/i386/job.yml +++ b/azure/i386/job.yml @@ -30,7 +30,6 @@ jobs: --with-pdo-sqlite \ --without-pear \ --enable-gd \ - --with-avif \ --with-jpeg \ --with-webp \ --with-freetype \ From 31c8c664ef0f372db694aac4dc63d0882d469941 Mon Sep 17 00:00:00 2001 From: Ben Morss Date: Mon, 24 May 2021 12:51:41 -0400 Subject: [PATCH 21/37] Remove avif from a few more spots in test configs --- azure/configure.yml | 1 - azure/i386/apt.yml | 1 - azure/macos/job.yml | 1 - 3 files changed, 3 deletions(-) diff --git a/azure/configure.yml b/azure/configure.yml index b65ac0dedc034..9869de514e82c 100644 --- a/azure/configure.yml +++ b/azure/configure.yml @@ -17,7 +17,6 @@ steps: --enable-intl \ --without-pear \ --enable-gd \ - --with-avif \ --with-jpeg \ --with-webp \ --with-freetype \ diff --git a/azure/i386/apt.yml b/azure/i386/apt.yml index 4671c4fe5bcc0..9ae39443755d8 100644 --- a/azure/i386/apt.yml +++ b/azure/i386/apt.yml @@ -44,6 +44,5 @@ steps: libffi-dev:i386 \ libfreetype6-dev:i386 \ libsodium-dev:i386 \ - libavif-dev:i386 \ ${{ parameters.packages }} displayName: 'APT' diff --git a/azure/macos/job.yml b/azure/macos/job.yml index 60205a719c907..ed2e8d9d223e1 100644 --- a/azure/macos/job.yml +++ b/azure/macos/job.yml @@ -29,7 +29,6 @@ jobs: --with-pdo-sqlite \ --without-pear \ --enable-gd \ - --with-avif \ --with-jpeg \ --with-webp \ --with-freetype \ From 8af2262337f3b0dcf06035548cf5fe8657905580 Mon Sep 17 00:00:00 2001 From: Ben Morss Date: Mon, 24 May 2021 12:52:03 -0400 Subject: [PATCH 22/37] Add imagecreatefromavif config --- Zend/Optimizer/zend_func_info.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Zend/Optimizer/zend_func_info.c b/Zend/Optimizer/zend_func_info.c index 4ca4dc3810ae0..851db8bfac3a0 100644 --- a/Zend/Optimizer/zend_func_info.c +++ b/Zend/Optimizer/zend_func_info.c @@ -760,6 +760,9 @@ static const func_info_t func_infos[] = { #ifdef HAVE_GD_JPG F1("imagecreatefromjpeg", MAY_BE_FALSE | MAY_BE_OBJECT), #endif +#ifdef HAVE_GD_AVIF + F1("imagecreatefromavif", MAY_BE_FALSE | MAY_BE_OBJECT), +#endif #ifdef HAVE_GD_PNG F1("imagecreatefrompng", MAY_BE_FALSE | MAY_BE_OBJECT), #endif From 1c7ef5e8e7a143a21f709929aef4186d16d1c0ae Mon Sep 17 00:00:00 2001 From: Ben Morss Date: Mon, 24 May 2021 12:56:57 -0400 Subject: [PATCH 23/37] Removed libavif-dev package from azure --- azure/apt.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/azure/apt.yml b/azure/apt.yml index aa29b6ab11458..9166509dccae7 100644 --- a/azure/apt.yml +++ b/azure/apt.yml @@ -12,7 +12,6 @@ steps: slapd \ language-pack-de \ re2c \ - libavif-dev \ libgmp-dev \ libicu-dev \ libtidy-dev \ From 76f3a98dcb93a4906e3021192e42b4cdf5dd6d03 Mon Sep 17 00:00:00 2001 From: Ben Morss Date: Mon, 24 May 2021 14:19:05 -0400 Subject: [PATCH 24/37] Install libavif in freebsd --- .cirrus.yml | 2 +- ext/gd/.DS_Store | Bin 0 -> 10244 bytes 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 ext/gd/.DS_Store diff --git a/.cirrus.yml b/.cirrus.yml index 83661eee0e059..27df6f5b6616a 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -10,7 +10,7 @@ task: install_script: #- sed -i -e 's/quarterly/latest/g' /etc/pkg/FreeBSD.conf #- pkg upgrade -y - - pkg install -y autoconf bison gmake re2c icu libiconv png freetype2 enchant2 bzip2 krb5 t1lib gmp tidyp libsodium libzip libxml2 libxslt openssl oniguruma pkgconf webp + - pkg install -y autoconf bison gmake re2c icu libiconv png freetype2 enchant2 bzip2 krb5 t1lib gmp tidyp libsodium libzip libxml2 libxslt openssl oniguruma pkgconf webp libavif script: - ./buildconf -f - ./configure --prefix=/usr/local --enable-debug --enable-option-checking=fatal --enable-fpm --with-pdo-sqlite --without-pear --with-bz2 --with-avif --with-jpeg --with-webp --with-freetype --enable-gd --enable-exif --with-zip --with-zlib --enable-soap --enable-xmlreader --with-xsl --with-libxml --enable-shmop --enable-pcntl --enable-mbstring --with-curl --enable-sockets --with-openssl --with-iconv=/usr/local --enable-bcmath --enable-calendar --enable-ftp --with-kerberos --with-ffi --enable-zend-test --enable-intl --with-mhash --with-sodium --enable-werror --with-config-file-path=/etc --with-config-file-scan-dir=/etc/php.d diff --git a/ext/gd/.DS_Store b/ext/gd/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..1731f4c51750fcfa715a0c7b9f946e4b5ee657f6 GIT binary patch literal 10244 zcmeHMYitx%6h5c4Ff+7v3VpIHU0JF;3ba5iMIPI2E0l+=>_S^wT4r~r?S$#fGBdlS z6in4<)EJFoVnmGu{RauZNQgf)QSlLtkJ$K1d?fxe{viG^F~-Nab7xB*)Wkn($lPS^ zIrrRi?w$MHZ}0B83ji3+r0M}e03guAq+CeVO$zI0&zzFySqexZ#RJ%hQ9GT`&BPpE z-{2$QBj6+8Bj6+8Bk=z~fWEU?5f*dl*FFM10zLv$2(a@ZL=Te@Pfl>@9vxJJKq@k`Yf%aLK~~c{rdqGkO^cy0cSU z$aM#daOu}R0zLwB5n#D{0XU$7P4)Er{ryB**KDV*?hDLYkYBKHk-$oka5Oe-j>a6t z$=FfF>Se7?#Tia`dfYViDP2h%*3{7fxwOSJ97Qu!%MI32D!KG^X-3K%jhY!FWxM0V zc!$W!fLu8~Uf@k~}_S zvDa-eb<>LK8MRwWnnp}JrFJ{&Nrx!|@{(D82h~*n4O4t9O+KYJ4DMLFEmbvohb%4C zF*syHb2QWFnbzCWXA|n}jylqA44O1!mQe0UGdKINYS|>`#CP{7 zmZca&YIN+Vt|U~w!-$%WV~#LSHX1FY(^A<;?o6??lGKc$@UH6|&TynNr>y3R3}LPS zgd>;FySgA_+%OGQ6vL5yUatV_pc(c;42EG8o`iF739iC5_!@qKUoaobaV4(9Ew}@B z;U2sX4`Lj9@Cf$u_`KY{2EFk-fhkg^QCGLKE&S>!@44K*eu*A+X;%a7d!_yJVl@+i zuB54FMhtsEE=ekSGNUVw+N|qrf9$_m1N|=81ATOErQsoXf@t*=ya2DlWw-)wz`O7vd<>t!r$n;v;Yaux zeuLlP5BL)W6mc;YVil1tjH|E?n{XR$C-OycAMVF{v4iM$6#MZQDma8`Jb^Ykcp4wZ zNANLx9M9s5_!7R1=kYRL#W(RSd>gOfNB9{|^7oq}>;dn6J%QhlGLx|0L6p~jGr|Vj z?veKVH-!BvcLbJ}tq8APzo~J1^VCMp+PmpAa+$-a;Zi0?33mf$@{rS63LYY6sVC=S zwY-RNNSI{a)uCWeX5`_`RW;PiBYyMdnzcbmUO?;>UFQuOrJ!6uMCHAkw@8wlPfX^$ zTbrnNA#qlitg5Iimv%}Kk$uc$aD&B~pd^U@oPQVKBD@Cgzz4*;&*5A60j|TZ#JK`2 z#tLHGatz`Myc5^ZaaW7$@h;p-+`F6D*M_^X9rqFg<9Ham-QzEbD)Da^HMEF-SscZa z_y9iW^6*i78lNF1K1)ozfUnHrUHdHFU7E?eY|Jur(-vzlfS4~GV0Y~ydXCY<3iF%b(hZ@? vy^bg8UdK~|UB|oWJK1u1JBy2uoyiF&vmeE$CzIIQ1) literal 0 HcmV?d00001 From 370f177df96e637bb9af8cc62fcc6de0cec4e4b9 Mon Sep 17 00:00:00 2001 From: Ben Morss Date: Mon, 24 May 2021 14:57:14 -0400 Subject: [PATCH 25/37] Removed conflict resolution crud from rebase --- ext/gd/libgd/gd_avif.c | 41 ----------------------------------------- 1 file changed, 41 deletions(-) diff --git a/ext/gd/libgd/gd_avif.c b/ext/gd/libgd/gd_avif.c index c2f024a6b32ca..8d9d65708e12d 100644 --- a/ext/gd/libgd/gd_avif.c +++ b/ext/gd/libgd/gd_avif.c @@ -359,15 +359,7 @@ gdImagePtr gdImageCreateFromAvifCtx (gdIOCtx *ctx) goto cleanup; if (!isAvifSrgbImage(decoder->image)) -<<<<<<< HEAD -<<<<<<< HEAD zend_error(E_WARNING, "Image's color profile is not sRGB"); -======= - gd_error_ex(LOG_WARNING, "Image's color profile is not sRGB"); ->>>>>>> d6dfd6b992 (Incremental commit) -======= - zend_error(E_WARNING, "Image's color profile is not sRGB"); ->>>>>>> bc3489e29b (Change gd includes to quotes instead of angle brackets) // Set up the avifRGBImage, and convert it from YUV to an 8-bit RGB image. // (While AVIF image pixel depth can be 8, 10, or 12 bits, GD truecolor images are 8-bit.) @@ -467,13 +459,6 @@ void gdImageAvifCtx(gdImagePtr im, gdIOCtx *outfile, int quality, int speed) avifResult result; avifRGBImage rgb; avifRWData avifOutput = AVIF_DATA_EMPTY; -<<<<<<< HEAD -<<<<<<< HEAD -======= - avifBool failed = AVIF_FALSE; ->>>>>>> d6dfd6b992 (Incremental commit) -======= ->>>>>>> bc3489e29b (Change gd includes to quotes instead of angle brackets) avifBool lossless = quality == 100; avifEncoder *encoder = NULL; @@ -582,24 +567,10 @@ void gdImageAvifEx(gdImagePtr im, FILE *outFile, int quality, int speed) { gdIOCtx *out = gdNewFileCtx(outFile); -<<<<<<< HEAD -<<<<<<< HEAD -======= ->>>>>>> bc3489e29b (Change gd includes to quotes instead of angle brackets) if (out != NULL) { gdImageAvifCtx(im, out, quality, speed); out->gd_free(out); } -<<<<<<< HEAD -======= - if (out == NULL) - return; - - gdImageAvifCtx(im, out, quality, speed); - out->gd_free(out); ->>>>>>> d6dfd6b992 (Incremental commit) -======= ->>>>>>> bc3489e29b (Change gd includes to quotes instead of angle brackets) } void gdImageAvif(gdImagePtr im, FILE *outFile) @@ -616,20 +587,8 @@ void * gdImageAvifPtrEx(gdImagePtr im, int *size, int quality, int speed) return NULL; } -<<<<<<< HEAD -<<<<<<< HEAD - gdImageAvifCtx(im, out, quality, speed); - rv = gdDPExtractData(out, size); -======= - if (gdImageAvifCtx(im, out, quality, speed)) - rv = NULL; - else - rv = gdDPExtractData(out, size); ->>>>>>> d6dfd6b992 (Incremental commit) -======= gdImageAvifCtx(im, out, quality, speed); rv = gdDPExtractData(out, size); ->>>>>>> bc3489e29b (Change gd includes to quotes instead of angle brackets) out->gd_free(out); return rv; From 2dafbdec0e6659c4d593d86e13936f130f8f9c7b Mon Sep 17 00:00:00 2001 From: Ben Morss Date: Mon, 24 May 2021 20:21:46 -0400 Subject: [PATCH 26/37] Use avif memory allocators Using avifAlloc() here means that libavif has a chance to also free this memory block, which it does in places like avifIOMemoryReaderDestroy(). --- ext/gd/libgd/gd_avif.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/gd/libgd/gd_avif.c b/ext/gd/libgd/gd_avif.c index 8d9d65708e12d..a3db421e08838 100644 --- a/ext/gd/libgd/gd_avif.c +++ b/ext/gd/libgd/gd_avif.c @@ -176,7 +176,7 @@ static avifResult readFromCtx(avifIO *io, uint32_t readFlags, uint64_t offset, s if (!ctx->seek(ctx, offset)) return AVIF_RESULT_IO_ERROR; - dataBuf = gdMalloc(size); + dataBuf = avifAlloc(size); if (!dataBuf) { zend_error(E_ERROR, "avif error - couldn't allocate memory"); return AVIF_RESULT_UNKNOWN_ERROR; @@ -186,7 +186,7 @@ static avifResult readFromCtx(avifIO *io, uint32_t readFlags, uint64_t offset, s // If getBuf() returns a negative value, that means there was an error. int charsRead = ctx->getBuf(ctx, dataBuf, size); if (charsRead < 0) { - gdFree(dataBuf); + avifFree(dataBuf); return AVIF_RESULT_IO_ERROR; } From 5da6a4a967af3894f637727c4399e1a51ef1d922 Mon Sep 17 00:00:00 2001 From: Ben Morss Date: Tue, 25 May 2021 14:38:36 -0400 Subject: [PATCH 27/37] Fixes from code review * removed spurious .DS_Store * fixed broken switch statement * fixed indent --- ext/gd/.DS_Store | Bin 10244 -> 0 bytes ext/gd/gd.c | 1 + .../tests/image/image_type_to_extension.phpt | 2 +- 3 files changed, 2 insertions(+), 1 deletion(-) delete mode 100644 ext/gd/.DS_Store diff --git a/ext/gd/.DS_Store b/ext/gd/.DS_Store deleted file mode 100644 index 1731f4c51750fcfa715a0c7b9f946e4b5ee657f6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10244 zcmeHMYitx%6h5c4Ff+7v3VpIHU0JF;3ba5iMIPI2E0l+=>_S^wT4r~r?S$#fGBdlS z6in4<)EJFoVnmGu{RauZNQgf)QSlLtkJ$K1d?fxe{viG^F~-Nab7xB*)Wkn($lPS^ zIrrRi?w$MHZ}0B83ji3+r0M}e03guAq+CeVO$zI0&zzFySqexZ#RJ%hQ9GT`&BPpE z-{2$QBj6+8Bj6+8Bk=z~fWEU?5f*dl*FFM10zLv$2(a@ZL=Te@Pfl>@9vxJJKq@k`Yf%aLK~~c{rdqGkO^cy0cSU z$aM#daOu}R0zLwB5n#D{0XU$7P4)Er{ryB**KDV*?hDLYkYBKHk-$oka5Oe-j>a6t z$=FfF>Se7?#Tia`dfYViDP2h%*3{7fxwOSJ97Qu!%MI32D!KG^X-3K%jhY!FWxM0V zc!$W!fLu8~Uf@k~}_S zvDa-eb<>LK8MRwWnnp}JrFJ{&Nrx!|@{(D82h~*n4O4t9O+KYJ4DMLFEmbvohb%4C zF*syHb2QWFnbzCWXA|n}jylqA44O1!mQe0UGdKINYS|>`#CP{7 zmZca&YIN+Vt|U~w!-$%WV~#LSHX1FY(^A<;?o6??lGKc$@UH6|&TynNr>y3R3}LPS zgd>;FySgA_+%OGQ6vL5yUatV_pc(c;42EG8o`iF739iC5_!@qKUoaobaV4(9Ew}@B z;U2sX4`Lj9@Cf$u_`KY{2EFk-fhkg^QCGLKE&S>!@44K*eu*A+X;%a7d!_yJVl@+i zuB54FMhtsEE=ekSGNUVw+N|qrf9$_m1N|=81ATOErQsoXf@t*=ya2DlWw-)wz`O7vd<>t!r$n;v;Yaux zeuLlP5BL)W6mc;YVil1tjH|E?n{XR$C-OycAMVF{v4iM$6#MZQDma8`Jb^Ykcp4wZ zNANLx9M9s5_!7R1=kYRL#W(RSd>gOfNB9{|^7oq}>;dn6J%QhlGLx|0L6p~jGr|Vj z?veKVH-!BvcLbJ}tq8APzo~J1^VCMp+PmpAa+$-a;Zi0?33mf$@{rS63LYY6sVC=S zwY-RNNSI{a)uCWeX5`_`RW;PiBYyMdnzcbmUO?;>UFQuOrJ!6uMCHAkw@8wlPfX^$ zTbrnNA#qlitg5Iimv%}Kk$uc$aD&B~pd^U@oPQVKBD@Cgzz4*;&*5A60j|TZ#JK`2 z#tLHGatz`Myc5^ZaaW7$@h;p-+`F6D*M_^X9rqFg<9Ham-QzEbD)Da^HMEF-SscZa z_y9iW^6*i78lNF1K1)ozfUnHrUHdHFU7E?eY|Jur(-vzlfS4~GV0Y~ydXCY<3iF%b(hZ@? vy^bg8UdK~|UB|oWJK1u1JBy2uoyiF&vmeE$CzIIQ1) diff --git a/ext/gd/gd.c b/ext/gd/gd.c index 2b52bf2067399..08974023a65d3 100644 --- a/ext/gd/gd.c +++ b/ext/gd/gd.c @@ -1600,6 +1600,7 @@ PHP_FUNCTION(imagecreatefromstring) RETURN_FALSE; #endif + case PHP_GDIMG_TYPE_AVIF: #ifdef HAVE_GD_AVIF im = _php_image_create_from_string(data, "AVIF", gdImageCreateFromAvifCtx); break; diff --git a/ext/standard/tests/image/image_type_to_extension.phpt b/ext/standard/tests/image/image_type_to_extension.phpt index 1685bea8e15c0..9b0d991d070f7 100644 --- a/ext/standard/tests/image/image_type_to_extension.phpt +++ b/ext/standard/tests/image/image_type_to_extension.phpt @@ -24,7 +24,7 @@ image_type_to_extension() "IMAGETYPE_JPEG2000" => IMAGETYPE_JPEG2000, "IMAGETYPE_XBM" => IMAGETYPE_XBM, "IMAGETYPE_WEBP" => IMAGETYPE_WEBP, - "IMAGETYPE_AVIF" => IMAGETYPE_AVIF, + "IMAGETYPE_AVIF" => IMAGETYPE_AVIF, ); foreach($constants as $name => $constant) { printf("Constant: %s\n\tWith dot: %s\n\tWithout dot: %s\n", $name, image_type_to_extension($constant), image_type_to_extension($constant, false)); From 13e211a04cf3ff7a2793927b4ec9d6e33009aab3 Mon Sep 17 00:00:00 2001 From: Ben Morss Date: Tue, 25 May 2021 14:39:57 -0400 Subject: [PATCH 28/37] Make this work with libavif 0.8.2 Propagate change made in libavif a while ago, but which didn't get into this file originally... --- ext/gd/libgd/gd_avif.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/gd/libgd/gd_avif.c b/ext/gd/libgd/gd_avif.c index a3db421e08838..f5edd0daf9fb1 100644 --- a/ext/gd/libgd/gd_avif.c +++ b/ext/gd/libgd/gd_avif.c @@ -192,7 +192,7 @@ static avifResult readFromCtx(avifIO *io, uint32_t readFlags, uint64_t offset, s out->data = dataBuf; out->size = charsRead; - return charsRead == size ? AVIF_RESULT_OK : AVIF_RESULT_TRUNCATED_DATA; + return AVIF_RESULT_OK; } // avif.h says this is optional, but it seemed easy to implement. From 1e1cb57fa4a124c10e336d2e448aa4fe2681be43 Mon Sep 17 00:00:00 2001 From: Ben Morss Date: Tue, 25 May 2021 21:02:58 -0400 Subject: [PATCH 29/37] Include image-to-image test New test writes AVIF image losslessly, reads that back in, and compares that to the original --- ext/gd/tests/avif_decode_encode.phpt | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/ext/gd/tests/avif_decode_encode.phpt b/ext/gd/tests/avif_decode_encode.phpt index 2e4f021a8473e..a1a60387ee21d 100644 --- a/ext/gd/tests/avif_decode_encode.phpt +++ b/ext/gd/tests/avif_decode_encode.phpt @@ -13,9 +13,11 @@ gd ?> --FILE-- Date: Tue, 25 May 2021 21:38:42 -0400 Subject: [PATCH 30/37] Newline between test output and expected output --- ext/gd/tests/avif_decode_encode.phpt | 1 + 1 file changed, 1 insertion(+) diff --git a/ext/gd/tests/avif_decode_encode.phpt b/ext/gd/tests/avif_decode_encode.phpt index a1a60387ee21d..f823f6c9967ee 100644 --- a/ext/gd/tests/avif_decode_encode.phpt +++ b/ext/gd/tests/avif_decode_encode.phpt @@ -59,6 +59,7 @@ gd echo $success ? "ok\n" : "failed\n"; } ?> + --EXPECT-- Decoding AVIF image: ok Default AVIF encoding: ok From b4c869c0f8b618313c851395021cafc00301a988 Mon Sep 17 00:00:00 2001 From: Ben Morss Date: Tue, 25 May 2021 21:39:35 -0400 Subject: [PATCH 31/37] Use gd_error() instead of zend_error() Our goal is to have fewer differences from libgd. The change here I'm introducing in error levels in one case is something I now want to put into libgd. --- ext/gd/libgd/gd_avif.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/ext/gd/libgd/gd_avif.c b/ext/gd/libgd/gd_avif.c index f5edd0daf9fb1..01bcbf14abdb8 100644 --- a/ext/gd/libgd/gd_avif.c +++ b/ext/gd/libgd/gd_avif.c @@ -9,6 +9,7 @@ #include #include "gd.h" +#include "gd_errors.h" #include "gdhelpers.h" #include "gd_intern.h" @@ -141,7 +142,7 @@ static avifBool isAvifSrgbImage(avifImage *avifIm) { */ static avifBool isAvifError(avifResult result, const char *msg) { if (result != AVIF_RESULT_OK) { - zend_error(E_ERROR, "avif error - %s: %s", msg, avifResultToString(result)); + gd_error("avif error - %s: %s", msg, avifResultToString(result)); return AVIF_TRUE; } @@ -178,7 +179,7 @@ static avifResult readFromCtx(avifIO *io, uint32_t readFlags, uint64_t offset, s dataBuf = avifAlloc(size); if (!dataBuf) { - zend_error(E_ERROR, "avif error - couldn't allocate memory"); + gd_error("avif error - couldn't allocate memory"); return AVIF_RESULT_UNKNOWN_ERROR; } @@ -343,7 +344,7 @@ gdImagePtr gdImageCreateFromAvifCtx (gdIOCtx *ctx) io = createAvifIOFromCtx(ctx); if (!io) { - zend_error(E_ERROR, "avif error - Could not allocate memory"); + gd_error("avif error - Could not allocate memory"); goto cleanup; } @@ -359,7 +360,7 @@ gdImagePtr gdImageCreateFromAvifCtx (gdIOCtx *ctx) goto cleanup; if (!isAvifSrgbImage(decoder->image)) - zend_error(E_WARNING, "Image's color profile is not sRGB"); + gd_error_ex(GD_NOTICE, "Image's color profile is not sRGB"); // Set up the avifRGBImage, and convert it from YUV to an 8-bit RGB image. // (While AVIF image pixel depth can be 8, 10, or 12 bits, GD truecolor images are 8-bit.) @@ -373,7 +374,7 @@ gdImagePtr gdImageCreateFromAvifCtx (gdIOCtx *ctx) im = gdImageCreateTrueColor(decoder->image->width, decoder->image->height); if (!im) { - zend_error(E_ERROR, "avif error - Could not create GD truecolor image"); + gd_error("avif error - Could not create GD truecolor image"); goto cleanup; } @@ -470,17 +471,17 @@ void gdImageAvifCtx(gdImagePtr im, gdIOCtx *outfile, int quality, int speed) return; if (!gdImageTrueColor(im)) { - zend_error(E_ERROR, "avif doesn't support palette images"); + gd_error("avif error - avif doesn't support palette images"); return; } if (!gdImageSX(im) || !gdImageSY(im)) { - zend_error(E_ERROR, "image dimensions must not be zero"); + gd_error("avif error - image dimensions must not be zero"); return; } if (overflow2(gdImageSX(im), gdImageSY(im))) { - zend_error(E_ERROR, "image dimensions are too large"); + gd_error("avif error - image dimensions are too large"); return; } From e8770a51da5ffc8925b87542d307313d50c5eff6 Mon Sep 17 00:00:00 2001 From: Ben Morss Date: Thu, 3 Jun 2021 09:21:02 -0400 Subject: [PATCH 32/37] Restore libavif, lost during merge Co-authored-by: Nikita Popov --- .cirrus.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.cirrus.yml b/.cirrus.yml index d6ad10f0c807f..917859dad2b81 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -11,7 +11,7 @@ task: #- sed -i -e 's/quarterly/latest/g' /etc/pkg/FreeBSD.conf #- pkg upgrade -y - kldload accf_http - - pkg install -y autoconf bison gmake re2c icu libiconv png freetype2 enchant2 bzip2 krb5 t1lib gmp tidyp libsodium libzip libxml2 libxslt openssl oniguruma pkgconf webp + - pkg install -y autoconf bison gmake re2c icu libiconv png freetype2 enchant2 bzip2 krb5 t1lib gmp tidyp libsodium libzip libxml2 libxslt openssl oniguruma pkgconf webp libavif script: - ./buildconf -f - ./configure --prefix=/usr/local --enable-debug --enable-option-checking=fatal --enable-fpm --with-pdo-sqlite --without-pear --with-bz2 --with-avif --with-jpeg --with-webp --with-freetype --enable-gd --enable-exif --with-zip --with-zlib --enable-soap --enable-xmlreader --with-xsl --with-libxml --enable-shmop --enable-pcntl --enable-mbstring --with-curl --enable-sockets --with-openssl --with-iconv=/usr/local --enable-bcmath --enable-calendar --enable-ftp --with-kerberos --with-ffi --enable-zend-test --enable-intl --with-mhash --with-sodium --enable-werror --with-config-file-path=/etc --with-config-file-scan-dir=/etc/php.d From 41aedcf679526d953a251eb964a951d1e2191140 Mon Sep 17 00:00:00 2001 From: Ben Morss Date: Thu, 3 Jun 2021 10:40:05 -0400 Subject: [PATCH 33/37] Revert changes to ext/standard files These will be included in PR #7091 instead. --- ext/standard/image.c | 19 ++----------------- ext/standard/php_image.h | 3 +-- 2 files changed, 3 insertions(+), 19 deletions(-) diff --git a/ext/standard/image.c b/ext/standard/image.c index f7a3a4b4b58c3..2154f8e32295b 100644 --- a/ext/standard/image.c +++ b/ext/standard/image.c @@ -5,7 +5,7 @@ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | - | https://www.php.net/license/3_01.txt | + | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | @@ -87,8 +87,7 @@ PHP_MINIT_FUNCTION(imagetypes) REGISTER_LONG_CONSTANT("IMAGETYPE_JPEG2000",IMAGE_FILETYPE_JPC, CONST_CS | CONST_PERSISTENT); /* keep alias */ REGISTER_LONG_CONSTANT("IMAGETYPE_XBM", IMAGE_FILETYPE_XBM, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("IMAGETYPE_ICO", IMAGE_FILETYPE_ICO, CONST_CS | CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("IMAGETYPE_WEBP", IMAGE_FILETYPE_WEBP, CONST_CS | CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("IMAGETYPE_AVIF", IMAGE_FILETYPE_AVIF, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IMAGETYPE_WEBP", IMAGE_FILETYPE_WEBP, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("IMAGETYPE_UNKNOWN", IMAGE_FILETYPE_UNKNOWN, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("IMAGETYPE_COUNT", IMAGE_FILETYPE_COUNT, CONST_CS | CONST_PERSISTENT); return SUCCESS; @@ -1149,13 +1148,6 @@ static struct gfxinfo *php_handle_webp(php_stream * stream) } /* }}} */ -/* {{{ php_handle_avif }}} */ -/* TODO: This is just a stub */ -static struct gfxinfo *php_handle_avif(php_stream * stream) { - return NULL; -} - - /* {{{ php_image_type_to_mime_type * Convert internal image_type to mime type */ PHPAPI char * php_image_type_to_mime_type(int image_type) @@ -1191,8 +1183,6 @@ PHPAPI char * php_image_type_to_mime_type(int image_type) return "image/vnd.microsoft.icon"; case IMAGE_FILETYPE_WEBP: return "image/webp"; - case IMAGE_FILETYPE_AVIF: - return "image/avif"; default: case IMAGE_FILETYPE_UNKNOWN: return "application/octet-stream"; /* suppose binary format */ @@ -1275,8 +1265,6 @@ PHP_FUNCTION(image_type_to_extension) case IMAGE_FILETYPE_WEBP: imgext = ".webp"; break; - case IMAGE_FILETYPE_AVIF: - imgext = ".avif"; } if (imgext) { @@ -1443,9 +1431,6 @@ static void php_getimagesize_from_stream(php_stream *stream, char *input, zval * case IMAGE_FILETYPE_WEBP: result = php_handle_webp(stream); break; - case IMAGE_FILETYPE_AVIF: - result = php_handle_avif(stream); - break; default: case IMAGE_FILETYPE_UNKNOWN: break; diff --git a/ext/standard/php_image.h b/ext/standard/php_image.h index 9b0c33d7738bd..3649e62198b50 100644 --- a/ext/standard/php_image.h +++ b/ext/standard/php_image.h @@ -5,7 +5,7 @@ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | - | https://www.php.net/license/3_01.txt | + | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | @@ -43,7 +43,6 @@ typedef enum IMAGE_FILETYPE_XBM, IMAGE_FILETYPE_ICO, IMAGE_FILETYPE_WEBP, - IMAGE_FILETYPE_AVIF, /* WHEN EXTENDING: PLEASE ALSO REGISTER IN image.c:PHP_MINIT_FUNCTION(imagetypes) */ IMAGE_FILETYPE_COUNT } image_filetype; From b0959ab7b5d8cc5bdefe52b66051ccc52ae65d0f Mon Sep 17 00:00:00 2001 From: Ben Morss Date: Thu, 3 Jun 2021 11:15:46 -0400 Subject: [PATCH 34/37] Revert AVIF from image type tests This will be covered in #7091 . --- ext/standard/tests/image/image_type_to_extension.phpt | 3 +-- .../tests/image/image_type_to_mime_type_variation3.phpt | 3 --- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/ext/standard/tests/image/image_type_to_extension.phpt b/ext/standard/tests/image/image_type_to_extension.phpt index 9b0d991d070f7..a22ea34426147 100644 --- a/ext/standard/tests/image/image_type_to_extension.phpt +++ b/ext/standard/tests/image/image_type_to_extension.phpt @@ -23,8 +23,7 @@ image_type_to_extension() "IMAGETYPE_WBMP" => IMAGETYPE_WBMP, "IMAGETYPE_JPEG2000" => IMAGETYPE_JPEG2000, "IMAGETYPE_XBM" => IMAGETYPE_XBM, - "IMAGETYPE_WEBP" => IMAGETYPE_WEBP, - "IMAGETYPE_AVIF" => IMAGETYPE_AVIF, + "IMAGETYPE_WEBP" => IMAGETYPE_WEBP ); foreach($constants as $name => $constant) { printf("Constant: %s\n\tWith dot: %s\n\tWithout dot: %s\n", $name, image_type_to_extension($constant), image_type_to_extension($constant, false)); diff --git a/ext/standard/tests/image/image_type_to_mime_type_variation3.phpt b/ext/standard/tests/image/image_type_to_mime_type_variation3.phpt index fc17cb5ecd947..81b50a8af35b4 100644 --- a/ext/standard/tests/image/image_type_to_mime_type_variation3.phpt +++ b/ext/standard/tests/image/image_type_to_mime_type_variation3.phpt @@ -71,8 +71,5 @@ string\(24\) "image\/vnd.microsoft.icon" -- Iteration 18 -- string\(10\) "image\/webp" --- Iteration 19 -- -string\(10\) "image\/avif" - -- Iteration 20 -- string\(24\) "application\/octet-stream" From ebe74df9176a15d07a9f8503a0bed9892b00596c Mon Sep 17 00:00:00 2001 From: Ben Morss Date: Thu, 3 Jun 2021 12:05:59 -0400 Subject: [PATCH 35/37] Removed AVIF from tests properly, this time, I hope --- ext/standard/tests/image/image_type_to_extension.phpt | 3 --- .../tests/image/image_type_to_mime_type_variation3.phpt | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/ext/standard/tests/image/image_type_to_extension.phpt b/ext/standard/tests/image/image_type_to_extension.phpt index a22ea34426147..fd60fc454e10b 100644 --- a/ext/standard/tests/image/image_type_to_extension.phpt +++ b/ext/standard/tests/image/image_type_to_extension.phpt @@ -85,9 +85,6 @@ Constant: IMAGETYPE_XBM Constant: IMAGETYPE_WEBP With dot: .webp Without dot: webp -Constant: IMAGETYPE_AVIF - With dot: .avif - Without dot: avif bool(false) bool(false) Done diff --git a/ext/standard/tests/image/image_type_to_mime_type_variation3.phpt b/ext/standard/tests/image/image_type_to_mime_type_variation3.phpt index 81b50a8af35b4..49a53c468b1d3 100644 --- a/ext/standard/tests/image/image_type_to_mime_type_variation3.phpt +++ b/ext/standard/tests/image/image_type_to_mime_type_variation3.phpt @@ -71,5 +71,5 @@ string\(24\) "image\/vnd.microsoft.icon" -- Iteration 18 -- string\(10\) "image\/webp" --- Iteration 20 -- +-- Iteration 19 -- string\(24\) "application\/octet-stream" From 971812ea819db8591b060787832b9a2e84807b3b Mon Sep 17 00:00:00 2001 From: Ben Morss Date: Thu, 3 Jun 2021 14:05:07 -0400 Subject: [PATCH 36/37] restore https in license URL a horrible artifact of merging --- ext/standard/image.c | 2 +- ext/standard/php_image.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/standard/image.c b/ext/standard/image.c index 2154f8e32295b..5e176369a5d05 100644 --- a/ext/standard/image.c +++ b/ext/standard/image.c @@ -5,7 +5,7 @@ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | - | http://www.php.net/license/3_01.txt | + | https://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | diff --git a/ext/standard/php_image.h b/ext/standard/php_image.h index 3649e62198b50..780fdea7b7f8d 100644 --- a/ext/standard/php_image.h +++ b/ext/standard/php_image.h @@ -5,7 +5,7 @@ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | - | http://www.php.net/license/3_01.txt | + | https://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | From d6603a9457f0e6dc6a26c73b944ca778d042f54c Mon Sep 17 00:00:00 2001 From: Ben Morss Date: Mon, 7 Jun 2021 09:06:16 -0400 Subject: [PATCH 37/37] Removed spurious spaces --- ext/standard/image.c | 2 +- ext/standard/php_image.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/standard/image.c b/ext/standard/image.c index 5e176369a5d05..ed180b7bca6df 100644 --- a/ext/standard/image.c +++ b/ext/standard/image.c @@ -5,7 +5,7 @@ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | - | https://www.php.net/license/3_01.txt | + | https://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | diff --git a/ext/standard/php_image.h b/ext/standard/php_image.h index 780fdea7b7f8d..8311f4b2ab8fb 100644 --- a/ext/standard/php_image.h +++ b/ext/standard/php_image.h @@ -5,7 +5,7 @@ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | - | https://www.php.net/license/3_01.txt | + | https://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. |