ImageResizerService   A
last analyzed

Complexity

Total Complexity 28

Size/Duplication

Total Lines 253
Duplicated Lines 0 %

Importance

Changes 5
Bugs 0 Features 0
Metric Value
eloc 75
dl 0
loc 253
rs 10
c 5
b 0
f 0
wmc 28

11 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A cropImage() 0 29 4
A cropAndResize() 0 25 5
A resizeImage() 0 29 4
A setLogger() 0 5 1
A scaleThumbnail() 0 11 5
A setAdapter() 0 4 1
A getLogger() 0 3 1
A generateThumbFilepath() 0 18 1
A getAdapter() 0 3 1
A scaleAndCropThumbnail() 0 22 4
1
<?php
2
3
namespace Rvdlee\ZfImageResizer\Service;
4
5
use Exception;
6
use Rvdlee\ZfImageResizer\Exception\InvalidArgumentException;
7
use Rvdlee\ZfImageResizer\Interfaces\ImageResizerInterface;
8
use Rvdlee\ZfImageResizer\Model\Image;
9
use Zend\Log\LoggerInterface;
10
11
class ImageResizerService
12
{
13
    /**
14
     * @var ImageResizerInterface
15
     */
16
    protected $adapter;
17
18
    /**
19
     * @var LoggerInterface
20
     */
21
    protected $logger;
22
23
    /**
24
     * @param ImageResizerInterface $adapter
25
     *
26
     * @throws InvalidArgumentException
27
     */
28
    public function __construct(ImageResizerInterface $adapter, LoggerInterface $logger)
29
    {
30
        $this->setLogger($logger);
31
        $this->getLogger()->info('Constucting ImageResizerService');
32
        $this->setAdapter($adapter);
33
    }
34
35
    /**
36
     * @param string $imagePath
37
     * @param int    $newWidth
38
     * @param int    $newHeight
39
     * @param bool   $returnBase64
40
     * @return string
41
     * @throws InvalidArgumentException
42
     */
43
    public function resizeImage(string $imagePath, int $newWidth = 0, int $newHeight = 0, bool $returnBase64 = false): string
44
    {
45
        /** @var Image $image */
46
        $image = new Image($imagePath, $newWidth, $newHeight);
47
48
        /**
49
         * If the image already exists, return the path and notify via logger
50
         */
51
        if (file_exists($image->getTargetPath())) {
52
            $this->getLogger()->info('Image already exists, not resizing...');
53
            return $image->getTargetPath();
54
        }
55
56
        try {
57
            if ($this->getAdapter()->canHandle($imagePath)) {
58
                /** @var string $command */
59
                $command = $this->getAdapter()->resizeCommand($image, $returnBase64);
60
61
                $this->getLogger()->info(sprintf('Handling %s via %s', $imagePath, get_class($this->getAdapter())));
62
                $output = shell_exec(sprintf('%s 2>&1', $command));
63
                $this->getLogger()->info($output);
64
            }
65
        } catch (Exception $exception) {
66
            $this->getLogger()->err(
67
                sprintf('Exception when handling %s to via %s', $imagePath, get_class($this->getAdapter()))
68
            );
69
        }
70
71
        return $image->getTargetPath();
72
    }
73
74
    /**
75
     * @param string $imagePath
76
     * @param int    $cropWidth
77
     * @param int    $cropHeight
78
     * @param string $mode
79
     * @param int    $x
80
     * @param int    $y
81
     * @return string
82
     * @throws InvalidArgumentException
83
     */
84
    public function cropImage(string $imagePath, int $cropWidth, int $cropHeight, string $mode = Image::MANUAL_CROP, int $x = 0, int $y = 0): string
85
    {
86
        /** @var Image $image */
87
        $image = new Image($imagePath, $cropWidth, $cropHeight, $mode, $x, $y);
88
89
        /**
90
         * If the image already exists, return the path and notify via logger
91
         */
92
        if (file_exists($image->getTargetPath())) {
93
            $this->getLogger()->info('Image already exists, not resizing...');
94
            return $image->getTargetPath();
95
        }
96
97
        try {
98
            if ($this->getAdapter()->canHandle($imagePath)) {
99
                /** @var string $command */
100
                $command = $this->getAdapter()->cropCommand($image, $mode, $x, $y);
101
102
                $this->getLogger()->info(sprintf('Handling %s via %s', $imagePath, get_class($this->getAdapter())));
103
                $output = shell_exec(sprintf('%s 2>&1', $command));
104
                $this->getLogger()->info($output);
105
            }
106
        } catch (Exception $exception) {
107
            $this->getLogger()->err(
108
                sprintf('Exception when handling %s to via %s', $imagePath, get_class($this->getAdapter()))
109
            );
110
        }
111
112
        return $image->getTargetPath();
113
    }
114
115
    /**
116
     * @param string $imagePath
117
     * @param int    $cropWidth
118
     * @param int    $cropHeight
119
     * @param int    $finalWidth
120
     * @param int    $finalHeight
121
     * @param string $mode
122
     * @param int    $x
123
     * @param int    $y
124
     * @return string
125
     * @throws InvalidArgumentException
126
     */
127
    public function cropAndResize(string $imagePath, int $cropWidth, int $cropHeight, int $finalWidth, int $finalHeight, string $mode = Image::MANUAL_CROP, int $x = 0, int $y = 0): string
128
    {
129
        // If final width has not been set, set it to the cropWidth as a fallback
130
        if ($finalWidth === 0) {
131
            $finalWidth = $cropWidth;
132
        }
133
        // If final width has not been set, set it to the cropHeight as a fallback
134
        if ($finalWidth === 0) {
135
            $finalWidth = $cropWidth;
136
        }
137
138
        // First crop the image at the highest possible resolution for best effect
139
        $resized = $resizedCropped = $this->cropImage($imagePath, $cropWidth, $cropHeight, $mode, $x, $y);
140
141
        // Resize if the final height or width differs from the cropped width and height
142
        if ($cropWidth !== $finalWidth || $cropHeight !== $finalHeight) {
143
            // Resize that image to the desired final width and height
144
            $resizedCropped = $this->resizeImage($resized, $finalWidth, $finalHeight);
145
146
            // Delete the resized image, we dont need it anymore
147
            unlink($resized);
148
        }
149
150
        // Return the cropped and resized image
151
        return $resizedCropped;
152
    }
153
154
    /**
155
     * @param string $filepath
156
     * @param int $width
157
     * @param int $height
158
     * @return string
159
     * @throws \Gumlet\ImageResizeException
160
     */
161
    public function scaleAndCropThumbnail(string $filepath, int $width, int $height): string
162
    {
163
        [$orginalWidth, $originalHeight] = getimagesize($filepath);
164
        $ratio = ($orginalWidth > $originalHeight ? $orginalWidth : $originalHeight) / ($orginalWidth < $originalHeight ? $orginalWidth : $originalHeight);
165
166
        if ($orginalWidth > $originalHeight) {
167
            $targetWidth = round($height * $ratio);
168
            $scaledImage = $this->scaleThumbnail($filepath, (int) $targetWidth, $height);
169
        } else {
170
            $targetHeight = round($width * $ratio);
171
            $scaledImage = $this->scaleThumbnail($filepath, $width, (int) $targetHeight);
172
        }
173
174
        $thumbpath = $this->generateThumbFilepath($filepath);
0 ignored issues
show
Unused Code introduced by
The assignment to $thumbpath is dead and can be removed.
Loading history...
175
176
        // Crop the scaled image for best result
177
        $croppedImage = $this->cropImage($scaledImage, $width, $height, Image::CENTERED_CROP);
178
179
        // Delete the scaled image, this only served for improved thumb quality
180
        unlink($scaledImage);
181
182
        return $croppedImage;
183
    }
184
185
    /**
186
     * Scale by ratio, width or height is optional but one needs to be provided, it will calculate the
187
     * ratio by either one of these.
188
     *
189
     * @param string $filepath
190
     * @param int $targetWidth
191
     * @param int $targetHeight
192
     * @return string
193
     * @throws \Gumlet\ImageResizeException
194
     */
195
    public function scaleThumbnail(string $filepath, int $targetWidth = 0, int $targetHeight = 0)
196
    {
197
        if (!file_exists($filepath) && is_file($filepath)) {
198
            throw new InvalidArgumentException('File does not exist!');
199
        }
200
201
        if ($targetHeight >! 0 || $targetWidth >! 0) {
202
            throw new InvalidArgumentException('targetWidth or targetHeight needs to be defined.');
203
        }
204
205
        return $this->resizeImage($filepath, $targetWidth, $targetHeight);
206
    }
207
208
    public function generateThumbFilepath(string $filepath): string
209
    {
210
        // Extract the basename out of the path
211
        $filename = basename($filepath);
212
        // Get the filepath
213
        $explodedFilepath = explode(DIRECTORY_SEPARATOR, $filepath);
214
        // Reconstruct the base file path
215
        $baseFilepath = implode(DIRECTORY_SEPARATOR, array_slice($explodedFilepath, 0, count($explodedFilepath)-1));
216
        // Explode the filename
217
        $explodedFilename = explode('.', $filename);
218
        // Generate new name
219
        $thumbname = sprintf(
220
            '%s.%s',
221
            bin2hex(random_bytes(64)),
222
            end($explodedFilename)
223
        );
224
225
        return $baseFilepath . DIRECTORY_SEPARATOR . $thumbname;
226
    }
227
228
    /**
229
     * @return ImageResizerInterface
230
     */
231
    public function getAdapter(): ImageResizerInterface
232
    {
233
        return $this->adapter;
234
    }
235
236
    /**
237
     * @param ImageResizerInterface $adapter
238
     * @return ImageResizerService
239
     */
240
    public function setAdapter(ImageResizerInterface $adapter): ImageResizerService
241
    {
242
        $this->adapter = $adapter;
243
        return $this;
244
    }
245
246
    /**
247
     * @return LoggerInterface
248
     */
249
    public function getLogger(): LoggerInterface
250
    {
251
        return $this->logger;
252
    }
253
254
    /**
255
     * @param LoggerInterface $logger
256
     *
257
     * @return ImageResizerService
258
     */
259
    public function setLogger(LoggerInterface $logger): ImageResizerService
260
    {
261
        $this->logger = $logger;
262
263
        return $this;
264
    }
265
}