Completed
Push — master ( 8a2797...318aef )
by Jonathan
02:16
created

src/Manipulators/Size.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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 int|null
18
     */
19
    protected $maxImageSize;
20
21
    /**
22
     * Create Size instance.
23
     * @param int|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 int|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 int|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 4
        }
67
68 6
        return $image;
69
    }
70
71
    /**
72
     * Resolve width.
73
     * @return int 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 int 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 crop.
124
     * @return array The resolved crop.
125
     */
126 9
    public function getCrop()
127
    {
128
        $cropMethods = [
129 9
            'crop-top-left' => [0, 0],
130 6
            'crop-top' => [50, 0],
131 6
            'crop-top-right' => [100, 0],
132 6
            'crop-left' => [0, 50],
133 6
            'crop-center' => [50, 50],
134 6
            'crop-right' => [100, 50],
135 6
            'crop-bottom-left' => [0, 100],
136 6
            'crop-bottom' => [50, 100],
137 6
            'crop-bottom-right' => [100, 100],
138 6
        ];
139
140 9
        if (array_key_exists($this->fit, $cropMethods)) {
141 3
            return $cropMethods[$this->fit];
142
        }
143
144 9
        if (preg_match('/^crop-([\d]{1,3})-([\d]{1,3})*$/', $this->fit, $matches)) {
145 3
            if ($matches[1] > 100 or $matches[2] > 100) {
146 3
                return [50, 50];
147
            }
148
149 3
            return [(int) $matches[1], (int) $matches[2]];
150
        }
151
152 9
        return [50, 50];
153
    }
154
155
    /**
156
     * Resolve the device pixel ratio.
157
     * @return double The device pixel ratio.
158
     */
159 9
    public function getDpr()
160
    {
161 9
        if (!is_numeric($this->dpr)) {
162 9
            return 1.0;
163
        }
164
165 3
        if ($this->dpr < 0 or $this->dpr > 8) {
166 3
            return 1.0;
167
        }
168
169 3
        return (double) $this->dpr;
170
    }
171
172
    /**
173
     * Resolve missing image dimensions.
174
     * @param  Image    $image  The source image.
175
     * @param  int|null $width  The image width.
176
     * @param  int|null $height The image height.
177
     * @return int[]    The resolved width and height.
178
     */
179 9
    public function resolveMissingDimensions(Image $image, $width, $height)
180
    {
181 9
        if (!$width and !$height) {
182 3
            $width = $image->width();
183 3
            $height = $image->height();
184 2
        }
185
186 9
        if (!$width) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $width of type integer|null is loosely compared to false; this is ambiguous if the integer can be zero. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
187 3
            $width = $height * ($image->width() / $image->height());
188 2
        }
189
190 9
        if (!$height) {
191 6
            $height = $width / ($image->width() / $image->height());
192 4
        }
193
194
        return [
195 9
            (int) $width,
196 9
            (int) $height,
197 6
        ];
198
    }
199
200
    /**
201
     * Apply the device pixel ratio.
202
     * @param  int   $width  The target image width.
203
     * @param  int   $height The target image height.
204
     * @param  int   $dpr    The device pixel ratio.
205
     * @return int[] The modified width and height.
206
     */
207 6
    public function applyDpr($width, $height, $dpr)
208
    {
209 6
        $width = $width * $dpr;
210 6
        $height = $height * $dpr;
211
212
        return [
213 6
            (int) $width,
214 6
            (int) $height,
215 4
        ];
216
    }
217
218
    /**
219
     * Limit image size to maximum allowed image size.
220
     * @param  int   $width  The image width.
221
     * @param  int   $height The image height.
222
     * @return int[] The limited width and height.
223
     */
224 9
    public function limitImageSize($width, $height)
225
    {
226 9
        if ($this->maxImageSize !== null) {
227 3
            $imageSize = $width * $height;
228
229 3
            if ($imageSize > $this->maxImageSize) {
230 3
                $width = $width / sqrt($imageSize / $this->maxImageSize);
231 3
                $height = $height / sqrt($imageSize / $this->maxImageSize);
232 2
            }
233 2
        }
234
235
        return [
236 9
            (int) $width,
237 9
            (int) $height,
238 6
        ];
239
    }
240
241
    /**
242
     * Perform resize image manipulation.
243
     * @param  Image  $image  The source image.
244
     * @param  string $fit    The fit.
245
     * @param  int    $width  The width.
246
     * @param  int    $height The height.
247
     * @return Image  The manipulated image.
248
     */
249 9
    public function runResize(Image $image, $fit, $width, $height)
250
    {
251 9
        if ($fit === 'contain') {
252 9
            return $this->runContainResize($image, $width, $height);
253
        }
254
255 3
        if ($fit === 'fill') {
256 3
            return $this->runFillResize($image, $width, $height);
257
        }
258
259 3
        if ($fit === 'max') {
260 3
            return $this->runMaxResize($image, $width, $height);
261
        }
262
263 3
        if ($fit === 'stretch') {
264 3
            return $this->runStretchResize($image, $width, $height);
265
        }
266
267 3
        if ($fit === 'crop') {
268 3
            return $this->runCropResize($image, $width, $height);
269
        }
270
271 3
        return $image;
272
    }
273
274
    /**
275
     * Perform contain resize image manipulation.
276
     * @param  Image $image  The source image.
277
     * @param  int   $width  The width.
278
     * @param  int   $height The height.
279
     * @return Image The manipulated image.
280
     */
281 12
    public function runContainResize(Image $image, $width, $height)
282
    {
283
        return $image->resize($width, $height, function ($constraint) {
284
            $constraint->aspectRatio();
285 12
        });
286
    }
287
288
    /**
289
     * Perform max resize image manipulation.
290
     * @param  Image $image  The source image.
291
     * @param  int   $width  The width.
292
     * @param  int   $height The height.
293
     * @return Image The manipulated image.
294
     */
295 9
    public function runMaxResize(Image $image, $width, $height)
296
    {
297
        return $image->resize($width, $height, function ($constraint) {
298
            $constraint->aspectRatio();
299
            $constraint->upsize();
300 9
        });
301
    }
302
303
    /**
304
     * Perform fill resize image manipulation.
305
     * @param  Image $image  The source image.
306
     * @param  int   $width  The width.
307
     * @param  int   $height The height.
308
     * @return Image The manipulated image.
309
     */
310 6
    public function runFillResize($image, $width, $height)
311
    {
312 6
        $image = $this->runMaxResize($image, $width, $height);
313
314 6
        return $image->resizeCanvas($width, $height, 'center');
315
    }
316
317
    /**
318
     * Perform stretch resize image manipulation.
319
     * @param  Image $image  The source image.
320
     * @param  int   $width  The width.
321
     * @param  int   $height The height.
322
     * @return Image The manipulated image.
323
     */
324 6
    public function runStretchResize(Image $image, $width, $height)
325
    {
326 6
        return $image->resize($width, $height);
327
    }
328
329
    /**
330
     * Perform crop resize image manipulation.
331
     * @param  Image $image  The source image.
332
     * @param  int   $width  The width.
333
     * @param  int   $height The height.
334
     * @return Image The manipulated image.
335
     */
336 6
    public function runCropResize(Image $image, $width, $height)
337
    {
338 6
        list($offset_percentage_x, $offset_percentage_y) = $this->getCrop();
339
340 6
        $resize_width = $width;
341 6
        $resize_height = (int) ($width * ($image->height() / $image->width()));
342
343 6
        if ($height > $resize_height) {
344
            $resize_width = (int) ($height * ($image->width() / $image->height()));
345
            $resize_height = $height;
346
        }
347
348 6
        $image->resize($resize_width, $resize_height, function ($constraint) {
349
            $constraint->aspectRatio();
350 6
        });
351
352 6
        $offset_x = (int) (($image->width() * $offset_percentage_x / 100) - ($width / 2));
353 6
        $offset_y = (int) (($image->height() * $offset_percentage_y / 100) - ($height / 2));
354
355 6
        $max_offset_x = $image->width() - $width;
356 6
        $max_offset_y = $image->height() - $height;
357
358 6
        if ($offset_x < 0) {
359
            $offset_x = 0;
360
        }
361
362 6
        if ($offset_y < 0) {
363
            $offset_y = 0;
364
        }
365
366 6
        if ($offset_x > $max_offset_x) {
367
            $offset_x = $max_offset_x;
368
        }
369
370 6
        if ($offset_y > $max_offset_y) {
371
            $offset_y = $max_offset_y;
372
        }
373
374 6
        return $image->crop(
375 4
            $width,
376 4
            $height,
377 4
            $offset_x,
378
            $offset_y
379 4
        );
380
    }
381
}
382