]> BookStack Code Mirror - bookstack/blobdiff - app/Uploads/ImageResizer.php
Thumbnails: Fixed thumnail orientation
[bookstack] / app / Uploads / ImageResizer.php
index d09177fff5c71966bbaab354ae5dce1e7505fe99..5f095658f3fc49412245c4fa826d35cb8a86865b 100644 (file)
@@ -7,11 +7,13 @@ use Exception;
 use GuzzleHttp\Psr7\Utils;
 use Illuminate\Support\Facades\Cache;
 use Intervention\Image\Decoders\BinaryImageDecoder;
+use Intervention\Image\Drivers\Gd\Decoders\NativeObjectDecoder;
 use Intervention\Image\Drivers\Gd\Driver;
 use Intervention\Image\Encoders\AutoEncoder;
 use Intervention\Image\Encoders\PngEncoder;
 use Intervention\Image\Interfaces\ImageInterface as InterventionImage;
 use Intervention\Image\ImageManager;
+use Intervention\Image\Origin;
 
 class ImageResizer
 {
@@ -99,7 +101,7 @@ class ImageResizer
         }
 
         // If not in cache and thumbnail does not exist, generate thumb and cache path
-        $thumbData = $this->resizeImageData($imageData, $width, $height, $keepRatio);
+        $thumbData = $this->resizeImageData($imageData, $width, $height, $keepRatio, $this->getExtension($image));
         $disk->put($thumbFilePath, $thumbData, true);
         Cache::put($thumbCacheKey, $thumbFilePath, static::THUMBNAIL_CACHE_TIME);
 
@@ -120,7 +122,7 @@ class ImageResizer
         ?string $format = null,
     ): string {
         try {
-            $thumb = $this->interventionFromImageData($imageData);
+            $thumb = $this->interventionFromImageData($imageData, $format);
         } catch (Exception $e) {
             throw new ImageUploadException(trans('errors.cannot_create_thumbs'));
         }
@@ -154,11 +156,26 @@ class ImageResizer
      * Performs some manual library usage to ensure image is specifically loaded
      * from given binary data instead of data being misinterpreted.
      */
-    protected function interventionFromImageData(string $imageData): InterventionImage
+    protected function interventionFromImageData(string $imageData, ?string $fileType): InterventionImage
     {
-        $manager = new ImageManager(new Driver());
+        $manager = new ImageManager(
+            new Driver(),
+            autoOrientation: false,
+        );
 
-        return $manager->read($imageData, BinaryImageDecoder::class);
+        // Ensure gif images are decoded natively instead of deferring to intervention GIF
+        // handling since we don't need the added animation support.
+        $isGif = $fileType === 'gif';
+        $decoder = $isGif ? NativeObjectDecoder::class : BinaryImageDecoder::class;
+        $input = $isGif ? @imagecreatefromstring($imageData) : $imageData;
+
+        $image = $manager->read($input, $decoder);
+
+        if ($isGif) {
+            $image->setOrigin(new Origin('image/gif'));
+        }
+
+        return $image;
     }
 
     /**
@@ -209,7 +226,15 @@ class ImageResizer
      */
     protected function isGif(Image $image): bool
     {
-        return strtolower(pathinfo($image->path, PATHINFO_EXTENSION)) === 'gif';
+        return $this->getExtension($image) === 'gif';
+    }
+
+    /**
+     * Get the extension for the given image, normalised to lower-case.
+     */
+    protected function getExtension(Image $image): string
+    {
+        return strtolower(pathinfo($image->path, PATHINFO_EXTENSION));
     }
 
     /**