diff --git a/ext/standard/image.c b/ext/standard/image.c index 2154f8e32295b..7d9ea30935f71 100644 --- a/ext/standard/image.c +++ b/ext/standard/image.c @@ -50,6 +50,7 @@ PHPAPI const char php_sig_iff[4] = {'F','O','R','M'}; PHPAPI const char php_sig_ico[4] = {(char)0x00, (char)0x00, (char)0x01, (char)0x00}; PHPAPI const char php_sig_riff[4] = {'R', 'I', 'F', 'F'}; PHPAPI const char php_sig_webp[4] = {'W', 'E', 'B', 'P'}; +PHPAPI const char php_sig_avif[4] = {'a', 'v', 'i', 'f'}; /* REMEMBER TO ADD MIME-TYPE TO FUNCTION php_image_type_to_mime_type */ /* PCX must check first 64bytes and byte 0=0x0a and byte2 < 0x06 */ @@ -88,6 +89,7 @@ PHP_MINIT_FUNCTION(imagetypes) 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_UNKNOWN", IMAGE_FILETYPE_UNKNOWN, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("IMAGETYPE_COUNT", IMAGE_FILETYPE_COUNT, CONST_CS | CONST_PERSISTENT); return SUCCESS; @@ -1148,6 +1150,103 @@ static struct gfxinfo *php_handle_webp(php_stream * stream) } /* }}} */ +/* {{{ php_handle_avif + */ +static struct gfxinfo *php_handle_avif(php_stream * stream) { + struct gfxinfo *result = NULL; + unsigned int width = 0, height = 0; + unsigned char channels = 0, bits = 0, i, bits_tmp; + unsigned int size, type; + size_t begin, end, pos = 0; + int check_ispe = 0, check_pixi = 0, eof; + + if (php_stream_seek(stream, 0, SEEK_SET)) { + return NULL; + } + for(;;) { + eof = php_stream_eof(stream); + if (eof == -1) { + return NULL; + } else if ((check_ispe == 1 && check_pixi == 1) || eof == 1) { + break; + } + + begin = pos; + size = php_read4(stream); pos += 4; + type = php_read4(stream); pos += 4; + end = begin + size; + + switch (type) { + case 1835365473u: /* meta */ + if (php_stream_seek(stream, 4, SEEK_CUR)) { + return NULL; + } + pos += 4; + continue; + + case 1768977008u: /* iprp */ + case 1768973167u: /* ipco */ + continue; + + case 1769173093u: /* ispe */ + if (php_stream_seek(stream, 4, SEEK_CUR)) { + return NULL; + } + pos += 4; + width = php_read4(stream); pos += 4; + height = php_read4(stream); pos += 4; + check_ispe = 1; + break; + + case 1885960297u: /* pixi */ + if (php_stream_seek(stream, 4, SEEK_CUR)) { + return NULL; + } + pos += 4; + + /* channels */ + if (php_stream_read(stream, (char *)&channels, 1) != 1) { + return NULL; + } + pos++; + + /* bits */ + for (i = 0; i < channels; i++) { + if (php_stream_read(stream, (char *)&bits_tmp, 1) != 1) { + return NULL; + } + pos++; + + if (bits_tmp > bits) { + bits = bits_tmp; + } + } + check_pixi = 1; + break; + + default: + break; + } + + pos = end; + if (php_stream_seek(stream, end, SEEK_SET)) { + return NULL; + } + } + + result = (struct gfxinfo *) ecalloc(1, sizeof(struct gfxinfo)); + if (result == NULL) { + return NULL; + } + + result->width = width; + result->height = height; + result->bits = bits; + result->channels = channels; + return result; +} +/* }}} */ + /* {{{ php_image_type_to_mime_type * Convert internal image_type to mime type */ PHPAPI char * php_image_type_to_mime_type(int image_type) @@ -1183,6 +1282,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 */ @@ -1265,6 +1366,9 @@ PHP_FUNCTION(image_type_to_extension) case IMAGE_FILETYPE_WEBP: imgext = ".webp"; break; + case IMAGE_FILETYPE_AVIF: + imgext = ".avif"; + break; } if (imgext) { @@ -1347,6 +1451,8 @@ PHPAPI int php_getimagetype(php_stream * stream, const char *input, char *filety /* BYTES READ: 12 */ if (twelve_bytes_read && !memcmp(filetype, php_sig_jp2, 12)) { return IMAGE_FILETYPE_JP2; + } else if (twelve_bytes_read && !memcmp(filetype+8, php_sig_avif, 4)) { + return IMAGE_FILETYPE_AVIF; } /* AFTER ALL ABOVE FAILED */ @@ -1431,6 +1537,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 3649e62198b50..afd75138f2ddf 100644 --- a/ext/standard/php_image.h +++ b/ext/standard/php_image.h @@ -43,6 +43,7 @@ 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; diff --git a/ext/standard/tests/image/getimagesize.phpt b/ext/standard/tests/image/getimagesize.phpt index 582959f3ae6ee..0e6f7d7227bb5 100644 --- a/ext/standard/tests/image/getimagesize.phpt +++ b/ext/standard/tests/image/getimagesize.phpt @@ -23,7 +23,7 @@ GetImageSize() var_dump($result); ?> --EXPECT-- -array(16) { +array(17) { ["test-1pix.bmp"]=> array(6) { [0]=> @@ -268,4 +268,21 @@ array(16) { ["mime"]=> string(10) "image/tiff" } + ["test8pix.avif"]=> + array(7) { + [0]=> + int(8) + [1]=> + int(1) + [2]=> + int(19) + [3]=> + string(20) "width="8" height="1"" + ["bits"]=> + int(8) + ["channels"]=> + int(3) + ["mime"]=> + string(10) "image/avif" + } } diff --git a/ext/standard/tests/image/getimagesize_avif_monochrome.phpt b/ext/standard/tests/image/getimagesize_avif_monochrome.phpt new file mode 100644 index 0000000000000..d735749c9f0aa --- /dev/null +++ b/ext/standard/tests/image/getimagesize_avif_monochrome.phpt @@ -0,0 +1,34 @@ +--TEST-- +GetImageSize() for avif using monochrome format +--FILE-- + +--EXPECT-- +*** Testing getimagesize() : avif using monochrome format *** +array(7) { + [0]=> + int(8) + [1]=> + int(1) + [2]=> + int(19) + [3]=> + string(20) "width="8" height="1"" + ["bits"]=> + int(8) + ["channels"]=> + int(1) + ["mime"]=> + string(10) "image/avif" +} +array(0) { +} diff --git a/ext/standard/tests/image/image_type_to_extension.phpt b/ext/standard/tests/image/image_type_to_extension.phpt index fd60fc454e10b..7353fc05fd94a 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 diff --git a/ext/standard/tests/image/image_type_to_mime_type.phpt b/ext/standard/tests/image/image_type_to_mime_type.phpt index b4f6d3c403fa1..cf00544b507ec 100644 --- a/ext/standard/tests/image/image_type_to_mime_type.phpt +++ b/ext/standard/tests/image/image_type_to_mime_type.phpt @@ -24,7 +24,7 @@ image_type_to_mime_type() var_dump($result); ?> --EXPECT-- -array(16) { +array(17) { ["test-1pix.bmp"]=> string(9) "image/bmp" ["test12pix.webp"]=> @@ -57,4 +57,6 @@ array(16) { string(29) "application/x-shockwave-flash" ["test4pix.tiff"]=> string(10) "image/tiff" + ["test8pix.avif"]=> + string(10) "image/avif" } diff --git a/ext/standard/tests/image/image_type_to_mime_type_basic.phpt b/ext/standard/tests/image/image_type_to_mime_type_basic.phpt index bf5a1ee250990..882146ef3aeea 100644 --- a/ext/standard/tests/image/image_type_to_mime_type_basic.phpt +++ b/ext/standard/tests/image/image_type_to_mime_type_basic.phpt @@ -22,7 +22,8 @@ $image_types = array ( IMAGETYPE_WBMP, IMAGETYPE_JPEG2000, IMAGETYPE_XBM, - IMAGETYPE_WEBP + IMAGETYPE_WEBP, + IMAGETYPE_AVIF ); foreach($image_types as $image_type) { @@ -51,5 +52,6 @@ string(18) "image/vnd.wap.wbmp" string(24) "application/octet-stream" string(9) "image/xbm" string(10) "image/webp" +string(10) "image/avif" Done image_type_to_mime_type() test 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" diff --git a/ext/standard/tests/image/monochrome.avif b/ext/standard/tests/image/monochrome.avif new file mode 100644 index 0000000000000..488ced08678ff Binary files /dev/null and b/ext/standard/tests/image/monochrome.avif differ diff --git a/ext/standard/tests/image/test8pix.avif b/ext/standard/tests/image/test8pix.avif new file mode 100644 index 0000000000000..6e2224749bc45 Binary files /dev/null and b/ext/standard/tests/image/test8pix.avif differ