mirror of
https://github.com/BookStackApp/BookStack.git
synced 2024-11-23 11:22:33 +01:00
Images: Reverted some thumbnails to be on-demand generated
Added since we can't always be sure of future image usage, and in many cases we don't generate ahead-of-time. Also: - Simplified image handling on certain models. - Updated various string handling operations to use newer functions.
This commit is contained in:
parent
5af3041b9b
commit
5c318a45b8
@ -40,26 +40,19 @@ class Book extends Entity implements HasCoverImage
|
||||
|
||||
/**
|
||||
* Returns book cover image, if book cover not exists return default cover image.
|
||||
*
|
||||
* @param int $width - Width of the image
|
||||
* @param int $height - Height of the image
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getBookCover($width = 440, $height = 250)
|
||||
public function getBookCover(int $width = 440, int $height = 250): string
|
||||
{
|
||||
$default = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==';
|
||||
if (!$this->image_id) {
|
||||
if (!$this->image_id || !$this->cover) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
try {
|
||||
$cover = $this->cover ? url($this->cover->getThumb($width, $height, false)) : $default;
|
||||
return $this->cover->getThumb($width, $height, false) ?? $default;
|
||||
} catch (Exception $err) {
|
||||
$cover = $default;
|
||||
return $default;
|
||||
}
|
||||
|
||||
return $cover;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3,6 +3,7 @@
|
||||
namespace BookStack\Entities\Models;
|
||||
|
||||
use BookStack\Uploads\Image;
|
||||
use Exception;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
@ -49,28 +50,21 @@ class Bookshelf extends Entity implements HasCoverImage
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns BookShelf cover image, if cover does not exists return default cover image.
|
||||
*
|
||||
* @param int $width - Width of the image
|
||||
* @param int $height - Height of the image
|
||||
*
|
||||
* @return string
|
||||
* Returns shelf cover image, if cover not exists return default cover image.
|
||||
*/
|
||||
public function getBookCover($width = 440, $height = 250)
|
||||
public function getBookCover(int $width = 440, int $height = 250): string
|
||||
{
|
||||
// TODO - Make generic, focused on books right now, Perhaps set-up a better image
|
||||
$default = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==';
|
||||
if (!$this->image_id) {
|
||||
if (!$this->image_id || !$this->cover) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
try {
|
||||
$cover = $this->cover ? url($this->cover->getThumb($width, $height, false)) : $default;
|
||||
} catch (\Exception $err) {
|
||||
$cover = $default;
|
||||
return $this->cover->getThumb($width, $height, false) ?? $default;
|
||||
} catch (Exception $err) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
return $cover;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -45,13 +45,14 @@ class Image extends Model
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an (already existing) thumbnail for this image.
|
||||
* Get a thumbnail URL for this image.
|
||||
* Attempts to generate the thumbnail if not already existing.
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function getThumb(?int $width, ?int $height, bool $keepRatio = false): ?string
|
||||
{
|
||||
return app()->make(ImageService::class)->getThumbnail($this, $width, $height, $keepRatio);
|
||||
return app()->make(ImageService::class)->getThumbnail($this, $width, $height, $keepRatio, false, true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -21,23 +21,18 @@ use Intervention\Image\Exception\NotSupportedException;
|
||||
use Intervention\Image\Image as InterventionImage;
|
||||
use Intervention\Image\ImageManager;
|
||||
use League\Flysystem\WhitespacePathNormalizer;
|
||||
use Psr\SimpleCache\InvalidArgumentException;
|
||||
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
||||
use Symfony\Component\HttpFoundation\StreamedResponse;
|
||||
|
||||
class ImageService
|
||||
{
|
||||
protected ImageManager $imageTool;
|
||||
protected Cache $cache;
|
||||
protected FilesystemManager $fileSystem;
|
||||
|
||||
protected static array $supportedExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
|
||||
|
||||
public function __construct(ImageManager $imageTool, FilesystemManager $fileSystem, Cache $cache)
|
||||
{
|
||||
$this->imageTool = $imageTool;
|
||||
$this->fileSystem = $fileSystem;
|
||||
$this->cache = $cache;
|
||||
public function __construct(
|
||||
protected ImageManager $imageTool,
|
||||
protected FilesystemManager $fileSystem,
|
||||
protected Cache $cache
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
@ -206,7 +201,7 @@ class ImageService
|
||||
* Save image data for the given path in the public space, if possible,
|
||||
* for the provided storage mechanism.
|
||||
*/
|
||||
protected function saveImageDataInPublicSpace(Storage $storage, string $path, string $data)
|
||||
protected function saveImageDataInPublicSpace(Storage $storage, string $path, string $data): void
|
||||
{
|
||||
$storage->put($path, $data);
|
||||
|
||||
@ -269,8 +264,14 @@ class ImageService
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getThumbnail(Image $image, ?int $width, ?int $height, bool $keepRatio = false, bool $shouldCreate = false): ?string
|
||||
{
|
||||
public function getThumbnail(
|
||||
Image $image,
|
||||
?int $width,
|
||||
?int $height,
|
||||
bool $keepRatio = false,
|
||||
bool $shouldCreate = false,
|
||||
bool $canCreate = false,
|
||||
): ?string {
|
||||
// Do not resize GIF images where we're not cropping
|
||||
if ($keepRatio && $this->isGif($image)) {
|
||||
return $this->getPublicUrl($image->path);
|
||||
@ -305,7 +306,7 @@ class ImageService
|
||||
return $this->getPublicUrl($image->path);
|
||||
}
|
||||
|
||||
if (!$shouldCreate) {
|
||||
if (!$shouldCreate && !$canCreate) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -559,7 +560,7 @@ class ImageService
|
||||
// Check the image file exists
|
||||
&& $disk->exists($imagePath)
|
||||
// Check the file is likely an image file
|
||||
&& strpos($disk->mimeType($imagePath), 'image/') === 0;
|
||||
&& str_starts_with($disk->mimeType($imagePath), 'image/');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -568,14 +569,14 @@ class ImageService
|
||||
*/
|
||||
protected function checkUserHasAccessToRelationOfImageAtPath(string $path): bool
|
||||
{
|
||||
if (strpos($path, '/uploads/images/') === 0) {
|
||||
if (str_starts_with($path, '/uploads/images/')) {
|
||||
$path = substr($path, 15);
|
||||
}
|
||||
|
||||
// Strip thumbnail element from path if existing
|
||||
$originalPathSplit = array_filter(explode('/', $path), function (string $part) {
|
||||
$resizedDir = (strpos($part, 'thumbs-') === 0 || strpos($part, 'scaled-') === 0);
|
||||
$missingExtension = strpos($part, '.') === false;
|
||||
$resizedDir = (str_starts_with($part, 'thumbs-') || str_starts_with($part, 'scaled-'));
|
||||
$missingExtension = !str_contains($part, '.');
|
||||
|
||||
return !($resizedDir && $missingExtension);
|
||||
});
|
||||
@ -641,9 +642,9 @@ class ImageService
|
||||
$url = ltrim(trim($url), '/');
|
||||
|
||||
// Handle potential relative paths
|
||||
$isRelative = strpos($url, 'http') !== 0;
|
||||
$isRelative = !str_starts_with($url, 'http');
|
||||
if ($isRelative) {
|
||||
if (strpos(strtolower($url), 'uploads/images') === 0) {
|
||||
if (str_starts_with(strtolower($url), 'uploads/images')) {
|
||||
return trim($url, '/');
|
||||
}
|
||||
|
||||
@ -658,7 +659,7 @@ class ImageService
|
||||
|
||||
foreach ($potentialHostPaths as $potentialBasePath) {
|
||||
$potentialBasePath = strtolower($potentialBasePath);
|
||||
if (strpos(strtolower($url), $potentialBasePath) === 0) {
|
||||
if (str_starts_with(strtolower($url), $potentialBasePath)) {
|
||||
return 'uploads/images/' . trim(substr($url, strlen($potentialBasePath)), '/');
|
||||
}
|
||||
}
|
||||
@ -679,7 +680,7 @@ class ImageService
|
||||
// region-based url will be used to prevent http issues.
|
||||
if (!$storageUrl && config('filesystems.images') === 's3') {
|
||||
$storageDetails = config('filesystems.disks.s3');
|
||||
if (strpos($storageDetails['bucket'], '.') === false) {
|
||||
if (!str_contains($storageDetails['bucket'], '.')) {
|
||||
$storageUrl = 'https://' . $storageDetails['bucket'] . '.s3.amazonaws.com';
|
||||
} else {
|
||||
$storageUrl = 'https://s3-' . $storageDetails['region'] . '.amazonaws.com/' . $storageDetails['bucket'];
|
||||
|
@ -244,7 +244,7 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
|
||||
}
|
||||
|
||||
try {
|
||||
$avatar = $this->avatar ? url($this->avatar->getThumb($size, $size, false)) : $default;
|
||||
$avatar = $this->avatar?->getThumb($size, $size, false) ?? $default;
|
||||
} catch (Exception $err) {
|
||||
$avatar = $default;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user