From 4ef6659698b63b7619a5b8ef3e5fef5a3e336eef Mon Sep 17 00:00:00 2001 From: Benstone Zhang Date: Wed, 25 Jun 2025 17:09:36 +0800 Subject: [PATCH] getimagesize support HEIF/HEIC Signed-off-by: Benstone Zhang --- ext/standard/basic_functions.stub.php | 5 +++++ ext/standard/basic_functions_arginfo.h | 1 + ext/standard/image.c | 20 ++++++++++++++++++ ext/standard/php_image.h | 1 + ext/standard/tests/image/getimagesize.phpt | 19 ++++++++++++++++- .../tests/image/image_type_to_mime_type.phpt | 4 +++- .../image/image_type_to_mime_type_basic.phpt | 4 +++- .../image_type_to_mime_type_variation3.phpt | 3 +++ ext/standard/tests/image/test4pix.heic | Bin 0 -> 6181 bytes 9 files changed, 54 insertions(+), 3 deletions(-) create mode 100644 ext/standard/tests/image/test4pix.heic diff --git a/ext/standard/basic_functions.stub.php b/ext/standard/basic_functions.stub.php index 09f63860f1163..7ad3234b81345 100644 --- a/ext/standard/basic_functions.stub.php +++ b/ext/standard/basic_functions.stub.php @@ -646,6 +646,11 @@ * @cvalue IMAGE_FILETYPE_AVIF */ const IMAGETYPE_AVIF = UNKNOWN; +/** + * @var int + * @cvalue IMAGE_FILETYPE_HEIF + */ +const IMAGETYPE_HEIF = UNKNOWN; /** * @var int * @cvalue IMAGE_FILETYPE_UNKNOWN diff --git a/ext/standard/basic_functions_arginfo.h b/ext/standard/basic_functions_arginfo.h index 37df4de7bdfcd..8407d9643c146 100644 --- a/ext/standard/basic_functions_arginfo.h +++ b/ext/standard/basic_functions_arginfo.h @@ -3645,6 +3645,7 @@ static void register_basic_functions_symbols(int module_number) REGISTER_LONG_CONSTANT("IMAGETYPE_ICO", IMAGE_FILETYPE_ICO, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("IMAGETYPE_WEBP", IMAGE_FILETYPE_WEBP, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("IMAGETYPE_AVIF", IMAGE_FILETYPE_AVIF, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IMAGETYPE_HEIF", IMAGE_FILETYPE_HEIF, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("IMAGETYPE_UNKNOWN", IMAGE_FILETYPE_UNKNOWN, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("IMAGETYPE_COUNT", IMAGE_FILETYPE_COUNT, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("INFO_GENERAL", PHP_INFO_GENERAL, CONST_PERSISTENT); diff --git a/ext/standard/image.c b/ext/standard/image.c index eeb1f1fa2813a..ef0ddade3be3c 100644 --- a/ext/standard/image.c +++ b/ext/standard/image.c @@ -51,6 +51,10 @@ 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_ftyp[4] = {'f', 't', 'y', 'p'}; +PHPAPI const char php_sig_mif1[4] = {'m', 'i', 'f', '1'}; +PHPAPI const char php_sig_heic[4] = {'h', 'e', 'i', 'c'}; +PHPAPI const char php_sig_heix[4] = {'h', 'e', 'i', 'x'}; /* 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 */ @@ -1254,6 +1258,8 @@ PHPAPI char * php_image_type_to_mime_type(int image_type) return "image/webp"; case IMAGE_FILETYPE_AVIF: return "image/avif"; + case IMAGE_FILETYPE_HEIF: + return "image/heif"; default: case IMAGE_FILETYPE_UNKNOWN: return "application/octet-stream"; /* suppose binary format */ @@ -1339,6 +1345,10 @@ PHP_FUNCTION(image_type_to_extension) case IMAGE_FILETYPE_AVIF: imgext = ".avif"; break; + case IMAGE_FILETYPE_HEIF: + imgext = ".heif"; + break; + break; } if (imgext) { @@ -1423,6 +1433,11 @@ PHPAPI int php_getimagetype(php_stream *stream, const char *input, char *filetyp return IMAGE_FILETYPE_JP2; } + if (twelve_bytes_read && !memcmp(filetype + 4, php_sig_ftyp, 4) && + (!memcmp(filetype + 8, php_sig_mif1, 4) || !memcmp(filetype + 8, php_sig_heic, 4) || !memcmp(filetype + 8, php_sig_heix, 4))) { + return IMAGE_FILETYPE_HEIF; + } + if (!php_stream_rewind(stream) && php_is_image_avif(stream)) { return IMAGE_FILETYPE_AVIF; } @@ -1515,6 +1530,11 @@ static void php_getimagesize_from_stream(php_stream *stream, char *input, zval * case IMAGE_FILETYPE_AVIF: result = php_handle_avif(stream); break; + case IMAGE_FILETYPE_HEIF: + if (!php_stream_rewind(stream)) { + 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 a41273e6745ae..f0f3edb7283eb 100644 --- a/ext/standard/php_image.h +++ b/ext/standard/php_image.h @@ -44,6 +44,7 @@ typedef enum IMAGE_FILETYPE_ICO, IMAGE_FILETYPE_WEBP, IMAGE_FILETYPE_AVIF, + IMAGE_FILETYPE_HEIF, /* WHEN EXTENDING: PLEASE ALSO REGISTER IN basic_function.stub.php */ IMAGE_FILETYPE_COUNT } image_filetype; diff --git a/ext/standard/tests/image/getimagesize.phpt b/ext/standard/tests/image/getimagesize.phpt index 472be1d25e366..085bf96287b91 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(17) { +array(18) { ["test-1pix.bmp"]=> array(6) { [0]=> @@ -216,6 +216,23 @@ array(17) { ["mime"]=> string(9) "image/gif" } + ["test4pix.heic"]=> + array(7) { + [0]=> + int(54) + [1]=> + int(84) + [2]=> + int(20) + [3]=> + string(22) "width="54" height="84"" + ["bits"]=> + int(8) + ["channels"]=> + int(3) + ["mime"]=> + string(10) "image/heif" + } ["test4pix.iff"]=> array(6) { [0]=> 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 5877efe531fd9..0102955babe73 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(17) { +array(18) { ["test-1pix.bmp"]=> string(9) "image/bmp" ["test12pix.webp"]=> @@ -49,6 +49,8 @@ array(17) { string(10) "image/webp" ["test4pix.gif"]=> string(9) "image/gif" + ["test4pix.heic"]=> + string(10) "image/heif" ["test4pix.iff"]=> string(9) "image/iff" ["test4pix.png"]=> 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..6aaa25551bd44 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_HEIF ); 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/heif" 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 fc17cb5ecd947..6626dc5a07c03 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 @@ -75,4 +75,7 @@ string\(10\) "image\/webp" string\(10\) "image\/avif" -- Iteration 20 -- +string\(10\) "image\/heif" + +-- Iteration 21 -- string\(24\) "application\/octet-stream" diff --git a/ext/standard/tests/image/test4pix.heic b/ext/standard/tests/image/test4pix.heic new file mode 100644 index 0000000000000000000000000000000000000000..93ca3ed1faf9ca8184e428b0d5a0d0519a93dbd7 GIT binary patch literal 6181 zcmeHKdstM}7T;&i0K+3dCCEp1n$%F6nKJ_-i~=(Zn2!dKm-xsWW)94WnK`F3Lpb+W};gyd!?pmf_iH@tVt{cbxuoq(G1?=lzq3CQ3>;Vxp;L>sr4{~BX;HaWf5x`lV=(qG6?k1_;`mB|EwOtj9Zl1e z(Z&@qRBol)!#Lg4ESHrNcuuf*7#naU`|vC@Od?{B#cGq15+{n%|6zsCK~neAT+zQo z^uYnyz(UqC;Xz-Iki{YNNBsdE>u*6Q>ov%OUk7CIH3&7_g;2!v1F{Jas*xImKE`M9 z0EDiIAR(L(J`RM&evf{=-qV9nDA@pZ#u$h&qOT7VNX&o`Cec`a+$%74M;al{95m1n zMOi*+?s@Xh(fLzlvOx4$Bk+RLiI$SPmIvqzpg)Rr^ZuYqfPNm7SgXSV3n1LbIhgBf zp+Q7n3)GK6K`59NIPs7pdA5SZ5>lbSkuZ|wo&L;+j0t>v8M%B#APneP2L~aDP&&37 z>xL4w2RcPKMR8AF2E~9khI@(~a0P^8?6g_LwGbN70{uWKoy}%633>_?Mns4j!0G5E zB2vV|0KZEN_vr#{#3&R1GC-(}7~PML5V1ZE*g$B-xx;~TlF*4b3UDWp($DWDQvH|+ zf09LVNhgs~J>HMW7eR)y?wN1S&d;SxSvlERImWzMS(y}kC_`n|nk_=gpTb;X zF|Pb=mYJHz38ik{Vr3|uI?jxAv@Tvx>-2OyrJbse)9K^!@$76tvW3Bj$i5$uy(>Ww z31uWAPjsTt#wU^d9ED;sK0*Ou%TUl5xSYg&;{9O%>d+m_>is*BU0AlEAAeu1^mzn$ z)pz=E8(`Xp!O~iUft`)eaNo7{}HQ@5giM3rABKHBe6{i?(#uv?mZe1ND)Hn3I`IS9-9*UD}R93=PKiRTWov&nBKmWK@D>qI>e zL1bZ5yy%k{z!h+B_#%}AH;W(k$pt_-8v>+g(CW21N~_h!0Z8;k$c?hebfTW75&CT_ zsT4B-Zy9u>n|v+CxP7-`p)QK<(7ZsEM$Vf?x91ayD zoZYfar~u)eft2ipT9jvCx#Urh%cFtew*oTV?+LjY1xtJ*=1U(14d#xQ+GuQ@4GO-F zusq(^!jCbQ6A%N4n4VeziB-yYs3N9>btNmiKHR0GSX;7k-V`%!=1q*9omnL?xmB5Y z)~Zr#l1-VKLQSvGS2%h6sG;D6;BxCLl9d+xd!`4B#Tq3gQaq)}%0hECW#R;eN>I~k zS_!k^WuebWpW&Mey=0}`GD`AR4(@& zehumH8!oUseydPeqos%|^CT-_Wzi%{85reL>vF3_^VC+(sbS#tqtU8q4KT2s(gvLT zzh_ric#-TU@^;R{x$WG4p!W~oFv(`^SI)yLPTZf(s$m?AlW}?6z}12!V2}PD#^s*n zD&~@vTAfBq#nVt}<26&nYJifg%yLvZ`7$?URxc=HOF1f?Enz(t2bGad4UR)9Ti~Q= zGaMGT-NZS0SV4T?B`ZO>G?vQtOI+fZIU8GCnGTPhWF^jH6|Gaz@p=AReUKt%FiES@ z>hk=_uB7^XuE!*CT?PVJQg|a5g3o5v)Wd#cVKI?kW#XsALHmTx)m-6z|QE{LlhUzm5+({yA)VcADtPfX}b zpW*nRY;)uMnx+LmA-Q%=WyivuM$KP$=HK5{(7651lBpw1-&VIC+IOAG>^gMp#l4-A z%6I-{``5Wyq$7WK?YOAe^HUco-?TXcqe9g+DJfH(hPI;O*j*ck-ZR?+<)2+MaW^Cw`+UcXwac-ygVm#2C?$dZc?=Z5h=@=HE3}(Ve{=NhJ6(s5wWt^V$YS69^e5pLzDqbWvh~rnp!((?hcD~> zIJhhKwha0Hsz=WV(d}7+y60&Ak~8B&Up?5~^=$Y>N7MfMF5R~|_KD!`)dk`2^)jCx zKAYHkCN1OM?VqeZwRKW@^NSx$s;eEFGG%fQ(-pHvdv^5h9a_t&r5oN_-L-Gw(qq@w z$IKSu4xe1TsIcsv;?`5L=FgTCZ@%zCQ(WKsbF?X`?`?hNsf&-)t^1(~lCs%$dw64X+QXNtt}Qx#|M4@_yf6Q; zCh*((VLur1+nb;5IC%Wcd860J+ASykRhOz^%j>Ta8bDrmX4d*`j8?w1yQ z%dQ=>GU?^RYgfH;;OSA*hHG{O)vWZ&cXWr+sq4I*<6Pr{QVlB}4m~pceeTLOt7pee zrB|zRZ+qt6HCLnOuRMEk&J1@OZQ86~@$T47X@M`e6o<0Vv%_xRbJg3$j=j}j+A!ku zbJSSFlC{r_Y`eW;XN&IB=`p&(#eC+~cFU#@RlkI{ytX}H?%tPI-?wF7aKgI2jawJE Y|M^wx^*v{8uYGCzF=6-h=bHF`0p`FPumAu6 literal 0 HcmV?d00001