1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Spatie\Image; |
4
|
|
|
|
5
|
|
|
use ReflectionClass; |
6
|
|
|
use Spatie\Image\Exceptions\InvalidManipulation; |
7
|
|
|
|
8
|
|
|
class Manipulations |
9
|
|
|
{ |
10
|
|
|
const CROP_TOP_LEFT = 'crop-top-left'; |
11
|
|
|
const CROP_TOP = 'crop-top'; |
12
|
|
|
const CROP_TOP_RIGHT = 'crop-top-right'; |
13
|
|
|
const CROP_LEFT = 'crop-left'; |
14
|
|
|
const CROP_CENTER = 'crop-center'; |
15
|
|
|
const CROP_RIGHT = 'crop-right'; |
16
|
|
|
const CROP_BOTTOM_LEFT = 'crop-bottom-left'; |
17
|
|
|
const CROP_BOTTOM = 'crop-bottom'; |
18
|
|
|
const CROP_BOTTOM_RIGHT = 'crop-bottom-right'; |
19
|
|
|
|
20
|
|
|
const ORIENTATION_AUTO = 'auto'; |
21
|
|
|
const ORIENTATION_90 = 90; |
22
|
|
|
const ORIENTATION_180 = 180; |
23
|
|
|
const ORIENTATION_270 = 270; |
24
|
|
|
|
25
|
|
|
const FIT_CONTAIN = 'contain'; |
26
|
|
|
const FIT_MAX = 'max'; |
27
|
|
|
const FIT_FILL = 'fill'; |
28
|
|
|
const FIT_STRETCH = 'stretch'; |
29
|
|
|
const FIT_CROP = 'crop'; |
30
|
|
|
|
31
|
|
|
const BORDER_OVERLAY = 'overlay'; |
32
|
|
|
const BORDER_SHRINK = 'shrink'; |
33
|
|
|
const BORDER_EXPAND = 'expand'; |
34
|
|
|
|
35
|
|
|
const FORMAT_JPG = 'jpg'; |
36
|
|
|
const FORMAT_PJPG = 'pjpg'; |
37
|
|
|
const FORMAT_PNG = 'png'; |
38
|
|
|
const FORMAT_GIF = 'gif'; |
39
|
|
|
|
40
|
|
|
const FILTER_GREYSCALE = 'greyscale'; |
41
|
|
|
const FILTER_SEPIA = 'sepia'; |
42
|
|
|
|
43
|
|
|
/** @var \Spatie\Image\ManipulationSequence */ |
44
|
|
|
protected $manipulationSequence; |
45
|
|
|
|
46
|
|
|
public function __construct(array $manipulations = []) |
47
|
|
|
{ |
48
|
|
|
$this->manipulationSequence = new ManipulationSequence($manipulations); |
49
|
|
|
} |
50
|
|
|
|
51
|
|
|
/** |
52
|
|
|
* @param string $orientation |
53
|
|
|
* |
54
|
|
|
* @return $this |
55
|
|
|
*/ |
56
|
|
View Code Duplication |
public function orientation(string $orientation) |
|
|
|
|
57
|
|
|
{ |
58
|
|
|
if (! $this->validateManipulation($orientation, 'orientation')) { |
59
|
|
|
throw InvalidManipulation::invalidParameter( |
60
|
|
|
'orientation', |
61
|
|
|
$orientation, |
62
|
|
|
$this->getValidManipulationOptions('orientation') |
63
|
|
|
); |
64
|
|
|
} |
65
|
|
|
|
66
|
|
|
return $this->addManipulation('orientation', $orientation); |
67
|
|
|
} |
68
|
|
|
|
69
|
|
|
/** |
70
|
|
|
* @param string $cropMethod |
71
|
|
|
* @param int $width |
72
|
|
|
* @param int $height |
73
|
|
|
* |
74
|
|
|
* @return $this |
75
|
|
|
*/ |
76
|
|
View Code Duplication |
public function crop(string $cropMethod, int $width, int $height) |
|
|
|
|
77
|
|
|
{ |
78
|
|
|
if (! $this->validateManipulation($cropMethod, 'crop')) { |
79
|
|
|
throw InvalidManipulation::invalidParameter( |
80
|
|
|
'cropmethod', |
81
|
|
|
$cropMethod, |
82
|
|
|
$this->getValidManipulationOptions('crop') |
83
|
|
|
); |
84
|
|
|
} |
85
|
|
|
|
86
|
|
|
$this->width($width); |
87
|
|
|
$this->height($height); |
88
|
|
|
|
89
|
|
|
return $this->addManipulation('crop', $cropMethod); |
90
|
|
|
} |
91
|
|
|
|
92
|
|
|
/** |
93
|
|
|
* @param int $width |
94
|
|
|
* @param int $height |
95
|
|
|
* @param int $focalX Crop center X in percent |
96
|
|
|
* @param int $focalY Crop center Y in percent |
97
|
|
|
* |
98
|
|
|
* @return $this |
99
|
|
|
*/ |
100
|
|
|
public function focalCrop(int $width, int $height, int $focalX, int $focalY) |
101
|
|
|
{ |
102
|
|
|
$this->width($width); |
103
|
|
|
$this->height($height); |
104
|
|
|
|
105
|
|
|
return $this->addManipulation('crop', "crop-{$focalX}-{$focalY}"); |
106
|
|
|
} |
107
|
|
|
|
108
|
|
|
/** |
109
|
|
|
* @param int $width |
110
|
|
|
* @param int $height |
111
|
|
|
* @param int $x |
112
|
|
|
* @param int $y |
113
|
|
|
* |
114
|
|
|
* @return $this |
115
|
|
|
*/ |
116
|
|
|
public function manualCrop(int $width, int $height, int $x, int $y) |
117
|
|
|
{ |
118
|
|
|
if ($width < 0) { |
119
|
|
|
throw InvalidManipulation::invalidWidth($width); |
120
|
|
|
} |
121
|
|
|
|
122
|
|
|
if ($height < 0) { |
123
|
|
|
throw InvalidManipulation::invalidWidth($height); |
124
|
|
|
} |
125
|
|
|
|
126
|
|
|
return $this->addManipulation('manualCrop', "{$width},{$height},{$x},{$y}"); |
127
|
|
|
} |
128
|
|
|
|
129
|
|
|
/** |
130
|
|
|
* @param int $width |
131
|
|
|
* |
132
|
|
|
* @return $this |
133
|
|
|
*/ |
134
|
|
|
public function width(int $width) |
135
|
|
|
{ |
136
|
|
|
if ($width < 0) { |
137
|
|
|
throw InvalidManipulation::invalidWidth($width); |
138
|
|
|
} |
139
|
|
|
|
140
|
|
|
return $this->addManipulation('width', $width); |
141
|
|
|
} |
142
|
|
|
|
143
|
|
|
/** |
144
|
|
|
* @param int $height |
145
|
|
|
* |
146
|
|
|
* @return $this |
147
|
|
|
*/ |
148
|
|
|
public function height(int $height) |
149
|
|
|
{ |
150
|
|
|
if ($height < 0) { |
151
|
|
|
throw InvalidManipulation::invalidWidth($height); |
152
|
|
|
} |
153
|
|
|
|
154
|
|
|
return $this->addManipulation('height', $height); |
155
|
|
|
} |
156
|
|
|
|
157
|
|
|
/** |
158
|
|
|
* @param string $fitMethod |
159
|
|
|
* @param int $width |
160
|
|
|
* @param int $height |
161
|
|
|
* |
162
|
|
|
* @return $this |
163
|
|
|
*/ |
164
|
|
View Code Duplication |
public function fit(string $fitMethod, int $width, int $height) |
|
|
|
|
165
|
|
|
{ |
166
|
|
|
if (! $this->validateManipulation($fitMethod, 'fit')) { |
167
|
|
|
throw InvalidManipulation::invalidParameter( |
168
|
|
|
'fit', |
169
|
|
|
$fitMethod, |
170
|
|
|
$this->getValidManipulationOptions('fit') |
171
|
|
|
); |
172
|
|
|
} |
173
|
|
|
|
174
|
|
|
$this->width($width); |
175
|
|
|
$this->height($height); |
176
|
|
|
|
177
|
|
|
return $this->addManipulation('fit', $fitMethod); |
178
|
|
|
} |
179
|
|
|
|
180
|
|
|
/** |
181
|
|
|
* @param int $ratio A value between 1 and 8 |
182
|
|
|
* |
183
|
|
|
* @return $this |
184
|
|
|
*/ |
185
|
|
|
public function devicePixelRatio(int $ratio) |
186
|
|
|
{ |
187
|
|
|
if ($ratio < 1 || $ratio > 8) { |
188
|
|
|
throw InvalidManipulation::valueNotInRange('ratio', $ratio, 1, 8); |
189
|
|
|
} |
190
|
|
|
|
191
|
|
|
return $this->addManipulation('devicePixelRatio', $ratio); |
192
|
|
|
} |
193
|
|
|
|
194
|
|
|
/** |
195
|
|
|
* @param int $brightness A value between -100 and 100 |
196
|
|
|
* |
197
|
|
|
* @return $this |
198
|
|
|
*/ |
199
|
|
|
public function brightness(int $brightness) |
200
|
|
|
{ |
201
|
|
|
if ($brightness < -100 || $brightness > 100) { |
202
|
|
|
throw InvalidManipulation::valueNotInRange('brightness', $brightness, -100, 100); |
203
|
|
|
} |
204
|
|
|
|
205
|
|
|
return $this->addManipulation('brightness', $brightness); |
206
|
|
|
} |
207
|
|
|
|
208
|
|
|
/** |
209
|
|
|
* @param float $gamma A value between 0.01 and 9.99 |
210
|
|
|
* |
211
|
|
|
* @return $this |
212
|
|
|
*/ |
213
|
|
|
public function gamma(float $gamma) |
214
|
|
|
{ |
215
|
|
|
if ($gamma < 0.01 || $gamma > 9.99) { |
216
|
|
|
throw InvalidManipulation::valueNotInRange('gamma', $gamma, 0.01, 9.00); |
217
|
|
|
} |
218
|
|
|
|
219
|
|
|
return $this->addManipulation('gamma', $gamma); |
220
|
|
|
} |
221
|
|
|
|
222
|
|
|
/** |
223
|
|
|
* @param int $contrast A value between -100 and 100 |
224
|
|
|
* |
225
|
|
|
* @return $this |
226
|
|
|
*/ |
227
|
|
|
public function contrast(int $contrast) |
228
|
|
|
{ |
229
|
|
|
if ($contrast < -100 || $contrast > 100) { |
230
|
|
|
throw InvalidManipulation::valueNotInRange('contrast', $contrast, -100, 100); |
231
|
|
|
} |
232
|
|
|
|
233
|
|
|
return $this->addManipulation('contrast', $contrast); |
234
|
|
|
} |
235
|
|
|
|
236
|
|
|
/** |
237
|
|
|
* @param int $sharpen A value between 0 and 100 |
238
|
|
|
* |
239
|
|
|
* @return $this |
240
|
|
|
*/ |
241
|
|
|
public function sharpen(int $sharpen) |
242
|
|
|
{ |
243
|
|
|
if ($sharpen < 0 || $sharpen > 100) { |
244
|
|
|
throw InvalidManipulation::valueNotInRange('sharpen', $sharpen, 0, 100); |
245
|
|
|
} |
246
|
|
|
|
247
|
|
|
return $this->addManipulation('sharpen', $sharpen); |
248
|
|
|
} |
249
|
|
|
|
250
|
|
|
/** |
251
|
|
|
* @param int $blur A value between 0 and 100 |
252
|
|
|
* |
253
|
|
|
* @return $this |
254
|
|
|
*/ |
255
|
|
View Code Duplication |
public function blur(int $blur) |
|
|
|
|
256
|
|
|
{ |
257
|
|
|
if ($blur < 0 || $blur > 100) { |
258
|
|
|
throw InvalidManipulation::valueNotInRange('blur', $blur, 0, 100); |
259
|
|
|
} |
260
|
|
|
|
261
|
|
|
return $this->addManipulation('blur', $blur); |
262
|
|
|
} |
263
|
|
|
|
264
|
|
|
/** |
265
|
|
|
* @param int $pixelate A value between 0 and 1000 |
266
|
|
|
* |
267
|
|
|
* @return $this |
268
|
|
|
*/ |
269
|
|
|
public function pixelate(int $pixelate) |
270
|
|
|
{ |
271
|
|
|
if ($pixelate < 0 || $pixelate > 1000) { |
272
|
|
|
throw InvalidManipulation::valueNotInRange('pixelate', $pixelate, 0, 1000); |
273
|
|
|
} |
274
|
|
|
|
275
|
|
|
return $this->addManipulation('pixelate', $pixelate); |
276
|
|
|
} |
277
|
|
|
|
278
|
|
|
/** |
279
|
|
|
* @return $this |
280
|
|
|
*/ |
281
|
|
|
public function greyscale() |
282
|
|
|
{ |
283
|
|
|
return $this->filter('greyscale'); |
284
|
|
|
} |
285
|
|
|
|
286
|
|
|
/** |
287
|
|
|
* @return $this |
288
|
|
|
*/ |
289
|
|
|
public function sepia() |
290
|
|
|
{ |
291
|
|
|
return $this->filter('sepia'); |
292
|
|
|
} |
293
|
|
|
|
294
|
|
|
/** |
295
|
|
|
* @param string $colorName |
296
|
|
|
* |
297
|
|
|
* @return $this |
298
|
|
|
*/ |
299
|
|
|
public function background(string $colorName) |
300
|
|
|
{ |
301
|
|
|
return $this->addManipulation('background', $colorName); |
302
|
|
|
} |
303
|
|
|
|
304
|
|
|
/** |
305
|
|
|
* @param int $width |
306
|
|
|
* @param string $color |
307
|
|
|
* @param string $borderType |
308
|
|
|
* |
309
|
|
|
* @return $this |
310
|
|
|
*/ |
311
|
|
|
public function border(int $width, string $color, string $borderType = 'overlay') |
312
|
|
|
{ |
313
|
|
|
if ($width < 0) { |
314
|
|
|
throw InvalidManipulation::invalidWidth($width); |
315
|
|
|
} |
316
|
|
|
|
317
|
|
|
if (! $this->validateManipulation($borderType, 'border')) { |
318
|
|
|
throw InvalidManipulation::invalidParameter( |
319
|
|
|
'border', |
320
|
|
|
$borderType, |
321
|
|
|
$this->getValidManipulationOptions('border') |
322
|
|
|
); |
323
|
|
|
} |
324
|
|
|
|
325
|
|
|
return $this->addManipulation('border', "{$width},{$color},{$borderType}"); |
326
|
|
|
} |
327
|
|
|
|
328
|
|
|
/** |
329
|
|
|
* @param int $quality |
330
|
|
|
* |
331
|
|
|
* @return $this |
332
|
|
|
*/ |
333
|
|
View Code Duplication |
public function quality(int $quality) |
|
|
|
|
334
|
|
|
{ |
335
|
|
|
if ($quality < 0 || $quality > 100) { |
336
|
|
|
throw InvalidManipulation::valueNotInRange('quality', $quality, 0, 100); |
337
|
|
|
} |
338
|
|
|
|
339
|
|
|
return $this->addManipulation('quality', $quality); |
340
|
|
|
} |
341
|
|
|
|
342
|
|
|
/** |
343
|
|
|
* @param string $format |
344
|
|
|
* |
345
|
|
|
* @return $this |
346
|
|
|
*/ |
347
|
|
View Code Duplication |
public function format(string $format) |
|
|
|
|
348
|
|
|
{ |
349
|
|
|
if (! $this->validateManipulation($format, 'format')) { |
350
|
|
|
throw InvalidManipulation::invalidParameter( |
351
|
|
|
'format', |
352
|
|
|
$format, |
353
|
|
|
$this->getValidManipulationOptions('format') |
354
|
|
|
); |
355
|
|
|
} |
356
|
|
|
|
357
|
|
|
return $this->addManipulation('format', $format); |
358
|
|
|
} |
359
|
|
|
|
360
|
|
|
/** |
361
|
|
|
* @param string $filterName |
362
|
|
|
* |
363
|
|
|
* @return $this |
364
|
|
|
*/ |
365
|
|
View Code Duplication |
protected function filter(string $filterName) |
|
|
|
|
366
|
|
|
{ |
367
|
|
|
if (! $this->validateManipulation($filterName, 'filter')) { |
368
|
|
|
throw InvalidManipulation::invalidParameter( |
369
|
|
|
'filter', |
370
|
|
|
$filterName, |
371
|
|
|
$this->getValidManipulationOptions('filter') |
372
|
|
|
); |
373
|
|
|
} |
374
|
|
|
|
375
|
|
|
return $this->addManipulation('filter', $filterName); |
376
|
|
|
} |
377
|
|
|
|
378
|
|
|
/** |
379
|
|
|
* @return $this |
380
|
|
|
*/ |
381
|
|
|
public function apply() |
382
|
|
|
{ |
383
|
|
|
$this->manipulationSequence->startNewGroup(); |
384
|
|
|
|
385
|
|
|
return $this; |
386
|
|
|
} |
387
|
|
|
|
388
|
|
|
public function removeManipulation(string $name) |
389
|
|
|
{ |
390
|
|
|
$this->manipulationSequence->removeManipulation($name); |
391
|
|
|
} |
392
|
|
|
|
393
|
|
|
public function hasManipulation(string $manipulationName): bool |
394
|
|
|
{ |
395
|
|
|
return ! is_null($this->getManipulationArgument($manipulationName)); |
396
|
|
|
} |
397
|
|
|
|
398
|
|
|
/** |
399
|
|
|
* @param string $manipulationName |
400
|
|
|
* |
401
|
|
|
* @return string|null |
402
|
|
|
*/ |
403
|
|
|
public function getManipulationArgument(string $manipulationName) |
404
|
|
|
{ |
405
|
|
|
foreach ($this->manipulationSequence->getGroups() as $manipulationSet) { |
406
|
|
|
if (array_key_exists($manipulationName, $manipulationSet)) { |
407
|
|
|
return $manipulationSet[$manipulationName]; |
408
|
|
|
} |
409
|
|
|
} |
410
|
|
|
} |
411
|
|
|
|
412
|
|
|
protected function addManipulation(string $manipulationName, string $manipulationArgument) |
413
|
|
|
{ |
414
|
|
|
$this->manipulationSequence->addManipulation($manipulationName, $manipulationArgument); |
415
|
|
|
|
416
|
|
|
return $this; |
417
|
|
|
} |
418
|
|
|
|
419
|
|
|
public function mergeManipulations(Manipulations $manipulations) |
420
|
|
|
{ |
421
|
|
|
$this->manipulationSequence->merge($manipulations->manipulationSequence); |
422
|
|
|
|
423
|
|
|
return $this; |
424
|
|
|
} |
425
|
|
|
|
426
|
|
|
public function getManipulationSequence(): ManipulationSequence |
427
|
|
|
{ |
428
|
|
|
return $this->manipulationSequence; |
429
|
|
|
} |
430
|
|
|
|
431
|
|
|
protected function validateManipulation(string $value, string $constantNamePrefix): bool |
432
|
|
|
{ |
433
|
|
|
return in_array($value, $this->getValidManipulationOptions($constantNamePrefix)); |
434
|
|
|
} |
435
|
|
|
|
436
|
|
|
protected function getValidManipulationOptions(string $manipulation): array |
437
|
|
|
{ |
438
|
|
|
$options = (new ReflectionClass(static::class))->getConstants(); |
439
|
|
|
|
440
|
|
|
return array_filter($options, function ($value, $name) use ($manipulation) { |
441
|
|
|
return strpos($name, strtoupper($manipulation)) === 0; |
442
|
|
|
}, ARRAY_FILTER_USE_BOTH); |
443
|
|
|
} |
444
|
|
|
} |
445
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.