Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
233 / 233
100.00% covered (success)
100.00%
26 / 26
CRAP
100.00% covered (success)
100.00%
1 / 1
Parser
100.00% covered (success)
100.00%
233 / 233
100.00% covered (success)
100.00%
26 / 26
82
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 createImageFromFile
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 createImageFromStream
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 loadImageFromFile
100.00% covered (success)
100.00%
22 / 22
100.00% covered (success)
100.00%
1 / 1
10
 loadImageFromStream
100.00% covered (success)
100.00%
34 / 34
100.00% covered (success)
100.00%
1 / 1
11
 setX
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 setY
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 setIndex
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getX
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getY
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getWidth
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getHeight
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getConvertedImage
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getIndex
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getStream
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 getXObject
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getObjects
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 parse
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 parseImageData
100.00% covered (success)
100.00%
40 / 40
100.00% covered (success)
100.00%
1 / 1
15
 parsePng
100.00% covered (success)
100.00%
45 / 45
100.00% covered (success)
100.00%
1 / 1
9
 parseJpeg
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
3
 createResource
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
5
 convertToJpeg
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
1
 convertImage
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
3
 resizeImage
100.00% covered (success)
100.00%
20 / 20
100.00% covered (success)
100.00%
1 / 1
5
 readInt
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2declare(strict_types=1);
3/**
4 * Pop PHP Framework (https://www.popphp.org/)
5 *
6 * @link       https://github.com/popphp/popphp-framework
7 * @author     Nick Sagona, III <nick@popphp.org>
8 * @copyright  Copyright (c) 2009-2026 Nick Sagona, III
9 * @license    https://www.popphp.org/license     New BSD License
10 */
11
12/**
13 * @namespace
14 */
15namespace Pop\Pdf\Build\Image;
16
17use Pop\Pdf\Build\PdfObject\StreamObject;
18
19/**
20 * Pdf image parser class
21 *
22 * @category   Pop
23 * @package    Pop\Pdf
24 * @author     Nick Sagona, III <nick@popphp.org>
25 * @copyright  Copyright (c) 2009-2026 Nick Sagona, III
26 * @license    https://www.popphp.org/license     New BSD License
27 * @version    6.0.0
28 */
29class Parser
30{
31
32    /**
33     * Image width
34     * @var int
35     */
36    protected int $width = 0;
37
38    /**
39     * Image height
40     * @var int
41     */
42    protected int $height = 0;
43
44    /**
45     * Image resize value
46     * @var ?array
47     */
48    protected ?array $resize = null;
49
50    /**
51     * Image mime
52     * @var ?string
53     */
54    protected ?string $mime = null;
55
56    /**
57     * Image color mode
58     * @var mixed
59     */
60    protected mixed $colorMode = null;
61
62    /**
63     * Number of channels in the image
64     * @var ?int
65     */
66    protected ?int $channels = null;
67
68    /**
69     * Image bit-depth
70     * @var int
71     */
72    protected int $depth = 0;
73
74    /**
75     * Image basename
76     * @var ?string
77     */
78    protected ?string $basename = null;
79
80    /**
81     * Image filename
82     * @var ?string
83     */
84    protected ?string $filename = null;
85
86    /**
87     * Image extension
88     * @var ?string
89     */
90    protected ?string $extension = null;
91
92    /**
93     * Image fullpath
94     * @var ?string
95     */
96    protected ?string $fullpath = null;
97
98    /**
99     * Image stream
100     * @var ?string
101     */
102    protected ?string $stream = null;
103
104    /**
105     * Image total number of colors
106     * @var int
107     */
108    protected int $colorTotal = 0;
109
110    /**
111     * Flag for if the image has an alpha channel
112     * @var bool
113     */
114    protected bool $alpha = false;
115
116    /**
117     * Image data
118     * @var mixed
119     */
120    protected mixed $imageData = null;
121
122    /**
123     * Image data length
124     * @var ?int
125     */
126    protected ?int$imageDataLength = null;
127
128    /**
129     * GD image resource
130     * @var mixed
131     */
132    protected mixed $resource = null;
133
134    /**
135     * Image X Coordinate
136     * @var int
137     */
138    protected int $x = 0;
139
140    /**
141     * Image Y Coordinate
142     * @var int
143     */
144    protected int $y = 0;
145
146    /**
147     * Image object index
148     * @var ?int
149     */
150    protected ?int $index = null;
151
152    /**
153     * Image objects
154     * @var array
155     */
156    protected array $objects = [];
157
158    /**
159     * Converted GIF to PNG image
160     * @var ?string
161     */
162    protected ?string $convertedImage = null;
163
164    /**
165     * Resized image
166     * @var ?string
167     */
168    protected ?string $resizedImage = null;
169
170    /**
171     * Constructor
172     *
173     * Instantiate a image parser object
174     *
175     * @param  int $x
176     * @param  int $y
177     */
178    public function __construct(int $x, int $y)
179    {
180        $this->setX($x);
181        $this->setY($y);
182    }
183
184    /**
185     * Create image from file
186     *
187     * @param  string $imageFile
188     * @param  int    $x
189     * @param  int    $y
190     * @param  ?array $resize
191     * @param  bool   $preserveResolution
192     * @return Parser
193     */
194    public static function createImageFromFile(
195        string $imageFile, int $x, int $y, ?array $resize = null, bool $preserveResolution = false
196    ): Parser
197    {
198        $parser = new self($x, $y);
199        $parser->loadImageFromFile($imageFile, $resize, $preserveResolution);
200        return $parser;
201    }
202
203    /**
204     * Create image from stream
205     *
206     * @param  string $imageStream
207     * @param  int    $x
208     * @param  int    $y
209     * @param  ?array $resize
210     * @param  bool   $preserveResolution
211     * @return Parser
212     */
213    public static function createImageFromStream(
214        string $imageStream, int $x, int $y, ?array $resize = null, bool $preserveResolution = false
215    ): Parser
216    {
217        $parser = new self($x, $y);
218        $parser->loadImageFromStream($imageStream, $resize, $preserveResolution);
219        return $parser;
220    }
221
222    /**
223     * Load image from file
224     *
225     * @param  string $imageFile
226     * @param  ?array $resize
227     * @param  bool   $preserveResolution
228     * @throws Exception
229     * @return Parser
230     */
231    public function loadImageFromFile(string $imageFile, ?array $resize = null, bool $preserveResolution = false): Parser
232    {
233        $parts           = pathinfo($imageFile);
234        $this->fullpath  = realpath($imageFile);
235        $this->basename  = $parts['basename'];
236        $this->filename  = $parts['filename'];
237        $this->extension = (isset($parts['extension']) && ($parts['extension'] != '')) ? $parts['extension'] : null;
238        $this->stream    = null;
239
240        // Convert GIF image to PNG
241        if (strtolower($this->extension) == 'gif') {
242            $this->convertImage();
243        } else {
244            $this->mime = (strtolower($this->extension) == 'png') ? 'image/png' : 'image/jpeg';
245        }
246
247        // If resize dimensions are passed
248        if (($resize !== null) && !($preserveResolution)) {
249            $this->resizeImage($resize);
250        }
251
252        $imgSize = getimagesize($this->fullpath);
253
254        if ($resize !== null) {
255            $this->resize = $resize;
256        }
257
258        $this->width    = $imgSize[0];
259        $this->height   = $imgSize[1];
260        $this->channels = (isset($imgSize['channels'])) ? $imgSize['channels'] : null;
261        $this->depth    = (isset($imgSize['bits'])) ? $imgSize['bits'] : null;
262
263        $this->imageData       = file_get_contents($this->fullpath);
264        $this->imageDataLength = strlen($this->imageData);
265
266        $this->parseImageData();
267
268        return $this;
269    }
270
271    /**
272     * Load image from stream
273     *
274     * @param  string $imageStream
275     * @param  ?array $resize
276     * @param  bool   $preserveResolution
277     * @throws Exception
278     * @return Parser
279     */
280    public function loadImageFromStream(string $imageStream, ?array $resize = null, bool $preserveResolution = false): Parser
281    {
282        $this->stream = $imageStream;
283        $imgSize      = getimagesizefromstring($this->stream);
284
285        $this->fullpath = null;
286
287        switch ($imgSize['mime']) {
288            case 'image/jpeg':
289                $this->basename  = 'image.jpg';
290                $this->filename  = 'image';
291                $this->extension = 'jpg';
292                break;
293            case 'image/gif':
294                $this->basename  = 'image.gif';
295                $this->filename  = 'image';
296                $this->extension = 'gif';
297                break;
298            case 'image/png':
299                $this->basename  = 'image.png';
300                $this->filename  = 'image';
301                $this->extension = 'png';
302                break;
303        }
304
305        // Convert GIF image to PNG
306        if (strtolower($this->extension) == 'gif') {
307            $this->convertImage();
308        } else {
309            $this->mime = (strtolower($this->extension) == 'png') ? 'image/png' : 'image/jpeg';
310        }
311
312        // If resize dimensions are passed
313        if (($resize !== null) && !($preserveResolution)) {
314            $this->resizeImage($resize);
315        }
316
317        if ($resize !== null) {
318            $this->resize = $resize;
319        }
320
321        $this->width    = $imgSize[0];
322        $this->height   = $imgSize[1];
323        $this->channels = (isset($imgSize['channels'])) ? $imgSize['channels'] : null;
324        $this->depth    = (isset($imgSize['bits'])) ? $imgSize['bits'] : null;
325
326        $this->imageData       = $this->stream;
327        $this->imageDataLength = strlen($this->imageData);
328
329        $this->parseImageData();
330
331        return $this;
332    }
333
334    /**
335     * Set the X coordinate
336     *
337     * @param  int $x
338     * @return Parser
339     */
340    public function setX(int $x): Parser
341    {
342        $this->x = $x;
343        return $this;
344    }
345
346    /**
347     * Set the Y coordinate
348     *
349     * @param  int $y
350     * @return Parser
351     */
352    public function setY(int $y): Parser
353    {
354        $this->y = (int)$y;
355        return $this;
356    }
357
358    /**
359     * Set the image object index
360     *
361     * @param  int $i
362     * @return Parser
363     */
364    public function setIndex(int $i): Parser
365    {
366        $this->index = $i;
367        return $this;
368    }
369
370    /**
371     * Get the X coordinate
372     *
373     * @return int
374     */
375    public function getX(): int
376    {
377        return $this->x;
378    }
379
380    /**
381     * Get the Y coordinate
382     *
383     * @return int
384     */
385    public function getY(): int
386    {
387        return $this->y;
388    }
389
390    /**
391     * Get the width
392     *
393     * @return int
394     */
395    public function getWidth(): int
396    {
397        return $this->width;
398    }
399
400    /**
401     * Get the height
402     *
403     * @return int
404     */
405    public function getHeight(): int
406    {
407        return $this->height;
408    }
409
410    /**
411     * Get the converted image
412     *
413     * @return ?string
414     */
415    public function getConvertedImage(): ?string
416    {
417        return $this->convertedImage;
418    }
419
420    /**
421     * Get the image object index
422     *
423     * @return ?int
424     */
425    public function getIndex(): ?int
426    {
427        return $this->index;
428    }
429
430    /**
431     * Get the image stream
432     *
433     * @return string
434     */
435    public function getStream(): string
436    {
437        $width  = $this->resize['width'] ?? $this->width;
438        $height = $this->resize['height'] ?? $this->height;
439        return "\n\nq\n\n1 0 0 1 {$this->x} {$this->y} cm\n{$width} 0 0 {$height} 0 0 cm\n/I{$this->index} Do\n\nQ\n\n";
440    }
441
442    /**
443     * Get the XObject
444     *
445     * @return string
446     */
447    public function getXObject(): string
448    {
449        return "/I{$this->index} {$this->index} 0 R";
450    }
451
452    /**
453     * Get the image objects
454     *
455     * @throws Exception
456     * @return array
457     */
458    public function getObjects(): array
459    {
460        if (count($this->objects) == 0) {
461            $this->parse();
462        }
463        return $this->objects;
464    }
465
466    /**
467     * Parse the image data and create the image objects
468     *
469     * @throws Exception
470     * @return void
471     */
472    public function parse(): void
473    {
474        if ($this->index === null) {
475            throw new Exception('Error: The image index has not been set.');
476        }
477        if ($this->mime == 'image/png') {
478            $this->parsePng();
479        } else {
480            $this->parseJpeg();
481        }
482    }
483
484    /**
485     * Parse image data
486     *
487     * @return void
488     */
489    protected function parseImageData(): void
490    {
491        if (str_starts_with(strtolower($this->extension), 'jp')) {
492            switch ($this->channels) {
493                case 1:
494                    $this->colorMode = 'Gray';
495                    break;
496                case 3:
497                    $this->colorMode = 'RGB';
498                    break;
499                case 4:
500                    $this->colorMode = 'CMYK';
501                    break;
502            }
503        } else if (strtolower($this->extension) == 'png') {
504            $colorType  = ord($this->imageData[25]);
505            switch ($colorType) {
506                case 0:
507                    $this->channels  = 1;
508                    $this->colorMode = 'Gray';
509                    break;
510                case 2:
511                    $this->channels  = 3;
512                    $this->colorMode = 'RGB';
513                    break;
514                case 3:
515                    $this->channels  = 3;
516                    $this->colorMode = 'Indexed';
517                    break;
518                case 4:
519                    $this->channels  = 1;
520                    $this->colorMode = 'Gray';
521                    $this->alpha     = true;
522                    break;
523                case 6:
524                    $this->channels  = 3;
525                    $this->colorMode = 'RGB';
526                    $this->alpha     = true;
527                    break;
528            }
529        }
530
531        $this->createResource();
532
533        // Image clean up if the image was converted or resized.
534        if (($this->convertedImage !== null) && file_exists($this->convertedImage)) {
535            unlink($this->convertedImage);
536        }
537        if (($this->resizedImage !== null) && file_exists($this->resizedImage)) {
538            unlink($this->resizedImage);
539        }
540    }
541
542    /**
543     * Parse the PNG image data
544     *
545     * @throws Exception
546     * @return void
547     */
548    protected function parsePng(): void
549    {
550        // Define some PNG image-specific variables.
551        $PLTE      = null;
552        $TRNS      = null;
553        $maskIndex = null;
554        $mask      = null;
555        $palIndex  = null;
556
557        // Determine the PNG colorspace.
558        if ($this->colorMode == 'Gray') {
559            $numOfColors = 1;
560            $colorSpace  = '/DeviceGray';
561        } else if (stripos($this->colorMode, 'RGB') !== false) {
562            $numOfColors = 3;
563            $colorSpace  = '/DeviceRGB';
564        } else {
565            $numOfColors = 1;
566            $palIndex    = $this->index + 1;
567
568            // If the PNG is indexed, parse and read the palette and any transparencies that might exist.
569            if (str_contains($this->imageData, 'PLTE')) {
570                $lenByte   = substr($this->imageData, (strpos($this->imageData, "PLTE") - 4), 4);
571                $palLength = $this->readInt($lenByte);
572                $PLTE      = substr($this->imageData, (strpos($this->imageData, "PLTE") + 4), $palLength);
573                $mask      = null;
574
575                // If a transparency exists, parse it and set the mask accordingly, along with the palette.
576                if (str_contains($this->imageData, 'tRNS')) {
577                    $lenByte   = substr($this->imageData, (strpos($this->imageData, "tRNS") - 4), 4);
578                    $TRNS      = substr($this->imageData, (strpos($this->imageData, "tRNS") + 4), $this->readInt($lenByte));
579                    $maskIndex = strpos($TRNS, chr(0));
580                    $mask      = "    /Mask [" . $maskIndex . " " . $maskIndex . "]\n";
581                }
582            }
583
584            $this->colorTotal = imagecolorstotal($this->resource);
585            $colorSpace       = "[/Indexed /DeviceRGB " . ($this->colorTotal - 1) . " " . $palIndex . " 0 R]";
586        }
587
588        // Parse header data, bits and color type
589        $lenByte   = substr($this->imageData, (strpos($this->imageData, "IHDR") - 4), 4);
590        $header    = substr($this->imageData, (strpos($this->imageData, "IHDR") + 4), $this->readInt($lenByte));
591        $bits      = ord(substr($header, 8, 1));
592        $colorType = ord(substr($header, 9, 1));
593
594        // Make sure the PNG does not contain a true alpha channel.
595        if (($colorType >= 4) && (($bits == 8) || ($bits == 16))) {
596            throw new Exception('Error: PNG alpha channels are not supported. Only 8-bit transparent PNG images are supported.');
597        }
598
599        // Parse and set the PNG image data and data length.
600        $lenByte = substr($this->imageData, (strpos($this->imageData, "IDAT") - 4), 4);
601        $this->imageDataLength = $this->readInt($lenByte);
602        $IDAT = substr($this->imageData, (strpos($this->imageData, "IDAT") + 4), $this->imageDataLength);
603
604        // Add the image to the objects array.
605        $this->objects[$this->index] = StreamObject::parse(
606            "{$this->index} 0 obj\n<<\n    /Type /XObject\n    /Subtype /Image\n    /Width " . $this->width .
607            "\n    /Height " . $this->height . "\n    /ColorSpace {$colorSpace}\n    /BitsPerComponent " . $bits .
608            "\n    /Filter /FlateDecode\n    /DecodeParms <</Predictor 15 /Colors {$numOfColors} /BitsPerComponent " .
609            $bits . " /Columns " . $this->width . ">>\n{$mask}    /Length {$this->imageDataLength}\n>>\nstream\n{$IDAT}\nendstream\nendobj\n"
610        );
611
612        // If it exists, add the image palette to the objects array.
613        if ($PLTE != '') {
614            $this->objects[$palIndex] = StreamObject::parse(
615                "{$palIndex} 0 obj\n<<\n    /Length " . $palLength . "\n>>\nstream\n{$PLTE}\nendstream\nendobj\n"
616            );
617            $this->objects[$palIndex]->setPalette(true);
618        }
619    }
620
621    /**
622     * Parse the JPG image data
623     *
624     * @return void
625     */
626    protected function parseJpeg(): void
627    {
628        // Add the image to the objects array.
629        $colorMode  = (strtolower($this->colorMode) == 'srgb') ? 'RGB' : $this->colorMode;
630        $colorSpace = ($this->colorMode == 'CMYK') ? "/DeviceCMYK\n    /Decode [1 0 1 0 1 0 1 0]" : "/Device" . $colorMode;
631        $this->objects[$this->index] = StreamObject::parse(
632            "{$this->index} 0 obj\n<<\n    /Type /XObject\n    /Subtype /Image\n    /Width " . $this->width .
633            "\n    /Height " . $this->height . "\n    /ColorSpace {$colorSpace}\n    /BitsPerComponent 8\n    " .
634            "/Filter /DCTDecode\n    /Length {$this->imageDataLength}\n>>\nstream\n{$this->imageData}\nendstream\nendobj\n"
635        );
636    }
637
638    /**
639     * Create a new image resource based on the current image type
640     * of the image object.
641     *
642     * @return void
643     */
644    protected function createResource(): void
645    {
646        if ($this->stream !== null) {
647            $this->resource = imagecreatefromstring($this->stream);
648        } else if (file_exists($this->fullpath)) {
649            // GIFs are always converted to PNG (convertImage()) before
650            // $this->mime is set, so it's never 'image/gif' here.
651            switch ($this->mime) {
652                case 'image/png':
653                    $this->resource = imagecreatefrompng($this->fullpath);
654                    break;
655                case 'image/jpeg':
656                    $this->resource = imagecreatefromjpeg($this->fullpath);
657                    break;
658            }
659        }
660    }
661
662    /**
663     * Method to convert the image to Jpg
664     *
665     * @param  int $quality
666     * @return void
667     */
668    public function convertToJpeg(int $quality = 70): void
669    {
670        $this->convertedImage = realpath(sys_get_temp_dir()) . DIRECTORY_SEPARATOR . $this->filename . '_' . time() . '.jpg';
671
672        $result = imagecreatetruecolor($this->width, $this->height);
673        imagecopyresampled(
674            $result, $this->resource, 0, 0, 0, 0, $this->width, $this->height, $this->width, $this->height
675        );
676
677        $this->resource = $result;
678        $this->width    = imagesx($this->resource);
679        $this->height   = imagesy($this->resource);
680
681        imagejpeg($this->resource, $this->convertedImage, $quality);
682    }
683
684    /**
685     * Method to convert the image from GIF to PNG.
686     *
687     * @return void
688     */
689    protected function convertImage(): void
690    {
691        // Define the temp converted image.
692        $this->convertedImage = realpath(sys_get_temp_dir()) . DIRECTORY_SEPARATOR . $this->filename . '_' . time() . '.png';
693
694        // Convert the GIF to PNG, save and clear the output buffer.
695
696        $resource = ($this->stream !== null) ?
697            imagecreatefromstring($this->stream) : imagecreatefromgif($this->fullpath);
698
699        imageinterlace($resource, false);
700        imagepng($resource, $this->convertedImage);
701
702        // Change the type of the image object to the new,
703        // requested image type.
704        $this->extension = 'png';
705        $this->mime      = 'image/png';
706
707        // Redefine the image object properties with the new values.
708        if ($this->stream !== null) {
709            $this->stream = file_get_contents($this->convertedImage);
710        } else {
711            $this->fullpath = $this->convertedImage;
712        }
713        $this->basename = basename($this->convertedImage);
714        $this->filename = basename($this->convertedImage, '.png');
715    }
716
717    /**
718     * Method to resize the image.
719     *
720     * @param  array $resize
721     * @return void
722     */
723    protected function resizeImage(array $resize): void
724    {
725        // Define the temp resized image.
726        $this->resizedImage = realpath(sys_get_temp_dir()) . DIRECTORY_SEPARATOR . $this->filename . '_' . time() . '.' . $this->extension;
727
728        // Get image properties.
729        if ($this->stream !== null) {
730            $imgSize  = getimagesizefromstring($this->stream);
731            $resource = imagecreatefromstring($this->stream);
732        } else {
733            $imgSize  = getimagesize($this->fullpath);
734            $resource = ($this->mime == 'image/png') ?
735                imagecreatefrompng($this->fullpath) : imagecreatefromjpeg($this->fullpath);
736        }
737
738        $width  = $imgSize[0];
739        $height = $imgSize[1];
740        $output = imagecreatetruecolor($resize['width'], $resize['height']);
741
742        imagecopyresampled($output, $resource, 0, 0, 0, 0, $resize['width'], $resize['height'], $width, $height);
743
744        if ($this->mime == 'image/png') {
745            imagepng($output, $this->resizedImage, 1);
746            $this->filename = basename($this->resizedImage, '.png');
747        } else {
748            imagejpeg($output, $this->resizedImage, 90);
749            $this->filename = basename($this->resizedImage, '.jpg');
750        }
751
752        $this->basename = basename($this->resizedImage);
753
754        if ($this->stream !== null) {
755            $this->stream = file_get_contents($this->resizedImage);
756        } else {
757            $this->fullpath = $this->resizedImage;
758        }
759    }
760
761    /**
762     * Method to read an unsigned integer.
763     *
764     * @param  string $data
765     * @return int
766     */
767    protected function readInt(string $data): int
768    {
769        $ary = unpack('Nlength', $data);
770        return $ary['length'];
771    }
772
773}