Completed
Push — master ( 2bb66e...c45cef )
by Jonathan
04:16
created

Size::resolveCropOffset()   B

Complexity

Conditions 5
Paths 16

Duplication

Lines 0
Ratio 0 %

Size

Total Lines 28
Code Lines 15

Code Coverage

Tests 11
CRAP Score 6.8668

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 28
ccs 11
cts 19
cp 0.5789
rs 8.439
cc 5
eloc 15
nc 16
nop 3
crap 6.8668
1
<?php
2
3
namespace League\Glide\Manipulators;
4
5
use Intervention\Image\Image;
6
7
/**
8
 * @property string $dpr
9
 * @property string $fit
10
 * @property string $h
11
 * @property string $w
12
 */
13
class Size extends BaseManipulator
14
{
15
    /**
16
     * Maximum image size in pixels.
17
     * @var integer|null
18
     */
19
    protected $maxImageSize;
20
21
    /**
22
     * Create Size instance.
23
     * @param integer|null $maxImageSize Maximum image size in pixels.
24
     */
25 66
    public function __construct($maxImageSize = null)
26
    {
27 66
        $this->maxImageSize = $maxImageSize;
28 66
    }
29
30
    /**
31
     * Set the maximum image size.
32
     * @param integer|null Maximum image size in pixels.
33
     */
34 6
    public function setMaxImageSize($maxImageSize)
35
    {
36 6
        $this->maxImageSize = $maxImageSize;
37 6
    }
38
39
    /**
40
     * Get the maximum image size.
41
     * @return integer|null Maximum image size in pixels.
42
     */
43 6
    public function getMaxImageSize()
44
    {
45 6
        return $this->maxImageSize;
46
    }
47
48
    /**
49
     * Perform size image manipulation.
50
     * @param  Image $image The source image.
51
     * @return Image The manipulated image.
52
     */
53 6
    public function run(Image $image)
54
    {
55 6
        $width = $this->getWidth();
56 6
        $height = $this->getHeight();
57 6
        $fit = $this->getFit();
58 6
        $dpr = $this->getDpr();
59
60 6
        list($width, $height) = $this->resolveMissingDimensions($image, $width, $height);
61 6
        list($width, $height) = $this->applyDpr($width, $height, $dpr);
62 6
        list($width, $height) = $this->limitImageSize($width, $height);
63
64 6
        if ((int) $width !== (int) $image->width() or (int) $height !== (int) $image->height()) {
65 6
            $image = $this->runResize($image, $fit, (int) $width, (int) $height);
66 6
        }
67
68 6
        return $image;
69
    }
70
71
    /**
72
     * Resolve width.
73
     * @return integer|null The resolved width.
74
     */
75 9
    public function getWidth()
76
    {
77 9
        if (!is_numeric($this->w)) {
78 3
            return;
79
        }
80
81 9
        if ($this->w <= 0) {
82 3
            return;
83
        }
84
85 9
        return (int) $this->w;
86
    }
87
88
    /**
89
     * Resolve height.
90
     * @return integer|null The resolved height.
91
     */
92 9
    public function getHeight()
93
    {
94 9
        if (!is_numeric($this->h)) {
95 6
            return;
96
        }
97
98 6
        if ($this->h <= 0) {
99 3
            return;
100
        }
101
102 6
        return (int) $this->h;
103
    }
104
105
    /**
106
     * Resolve fit.
107
     * @return string The resolved fit.
108
     */
109 9
    public function getFit()
110
    {
111 9
        if (in_array($this->fit, ['contain', 'fill', 'max', 'stretch'], true)) {
112 3
            return $this->fit;
113
        }
114
115 9
        if (preg_match('/^(crop)(-top-left|-top|-top-right|-left|-center|-right|-bottom-left|-bottom|-bottom-right|-[\d]{1,3}-[\d]{1,3})*$/', $this->fit)) {
116 3
            return 'crop';
117
        }
118
119 9
        return 'contain';
120
    }
121
122
    /**
123
     * Resolve the device pixel ratio.
124
     * @return double The device pixel ratio.
125
     */
126 9
    public function getDpr()
127
    {
128 9
        if (!is_numeric($this->dpr)) {
129 9
            return 1.0;
130
        }
131
132 3
        if ($this->dpr < 0 or $this->dpr > 8) {
133 3
            return 1.0;
134
        }
135
136 3
        return (double) $this->dpr;
137
    }
138
139
    /**
140
     * Resolve missing image dimensions.
141
     * @param  Image        $image  The source image.
142
     * @param  integer|null $width  The image width.
143
     * @param  integer|null $height The image height.
144
     * @return integer[]    The resolved width and height.
145
     */
146 9
    public function resolveMissingDimensions(Image $image, $width, $height)
147
    {
148 9
        if (is_null($width) and is_null($height)) {
149 3
            $width = $image->width();
150 3
            $height = $image->height();
151 3
        }
152
153 9
        if (is_null($width)) {
154 3
            $width = $height * ($image->width() / $image->height());
155 3
        }
156
157 9
        if (is_null($height)) {
158 6
            $height = $width / ($image->width() / $image->height());
159 6
        }
160
161
        return [
162 9
            (int) $width,
163 9
            (int) $height,
164 9
        ];
165
    }
166
167
    /**
168
     * Apply the device pixel ratio.
169
     * @param  integer   $width  The target image width.
170
     * @param  integer   $height The target image height.
171
     * @param  integer   $dpr    The device pixel ratio.
172
     * @return integer[] The modified width and height.
173
     */
174 6
    public function applyDpr($width, $height, $dpr)
175
    {
176 6
        $width = $width * $dpr;
177 6
        $height = $height * $dpr;
178
179
        return [
180 6
            (int) $width,
181 6
            (int) $height,
182 6
        ];
183
    }
184
185
    /**
186
     * Limit image size to maximum allowed image size.
187
     * @param  integer   $width  The image width.
188
     * @param  integer   $height The image height.
189
     * @return integer[] The limited width and height.
190
     */
191 9
    public function limitImageSize($width, $height)
192
    {
193 9
        if ($this->maxImageSize !== null) {
194 3
            $imageSize = $width * $height;
195
196 3
            if ($imageSize > $this->maxImageSize) {
197 3
                $width = $width / sqrt($imageSize / $this->maxImageSize);
198 3
                $height = $height / sqrt($imageSize / $this->maxImageSize);
199 3
            }
200 3
        }
201
202
        return [
203 9
            (int) $width,
204 9
            (int) $height,
205 9
        ];
206
    }
207
208
    /**
209
     * Perform resize image manipulation.
210
     * @param  Image   $image  The source image.
211
     * @param  string  $fit    The fit.
212
     * @param  integer $width  The width.
213
     * @param  integer $height The height.
214
     * @return Image   The manipulated image.
215
     */
216 9
    public function runResize(Image $image, $fit, $width, $height)
217
    {
218 9
        if ($fit === 'contain') {
219 9
            return $this->runContainResize($image, $width, $height);
220
        }
221
222 3
        if ($fit === 'fill') {
223 3
            return $this->runFillResize($image, $width, $height);
224
        }
225
226 3
        if ($fit === 'max') {
227 3
            return $this->runMaxResize($image, $width, $height);
228
        }
229
230 3
        if ($fit === 'stretch') {
231 3
            return $this->runStretchResize($image, $width, $height);
232
        }
233
234 3
        if ($fit === 'crop') {
235 3
            return $this->runCropResize($image, $width, $height);
236
        }
237
238 3
        return $image;
239
    }
240
241
    /**
242
     * Perform contain resize image manipulation.
243
     * @param  Image   $image  The source image.
244
     * @param  integer $width  The width.
245
     * @param  integer $height The height.
246
     * @return Image   The manipulated image.
247
     */
248 12
    public function runContainResize(Image $image, $width, $height)
249
    {
250
        return $image->resize($width, $height, function ($constraint) {
251
            $constraint->aspectRatio();
252 12
        });
253
    }
254
255
    /**
256
     * Perform max resize image manipulation.
257
     * @param  Image   $image  The source image.
258
     * @param  integer $width  The width.
259
     * @param  integer $height The height.
260
     * @return Image   The manipulated image.
261
     */
262 9
    public function runMaxResize(Image $image, $width, $height)
263
    {
264
        return $image->resize($width, $height, function ($constraint) {
265
            $constraint->aspectRatio();
266
            $constraint->upsize();
267 9
        });
268
    }
269
270
    /**
271
     * Perform fill resize image manipulation.
272
     * @param  Image   $image  The source image.
273
     * @param  integer $width  The width.
274
     * @param  integer $height The height.
275
     * @return Image   The manipulated image.
276
     */
277 6
    public function runFillResize($image, $width, $height)
278
    {
279 6
        $image = $this->runMaxResize($image, $width, $height);
280
281 6
        return $image->resizeCanvas($width, $height, 'center');
282
    }
283
284
    /**
285
     * Perform stretch resize image manipulation.
286
     * @param  Image   $image  The source image.
287
     * @param  integer $width  The width.
288
     * @param  integer $height The height.
289
     * @return Image   The manipulated image.
290
     */
291 6
    public function runStretchResize(Image $image, $width, $height)
292
    {
293 6
        return $image->resize($width, $height);
294
    }
295
296
    /**
297
     * Perform crop resize image manipulation.
298
     * @param  Image   $image  The source image.
299
     * @param  integer $width  The width.
300
     * @param  integer $height The height.
301
     * @return Image   The manipulated image.
302
     */
303 6
    public function runCropResize(Image $image, $width, $height)
304
    {
305 6
        list($resize_width, $resize_height) = $this->resolveCropResizeDimensions($image, $width, $height);
306
307 6
        $image->resize($resize_width, $resize_height, function ($constraint) {
308
            $constraint->aspectRatio();
309 6
        });
310
311 6
        list($offset_x, $offset_y) = $this->resolveCropOffset($image, $width, $height);
312
313 6
        return $image->crop($width, $height, $offset_x, $offset_y);
314
    }
315
316
    /**
317
     * Resolve the crop resize dimensions.
318
     * @param  Image   $image  The source image.
319
     * @param  integer $width  The width.
320
     * @param  integer $height The height.
321
     * @return array   The resize dimensions.
322
     */
323 6
    public function resolveCropResizeDimensions(Image $image, $width, $height)
324
    {
325 6
        if ($height > $width * ($image->height() / $image->width())) {
326
            return [$height * ($image->width() / $image->height()), $height];
327
        }
328
329 6
        return [$width, $width * ($image->height() / $image->width())];
330
    }
331
332
    /**
333
     * Resolve the crop offset.
334
     * @param  Image   $image  The source image.
335
     * @param  integer $width  The width.
336
     * @param  integer $height The height.
337
     * @return array   The crop offset.
338
     */
339 6
    public function resolveCropOffset(Image $image, $width, $height)
340
    {
341 6
        list($offset_percentage_x, $offset_percentage_y) = $this->getCrop();
342
343 6
        $offset_x = (int) (($image->width() * $offset_percentage_x / 100) - ($width / 2));
344 6
        $offset_y = (int) (($image->height() * $offset_percentage_y / 100) - ($height / 2));
345
346 6
        $max_offset_x = $image->width() - $width;
347 6
        $max_offset_y = $image->height() - $height;
348
349 6
        if ($offset_x < 0) {
350
            $offset_x = 0;
351
        }
352
353 6
        if ($offset_y < 0) {
354
            $offset_y = 0;
355
        }
356
357 6
        if ($offset_x > $max_offset_x) {
358
            $offset_x = $max_offset_x;
359
        }
360
361 6
        if ($offset_y > $max_offset_y) {
362
            $offset_y = $max_offset_y;
363
        }
364
365 6
        return [$offset_x, $offset_y];
366
    }
367
368
    /**
369
     * Resolve crop.
370
     * @return integer[] The resolved crop.
371
     */
372 9
    public function getCrop()
373
    {
374
        $cropMethods = [
375 9
            'crop-top-left' => [0, 0],
376 9
            'crop-top' => [50, 0],
377 9
            'crop-top-right' => [100, 0],
378 9
            'crop-left' => [0, 50],
379 9
            'crop-center' => [50, 50],
380 9
            'crop-right' => [100, 50],
381 9
            'crop-bottom-left' => [0, 100],
382 9
            'crop-bottom' => [50, 100],
383 9
            'crop-bottom-right' => [100, 100],
384 9
        ];
385
386 9
        if (array_key_exists($this->fit, $cropMethods)) {
387 3
            return $cropMethods[$this->fit];
388
        }
389
390 9
        if (preg_match('/^crop-([\d]{1,3})-([\d]{1,3})*$/', $this->fit, $matches)) {
391 3
            if ($matches[1] > 100 or $matches[2] > 100) {
392 3
                return [50, 50];
393
            }
394
395
            return [
396 3
                (int) $matches[1],
397 3
                (int) $matches[2],
398 3
            ];
399
        }
400
401 9
        return [50, 50];
402
    }
403
}
404