mirror of
https://github.com/BookStackApp/BookStack.git
synced 2024-10-01 01:36:00 -04:00
96 lines
3.0 KiB
PHP
96 lines
3.0 KiB
PHP
|
<?php
|
||
|
|
||
|
namespace BookStack\Uploads;
|
||
|
|
||
|
use BookStack\Exceptions\ImageUploadException;
|
||
|
use GuzzleHttp\Psr7\Utils;
|
||
|
use Intervention\Image\Exception\NotSupportedException;
|
||
|
use Intervention\Image\Image as InterventionImage;
|
||
|
use Intervention\Image\ImageManager;
|
||
|
|
||
|
class ImageResizer
|
||
|
{
|
||
|
public function __construct(
|
||
|
protected ImageManager $intervention
|
||
|
) {
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Resize the image of given data to the specified size, and return the new image data.
|
||
|
*
|
||
|
* @throws ImageUploadException
|
||
|
*/
|
||
|
protected function resizeImageData(string $imageData, ?int $width, ?int $height, bool $keepRatio): string
|
||
|
{
|
||
|
try {
|
||
|
$thumb = $this->intervention->make($imageData);
|
||
|
} catch (NotSupportedException $e) {
|
||
|
throw new ImageUploadException(trans('errors.cannot_create_thumbs'));
|
||
|
}
|
||
|
|
||
|
$this->orientImageToOriginalExif($thumb, $imageData);
|
||
|
|
||
|
if ($keepRatio) {
|
||
|
$thumb->resize($width, $height, function ($constraint) {
|
||
|
$constraint->aspectRatio();
|
||
|
$constraint->upsize();
|
||
|
});
|
||
|
} else {
|
||
|
$thumb->fit($width, $height);
|
||
|
}
|
||
|
|
||
|
$thumbData = (string) $thumb->encode();
|
||
|
|
||
|
// Use original image data if we're keeping the ratio
|
||
|
// and the resizing does not save any space.
|
||
|
if ($keepRatio && strlen($thumbData) > strlen($imageData)) {
|
||
|
return $imageData;
|
||
|
}
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
}
|
||
|
}
|