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