1 | <?php |
||||
2 | /** |
||||
3 | * Image Optimize plugin for Craft CMS |
||||
4 | * |
||||
5 | * Automatically optimize images after they've been transformed |
||||
6 | * |
||||
7 | * @link https://nystudio107.com |
||||
0 ignored issues
–
show
Coding Style
introduced
by
![]() |
|||||
8 | * @copyright Copyright (c) 2017 nystudio107 |
||||
0 ignored issues
–
show
|
|||||
9 | */ |
||||
0 ignored issues
–
show
|
|||||
10 | |||||
11 | namespace nystudio107\imageoptimize\models; |
||||
12 | |||||
13 | use Craft; |
||||
14 | use craft\base\Model; |
||||
15 | use craft\helpers\Template; |
||||
16 | use craft\validators\ArrayValidator; |
||||
17 | use nystudio107\imageoptimize\helpers\Color as ColorHelper; |
||||
18 | use nystudio107\imageoptimize\helpers\UrlHelper; |
||||
19 | use nystudio107\imageoptimize\ImageOptimize; |
||||
20 | use function strlen; |
||||
21 | |||||
22 | /** |
||||
0 ignored issues
–
show
|
|||||
23 | * @author nystudio107 |
||||
0 ignored issues
–
show
Content of the @author tag must be in the form "Display Name <[email protected]>"
![]() |
|||||
24 | * @package ImageOptimize |
||||
0 ignored issues
–
show
|
|||||
25 | * @since 1.2.0 |
||||
0 ignored issues
–
show
|
|||||
26 | */ |
||||
0 ignored issues
–
show
|
|||||
27 | class OptimizedImage extends Model |
||||
28 | { |
||||
29 | // Public Properties |
||||
30 | // ========================================================================= |
||||
31 | |||||
32 | /** |
||||
0 ignored issues
–
show
|
|||||
33 | * @var ?array An array of optimized image variant URLs |
||||
34 | */ |
||||
35 | public ?array $optimizedImageUrls = []; |
||||
36 | |||||
37 | /** |
||||
0 ignored issues
–
show
|
|||||
38 | * @var ?array An array of optimized .webp image variant URLs |
||||
39 | */ |
||||
40 | public ?array $optimizedWebPImageUrls = []; |
||||
41 | |||||
42 | /** |
||||
0 ignored issues
–
show
|
|||||
43 | * @var ?array An array of the widths of the optimized image variants |
||||
44 | */ |
||||
45 | public ?array $variantSourceWidths = []; |
||||
46 | |||||
47 | /** |
||||
0 ignored issues
–
show
|
|||||
48 | * @var ?array An array of the heights of the optimized image variants |
||||
49 | */ |
||||
50 | public ?array $variantHeights = []; |
||||
51 | |||||
52 | /** |
||||
0 ignored issues
–
show
|
|||||
53 | * @var array An array of the x,y image focal point coords, ranging from 0.0 to 1.0 |
||||
54 | */ |
||||
55 | public ?array $focalPoint = []; |
||||
56 | |||||
57 | /** |
||||
0 ignored issues
–
show
|
|||||
58 | * @var int The width of the original source image |
||||
59 | */ |
||||
60 | public ?int $originalImageWidth = 0; |
||||
61 | |||||
62 | /** |
||||
0 ignored issues
–
show
|
|||||
63 | * @var ?int The height of the original source image |
||||
64 | */ |
||||
65 | public ?int $originalImageHeight = 0; |
||||
66 | |||||
67 | /** |
||||
0 ignored issues
–
show
|
|||||
68 | * @var ?string The base64 encoded placeholder LQIP image |
||||
69 | */ |
||||
70 | public ?string $placeholder = ''; |
||||
71 | |||||
72 | /** |
||||
0 ignored issues
–
show
|
|||||
73 | * @var ?string The base64 encoded placeholder LQIP SVG image |
||||
74 | */ |
||||
75 | public ?string $placeholderSvg = ''; |
||||
76 | |||||
77 | /** |
||||
0 ignored issues
–
show
|
|||||
78 | * @var ?array An array the 5 most dominant colors in the image |
||||
79 | */ |
||||
80 | public ?array $colorPalette = []; |
||||
81 | |||||
82 | /** |
||||
0 ignored issues
–
show
|
|||||
83 | * @var ?int The overall lightness of the image, from 0..100 |
||||
84 | */ |
||||
85 | public ?int $lightness = 0; |
||||
86 | |||||
87 | /** |
||||
0 ignored issues
–
show
|
|||||
88 | * @var ?int The width of the placeholder image |
||||
89 | */ |
||||
90 | public ?int $placeholderWidth = 0; |
||||
91 | |||||
92 | /** |
||||
0 ignored issues
–
show
|
|||||
93 | * @var ?int The height of the placeholder image |
||||
94 | */ |
||||
95 | public ?int $placeholderHeight = 0; |
||||
96 | |||||
97 | /** |
||||
0 ignored issues
–
show
|
|||||
98 | * @var ?array An array of errors logged when generating the image transforms |
||||
99 | */ |
||||
100 | public ?array $stickyErrors = []; |
||||
101 | |||||
102 | // Public Methods |
||||
103 | // ========================================================================= |
||||
104 | |||||
105 | /** |
||||
0 ignored issues
–
show
|
|||||
106 | * @inheritdoc |
||||
107 | */ |
||||
0 ignored issues
–
show
|
|||||
108 | public function rules(): array |
||||
109 | { |
||||
110 | return [ |
||||
111 | ['optimizedImageUrls', ArrayValidator::class], |
||||
112 | ['optimizedWebPImageUrls', ArrayValidator::class], |
||||
113 | ['variantSourceWidths', ArrayValidator::class], |
||||
114 | ['variantHeights', ArrayValidator::class], |
||||
115 | ['focalPoint', 'safe'], |
||||
116 | ['originalImageWidth', 'integer'], |
||||
117 | ['originalImageHeight', 'integer'], |
||||
118 | ['placeholder', 'string'], |
||||
119 | ['placeholderSvg', 'string'], |
||||
120 | ['colorPalette', ArrayValidator::class], |
||||
121 | ['placeholderWidth', 'integer'], |
||||
122 | ['placeholderHeight', 'integer'], |
||||
123 | ['stickyErrors', ArrayValidator::class], |
||||
124 | ]; |
||||
125 | } |
||||
126 | |||||
127 | /** |
||||
128 | * Return the first image variant URL or the specific one passed in via |
||||
129 | * $width |
||||
130 | * |
||||
131 | * @param int $width |
||||
0 ignored issues
–
show
|
|||||
132 | * |
||||
133 | * @return string |
||||
134 | */ |
||||
135 | public function src(int $width = 0): string |
||||
136 | { |
||||
137 | if (empty($width)) { |
||||
138 | return Template::raw(reset($this->optimizedImageUrls)); |
||||
0 ignored issues
–
show
It seems like
$this->optimizedImageUrls can also be of type null ; however, parameter $array of reset() does only seem to accept array|object , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
139 | } |
||||
140 | |||||
141 | return Template::raw($this->optimizedImageUrls[$width] ?? ''); |
||||
142 | } |
||||
143 | |||||
144 | /** |
||||
145 | * Getter for CraftQL |
||||
146 | * |
||||
147 | * @param int $width |
||||
0 ignored issues
–
show
|
|||||
148 | * |
||||
149 | * @return string |
||||
150 | */ |
||||
151 | public function getSrc(int $width = 0): string |
||||
152 | { |
||||
153 | return $this->src($width); |
||||
154 | } |
||||
155 | |||||
156 | /** |
||||
157 | * Return a string of image URLs and their sizes |
||||
158 | * |
||||
159 | * @param bool $dpr Whether to generate 1x, 2x srcsets vs the normal XXXw |
||||
160 | * srcsets |
||||
161 | * |
||||
162 | * @return string |
||||
163 | */ |
||||
164 | public function srcset(bool $dpr = false): string |
||||
165 | { |
||||
166 | return Template::raw($this->getSrcsetFromArray($this->optimizedImageUrls, $dpr)); |
||||
0 ignored issues
–
show
It seems like
$this->optimizedImageUrls can also be of type null ; however, parameter $array of nystudio107\imageoptimiz...e::getSrcsetFromArray() does only seem to accept array , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
167 | } |
||||
168 | |||||
169 | /** |
||||
170 | * Getter for CraftQL |
||||
171 | * |
||||
172 | * @param bool $dpr |
||||
0 ignored issues
–
show
|
|||||
173 | * |
||||
174 | * @return string |
||||
175 | */ |
||||
176 | public function getSrcset(bool $dpr = false): string |
||||
177 | { |
||||
178 | return $this->srcset($dpr); |
||||
179 | } |
||||
180 | |||||
181 | /** |
||||
182 | * Return a string of image URLs and their sizes that match $width |
||||
183 | * |
||||
184 | * @param int $width |
||||
0 ignored issues
–
show
|
|||||
185 | * @param bool $dpr Whether to generate 1x, 2x srcsets vs the normal XXXw |
||||
0 ignored issues
–
show
|
|||||
186 | * srcsets |
||||
187 | * |
||||
188 | * @return string |
||||
189 | */ |
||||
190 | public function srcsetWidth(int $width, bool $dpr = false): string |
||||
191 | { |
||||
192 | $subset = $this->getSrcsetSubsetArray($this->optimizedImageUrls, $width, 'width'); |
||||
0 ignored issues
–
show
It seems like
$this->optimizedImageUrls can also be of type null ; however, parameter $set of nystudio107\imageoptimiz...:getSrcsetSubsetArray() does only seem to accept array , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
193 | |||||
194 | return Template::raw($this->getSrcsetFromArray($subset, $dpr)); |
||||
195 | } |
||||
196 | |||||
197 | /** |
||||
198 | * Return a string of image URLs and their sizes that are at least $width |
||||
199 | * or larger |
||||
200 | * |
||||
201 | * @param int $width |
||||
0 ignored issues
–
show
|
|||||
202 | * @param bool $dpr Whether to generate 1x, 2x srcsets vs the normal XXXw |
||||
0 ignored issues
–
show
|
|||||
203 | * srcsets |
||||
204 | * |
||||
205 | * @return string |
||||
206 | */ |
||||
207 | public function srcsetMinWidth(int $width, bool $dpr = false): string |
||||
208 | { |
||||
209 | $subset = $this->getSrcsetSubsetArray($this->optimizedImageUrls, $width, 'minwidth'); |
||||
0 ignored issues
–
show
It seems like
$this->optimizedImageUrls can also be of type null ; however, parameter $set of nystudio107\imageoptimiz...:getSrcsetSubsetArray() does only seem to accept array , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
210 | |||||
211 | return Template::raw($this->getSrcsetFromArray($subset, $dpr)); |
||||
212 | } |
||||
213 | |||||
214 | /** |
||||
215 | * Return a string of image URLs and their sizes that are $width or smaller |
||||
216 | * |
||||
217 | * @param int $width |
||||
0 ignored issues
–
show
|
|||||
218 | * @param bool $dpr Whether to generate 1x, 2x srcsets vs the normal XXXw |
||||
0 ignored issues
–
show
|
|||||
219 | * srcsets |
||||
220 | * |
||||
221 | * @return string |
||||
222 | */ |
||||
223 | public function srcsetMaxWidth(int $width, bool $dpr = false): string |
||||
224 | { |
||||
225 | $subset = $this->getSrcsetSubsetArray($this->optimizedImageUrls, $width, 'maxwidth'); |
||||
0 ignored issues
–
show
It seems like
$this->optimizedImageUrls can also be of type null ; however, parameter $set of nystudio107\imageoptimiz...:getSrcsetSubsetArray() does only seem to accept array , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
226 | |||||
227 | return Template::raw($this->getSrcsetFromArray($subset, $dpr)); |
||||
228 | } |
||||
229 | |||||
230 | /** |
||||
231 | * Return the first webp image variant URL or the specific one passed in |
||||
232 | * via $width |
||||
233 | * |
||||
234 | * @param int $width |
||||
0 ignored issues
–
show
|
|||||
235 | * |
||||
236 | * @return string |
||||
237 | */ |
||||
238 | public function srcWebp(int $width = 0): string |
||||
239 | { |
||||
240 | if (empty($width)) { |
||||
241 | return Template::raw(reset($this->optimizedWebPImageUrls)); |
||||
0 ignored issues
–
show
It seems like
$this->optimizedWebPImageUrls can also be of type null ; however, parameter $array of reset() does only seem to accept array|object , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
242 | } |
||||
243 | |||||
244 | return Template::raw($this->optimizedWebPImageUrls[$width] ?? ''); |
||||
245 | } |
||||
246 | |||||
247 | /** |
||||
248 | * Getter for CraftQL |
||||
249 | * |
||||
250 | * @param int $width |
||||
0 ignored issues
–
show
|
|||||
251 | * |
||||
252 | * @return string |
||||
253 | */ |
||||
254 | public function getSrcWebp(int $width = 0): string |
||||
255 | { |
||||
256 | return $this->srcWebp($width); |
||||
257 | } |
||||
258 | |||||
259 | /** |
||||
260 | * Return a string of webp image URLs and their sizes |
||||
261 | * |
||||
262 | * @param bool $dpr Whether to generate 1x, 2x srcsets vs the normal XXXw |
||||
263 | * srcsets |
||||
264 | * |
||||
265 | * @return string |
||||
266 | */ |
||||
267 | public function srcsetWebp(bool $dpr = false): string |
||||
268 | { |
||||
269 | return Template::raw($this->getSrcsetFromArray($this->optimizedWebPImageUrls, $dpr)); |
||||
0 ignored issues
–
show
It seems like
$this->optimizedWebPImageUrls can also be of type null ; however, parameter $array of nystudio107\imageoptimiz...e::getSrcsetFromArray() does only seem to accept array , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
270 | } |
||||
271 | |||||
272 | /** |
||||
273 | * Getter for CraftQL |
||||
274 | * |
||||
275 | * @param bool $dpr |
||||
0 ignored issues
–
show
|
|||||
276 | * |
||||
277 | * @return string |
||||
278 | */ |
||||
279 | public function getSrcsetWebp(bool $dpr = false): string |
||||
280 | { |
||||
281 | return $this->srcsetWebp($dpr); |
||||
282 | } |
||||
283 | |||||
284 | /** |
||||
285 | * Return a string of webp image URLs and their sizes that match $width |
||||
286 | * |
||||
287 | * @param int $width |
||||
0 ignored issues
–
show
|
|||||
288 | * @param bool $dpr Whether to generate 1x, 2x srcsets vs the normal XXXw |
||||
0 ignored issues
–
show
|
|||||
289 | * srcsets |
||||
290 | * |
||||
291 | * @return string |
||||
292 | */ |
||||
293 | public function srcsetWidthWebp(int $width, bool $dpr = false): string |
||||
294 | { |
||||
295 | $subset = $this->getSrcsetSubsetArray($this->optimizedWebPImageUrls, $width, 'width'); |
||||
0 ignored issues
–
show
It seems like
$this->optimizedWebPImageUrls can also be of type null ; however, parameter $set of nystudio107\imageoptimiz...:getSrcsetSubsetArray() does only seem to accept array , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
296 | |||||
297 | return Template::raw($this->getSrcsetFromArray($subset, $dpr)); |
||||
298 | } |
||||
299 | |||||
300 | /** |
||||
301 | * Return a string of webp image URLs and their sizes that are at least |
||||
302 | * $width or larger |
||||
303 | * |
||||
304 | * @param int $width |
||||
0 ignored issues
–
show
|
|||||
305 | * @param bool $dpr Whether to generate 1x, 2x srcsets vs the normal XXXw |
||||
0 ignored issues
–
show
|
|||||
306 | * srcsets |
||||
307 | * |
||||
308 | * @return string |
||||
309 | */ |
||||
310 | public function srcsetMinWidthWebp(int $width, bool $dpr = false): string |
||||
311 | { |
||||
312 | $subset = $this->getSrcsetSubsetArray($this->optimizedWebPImageUrls, $width, 'minwidth'); |
||||
0 ignored issues
–
show
It seems like
$this->optimizedWebPImageUrls can also be of type null ; however, parameter $set of nystudio107\imageoptimiz...:getSrcsetSubsetArray() does only seem to accept array , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
313 | |||||
314 | return Template::raw($this->getSrcsetFromArray($subset, $dpr)); |
||||
315 | } |
||||
316 | |||||
317 | /** |
||||
318 | * Return a string of webp image URLs and their sizes that are $width or |
||||
319 | * smaller |
||||
320 | * |
||||
321 | * @param int $width |
||||
0 ignored issues
–
show
|
|||||
322 | * @param bool $dpr Whether to generate 1x, 2x srcsets vs the normal XXXw |
||||
0 ignored issues
–
show
|
|||||
323 | * srcsets |
||||
324 | * |
||||
325 | * @return string |
||||
326 | */ |
||||
327 | public function srcsetMaxWidthWebp(int $width, bool $dpr = false): string |
||||
328 | { |
||||
329 | $subset = $this->getSrcsetSubsetArray($this->optimizedWebPImageUrls, $width, 'maxwidth'); |
||||
0 ignored issues
–
show
It seems like
$this->optimizedWebPImageUrls can also be of type null ; however, parameter $set of nystudio107\imageoptimiz...:getSrcsetSubsetArray() does only seem to accept array , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
330 | |||||
331 | return Template::raw($this->getSrcsetFromArray($subset, $dpr)); |
||||
332 | } |
||||
333 | |||||
334 | /** |
||||
335 | * Work around issues with `<img srcset>` returning sizes larger than are |
||||
336 | * available as per: |
||||
337 | * https://medium.com/@MRWwebDesign/responsive-images-the-sizes-attribute-and-unexpected-image-sizes-882a2eadb6db |
||||
338 | * |
||||
339 | * @return int |
||||
340 | */ |
||||
341 | public function maxSrcsetWidth(): int |
||||
342 | { |
||||
343 | $result = 0; |
||||
344 | if (!empty($this->optimizedImageUrls)) { |
||||
345 | $tempArray = $this->optimizedImageUrls; |
||||
346 | ksort($tempArray, SORT_NUMERIC); |
||||
347 | |||||
348 | $keys = array_keys($tempArray); |
||||
349 | $result = end($keys); |
||||
350 | } |
||||
351 | |||||
352 | return $result; |
||||
353 | } |
||||
354 | |||||
355 | /** |
||||
356 | * Getter for CraftQL |
||||
357 | * |
||||
358 | * @return int |
||||
359 | */ |
||||
360 | public function getMaxSrcsetWidth(): int |
||||
361 | { |
||||
362 | return $this->maxSrcsetWidth(); |
||||
363 | } |
||||
364 | |||||
365 | /** |
||||
366 | * Return the colors as an array of RGB colors |
||||
367 | */ |
||||
0 ignored issues
–
show
|
|||||
368 | public function colorPaletteRgb(): array |
||||
369 | { |
||||
370 | $colors = []; |
||||
371 | |||||
372 | foreach ($this->colorPalette as $color) { |
||||
373 | if (!empty($color)) { |
||||
374 | $colors[] = ColorHelper::HTMLToRGB($color); |
||||
375 | } |
||||
376 | } |
||||
377 | |||||
378 | return $colors; |
||||
379 | } |
||||
380 | |||||
381 | /** |
||||
382 | * Generate a complete <link rel="preload"> tag for this OptimizedImages model |
||||
383 | * ref: https://web.dev/preload-responsive-images/#imagesrcset-and-imagesizes |
||||
384 | * |
||||
385 | * @param array $config |
||||
0 ignored issues
–
show
|
|||||
386 | * @return LinkPreloadTag |
||||
0 ignored issues
–
show
|
|||||
387 | */ |
||||
388 | public function linkPreloadTag(array $config = []): LinkPreloadTag |
||||
389 | { |
||||
390 | return new LinkPreloadTag(array_merge($config, ['optimizedImage' => $this])); |
||||
391 | } |
||||
392 | |||||
393 | /** |
||||
394 | * Generate a complete <img> tag for this OptimizedImage model |
||||
395 | * |
||||
396 | * @param array $config |
||||
0 ignored issues
–
show
|
|||||
397 | * @return ImgTag |
||||
0 ignored issues
–
show
|
|||||
398 | */ |
||||
399 | public function imgTag(array $config = []): ImgTag |
||||
400 | { |
||||
401 | return new ImgTag(array_merge($config, ['optimizedImage' => $this])); |
||||
402 | } |
||||
403 | |||||
404 | /** |
||||
405 | * Generate a complete <picture> tag for this OptimizedImage model |
||||
406 | * |
||||
407 | * @param array $config |
||||
0 ignored issues
–
show
|
|||||
408 | * @return PictureTag |
||||
0 ignored issues
–
show
|
|||||
409 | */ |
||||
410 | public function pictureTag(array $config = []): PictureTag |
||||
411 | { |
||||
412 | return new PictureTag(array_merge($config, ['optimizedImage' => $this])); |
||||
413 | } |
||||
414 | |||||
415 | /** |
||||
416 | * Return a base64-encoded placeholder image |
||||
417 | * |
||||
418 | * @return string |
||||
419 | */ |
||||
420 | public function placeholderImage(): string |
||||
421 | { |
||||
422 | $header = 'data:image/jpeg;base64,'; |
||||
423 | if (!empty($this->placeholder)) { |
||||
424 | $content = $this->placeholder; |
||||
425 | } else { |
||||
426 | // At least return something |
||||
427 | return $this->defaultPlaceholderImage(); |
||||
428 | } |
||||
429 | |||||
430 | return Template::raw($header . rawurlencode($content)); |
||||
431 | } |
||||
432 | |||||
433 | /** |
||||
434 | * Getter for CraftQL |
||||
435 | * |
||||
436 | * @return string |
||||
437 | */ |
||||
438 | public function getPlaceholderImage(): string |
||||
439 | { |
||||
440 | return $this->placeholderImage(); |
||||
441 | } |
||||
442 | |||||
443 | /** |
||||
0 ignored issues
–
show
|
|||||
444 | * @return string |
||||
445 | */ |
||||
446 | public function placeholderImageSize(): string |
||||
447 | { |
||||
448 | $placeholder = $this->placeholderImage(); |
||||
449 | $contentLength = !empty(strlen($placeholder)) ? strlen($placeholder) : 0; |
||||
450 | |||||
451 | return ImageOptimize::$plugin->optimize->humanFileSize($contentLength, 1); |
||||
452 | } |
||||
453 | |||||
454 | /** |
||||
455 | * Return an SVG box as a placeholder image |
||||
456 | * |
||||
457 | * @param string|null $color |
||||
0 ignored issues
–
show
|
|||||
458 | * |
||||
459 | * @return string |
||||
460 | */ |
||||
461 | public function placeholderBox(?string $color = null): string |
||||
462 | { |
||||
463 | $width = $this->placeholderWidth ?? 1; |
||||
464 | $height = $this->placeholderHeight ?? 1; |
||||
465 | $color = $color ?? $this->colorPalette[0] ?? '#CCC'; |
||||
466 | |||||
467 | return Template::raw(ImageOptimize::$plugin->placeholder->generatePlaceholderBox($width, $height, $color)); |
||||
468 | } |
||||
469 | |||||
470 | /** |
||||
0 ignored issues
–
show
|
|||||
471 | * @param string|null $color |
||||
0 ignored issues
–
show
|
|||||
472 | * |
||||
473 | * @return string |
||||
474 | */ |
||||
475 | public function getPlaceholderBox(string $color = null): string |
||||
476 | { |
||||
477 | return $this->placeholderBox($color); |
||||
478 | } |
||||
479 | |||||
480 | /** |
||||
481 | * Getter for CraftQL |
||||
482 | * |
||||
483 | * @return string |
||||
484 | */ |
||||
485 | public function placeholderBoxSize(): string |
||||
486 | { |
||||
487 | $placeholder = $this->placeholderBox(); |
||||
488 | $contentLength = !empty(strlen($placeholder)) ? strlen($placeholder) : 0; |
||||
489 | |||||
490 | return ImageOptimize::$plugin->optimize->humanFileSize($contentLength, 1); |
||||
491 | } |
||||
492 | |||||
493 | /** |
||||
494 | * Return a silhouette of the image as an SVG placeholder |
||||
495 | * |
||||
496 | * @return string |
||||
497 | */ |
||||
498 | public function placeholderSilhouette(): string |
||||
499 | { |
||||
500 | $header = 'data:image/svg+xml,'; |
||||
501 | if (!empty($this->placeholderSvg)) { |
||||
502 | $content = $this->placeholderSvg; |
||||
503 | } else { |
||||
504 | // At least return something |
||||
505 | return $this->defaultPlaceholderImage(); |
||||
506 | } |
||||
507 | |||||
508 | return Template::raw($header . $content); |
||||
509 | } |
||||
510 | |||||
511 | /** |
||||
512 | * Getter for CraftQL |
||||
513 | * |
||||
514 | * @return string |
||||
515 | */ |
||||
516 | public function getPlaceholderSilhouette(): string |
||||
517 | { |
||||
518 | return $this->placeholderSilhouette(); |
||||
519 | } |
||||
520 | |||||
521 | /** |
||||
0 ignored issues
–
show
|
|||||
522 | * @return string |
||||
523 | */ |
||||
524 | public function placeholderSilhouetteSize(): string |
||||
525 | { |
||||
526 | $placeholder = $this->placeholderSilhouette(); |
||||
527 | $contentLength = !empty(strlen($placeholder)) ? strlen($placeholder) : 0; |
||||
528 | |||||
529 | return ImageOptimize::$plugin->optimize->humanFileSize($contentLength, 1); |
||||
530 | } |
||||
531 | |||||
532 | /** |
||||
533 | * Get the file size of any remote resource (using curl), |
||||
534 | * either in bytes or - default - as human-readable formatted string. |
||||
535 | * |
||||
536 | * @param string $url Takes the remote object's URL. |
||||
0 ignored issues
–
show
|
|||||
537 | * @param bool $formatSize Whether to return size in bytes or |
||||
0 ignored issues
–
show
|
|||||
538 | * formatted. |
||||
0 ignored issues
–
show
|
|||||
539 | * @param bool $useHead Whether to use HEAD requests. If false, |
||||
0 ignored issues
–
show
|
|||||
540 | * uses GET. |
||||
0 ignored issues
–
show
|
|||||
541 | * |
||||
542 | * @return mixed Returns human-readable formatted size |
||||
0 ignored issues
–
show
|
|||||
543 | * or size in bytes (default: formatted). |
||||
544 | * @noinspection PhpComposerExtensionStubsInspection*@author Stephan Schmitz <[email protected]> |
||||
545 | * @license MIT <http://eyecatchup.mit-license.org/> |
||||
0 ignored issues
–
show
|
|||||
546 | * @url <https://gist.github.com/eyecatchup/f26300ffd7e50a92bc4d> |
||||
0 ignored issues
–
show
|
|||||
547 | * |
||||
548 | * @noinspection PhpComposerExtensionStubsInspection |
||||
0 ignored issues
–
show
|
|||||
549 | */ |
||||
550 | public function getRemoteFileSize(string $url, bool $formatSize = true, bool $useHead = true): mixed |
||||
551 | { |
||||
552 | // Get an absolute URL with protocol that curl will be happy with |
||||
553 | $url = UrlHelper::absoluteUrlWithProtocol($url); |
||||
554 | $ch = curl_init($url); |
||||
555 | /** @noinspection CurlSslServerSpoofingInspection */ |
||||
0 ignored issues
–
show
|
|||||
556 | curl_setopt_array($ch, [ |
||||
0 ignored issues
–
show
|
|||||
557 | CURLOPT_RETURNTRANSFER => 1, |
||||
558 | CURLOPT_FOLLOWLOCATION => 1, |
||||
559 | CURLOPT_SSL_VERIFYPEER => 0, |
||||
560 | ]); |
||||
0 ignored issues
–
show
For multi-line function calls, the closing parenthesis should be on a new line.
If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line: someFunctionCall(
$firstArgument,
$secondArgument,
$thirdArgument
); // Closing parenthesis on a new line.
![]() |
|||||
561 | if ($useHead) { |
||||
562 | curl_setopt($ch, CURLOPT_NOBODY, 1); |
||||
563 | } |
||||
564 | curl_exec($ch); |
||||
565 | // content-length of download (in bytes), read from Content-Length: field |
||||
566 | $contentLength = curl_getinfo($ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD); |
||||
567 | $error = curl_error($ch); |
||||
568 | if (!empty($error)) { |
||||
569 | Craft::error($error, __METHOD__); |
||||
570 | } |
||||
571 | curl_close($ch); |
||||
572 | // cannot retrieve file size, return "-1" |
||||
573 | if (!$contentLength) { |
||||
574 | return -1; |
||||
575 | } |
||||
576 | // return size in bytes |
||||
577 | if (!$formatSize) { |
||||
578 | return $contentLength; |
||||
579 | } |
||||
580 | |||||
581 | return ImageOptimize::$plugin->optimize->humanFileSize($contentLength, 1); |
||||
582 | } |
||||
583 | |||||
584 | /** |
||||
0 ignored issues
–
show
|
|||||
585 | * @param array $array |
||||
0 ignored issues
–
show
|
|||||
586 | * @param bool $dpr |
||||
0 ignored issues
–
show
|
|||||
587 | * |
||||
588 | * @return string |
||||
589 | */ |
||||
590 | public function getSrcsetFromArray(array $array, bool $dpr = false): string |
||||
591 | { |
||||
592 | $srcset = ''; |
||||
593 | foreach ($array as $key => $value) { |
||||
594 | if ($dpr) { |
||||
595 | $descriptor = '1x'; |
||||
596 | if (!empty($array[(int)$key / 2])) { |
||||
597 | $descriptor = '2x'; |
||||
598 | } |
||||
599 | if (!empty($array[(int)$key / 3])) { |
||||
600 | $descriptor = '3x'; |
||||
601 | } |
||||
602 | } else { |
||||
603 | $descriptor = $key . 'w'; |
||||
604 | } |
||||
605 | $srcset .= $value . ' ' . $descriptor . ', '; |
||||
606 | } |
||||
607 | |||||
608 | return rtrim($srcset, ', '); |
||||
609 | } |
||||
610 | |||||
611 | // Protected Methods |
||||
612 | // ========================================================================= |
||||
613 | |||||
614 | protected function getSrcsetSubsetArray(array $set, int $width, string $comparison): array |
||||
0 ignored issues
–
show
|
|||||
615 | { |
||||
616 | $subset = []; |
||||
617 | $index = 0; |
||||
618 | if (empty($this->variantSourceWidths)) { |
||||
619 | return $subset; |
||||
620 | } |
||||
621 | // Sort the arrays by numeric key |
||||
622 | ksort($set, SORT_NUMERIC); |
||||
623 | // Sort the arrays by numeric key |
||||
624 | sort($this->variantSourceWidths, SORT_NUMERIC); |
||||
625 | foreach ($this->variantSourceWidths as $variantSourceWidth) { |
||||
626 | $match = false; |
||||
627 | switch ($comparison) { |
||||
628 | case 'width': |
||||
0 ignored issues
–
show
|
|||||
629 | if ($variantSourceWidth == $width) { |
||||
0 ignored issues
–
show
|
|||||
630 | $match = true; |
||||
631 | } |
||||
0 ignored issues
–
show
|
|||||
632 | break; |
||||
633 | |||||
634 | case 'minwidth': |
||||
0 ignored issues
–
show
|
|||||
635 | if ($variantSourceWidth >= $width) { |
||||
0 ignored issues
–
show
|
|||||
636 | $match = true; |
||||
637 | } |
||||
0 ignored issues
–
show
|
|||||
638 | break; |
||||
639 | |||||
640 | case 'maxwidth': |
||||
0 ignored issues
–
show
|
|||||
641 | if ($variantSourceWidth <= $width) { |
||||
0 ignored issues
–
show
|
|||||
642 | $match = true; |
||||
643 | } |
||||
0 ignored issues
–
show
|
|||||
644 | break; |
||||
645 | } |
||||
646 | if ($match) { |
||||
647 | $subset += array_slice($set, $index, 1, true); |
||||
648 | } |
||||
649 | $index++; |
||||
650 | } |
||||
651 | |||||
652 | return $subset; |
||||
653 | } |
||||
654 | |||||
655 | /** |
||||
656 | * Return a default placeholder image |
||||
657 | * |
||||
658 | * @return string |
||||
659 | */ |
||||
660 | protected function defaultPlaceholderImage(): string |
||||
661 | { |
||||
662 | $width = 1; |
||||
663 | $height = 1; |
||||
664 | $color = '#CCC'; |
||||
665 | |||||
666 | return Template::raw(ImageOptimize::$plugin->placeholder->generatePlaceholderBox($width, $height, $color)); |
||||
667 | } |
||||
668 | } |
||||
669 |