Skip to content

Commit 8b033c3

Browse files
authored
Merge pull request #26 from VanOns/feature/unsupported-image-types
Handle unsupported image types
2 parents b0c9d28 + 8300dc9 commit 8b033c3

File tree

12 files changed

+279
-92
lines changed

12 files changed

+279
-92
lines changed

composer.json

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,10 @@
22
"name": "van-ons/laravel-attachment-library",
33
"description": "A Laravel library for attaching files to Eloquent models.",
44
"keywords": [
5-
"van ons",
65
"laravel",
7-
"laravel-attachment-library",
86
"attachments",
9-
"library",
10-
"eloquent"
7+
"eloquent",
8+
"models"
119
],
1210
"homepage": "https://github.com/VanOns/laravel-attachment-library",
1311
"license": "MIT",

config/glide.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
'driver' => env('GLIDE_DRIVER', 'gd'),
66
'source' => storage_path('app/public'),
7+
78
/**
89
* The disk that will be used to store the resized images.
910
* Can be a name of an existing disk like public or a disk configuration.
@@ -15,11 +16,13 @@
1516
'url' => env('APP_URL') . '/img',
1617
'visibility' => 'public',
1718
],
19+
1820
/**
1921
* Here you can configure additional symbolic links that will
2022
* be created when the `storage:link` command is run.
2123
*/
22-
'links' => [ public_path('img') => storage_path('app/img') ],
24+
'links' => [public_path('img') => storage_path('app/img')],
25+
2326
'defaults' => [],
2427
'presets' => [],
2528
'max_image_size' => 2160 * 2160,

docs/basic-usage/responsive-images.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,14 @@ An example code snippet could be:
3333
->resize();
3434

3535
/**
36+
* Valid source:
3637
* [
3738
* 'width' => 500,
3839
* 'height' => 200,
3940
* 'url' => 'http://test.local/img/path-to-image.jpg?w=500&h=200&signature=....'
4041
* ]
42+
*
43+
* Invalid source:
44+
* []
4145
*/
4246
```

phpunit.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,6 @@
1313
<php>
1414
<env name="DB_CONNECTION" value="sqlite"/>
1515
<env name="DB_DATABASE" value=":memory:"/>
16+
<env name="CACHE_DRIVER" value="array"/>
1617
</php>
1718
</phpunit>

resources/views/components/image.blade.php

Lines changed: 62 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
use VanOns\LaravelAttachmentLibrary\Models\Attachment;
1212
1313
/**
14-
* @var string $path
14+
* @var string|int|Attachment|null $src
1515
* @var string $fit
1616
* @var string $size
1717
* @var array $breakpoints
@@ -29,51 +29,73 @@
2929

3030
<picture @class(['block overflow-hidden', $class]) {{ $attributes->except('class') }}>
3131
@if($src)
32-
@foreach($formats as $format)
33-
@foreach($keys->reverse() as $breakpoint)
34-
@php
35-
$index = $keys->search($breakpoint);
36-
$nextBreakpoint = $keys->get($index + 1) ?? $keys->get($index);
37-
$media = "(min-width: {$breakpoints[$breakpoint]}px)";
38-
$width = $breakpoints[$nextBreakpoint];
39-
$data = Resizer::src($src)->width($width)->size($size)->aspectRatio($aspectRatio)->format($format)->resize();
40-
@endphp
32+
@if($supportedByGlide)
33+
@foreach($formats as $format)
34+
@foreach($keys->reverse() as $breakpoint)
35+
@php
36+
$index = $keys->search($breakpoint);
37+
$nextBreakpoint = $keys->get($index + 1) ?? $keys->get($index);
38+
$media = "(min-width: {$breakpoints[$breakpoint]}px)";
39+
$width = $breakpoints[$nextBreakpoint];
40+
$data = Resizer::src($src)->width($width)->size($size)->aspectRatio($aspectRatio)->format($format)->resize();
41+
@endphp
4142

42-
<source
43-
srcset="{{ $data['url'] }}"
44-
media="{{ $media }}"
43+
@unless(empty($data))
44+
<source
45+
srcset="{{ $data['url'] }}"
46+
media="{{ $media }}"
47+
width="{{ $data['width'] }}"
48+
height="{{ $data['height'] }}"
49+
type="image/{{ $format }}"
50+
>
51+
@endunless
52+
@endforeach
53+
54+
@unless(empty($data = Resizer::src($src)->width($breakpoints[$keys->first()])->size($size)->aspectRatio($aspectRatio)->format($format)->resize()))
55+
<source
56+
srcset="{{ $data['url'] }}"
57+
width="{{ $data['width'] }}"
58+
height="{{ $data['height'] }}"
59+
type="image/{{ $format }}"
60+
>
61+
@endunless
62+
@endforeach
63+
64+
@unless(empty($data = Resizer::src($src)->width(end($breakpoints))->size($size)->aspectRatio($aspectRatio)->resize()))
65+
<img
66+
src="{{ $data['url'] }}"
4567
width="{{ $data['width'] }}"
4668
height="{{ $data['height'] }}"
47-
type="image/{{ $format }}"
48-
>
49-
@endforeach
69+
alt="{{ $alt }}"
5070

51-
@php($data = Resizer::src($src)->width($breakpoints[$keys->first()])->size($size)->aspectRatio($aspectRatio)->format($format)->resize())
52-
<source
53-
srcset="{{ $data['url'] }}"
54-
width="{{ $data['width'] }}"
55-
height="{{ $data['height'] }}"
56-
type="image/{{ $format }}"
57-
>
58-
@endforeach
71+
@if($lightbox)
72+
data-fancybox="{{ $lightboxGallery }}"
73+
@endif
5974

60-
@php($data = Resizer::src($src)->width(end($breakpoints))->size($size)->aspectRatio($aspectRatio)->resize())
61-
<img
62-
src="{{ $data['url'] }}"
63-
width="{{ $data['width'] }}"
64-
height="{{ $data['height'] }}"
65-
alt="{{ $alt }}"
75+
@class([
76+
'h-full w-full',
77+
'object-cover' => $fit === 'cover',
78+
'object-contain' => $fit === 'contain',
79+
$imageClass,
80+
])
81+
>
82+
@endunless
83+
@else
84+
<img
85+
src="{{ $attachment->url }}"
86+
alt="{{ $alt }}"
6687

67-
@if($lightbox)
68-
data-fancybox="{{ $lightboxGallery }}"
69-
@endif
88+
@if($lightbox)
89+
data-fancybox="{{ $lightboxGallery }}"
90+
@endif
7091

71-
@class([
72-
'h-full w-full',
73-
'object-cover' => $fit === 'cover',
74-
'object-contain' => $fit === 'contain',
75-
$imageClass,
76-
])
77-
>
92+
@class([
93+
'h-full w-full',
94+
'object-cover' => $fit === 'cover',
95+
'object-contain' => $fit === 'contain',
96+
$imageClass,
97+
])
98+
>
99+
@endif
78100
@endif
79101
</picture>

src/Glide/GlideManager.php

Lines changed: 87 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace VanOns\LaravelAttachmentLibrary\Glide;
44

5+
use Exception;
56
use Illuminate\Contracts\Filesystem\Filesystem;
67
use Illuminate\Support\Facades\Storage;
78
use League\Glide\Responses\SymfonyResponseFactory;
@@ -13,7 +14,7 @@ class GlideManager
1314
public function server(): Server
1415
{
1516
return ServerFactory::create([
16-
'driver' => config('glide.driver'),
17+
'driver' => $this->driver(),
1718
'source' => config('glide.source'),
1819
'cache' => $this->cacheDisk()->getDriver(),
1920
'defaults' => config('glide.defaults'),
@@ -26,6 +27,11 @@ public function server(): Server
2627
]);
2728
}
2829

30+
public function driver(): string
31+
{
32+
return config('glide.driver', 'gd');
33+
}
34+
2935
public function cacheDisk(): Filesystem
3036
{
3137
return is_string(config('glide.cache_disk'))
@@ -63,14 +69,91 @@ public function cacheSize(): int
6369

6470
public function cacheSizeHumanReadable(): string
6571
{
66-
6772
return $this->humanReadableSize($this->cacheSize());
6873
}
6974

7075
public function humanReadableSize(int $bytes, $decimals = 2): string
7176
{
7277
$size = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];
73-
$factor = floor((strlen(strval($bytes)) - 1) / 3);
74-
return sprintf("%.{$decimals}f", $bytes / pow(1024, $factor)) . ' ' . $size[$factor];
78+
$factor = floor((strlen((string) $bytes) - 1) / 3);
79+
return sprintf("%.{$decimals}f", $bytes / (1024 ** $factor)) . ' ' . $size[$factor];
80+
}
81+
82+
public function imageIsSupported(string $path, array $params = []): bool
83+
{
84+
try {
85+
$this->server()->makeImage($path, $params);
86+
return true;
87+
} catch (Exception) {
88+
return false;
89+
}
90+
}
91+
92+
/**
93+
* Retrieve supported image formats for the current driver.
94+
*
95+
* @param bool $onlyCommon Limit to results to the most common formats.
96+
*/
97+
public function getSupportedImageFormats(bool $onlyCommon = true): array
98+
{
99+
$commonFormats = [
100+
'AVIF',
101+
'BMP',
102+
'GIF',
103+
'HEIC',
104+
'HEIF',
105+
'ICO',
106+
'JPEG',
107+
'JPG',
108+
'PNG',
109+
'SVG',
110+
'TIFF',
111+
'WEBP',
112+
];
113+
114+
$driver = $this->driver();
115+
116+
if ($driver === 'gd' && function_exists('gd_info')) {
117+
$formats = gd_info();
118+
119+
$supported = collect();
120+
foreach ($formats as $key => $value) {
121+
if ($value === false) {
122+
continue;
123+
}
124+
125+
if ($onlyCommon) {
126+
foreach ($commonFormats as $format) {
127+
if (str_contains($key, $format)) {
128+
$supported->push($format);
129+
break;
130+
}
131+
}
132+
} else {
133+
$format = strtoupper(str_replace([' ', 'Support'], '', $key));
134+
$supported->push($format);
135+
}
136+
}
137+
138+
return $supported
139+
->unique()
140+
->values()
141+
->sort()
142+
->all();
143+
}
144+
145+
if ($driver === 'imagick' && class_exists(\Imagick::class)) {
146+
$formats = \Imagick::queryFormats();
147+
148+
return collect()
149+
->when($onlyCommon, fn ($collection) => $collection->merge($commonFormats)->filter(fn ($format) => in_array($format, $formats)))
150+
->when(!$onlyCommon, fn ($collection) => $collection->merge($formats))
151+
->unique()
152+
->values()
153+
->sort()
154+
->all();
155+
}
156+
157+
return [];
75158
}
76159
}

src/Glide/Resizer.php

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use Illuminate\Support\Facades\URL;
66
use VanOns\LaravelAttachmentLibrary\Enums\Fit;
77
use VanOns\LaravelAttachmentLibrary\Facades\AttachmentManager;
8+
use VanOns\LaravelAttachmentLibrary\Facades\Glide;
89
use VanOns\LaravelAttachmentLibrary\Models\Attachment;
910

1011
/**
@@ -87,7 +88,7 @@ public function calculateWidth(): ?float
8788
if ($this->height) {
8889
[$width, $height] = $this->getImageSize();
8990

90-
return ! empty($height)
91+
return !empty($height)
9192
? round($this->calculateHeight() / $height * $width)
9293
: 0;
9394
}
@@ -114,7 +115,7 @@ public function calculateHeight(): ?float
114115
if ($this->width) {
115116
[$width, $height] = $this->getImageSize();
116117

117-
return ! empty($width)
118+
return !empty($width)
118119
? round($this->calculateWidth() / $width * $height)
119120
: 0;
120121
}
@@ -159,7 +160,7 @@ public function getImageSize(): ?array
159160
/**
160161
* Set the aspect ratio for the image.
161162
*
162-
* @param string|float|null $aspectRatio Aspect ratio as a float or a string in the format 'width/height'.
163+
* @param string|float|null $aspectRatio Aspect ratio as a float or a string in the format 'width/height'.
163164
*/
164165
public function aspectRatio(string|float|null $aspectRatio): static
165166
{
@@ -206,14 +207,18 @@ protected function getPath(string|int|Attachment $src): ?string
206207

207208
public function cacheKey(): string
208209
{
209-
return sha1($this->path.$this->width.$this->height.$this->format.$this->size.$this->aspectRatio);
210+
return sha1($this->path . $this->width . $this->height . $this->format . $this->size . $this->aspectRatio);
210211
}
211212

212213
/**
213214
* Resize the image and return an array with the signed URL, width, and height of the image.
214215
*/
215216
public function resize(): array
216217
{
218+
if (!Glide::imageIsSupported($this->path)) {
219+
return [];
220+
}
221+
217222
$width = $this->calculateWidth();
218223
$height = $this->calculateHeight();
219224

src/Http/Controllers/GlideController.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@
55
use Illuminate\Http\Request;
66
use Illuminate\Routing\Controllers\HasMiddleware;
77
use Illuminate\Routing\Middleware\ValidateSignature;
8+
use Intervention\Image\Exception\NotReadableException;
89
use League\Glide\Filesystem\FileNotFoundException;
10+
use League\Glide\Filesystem\FilesystemException;
911
use League\Glide\Server;
1012
use Symfony\Component\HttpFoundation\Response;
13+
use VanOns\LaravelAttachmentLibrary\Facades\AttachmentManager;
1114
use VanOns\LaravelAttachmentLibrary\Glide\OptionsParser;
1215
use VanOns\LaravelAttachmentLibrary\Glide\Resizer;
1316

@@ -16,6 +19,7 @@ class GlideController implements HasMiddleware
1619
/**
1720
* Return image response with Glide parameters.
1821
*
22+
* @throws FilesystemException
1923
* @see Resizer for all available Glide parameters.
2024
*/
2125
public function __invoke(Request $request, string $options, string $path, OptionsParser $parser): Response
@@ -27,6 +31,14 @@ public function __invoke(Request $request, string $options, string $path, Option
2731
);
2832
} catch (FileNotFoundException) {
2933
abort(404);
34+
} catch (NotReadableException) {
35+
$attachment = AttachmentManager::file($path);
36+
if (!$attachment) {
37+
abort(404);
38+
}
39+
40+
// Return the original file if Glide cannot parse the image.
41+
return response()->file($attachment->absolute_path);
3042
}
3143
}
3244

0 commit comments

Comments
 (0)