]> BookStack Code Mirror - bookstack/blobdiff - app/Uploads/ImageService.php
Added 'Sort Book' action to chapters
[bookstack] / app / Uploads / ImageService.php
index 7243feeb0ec0fa1c23cad6fced69015e90d6fc4d..ca0db997b47a77b727ceb7eb33c126b49a62a0a5 100644 (file)
@@ -3,9 +3,9 @@
 namespace BookStack\Uploads;
 
 use BookStack\Exceptions\ImageUploadException;
-use BookStack\Util\WebSafeMimeSniffer;
 use ErrorException;
 use Exception;
+use GuzzleHttp\Psr7\Utils;
 use Illuminate\Contracts\Cache\Repository as Cache;
 use Illuminate\Contracts\Filesystem\FileNotFoundException;
 use Illuminate\Contracts\Filesystem\Filesystem as Storage;
@@ -15,6 +15,7 @@ use Illuminate\Support\Facades\DB;
 use Illuminate\Support\Facades\Log;
 use Illuminate\Support\Str;
 use Intervention\Image\Exception\NotSupportedException;
+use Intervention\Image\Image as InterventionImage;
 use Intervention\Image\ImageManager;
 use League\Flysystem\Util;
 use Psr\SimpleCache\InvalidArgumentException;
@@ -240,6 +241,7 @@ class ImageService
         }
 
         $initialHeader = substr($imageData, 0, strpos($imageData, 'IDAT'));
+
         return strpos($initialHeader, 'acTL') !== false;
     }
 
@@ -274,6 +276,7 @@ class ImageService
         $storage = $this->getStorageDisk($image->type);
         if ($storage->exists($this->adjustPathForStorageDisk($thumbFilePath, $image->type))) {
             $this->cache->put($thumbCacheKey, $thumbFilePath, 60 * 60 * 72);
+
             return $this->getPublicUrl($thumbFilePath);
         }
 
@@ -282,6 +285,7 @@ class ImageService
         // Do not resize apng images where we're not cropping
         if ($keepRatio && $this->isApngData($image, $imageData)) {
             $this->cache->put($thumbCacheKey, $image->path, 60 * 60 * 72);
+
             return $this->getPublicUrl($image->path);
         }
 
@@ -306,6 +310,8 @@ class ImageService
             throw new ImageUploadException(trans('errors.cannot_create_thumbs'));
         }
 
+        $this->orientImageToOriginalExif($thumb, $imageData);
+
         if ($keepRatio) {
             $thumb->resize($width, $height, function ($constraint) {
                 $constraint->aspectRatio();
@@ -326,6 +332,49 @@ class ImageService
         return $thumbData;
     }
 
+    /**
+     * Orientate the given intervention image based upon the given original image data.
+     * Intervention does have an `orientate` method but the exif data it needs is lost before it
+     * can be used (At least when created using binary string data) so we need to do some
+     * implementation on our side to use the original image data.
+     * Bulk of logic taken from: https://github.com/Intervention/image/blob/b734a4988b2148e7d10364b0609978a88d277536/src/Intervention/Image/Commands/OrientateCommand.php
+     * Copyright (c) Oliver Vogel, MIT License.
+     */
+    protected function orientImageToOriginalExif(InterventionImage $image, string $originalData): void
+    {
+        if (!extension_loaded('exif')) {
+            return;
+        }
+
+        $stream = Utils::streamFor($originalData)->detach();
+        $exif = @exif_read_data($stream);
+        $orientation = $exif ? ($exif['Orientation'] ?? null) : null;
+
+        switch ($orientation) {
+            case 2:
+                $image->flip();
+                break;
+            case 3:
+                $image->rotate(180);
+                break;
+            case 4:
+                $image->rotate(180)->flip();
+                break;
+            case 5:
+                $image->rotate(270)->flip();
+                break;
+            case 6:
+                $image->rotate(270);
+                break;
+            case 7:
+                $image->rotate(90)->flip();
+                break;
+            case 8:
+                $image->rotate(90);
+                break;
+        }
+    }
+
     /**
      * Get the raw data content from an image.
      *