From c4b766f1332d0235e7b3a6f6c4b96f9c9d5dddd2 Mon Sep 17 00:00:00 2001 From: Zankaria Date: Fri, 28 Mar 2025 12:14:10 +0100 Subject: [PATCH] GdMediaHandler.php: properly handle AVIF, rotated image sizes --- inc/Service/Media/GdMediaHandler.php | 44 +++++++++++++++++++++------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/inc/Service/Media/GdMediaHandler.php b/inc/Service/Media/GdMediaHandler.php index 2cac97da..64c5785b 100644 --- a/inc/Service/Media/GdMediaHandler.php +++ b/inc/Service/Media/GdMediaHandler.php @@ -11,7 +11,8 @@ use Vichan\Functions\{Fs, Metadata}; class GdMediaHandler implements MediaHandler { use MediaHandlerTrait; - private const PHP81 = \PHP_MAJOR_VERSION >= 8 && \PHP_MINOR_VERSION >= 1; + // GD requires PHP 8.1 to support avif, getimagesize in sniff_image requires PHP 8.2 + private const PHP_AVIF_SUPPORT = \PHP_MAJOR_VERSION >= 8 && \PHP_MINOR_VERSION >= 2; private bool $strip_redraw; @@ -33,7 +34,7 @@ class GdMediaHandler implements MediaHandler { case 'image/bmp': return \imagecreatefrombmp($file); case 'image/avif': - return self::PHP81 ? \imagecreatefromavif($file) : false; + return self::PHP_AVIF_SUPPORT ? \imagecreatefromavif($file) : false; } return false; } @@ -53,7 +54,7 @@ class GdMediaHandler implements MediaHandler { case 'image/bmp': return \imagebmp($gd, $file, true); case 'image/avif': - return self::PHP81 ? \imageavif($gd, $file, 30, 6) : false; + return self::PHP_AVIF_SUPPORT ? \imageavif($gd, $file, 30, 6) : false; } return false; } @@ -151,29 +152,50 @@ class GdMediaHandler implements MediaHandler { || ($mime === 'image/gif' && $info['GIF Read Support'] && $info['GIF Create Support']) || ($mime === 'image/webp' && $info['WebP Support']) || $mime === 'image/bmp' - || ($mime === 'image/avif' && self::PHP81 && $info['AVIF Support']); + || ($mime === 'image/avif' && self::PHP_AVIF_SUPPORT && $info['AVIF Support']); } public function openHandle(string $file_path, string $file_mime, int $file_kind): mixed { + $exif_orientation = null; + $exif_orientation_read = false; + try { list($width, $height, $mime) = Metadata\sniff_image($file_path); - if ($width > $this->image_max_width || $height > $this->image_max_height) { - throw new MediaException("Image too big", MediaException::ERR_IMAGE_TOO_LARGE); - } - if ($mime !== $file_mime) { - throw new MediaException("Mime type mismatch, expected $file_mime, got $mime", MediaException::ERR_COMPUTE_ERR); - } } catch (\RuntimeException $e) { throw new MediaException("Could not sniff '$file_path'", MediaException::ERR_NO_OPEN, $e); } + if ($mime !== $file_mime) { + throw new MediaException("Mime type mismatch, expected $file_mime, got $mime", MediaException::ERR_COMPUTE_ERR); + } + if ($width > $this->image_max_width && $height > $this->image_max_height) { + // Too big in all directions. + throw new MediaException("Image too big", MediaException::ERR_IMAGE_TOO_LARGE); + } elseif ($width > $this->image_max_width || $height > $this->image_max_height) { + // Too big in just one direction. + // Suppose the image is rotated by the exif orientation, would it fit? + if ($width <= $this->image_max_height && $height <= $this->image_max_width) { + $exif_orientation_read = true; + $exif_orientation = $this->getOrientation($file_path, $file_mime); + + // If width and height aren't inverted, then it wouldn't fit. + if ($exif_orientation === null || !Exif::exifOrientationOnSide($exif_orientation)) { + throw new MediaException("Image too big", MediaException::ERR_IMAGE_TOO_LARGE); + } + } else { + throw new MediaException("Image too big", MediaException::ERR_IMAGE_TOO_LARGE); + } + } + $gd = self::imageCreateFrom($file_path, $file_mime); if ($gd === false) { throw new MediaException("Could not open '$file_path'", MediaException::ERR_NO_OPEN); } // Fix the orientation once and for all. - $exif_orientation = $this->getOrientation($file_path, $file_mime); + if (!$exif_orientation_read) { + $exif_orientation = $this->getOrientation($file_path, $file_mime); + } if ($exif_orientation !== null) { $degrees = Exif::exifOrientationDegrees($exif_orientation); $flipped = Exif::exifOrientationIsFlipped($exif_orientation);