Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
97.87% |
46 / 47 |
|
94.12% |
16 / 17 |
CRAP | |
0.00% |
0 / 1 |
AbstractAdapter | |
97.87% |
46 / 47 |
|
94.12% |
16 / 17 |
32 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
11 / 11 |
|
100.00% |
1 / 1 |
9 | |||
createResource | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
getResource | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
hasResource | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getName | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getWidth | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getHeight | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getQuality | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getColorspace | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
isIndexed | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getFormat | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getExif | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
isGray | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
isRgb | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
isCmyk | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
setQuality | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
sendHeaders | |
91.67% |
11 / 12 |
|
0.00% |
0 / 1 |
8.04 | |||
__get | |
100.00% |
9 / 9 |
|
100.00% |
1 / 1 |
1 | |||
load | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
loadFromString | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
create | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
createIndex | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
resizeToWidth | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
resizeToHeight | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
resize | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
scale | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
crop | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
cropThumb | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
rotate | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
flip | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
flop | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
adjust | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
filter | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
layer | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
draw | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
effect | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
type | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
convert | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
writeToFile | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
outputToRawString | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
outputToHttp | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
destroy | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
createColor | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
__toString | n/a |
0 / 0 |
n/a |
0 / 0 |
0 |
1 | <?php |
2 | /** |
3 | * Pop PHP Framework (http://www.popphp.org/) |
4 | * |
5 | * @link https://github.com/popphp/popphp-framework |
6 | * @author Nick Sagona, III <dev@nolainteractive.com> |
7 | * @copyright Copyright (c) 2009-2024 NOLA Interactive, LLC. (http://www.nolainteractive.com) |
8 | * @license http://www.popphp.org/license New BSD License |
9 | */ |
10 | |
11 | /** |
12 | * @namespace |
13 | */ |
14 | namespace Pop\Image\Adapter; |
15 | |
16 | use Pop\Image\Adjust; |
17 | use Pop\Color\Color; |
18 | use Pop\Image\Draw; |
19 | use Pop\Image\Effect; |
20 | use Pop\Image\Filter; |
21 | use Pop\Image\Layer; |
22 | use Pop\Image\Type; |
23 | |
24 | /** |
25 | * Abstract adapter class |
26 | * |
27 | * @category Pop |
28 | * @package Pop\Image |
29 | * @author Nick Sagona, III <dev@nolainteractive.com> |
30 | * @copyright Copyright (c) 2009-2024 NOLA Interactive, LLC. (http://www.nolainteractive.com) |
31 | * @license http://www.popphp.org/license New BSD License |
32 | * @version 4.0.0 |
33 | */ |
34 | abstract class AbstractAdapter implements AdapterInterface |
35 | { |
36 | |
37 | /** |
38 | * Colorspace constants |
39 | */ |
40 | const IMAGE_GRAY = 1; |
41 | const IMAGE_RGB = 2; |
42 | const IMAGE_CMYK = 3; |
43 | |
44 | /** |
45 | * Image resource |
46 | * @var mixed |
47 | */ |
48 | protected mixed $resource = null; |
49 | |
50 | /** |
51 | * Image name |
52 | * @var string |
53 | */ |
54 | protected string $name = 'pop-image.jpg'; |
55 | |
56 | /** |
57 | * Image width |
58 | * @var int |
59 | */ |
60 | protected int $width = 640; |
61 | |
62 | /** |
63 | * Image height |
64 | * @var int |
65 | */ |
66 | protected int $height = 480; |
67 | |
68 | /** |
69 | * Image format |
70 | * @var string |
71 | */ |
72 | protected string $format = 'jpg'; |
73 | |
74 | /** |
75 | * Image quality |
76 | * @var int |
77 | */ |
78 | protected int $quality = 100; |
79 | |
80 | /** |
81 | * Image colorspace |
82 | * @var int |
83 | */ |
84 | protected int $colorspace = 2; |
85 | |
86 | /** |
87 | * Index color flag |
88 | * @var bool |
89 | */ |
90 | protected bool $indexed = false; |
91 | |
92 | /** |
93 | * EXIF data |
94 | * @var array |
95 | */ |
96 | protected array $exif = []; |
97 | |
98 | /** |
99 | * Image adjust object |
100 | * @var ?Adjust\AdjustInterface |
101 | */ |
102 | protected ?Adjust\AdjustInterface $adjust = null; |
103 | |
104 | /** |
105 | * Image draw object |
106 | * @var ?Draw\DrawInterface |
107 | */ |
108 | protected ?Draw\DrawInterface $draw = null; |
109 | |
110 | /** |
111 | * Image effect object |
112 | * @var ?Effect\EffectInterface |
113 | */ |
114 | protected ?Effect\EffectInterface $effect = null; |
115 | |
116 | /** |
117 | * Image filter object |
118 | * @var ?Filter\FilterInterface |
119 | */ |
120 | protected ?Filter\FilterInterface $filter = null; |
121 | |
122 | /** |
123 | * Image layer object |
124 | * @var ?Layer\LayerInterface |
125 | */ |
126 | protected ?Layer\LayerInterface $layer = null; |
127 | |
128 | /** |
129 | * Image type object |
130 | * @var ?Type\TypeInterface |
131 | */ |
132 | protected ?Type\TypeInterface $type = null; |
133 | |
134 | /** |
135 | * Constructor |
136 | * |
137 | * Instantiate an image object based on either a pre-existing image |
138 | * file on disk, or a new image file. |
139 | * |
140 | */ |
141 | public function __construct() |
142 | { |
143 | $args = func_get_args(); |
144 | |
145 | $this->createResource(); |
146 | |
147 | // $image |
148 | if (isset($args[0]) && !is_numeric($args[0]) && file_exists($args[0])) { |
149 | $this->name = $args[0]; |
150 | $this->load(); |
151 | // $width, $height, $name |
152 | } else if ((count($args) >= 2) && is_numeric($args[0]) && is_numeric($args[1])) { |
153 | $this->width = $args[0]; |
154 | $this->height = $args[1]; |
155 | if (isset($args[2]) && !is_numeric($args[2])) { |
156 | $this->name = $args[2]; |
157 | } |
158 | $this->create(); |
159 | } |
160 | } |
161 | |
162 | /** |
163 | * Create the image resource |
164 | * |
165 | * @return void |
166 | */ |
167 | abstract public function createResource(): void; |
168 | |
169 | /** |
170 | * Get the image resource |
171 | * |
172 | * @return mixed |
173 | */ |
174 | public function getResource(): mixed |
175 | { |
176 | return $this->resource; |
177 | } |
178 | |
179 | /** |
180 | * Determine if there is an image resource |
181 | * |
182 | * @return bool |
183 | */ |
184 | public function hasResource(): bool |
185 | { |
186 | return ($this->resource !== null); |
187 | } |
188 | |
189 | /** |
190 | * Get the image name |
191 | * |
192 | * @return string |
193 | */ |
194 | public function getName(): string |
195 | { |
196 | return $this->name; |
197 | } |
198 | |
199 | /** |
200 | * Get the image width |
201 | * |
202 | * @return int |
203 | */ |
204 | public function getWidth(): int |
205 | { |
206 | return $this->width; |
207 | } |
208 | |
209 | /** |
210 | * Get the image height |
211 | * |
212 | * @return int |
213 | */ |
214 | public function getHeight(): int |
215 | { |
216 | return $this->height; |
217 | } |
218 | |
219 | /** |
220 | * Get the image quality |
221 | * |
222 | * @return int |
223 | */ |
224 | public function getQuality(): int |
225 | { |
226 | return $this->quality; |
227 | } |
228 | |
229 | /** |
230 | * Get the colorspace |
231 | * |
232 | * @return int |
233 | */ |
234 | public function getColorspace(): int |
235 | { |
236 | return $this->colorspace; |
237 | } |
238 | |
239 | /** |
240 | * Determine if the image is index color |
241 | * |
242 | * @return bool |
243 | */ |
244 | public function isIndexed(): bool |
245 | { |
246 | return $this->indexed; |
247 | } |
248 | |
249 | /** |
250 | * Get the image format |
251 | * |
252 | * @return string |
253 | */ |
254 | public function getFormat(): string |
255 | { |
256 | return $this->format; |
257 | } |
258 | |
259 | /** |
260 | * Get the image EXIF data |
261 | * |
262 | * @return array |
263 | */ |
264 | public function getExif(): array |
265 | { |
266 | return $this->exif; |
267 | } |
268 | |
269 | /** |
270 | * Determine if the image is grayscale |
271 | * |
272 | * @return bool |
273 | */ |
274 | public function isGray(): bool |
275 | { |
276 | return ($this->colorspace == self::IMAGE_GRAY); |
277 | } |
278 | |
279 | /** |
280 | * Determine if the image is RGB |
281 | * |
282 | * @return bool |
283 | */ |
284 | public function isRgb(): bool |
285 | { |
286 | return ($this->colorspace == self::IMAGE_RGB); |
287 | } |
288 | |
289 | /** |
290 | * Determine if the image is CMYK |
291 | * |
292 | * @return bool |
293 | */ |
294 | public function isCmyk(): bool |
295 | { |
296 | return ($this->colorspace == self::IMAGE_CMYK); |
297 | } |
298 | |
299 | /** |
300 | * Set the image quality |
301 | * |
302 | * @oaram int $quality |
303 | * @return static |
304 | */ |
305 | public function setQuality(int $quality): static |
306 | { |
307 | $this->quality = $quality; |
308 | return $this; |
309 | } |
310 | |
311 | /** |
312 | * Send image headers the image |
313 | * |
314 | * @param ?string $to |
315 | * @param bool $download |
316 | * @param array $additionalHeaders |
317 | * @return void |
318 | */ |
319 | public function sendHeaders(?string $to = null, bool $download = false, array $additionalHeaders = []): void |
320 | { |
321 | if ($to === null) { |
322 | $to = ($this->name !== null) ? basename($this->name) : 'pop-image.' . $this->format; |
323 | } |
324 | |
325 | // Determine if the force download argument has been passed. |
326 | $headers = [ |
327 | 'Content-type' => 'image/' . (($this->format == 'jpg') ? 'jpeg' : $this->format), |
328 | 'Content-disposition' => (($download) ? 'attachment; ' : null) . 'filename=' . $to |
329 | ]; |
330 | |
331 | if (!empty($additionalHeaders)) { |
332 | $headers = $headers + $additionalHeaders; |
333 | } |
334 | |
335 | // Send the headers and output the image |
336 | if (!headers_sent()) { |
337 | header('HTTP/1.1 200 OK'); |
338 | foreach ($headers as $name => $value) { |
339 | header($name . ': ' . $value); |
340 | } |
341 | } |
342 | } |
343 | |
344 | /** |
345 | * Magic get method to return a manipulation object |
346 | * |
347 | * @param string $name |
348 | * @return mixed |
349 | */ |
350 | public function __get(string $name): mixed |
351 | { |
352 | return match ($name) { |
353 | 'adjust' => $this->adjust(), |
354 | 'filter' => $this->filter(), |
355 | 'layer' => $this->layer(), |
356 | 'draw' => $this->draw(), |
357 | 'effect' => $this->effect(), |
358 | 'type' => $this->type(), |
359 | default => null, |
360 | }; |
361 | } |
362 | |
363 | /** |
364 | * Load the image resource from the existing image file |
365 | * |
366 | * @param ?string $name |
367 | * @return AbstractAdapter |
368 | */ |
369 | abstract public function load(?string $name = null): AbstractAdapter; |
370 | |
371 | /** |
372 | * Load the image resource from data |
373 | * |
374 | * @param string $data |
375 | * @param ?string $name |
376 | * @return AbstractAdapter |
377 | */ |
378 | abstract public function loadFromString(string $data, ?string $name = null): AbstractAdapter; |
379 | |
380 | /** |
381 | * Create a new image resource |
382 | * |
383 | * @param ?int $width |
384 | * @param ?int $height |
385 | * @param ?string $name |
386 | * @return AbstractAdapter |
387 | */ |
388 | abstract public function create(?int $width = null, ?int $height = null, ?string $name = null): AbstractAdapter; |
389 | |
390 | /** |
391 | * Create a new indexed image resource |
392 | * |
393 | * @param ?int $width |
394 | * @param ?int $height |
395 | * @param ?string $name |
396 | * @return AbstractAdapter |
397 | */ |
398 | abstract public function createIndex(?int $width = null, ?int $height = null, ?string $name = null): AbstractAdapter; |
399 | |
400 | /** |
401 | * Resize the image object to the width parameter passed |
402 | * |
403 | * @param int $w |
404 | * @return AbstractAdapter |
405 | */ |
406 | abstract public function resizeToWidth(int $w): AbstractAdapter; |
407 | |
408 | /** |
409 | * Resize the image object to the height parameter passed |
410 | * |
411 | * @param int $h |
412 | * @return AbstractAdapter |
413 | */ |
414 | abstract public function resizeToHeight(int $h): AbstractAdapter; |
415 | |
416 | /** |
417 | * Resize the image object, allowing for the largest dimension |
418 | * to be scaled to the value of the $px argument. |
419 | * |
420 | * @param int $px |
421 | * @return AbstractAdapter |
422 | */ |
423 | abstract public function resize(int $px): AbstractAdapter; |
424 | |
425 | /** |
426 | * Scale the image object, allowing for the dimensions to be scaled |
427 | * proportionally to the value of the $scl argument. |
428 | * |
429 | * @param float $scale |
430 | * @return AbstractAdapter |
431 | */ |
432 | abstract public function scale(float $scale): AbstractAdapter; |
433 | |
434 | /** |
435 | * Crop the image object to a image whose dimensions are based on the |
436 | * value of the $wid and $hgt argument. The optional $x and $y arguments |
437 | * allow for the adjustment of the crop to select a certain area of the |
438 | * image to be cropped. |
439 | * |
440 | * @param int $w |
441 | * @param int $h |
442 | * @param int $x |
443 | * @param int $y |
444 | * @return AbstractAdapter |
445 | */ |
446 | abstract public function crop(int $w, int $h, int $x = 0, int $y = 0): AbstractAdapter; |
447 | |
448 | /** |
449 | * Crop the image object to a square image whose dimensions are based on the |
450 | * value of the $px argument. The optional $offset argument allows for the |
451 | * adjustment of the crop to select a certain area of the image to be cropped. |
452 | * |
453 | * @param int $px |
454 | * @param ?int $offset |
455 | * @return AbstractAdapter |
456 | */ |
457 | abstract public function cropThumb(int $px, ?int $offset = null): AbstractAdapter; |
458 | |
459 | /** |
460 | * Rotate the image object |
461 | * |
462 | * @param int $degrees |
463 | * @param ?Color\ColorInterface $bgColor |
464 | * @throws Exception |
465 | * @return AbstractAdapter |
466 | */ |
467 | abstract public function rotate(int $degrees, ?Color\ColorInterface $bgColor = null): AbstractAdapter; |
468 | |
469 | /** |
470 | * Method to flip the image over the x-axis |
471 | * |
472 | * @return AbstractAdapter |
473 | */ |
474 | abstract public function flip(): AbstractAdapter; |
475 | |
476 | /** |
477 | * Method to flip the image over the y-axis |
478 | * |
479 | * @return AbstractAdapter |
480 | */ |
481 | abstract public function flop(): AbstractAdapter; |
482 | |
483 | /** |
484 | * Get the image adjust object |
485 | * |
486 | * @return Adjust\AdjustInterface |
487 | */ |
488 | abstract public function adjust(): Adjust\AdjustInterface; |
489 | |
490 | /** |
491 | * Get the image filter object |
492 | * |
493 | * @return Filter\FilterInterface |
494 | */ |
495 | abstract public function filter(): Filter\FilterInterface; |
496 | |
497 | /** |
498 | * Get the image layer object |
499 | * |
500 | * @return Layer\LayerInterface |
501 | */ |
502 | abstract public function layer(): Layer\LayerInterface; |
503 | |
504 | /** |
505 | * Get the image draw object |
506 | * |
507 | * @return Draw\DrawInterface |
508 | */ |
509 | abstract public function draw(): Draw\DrawInterface; |
510 | |
511 | /** |
512 | * Get the image effect object |
513 | * |
514 | * @return Effect\EffectInterface |
515 | */ |
516 | abstract public function effect(): Effect\EffectInterface; |
517 | |
518 | /** |
519 | * Get the image type object |
520 | * |
521 | * @return Type\TypeInterface |
522 | */ |
523 | abstract public function type(): Type\TypeInterface; |
524 | |
525 | /** |
526 | * Convert the image object to another format |
527 | * |
528 | * @param string $type |
529 | * @throws Exception |
530 | * @return AbstractAdapter |
531 | */ |
532 | abstract public function convert(string $type): AbstractAdapter; |
533 | |
534 | /** |
535 | * Write the image object to a file on disk |
536 | * |
537 | * @param ?string $to |
538 | * @param int $quality |
539 | * @throws Exception |
540 | * @return void |
541 | */ |
542 | abstract public function writeToFile(?string $to = null, int $quality = 100): void; |
543 | |
544 | /** |
545 | * Output the image object to a raw string |
546 | * |
547 | * @param int $quality |
548 | * @throws Exception |
549 | * @return string|false |
550 | */ |
551 | abstract public function outputToRawString(int $quality = 100): string|false; |
552 | |
553 | /** |
554 | * Output the image object directly to HTTP |
555 | * |
556 | * @param int $quality |
557 | * @param ?string $to |
558 | * @param bool $download |
559 | * @param bool $sendHeaders |
560 | * @throws Exception |
561 | * @return void |
562 | */ |
563 | abstract public function outputToHttp(int $quality = 100, ?string $to = null, bool $download = false, bool $sendHeaders = true): void; |
564 | |
565 | /** |
566 | * Destroy the image object and the related image file directly |
567 | * |
568 | * @param bool $delete |
569 | * @return void |
570 | */ |
571 | abstract public function destroy(bool $delete = false): void; |
572 | |
573 | /** |
574 | * Create and return a color. |
575 | * |
576 | * @param ?Color\ColorInterface $color |
577 | * @param int $alpha |
578 | * @throws Exception |
579 | * @return mixed |
580 | */ |
581 | abstract public function createColor(?Color\ColorInterface $color = null, int $alpha = 100): mixed; |
582 | |
583 | /** |
584 | * Output the image |
585 | * |
586 | * @return string |
587 | */ |
588 | abstract public function __toString(): string; |
589 | |
590 | } |