Passed
Push — feat/responsive ( e58725 )
by Arnaud
05:00
created

Image::buildSrcset()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 19
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 12
c 0
b 0
f 0
nc 4
nop 2
dl 0
loc 19
rs 9.5555
1
<?php
2
/**
3
 * This file is part of the Cecil/Cecil package.
4
 *
5
 * Copyright (c) Arnaud Ligny <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace Cecil\Assets;
12
13
use Cecil\Assets\Image\Optimizers\Cwebp;
14
use Intervention\Image\ImageManagerStatic as ImageManager;
15
use Spatie\ImageOptimizer\OptimizerChain;
16
use Spatie\ImageOptimizer\Optimizers\Gifsicle;
17
use Spatie\ImageOptimizer\Optimizers\Jpegoptim;
18
use Spatie\ImageOptimizer\Optimizers\Optipng;
19
use Spatie\ImageOptimizer\Optimizers\Pngquant;
20
use Spatie\ImageOptimizer\Optimizers\Svgo;
21
22
class Image
23
{
24
    /**
25
     * Image Optimizer Chain.
26
     */
27
    public static function optimizer(int $quality): OptimizerChain
28
    {
29
        return (new OptimizerChain())
30
            ->addOptimizer(new Jpegoptim([
31
                "--max=$quality",
32
                '--strip-all',
33
                '--all-progressive',
34
            ]))
35
            ->addOptimizer(new Pngquant([
36
                "--quality=$quality",
37
                '--force',
38
                '--skip-if-larger',
39
            ]))
40
            ->addOptimizer(new Optipng([
41
                '-i0',
42
                '-o2',
43
                '-quiet',
44
            ]))
45
            ->addOptimizer(new Svgo([
46
                '--disable={cleanupIDs,removeViewBox}',
47
            ]))
48
            ->addOptimizer(new Gifsicle([
49
                '-b',
50
                '-O3',
51
            ]))
52
            ->addOptimizer(new Cwebp([
53
                '-m 6',
54
                '-pass 10',
55
                '-mt',
56
                '-q $quality',
57
            ]));
58
    }
59
60
    /**
61
     * Build the `srcset` attribute for responsive images.
62
     * ie: srcset="/img-480.jpg 480w, /img-800.jpg 800w".
63
     */
64
    public static function buildSrcset(Asset $asset, array $widths): string
65
    {
66
        $srcset = '';
67
        foreach ($widths as $width) {
68
            if ($width > $asset->getWidth() || $width > max($widths)) {
69
                break;
70
            }
71
            $a = clone $asset;
72
            $img = $a->resize($width);
73
            $srcset .= sprintf('%s %sw, ', $img, $width);
74
            unset($a);
75
        }
76
        rtrim($srcset, ', ');
77
        // add reference image
78
        if (!empty($srcset)) {
79
            $srcset .= sprintf('%s %sw', (string) $asset, $asset->getWidth());
80
        }
81
82
        return $srcset;
83
    }
84
85
    /**
86
     * Converts an asset image to WebP.
87
     */
88
    public static function convertTopWebp(Asset $asset, int $quality): Asset
89
    {
90
        $assetWebp = clone $asset;
91
        $format = 'webp';
92
        $image = ImageManager::make($assetWebp['content']);
93
        $assetWebp['content'] = (string) $image->encode($format, $quality);
94
        $assetWebp['path'] = preg_replace('/\.'.$asset['ext'].'$/m', ".$format", $asset['path']);
95
        $assetWebp['ext'] = $format;
96
97
        return $assetWebp;
98
    }
99
100
    /**
101
     * Tests if an asset is an animated gif.
102
     */
103
    public static function isAnimatedGif(Asset $asset): bool
104
    {
105
        // an animated gif contains multiple "frames", with each frame having a header made up of:
106
        // * a static 4-byte sequence (\x00\x21\xF9\x04)
107
        // * 4 variable bytes
108
        // * a static 2-byte sequence (\x00\x2C)
109
        $count = preg_match_all('#\x00\x21\xF9\x04.{4}\x00[\x2C\x21]#s', (string) $asset['content_source']);
110
111
        return $count > 1;
112
    }
113
}
114