ImageFactory::optimize()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 1
dl 0
loc 8
ccs 0
cts 2
cp 0
crap 6
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Pageon\Html\Image;
4
5
use Intervention\Image\Exception\NotReadableException;
6
use Intervention\Image\ImageManager;
7
use Intervention\Image\Image as ScaleableImage;
8
use Spatie\ImageOptimizer\OptimizerChain;
9
use Stitcher\File;
10
use Symfony\Component\Filesystem\Filesystem;
11
use Symfony\Component\Finder\Finder;
12
13
class ImageFactory
14
{
15
    /** @var \Pageon\Html\Image\Scaler */
16
    private $scaler;
17
18
    /** @var string */
19
    private $sourceDirectory;
20
21
    /** @var string */
22
    private $publicDirectory;
23
24
    /** @var \Intervention\Image\ImageManager */
25
    private $imageManager;
26
27
    /** @var \Spatie\ImageOptimizer\OptimizerChain */
28
    protected $optimizer;
29
30
    /** @var bool */
31
    private $cache = false;
32 4
33
    public function __construct(
34
        string $sourceDirectory,
35
        string $publicDirectory,
36
        Scaler $scaler,
37
        OptimizerChain $optimizer = null
38 4
    ) {
39 4
        $this->sourceDirectory = rtrim($sourceDirectory, '/');
40 4
        $this->publicDirectory = rtrim($publicDirectory, '/');
41
        $this->scaler = $scaler;
42 4
43 4
        $this->imageManager = new ImageManager([
44
            'driver' => 'gd',
45
        ]);
46 4
47 4
        $this->optimizer = $optimizer;
48
    }
49 4
50
    public static function make(
51
        string $sourceDirectory,
52
        string $publicDirectory,
53
        Scaler $scaler
54
    ): ImageFactory
55 4
    {
56
        return new self($sourceDirectory, $publicDirectory, $scaler);
57
    }
58
59
    public function enableCaching(bool $cache): ImageFactory
60
    {
61
        $this->cache = $cache;
62
63
        return $this;
64
    }
65 4
66
    public function create($src): Image
67 4
    {
68
        $srcPath = ltrim($src, '/');
69 4
70
        if ($this->cache && file_exists("{$this->publicDirectory}/{$srcPath}")) {
71
            return $this->createCachedImage($srcPath);
72
        }
73 4
74
        $image = Image::make($srcPath);
75 4
76
        $this->copySourceImageToDestination($srcPath);
77 4
78
        try {
79 4
            $scaleableImage = $this->imageManager->make("{$this->publicDirectory}/{$srcPath}");
80
81 4
            $this->optimize($scaleableImage->basePath());
82
83 4
            $variations = $this->scaler->getVariations($scaleableImage);
84
85 4
            $image->addSrcset($image->src(), $scaleableImage->getWidth());
86 4
87
            foreach ($variations as $width => $height) {
88
                if (!$width) {
89
                    continue;
90 4
                }
91
92
                $this->createScaledImage($image, $width, $height, $scaleableImage);
93 4
            }
94
        } catch (NotReadableException $exception) {
95
            // don't scale if not supported
96 4
        }
97
98
99
        return $image;
100
    }
101
102 4
    private function createScaledImage(
103
        Image $image,
104 4
        int $width,
105
        int $height,
106 4
        ScaleableImage $scaleableImage
107
    ): void {
108 4
        $scaleableImageClone = clone $scaleableImage;
109
110
        $scaledFileName = $this->createScaledFileName($image, $width, $height);
111
112
        $image->addSrcset($scaledFileName, $width);
113 4
114 4
        if ($this->cache && file_exists("{$this->publicDirectory}/{$scaledFileName}")) {
115
            return;
116 4
        }
117 4
118
        $scaleableImageClone
119 4
            ->resize($width, $height)
120
            ->save("{$this->publicDirectory}/{$scaledFileName}");
121 4
122
        $this->optimize("{$this->publicDirectory}/{$scaledFileName}");
123 4
    }
124
125 4
    private function createScaledFileName(Image $image, int $width, int $height): string
126
    {
127
        $srcPath = ltrim($image->src(), '/');
128 4
129
        $extension = pathinfo($srcPath, PATHINFO_EXTENSION);
130 4
131
        return str_replace(".{$extension}", "-{$width}x{$height}.{$extension}", $srcPath);
132 4
    }
133 4
134
    private function copySourceImageToDestination(string $srcPath): void
135
    {
136
        $fs = new Filesystem();
137
138
        $fs->copy(File::path($srcPath), "{$this->publicDirectory}/{$srcPath}");
139
    }
140
141
    private function createCachedImage(string $path): Image
142
    {
143
        $image = Image::make($path);
144
145
        $extension = pathinfo($path, PATHINFO_EXTENSION);
146
147
        $imageFilePath = pathinfo($image->src(), PATHINFO_DIRNAME);
148
149
        $imageFileName = pathinfo($image->src(), PATHINFO_FILENAME);
150
151
        $srcsetFiles = Finder::create()->files()
152
            ->in($this->publicDirectory . $imageFilePath)
153
            ->name("{$imageFileName}-*.{$extension}");
154
155
        foreach ($srcsetFiles->getIterator() as $srcsetFile) {
156
            $cachedFilename = $srcsetFile->getFilename();
157
158
            $size = (int) str_replace(".{$extension}", '', str_replace("{$imageFileName}-", '', $cachedFilename));
159
160 4
            $image->addSrcset("{$imageFilePath}/{$cachedFilename}", $size);
161
        }
162 4
163 4
        return $image;
164
    }
165
166
    private function optimize(string $path): void
167
    {
168
        if (! $this->optimizer) {
169
            return;
170
        }
171
172
        $this->optimizer->optimize($path);
173
    }
174
}
175