X-Git-Url: http://source.bookstackapp.com/bookstack/blobdiff_plain/31f1dca8a81e70aa8b5598fdaf4af772a28ac9c9..refs/pull/3598/head:/app/Uploads/ImageService.php diff --git a/app/Uploads/ImageService.php b/app/Uploads/ImageService.php index 7243feeb0..ca0db997b 100644 --- a/app/Uploads/ImageService.php +++ b/app/Uploads/ImageService.php @@ -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. *