From abb22c9e155b59233e87dae699dd354d1693243b Mon Sep 17 00:00:00 2001 From: Michael Date: Fri, 16 Feb 2024 21:03:28 +0000 Subject: [PATCH] Fixed animated picture detected --- src/Factory/Api/Mastodon/Attachment.php | 2 +- src/Module/Photo.php | 4 +-- .../HTTPClient/Client/HttpClientAccept.php | 2 +- src/Object/Image.php | 28 +++++++++++++++++-- 4 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/Factory/Api/Mastodon/Attachment.php b/src/Factory/Api/Mastodon/Attachment.php index ab66b71f2b..727b77630a 100644 --- a/src/Factory/Api/Mastodon/Attachment.php +++ b/src/Factory/Api/Mastodon/Attachment.php @@ -84,7 +84,7 @@ class Attachment extends BaseFactory $type = 'audio'; } elseif (($filetype == 'video') || ($attachment['type'] == Post\Media::VIDEO)) { $type = 'video'; - } elseif ($attachment['mimetype'] == 'image/gif') { + } elseif ($attachment['mimetype'] == image_type_to_mime_type(IMAGETYPE_GIF)) { $type = 'gifv'; } elseif (($filetype == 'image') || ($attachment['type'] == Post\Media::IMAGE)) { $type = 'image'; diff --git a/src/Module/Photo.php b/src/Module/Photo.php index 782b982daa..3a064c48ac 100644 --- a/src/Module/Photo.php +++ b/src/Module/Photo.php @@ -208,12 +208,12 @@ class Photo extends BaseApi } // if customsize is set and image is not a gif, resize it - if ($photo['type'] !== 'image/gif' && $customsize > 0 && $customsize <= Proxy::PIXEL_THUMB && $square_resize) { + if ($photo['type'] !== image_type_to_mime_type(IMAGETYPE_GIF) && $customsize > 0 && $customsize <= Proxy::PIXEL_THUMB && $square_resize) { $img = new Image($imgdata, $photo['type'], $photo['filename']); $img->scaleToSquare($customsize); $imgdata = $img->asString(); $mimetype = $img->getType(); - } elseif ($photo['type'] !== 'image/gif' && $customsize > 0) { + } elseif ($photo['type'] !== image_type_to_mime_type(IMAGETYPE_GIF) && $customsize > 0) { $img = new Image($imgdata, $photo['type'], $photo['filename']); $img->scaleDown($customsize); $imgdata = $img->asString(); diff --git a/src/Network/HTTPClient/Client/HttpClientAccept.php b/src/Network/HTTPClient/Client/HttpClientAccept.php index 76eb736fe2..11c317acb4 100644 --- a/src/Network/HTTPClient/Client/HttpClientAccept.php +++ b/src/Network/HTTPClient/Client/HttpClientAccept.php @@ -32,7 +32,7 @@ class HttpClientAccept public const ATOM_XML = 'application/atom+xml,text/xml;q=0.9,*/*;q=0.8'; public const FEED_XML = 'application/atom+xml,application/rss+xml;q=0.9,application/rdf+xml;q=0.8,text/xml;q=0.7,*/*;q=0.6'; public const HTML = 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'; - public const IMAGE = 'image/png,image/jpeg,image/gif,image/*;q=0.9,*/*;q=0.8'; + public const IMAGE = 'image/webp,image/png,image/jpeg,image/gif,image/*;q=0.9,*/*;q=0.8'; // @todo add image/avif once our minimal supported PHP version is 8.1.0 public const JRD_JSON = 'application/jrd+json,application/json;q=0.9'; public const JSON = 'application/json,*/*;q=0.9'; public const JSON_AS = 'application/activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams"'; diff --git a/src/Object/Image.php b/src/Object/Image.php index 76e7c7fe55..d938643751 100644 --- a/src/Object/Image.php +++ b/src/Object/Image.php @@ -95,7 +95,7 @@ class Image */ private function useImagick(string $data): bool { - if (!$this->isImagick()) { + if (!class_exists('Imagick')) { return false; } @@ -104,8 +104,30 @@ class Image return ($count > 0); } - // @todo add check for WebP - return ($this->imageType == IMAGETYPE_WEBP); + return (($this->imageType == IMAGETYPE_WEBP) && $this->isAnimatedWebP(substr($data, 0, 90))); + } + + /** + * Detect if a WebP image is animated. + * @see https://www.php.net/manual/en/function.imagecreatefromwebp.php#126269 + * @param string $data + * @return boolean + */ + private function isAnimatedWebP(string $data) { + $header_format = 'A4Riff/I1Filesize/A4Webp/A4Vp/A74Chunk'; + $header = unpack($header_format, $data); + + if (!isset($header['Riff']) || strtoupper($header['Riff']) !== 'RIFF') { + return false; + } + if (!isset($header['Webp']) || strtoupper($header['Webp']) !== 'WEBP') { + return false; + } + if (!isset($header['Vp']) || strpos(strtoupper($header['Vp']), 'VP8') === false) { + return false; + } + + return strpos(strtoupper($header['Chunk']), 'ANIM') !== false || strpos(strtoupper($header['Chunk']), 'ANMF') !== false; } /**