From ddf9d7b3159479dad04fedc3552a837ec54d1135 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20=C5=9Amia=C5=82ek?= Date: Fri, 31 Jul 2020 11:13:48 +0200 Subject: [PATCH 01/40] Fix incorrect @param type (#159) --- lib/ImageResize.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ImageResize.php b/lib/ImageResize.php index 76321ac..b5ad4b5 100644 --- a/lib/ImageResize.php +++ b/lib/ImageResize.php @@ -217,7 +217,7 @@ public function imageCreateJpegfromExif($filename) * Saves new image * * @param string $filename - * @param string $image_type + * @param integer $image_type * @param integer $quality * @param integer $permissions * @param boolean $exact_size From 72be1e2c2d576ac8c07cbd210f78f5f66338badc Mon Sep 17 00:00:00 2001 From: Dream me up Date: Fri, 31 Jul 2020 12:26:55 +0200 Subject: [PATCH 02/40] Handle alpga for webp is source have alpha (#161) --- lib/ImageResize.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/ImageResize.php b/lib/ImageResize.php index b5ad4b5..551155e 100644 --- a/lib/ImageResize.php +++ b/lib/ImageResize.php @@ -267,6 +267,10 @@ public function save($filename, $image_type = null, $quality = null, $permission $background = imagecolorallocate($dest_image, 255, 255, 255); imagefilledrectangle($dest_image, 0, 0, $this->getDestWidth(), $this->getDestHeight(), $background); } + + imagealphablending($dest_image, false); + imagesavealpha($dest_image, true); + break; case IMAGETYPE_PNG: From a5ec9f4c7c274d94d9844b5ec882f458d6f44915 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albert=20M=C3=B8ller=20Nielsen?= Date: Wed, 9 Dec 2020 03:57:04 +0100 Subject: [PATCH 03/40] Fixed truecolor issue resulting in big file sizes (#167) --- lib/ImageResize.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ImageResize.php b/lib/ImageResize.php index 551155e..002dfa6 100644 --- a/lib/ImageResize.php +++ b/lib/ImageResize.php @@ -274,7 +274,7 @@ public function save($filename, $image_type = null, $quality = null, $permission break; case IMAGETYPE_PNG: - if (!$this->quality_truecolor && !imageistruecolor($this->source_image)) { + if (!$this->quality_truecolor || !imageistruecolor($this->source_image)) { if( !empty($exact_size) && is_array($exact_size) ){ $dest_image = imagecreate($exact_size[0], $exact_size[1]); } else{ From bd01af1021bec10cff400ec38acda1c87d740d95 Mon Sep 17 00:00:00 2001 From: Aditya Patadia Date: Sat, 18 Dec 2021 21:30:51 +0530 Subject: [PATCH 04/40] added 8.0 and 8.1 version in tests --- .github/workflows/php-testing.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/php-testing.yml b/.github/workflows/php-testing.yml index ca0aaeb..6e722c0 100644 --- a/.github/workflows/php-testing.yml +++ b/.github/workflows/php-testing.yml @@ -9,7 +9,7 @@ jobs: fail-fast: false matrix: operating-system: [ubuntu-18.04] - php-versions: ['5.6', '7.0', '7.1', '7.2', '7.3', '7.4'] + php-versions: ['5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0', '8.1'] name: PHP ${{ matrix.php-versions }} Test on ${{ matrix.operating-system }} steps: - name: Checkout From 4b9e387358a7c21b909cbd5c19c904ab78c366ca Mon Sep 17 00:00:00 2001 From: Aditya Patadia Date: Sat, 18 Dec 2021 21:31:30 +0530 Subject: [PATCH 05/40] ubuntu version update --- .github/workflows/php-testing.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/php-testing.yml b/.github/workflows/php-testing.yml index 6e722c0..1a610ce 100644 --- a/.github/workflows/php-testing.yml +++ b/.github/workflows/php-testing.yml @@ -8,7 +8,7 @@ jobs: strategy: fail-fast: false matrix: - operating-system: [ubuntu-18.04] + operating-system: [ubuntu-20.04] php-versions: ['5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0', '8.1'] name: PHP ${{ matrix.php-versions }} Test on ${{ matrix.operating-system }} steps: From c8439b64d2e481b692e2e4144fcd338b34ee9856 Mon Sep 17 00:00:00 2001 From: Aditya Patadia Date: Sat, 18 Dec 2021 21:37:13 +0530 Subject: [PATCH 06/40] phpunit update --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 3cddca8..99723b7 100644 --- a/composer.json +++ b/composer.json @@ -36,7 +36,7 @@ }, "require-dev": { - "phpunit/phpunit": "^4.8", + "phpunit/phpunit": "^5.7", "apigen/apigen": "^4.1", "php-coveralls/php-coveralls": "^2.1", "ext-exif": "*", From e1ec3c07926ed919596087e1b31204d711bd5911 Mon Sep 17 00:00:00 2001 From: Aditya Patadia Date: Sat, 18 Dec 2021 21:39:45 +0530 Subject: [PATCH 07/40] drop versions 5.6, 7.0 and 7.1 from test --- .github/workflows/php-testing.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/php-testing.yml b/.github/workflows/php-testing.yml index 1a610ce..0ced5ec 100644 --- a/.github/workflows/php-testing.yml +++ b/.github/workflows/php-testing.yml @@ -9,7 +9,7 @@ jobs: fail-fast: false matrix: operating-system: [ubuntu-20.04] - php-versions: ['5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0', '8.1'] + php-versions: ['7.2', '7.3', '7.4', '8.0', '8.1'] name: PHP ${{ matrix.php-versions }} Test on ${{ matrix.operating-system }} steps: - name: Checkout From 671bd29a554036ffca7ffeaf5b19eb9f43121953 Mon Sep 17 00:00:00 2001 From: Aditya Patadia Date: Sat, 18 Dec 2021 21:40:01 +0530 Subject: [PATCH 08/40] Update composer.json --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 99723b7..667b39e 100644 --- a/composer.json +++ b/composer.json @@ -36,7 +36,7 @@ }, "require-dev": { - "phpunit/phpunit": "^5.7", + "phpunit/phpunit": "^8.5", "apigen/apigen": "^4.1", "php-coveralls/php-coveralls": "^2.1", "ext-exif": "*", From f268c7bf0e1e4aeaf5a785770545292818ba1b14 Mon Sep 17 00:00:00 2001 From: Aditya Patadia Date: Sat, 18 Dec 2021 21:43:16 +0530 Subject: [PATCH 09/40] Update phpunit.xml --- phpunit.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpunit.xml b/phpunit.xml index 6ea3a80..7bab324 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,6 +1,6 @@ + backupStaticAttributes="false"> test From 83ed1bc3f0e5770680e0c0401f7bc46768e9ac71 Mon Sep 17 00:00:00 2001 From: Aditya Patadia Date: Sat, 18 Dec 2021 21:47:32 +0530 Subject: [PATCH 10/40] gamma correction disabled by default. --- README.md | 4 ++-- lib/ImageResize.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9c44f30..474d7a4 100644 --- a/README.md +++ b/README.md @@ -359,11 +359,11 @@ Both functions will be used in the order in which they were added. Gamma color correction -------- -You can disable the gamma color correction enabled by default. +You can enable the gamma color correction which is disabled by default. ```php $image = new ImageResize('image.png'); -$image->gamma(false); +$image->gamma(true); ``` API Doc diff --git a/lib/ImageResize.php b/lib/ImageResize.php index 002dfa6..465da2c 100644 --- a/lib/ImageResize.php +++ b/lib/ImageResize.php @@ -24,7 +24,7 @@ class ImageResize public $quality_webp = 85; public $quality_png = 6; public $quality_truecolor = true; - public $gamma_correct = true; + public $gamma_correct = false; public $interlace = 1; From a07476f7ca0f3e27c27191a7b73018d69776cac7 Mon Sep 17 00:00:00 2001 From: Aditya Patadia Date: Sat, 18 Dec 2021 21:59:52 +0530 Subject: [PATCH 11/40] test cases updated for new phpunit --- README.md | 4 +++- composer.json | 2 +- test/ImageResizeTest.php | 31 +++++++++++-------------------- 3 files changed, 15 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 474d7a4..032a333 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ If using [Composer](https://getcomposer.org/), in your `composer.json` file add: ```json { "require": { - "gumlet/php-image-resize": "1.9.*" + "gumlet/php-image-resize": "2.0.*" } } ``` @@ -31,6 +31,8 @@ If you are still using PHP 5.3, please install version ```1.7.0``` and if you ar WebP support is added with PHP `5.6.0` and current version of library supports that. If you are facing issues, please use `1.9.2` version of this library. +For PHP versions >= 7.2, `2.0.1` or above version of this library should be used. + Otherwise: ```php diff --git a/composer.json b/composer.json index 667b39e..3e68112 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,7 @@ }], "require": { - "php": ">=5.5.0", + "php": ">=5.6.0", "ext-gd": "*", "ext-fileinfo": "*" }, diff --git a/test/ImageResizeTest.php b/test/ImageResizeTest.php index b771c31..f2c4275 100644 --- a/test/ImageResizeTest.php +++ b/test/ImageResizeTest.php @@ -106,39 +106,32 @@ public function testApplyFilter() * Bad load tests */ - /** - * @expectedException \Gumlet\ImageResizeException - * @expectedExceptionMessage File does not exist - */ public function testLoadNoFile() { + $this->expectException(ImageResizeException::class); + $this->expectExceptionMessage('File does not exist'); new ImageResize(null); } - /** - * @expectedException \Gumlet\ImageResizeException - * @expectedExceptionMessage Unsupported file type - */ public function testLoadUnsupportedFile() { + $this->expectException(ImageResizeException::class); + $this->expectExceptionMessage('Unsupported file type'); new ImageResize(__FILE__); } - /** - * @expectedException \Gumlet\ImageResizeException - * @expectedExceptionMessage image_data must not be empty - */ public function testLoadUnsupportedFileString() { + $this->expectException(ImageResizeException::class); + $this->expectExceptionMessage('image_data must not be empty'); ImageResize::createFromString(''); } - /** - * @expectedException \Gumlet\ImageResizeException - * @expectedExceptionMessage Unsupported image type - */ + public function testLoadUnsupportedImage() { + $this->expectException(ImageResizeException::class); + $this->expectExceptionMessage('Unsupported image type'); $filename = $this->getTempFile(); $image = fopen($filename, 'w'); @@ -148,12 +141,10 @@ public function testLoadUnsupportedImage() new ImageResize($filename); } - /** - * @expectedException \Gumlet\ImageResizeException - * @expectedExceptionMessage Unsupported image type - */ public function testInvalidString() { + $this->expectException(ImageResizeException::class); + $this->expectExceptionMessage('Unsupported image type'); ImageResize::createFromString(base64_decode($this->unsupported_image)); } From c76388407d7a341132850413122e86de7257fb93 Mon Sep 17 00:00:00 2001 From: Aditya Patadia Date: Sat, 18 Dec 2021 22:35:23 +0530 Subject: [PATCH 12/40] explicit integer conversion --- lib/ImageResize.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ImageResize.php b/lib/ImageResize.php index 465da2c..f0a01b9 100644 --- a/lib/ImageResize.php +++ b/lib/ImageResize.php @@ -431,12 +431,12 @@ public function resizeToShortSide($max_short, $allow_enlarge = false) { if ($this->getSourceHeight() < $this->getSourceWidth()) { $ratio = $max_short / $this->getSourceHeight(); - $long = $this->getSourceWidth() * $ratio; + $long = (int) ($this->getSourceWidth() * $ratio); $this->resize($long, $max_short, $allow_enlarge); } else { $ratio = $max_short / $this->getSourceWidth(); - $long = $this->getSourceHeight() * $ratio; + $long = (int) ($this->getSourceHeight() * $ratio); $this->resize($max_short, $long, $allow_enlarge); } From 8b3874a9d441c5d111e465407524bb6d4ed25f46 Mon Sep 17 00:00:00 2001 From: Aditya Patadia Date: Sat, 18 Dec 2021 22:40:14 +0530 Subject: [PATCH 13/40] all calculations have explicit integer conversions --- lib/ImageResize.php | 75 ++++++++------------------------------------- 1 file changed, 12 insertions(+), 63 deletions(-) diff --git a/lib/ImageResize.php b/lib/ImageResize.php index f0a01b9..a4de190 100644 --- a/lib/ImageResize.php +++ b/lib/ImageResize.php @@ -203,11 +203,7 @@ public function imageCreateJpegfromExif($filename) } if ($orientation === 5 || $orientation === 4 || $orientation === 7) { - if(function_exists('imageflip')) { - imageflip($img, IMG_FLIP_HORIZONTAL); - } else { - $this->imageFlip($img, IMG_FLIP_HORIZONTAL); - } + imageflip($img, IMG_FLIP_HORIZONTAL); } return $img; @@ -455,12 +451,12 @@ public function resizeToLongSide($max_long, $allow_enlarge = false) { if ($this->getSourceHeight() > $this->getSourceWidth()) { $ratio = $max_long / $this->getSourceHeight(); - $short = $this->getSourceWidth() * $ratio; + $short = (int) ($this->getSourceWidth() * $ratio); $this->resize($short, $max_long, $allow_enlarge); } else { $ratio = $max_long / $this->getSourceWidth(); - $short = $this->getSourceHeight() * $ratio; + $short = (int) ($this->getSourceHeight() * $ratio); $this->resize($max_long, $short, $allow_enlarge); } @@ -478,7 +474,7 @@ public function resizeToLongSide($max_long, $allow_enlarge = false) public function resizeToHeight($height, $allow_enlarge = false) { $ratio = $height / $this->getSourceHeight(); - $width = $this->getSourceWidth() * $ratio; + $width = (int) ($this->getSourceWidth() * $ratio); $this->resize($width, $height, $allow_enlarge); @@ -495,7 +491,7 @@ public function resizeToHeight($height, $allow_enlarge = false) public function resizeToWidth($width, $allow_enlarge = false) { $ratio = $width / $this->getSourceWidth(); - $height = $this->getSourceHeight() * $ratio; + $height = (int) ($this->getSourceHeight() * $ratio); $this->resize($width, $height, $allow_enlarge); @@ -518,11 +514,11 @@ public function resizeToBestFit($max_width, $max_height, $allow_enlarge = false) $ratio = $this->getSourceHeight() / $this->getSourceWidth(); $width = $max_width; - $height = $width * $ratio; + $height = (int) ($width * $ratio); if ($height > $max_height) { $height = $max_height; - $width = (int) round($height / $ratio); + $width = (int) ($height / $ratio); } return $this->resize($width, $height, $allow_enlarge); @@ -536,8 +532,8 @@ public function resizeToBestFit($max_width, $max_height, $allow_enlarge = false) */ public function scale($scale) { - $width = $this->getSourceWidth() * $scale / 100; - $height = $this->getSourceHeight() * $scale / 100; + $width = (int) ($this->getSourceWidth() * $scale / 100); + $height = (int) ($this->getSourceHeight() * $scale / 100); $this->resize($width, $height, true); @@ -608,7 +604,7 @@ public function crop($width, $height, $allow_enlarge = false, $position = self:: if ($ratio_dest < $ratio_source) { $this->resizeToHeight($height, $allow_enlarge); - $excess_width = ($this->getDestWidth() - $width) / $this->getDestWidth() * $this->getSourceWidth(); + $excess_width = (int) (($this->getDestWidth() - $width) * $this->getSourceWidth() / $this->getDestWidth()); $this->source_w = $this->getSourceWidth() - $excess_width; $this->source_x = $this->getCropPosition($excess_width, $position); @@ -617,7 +613,7 @@ public function crop($width, $height, $allow_enlarge = false, $position = self:: } else { $this->resizeToWidth($width, $allow_enlarge); - $excess_height = ($this->getDestHeight() - $height) / $this->getDestHeight() * $this->getSourceHeight(); + $excess_height = (int) (($this->getDestHeight() - $height) * $this->getSourceHeight() / $this->getDestHeight()); $this->source_h = $this->getSourceHeight() - $excess_height; $this->source_y = $this->getCropPosition($excess_height, $position); @@ -727,60 +723,13 @@ protected function getCropPosition($expectedSize, $position = self::CROPCENTER) return $size; } - /** - * Flips an image using a given mode if PHP version is lower than 5.5 - * - * @param resource $image - * @param integer $mode - * @return null - */ - public function imageFlip($image, $mode) - { - switch($mode) { - case self::IMG_FLIP_HORIZONTAL: { - $max_x = imagesx($image) - 1; - $half_x = $max_x / 2; - $sy = imagesy($image); - $temp_image = imageistruecolor($image)? imagecreatetruecolor(1, $sy): imagecreate(1, $sy); - for ($x = 0; $x < $half_x; ++$x) { - imagecopy($temp_image, $image, 0, 0, $x, 0, 1, $sy); - imagecopy($image, $image, $x, 0, $max_x - $x, 0, 1, $sy); - imagecopy($image, $temp_image, $max_x - $x, 0, 0, 0, 1, $sy); - } - break; - } - case self::IMG_FLIP_VERTICAL: { - $sx = imagesx($image); - $max_y = imagesy($image) - 1; - $half_y = $max_y / 2; - $temp_image = imageistruecolor($image)? imagecreatetruecolor($sx, 1): imagecreate($sx, 1); - for ($y = 0; $y < $half_y; ++$y) { - imagecopy($temp_image, $image, 0, 0, 0, $y, $sx, 1); - imagecopy($image, $image, 0, $y, 0, $max_y - $y, $sx, 1); - imagecopy($image, $temp_image, 0, $max_y - $y, 0, 0, $sx, 1); - } - break; - } - case self::IMG_FLIP_BOTH: { - $sx = imagesx($image); - $sy = imagesy($image); - $temp_image = imagerotate($image, 180, 0); - imagecopy($image, $temp_image, 0, 0, 0, 0, $sx, $sy); - break; - } - default: - return null; - } - imagedestroy($temp_image); - } - /** * Enable or not the gamma color correction on the image, enabled by default * * @param bool $enable * @return static */ - public function gamma($enable = true) + public function gamma($enable = false) { $this->gamma_correct = $enable; From 5ef461c53241933a3e14e4582a9d2884b8261213 Mon Sep 17 00:00:00 2001 From: Aditya Patadia Date: Sat, 18 Dec 2021 22:40:48 +0530 Subject: [PATCH 14/40] image flip test removed --- test/ImageResizeTest.php | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/test/ImageResizeTest.php b/test/ImageResizeTest.php index f2c4275..570c8b0 100644 --- a/test/ImageResizeTest.php +++ b/test/ImageResizeTest.php @@ -351,22 +351,6 @@ public function testCropLargerNotAllowed() $this->assertEquals(100, $resize->getDestHeight()); } - /** - * Image flip tests - */ - - public function testImageFlip() - { - $imageFileName = $this->createImage(200, 100, 'png'); - $resize = new ImageResize($imageFileName); - $image = imagecreatetruecolor(200, 100); - - $this::assertNull($resize->imageFlip($image, 0)); - $this::assertNull($resize->imageFlip($image, 1)); - $this::assertNull($resize->imageFlip($image, 2)); - $this->assertNull($resize->imageFlip($image, 3)); - } - /** * Save tests */ From 9a50d97d9d06f338533bf27195272a011a6f5ada Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sabri=20=C3=9Cnal?= Date: Mon, 3 Jan 2022 14:26:17 +0300 Subject: [PATCH 15/40] add $quality_webp --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 032a333..3c6c55c 100644 --- a/README.md +++ b/README.md @@ -237,7 +237,7 @@ $image->save('image.png', IMAGETYPE_PNG); Quality ------- -The properties `$quality_jpg` and `$quality_png` are available for you to configure: +The properties `$quality_jpg`, `$quality_webp` and `$quality_png` are available for you to configure: ```php $image = new ImageResize('image.jpg'); From 7499d39680e28fba2beea37896a95e29cf31f728 Mon Sep 17 00:00:00 2001 From: Roman Zaycev Date: Fri, 28 Jan 2022 00:54:54 +0700 Subject: [PATCH 16/40] BMP support --- lib/ImageResize.php | 38 +++++++++++++++++++++++++++++++++++ test/ImageResizeTest.php | 23 +++++++++++++++++++-- test/ressources/test_bmp.bmp | Bin 0 -> 142 bytes 3 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 test/ressources/test_bmp.bmp diff --git a/lib/ImageResize.php b/lib/ImageResize.php index a4de190..0eea1e6 100644 --- a/lib/ImageResize.php +++ b/lib/ImageResize.php @@ -105,6 +105,11 @@ public function __construct($filename) if (!defined('IMAGETYPE_WEBP')) { define('IMAGETYPE_WEBP', 18); } + + if (!defined('IMAGETYPE_BMP')) { + define('IMAGETYPE_BMP', 6); + } + if ($filename === null || empty($filename) || (substr($filename, 0, 5) !== 'data:' && !is_file($filename))) { throw new ImageResizeException('File does not exist'); } @@ -129,6 +134,10 @@ public function __construct($filename) if (!$checkWebp) { if (!$image_info) { + if (strstr(finfo_file($finfo, $filename), 'image') !== false) { + throw new ImageResizeException('Unsupported image type'); + } + throw new ImageResizeException('Could not read file'); } @@ -162,6 +171,13 @@ public function __construct($filename) break; + case IMAGETYPE_BMP: + if (version_compare(PHP_VERSION, '7.2.0', '<')) { + throw new ImageResizeException('For bmp support PHP >= 7.2.0 is required'); + } + $this->source_image = imagecreatefrombmp($filename); + break; + default: throw new ImageResizeException('Unsupported image type'); } @@ -170,6 +186,8 @@ public function __construct($filename) throw new ImageResizeException('Could not load image'); } + finfo_close($finfo); + return $this->resize($this->getSourceWidth(), $this->getSourceHeight()); } @@ -291,6 +309,22 @@ public function save($filename, $image_type = null, $quality = null, $permission imagecolortransparent($dest_image, $background); imagefill($dest_image, 0, 0, $background); break; + + case IMAGETYPE_BMP: + if (version_compare(PHP_VERSION, '7.2.0', '<')) { + throw new ImageResizeException('For WebP support PHP >= 7.2.0 is required'); + } + + if(!empty($exact_size) && is_array($exact_size)) { + $dest_image = imagecreatetruecolor($exact_size[0], $exact_size[1]); + $background = imagecolorallocate($dest_image, 255, 255, 255); + imagefilledrectangle($dest_image, 0, 0, $exact_size[0], $exact_size[1], $background); + } else { + $dest_image = imagecreatetruecolor($this->getDestWidth(), $this->getDestHeight()); + $background = imagecolorallocate($dest_image, 255, 255, 255); + imagefilledrectangle($dest_image, 0, 0, $this->getDestWidth(), $this->getDestHeight(), $background); + } + break; } imageinterlace($dest_image, $this->interlace); @@ -361,6 +395,10 @@ public function save($filename, $image_type = null, $quality = null, $permission imagepng($dest_image, $filename, $quality); break; + + case IMAGETYPE_BMP: + imagebmp($dest_image, $filename, $quality); + break; } if ($permissions) { diff --git a/test/ImageResizeTest.php b/test/ImageResizeTest.php index 570c8b0..1647bc4 100644 --- a/test/ImageResizeTest.php +++ b/test/ImageResizeTest.php @@ -10,10 +10,11 @@ class ImageResizeTest extends TestCase private $image_types = array( 'gif', 'jpeg', - 'png' + 'png', + 'bmp', ); - private $unsupported_image = 'Qk08AAAAAAAAADYAAAAoAAAAAQAAAAEAAAABABAAAAAAAAYAAAASCwAAEgsAAAAAAAAAAAAA/38AAAAA'; + private $unsupported_image = 'AAAKAAAAAAAAAAAAAQABABgAAF9SlQAAAAAAAAAAVFJVRVZJU0lPTi1YRklMRS4A'; private $image_string = 'R0lGODlhAQABAIAAAAQCBP///yH5BAEAAAEALAAAAAABAAEAAAICRAEAOw=='; private $data_url = 'data:image/gif;base64,R0lGODlhAQABAIAAAAQCBP///yH5BAEAAAEALAAAAAABAAEAAAICRAEAOw=='; @@ -67,6 +68,15 @@ public function testLoadWebp() $this->assertInstanceOf('\Gumlet\ImageResize', $resize); } + public function testLoadBmp() + { + $image = __DIR__ . '/ressources/test_bmp.bmp'; + $resize = new ImageResize($image); + + $this->assertEquals(IMAGETYPE_BMP, $resize->source_type); + $this->assertInstanceOf('\Gumlet\ImageResize', $resize); + } + public function testLoadString() { $resize = ImageResize::createFromString(base64_decode($this->image_string)); @@ -394,6 +404,15 @@ public function testSavePng() $this->assertEquals(IMAGETYPE_PNG, exif_imagetype($filename)); } + public function testSaveBmp() + { + $image = $this->createImage(200, 100, 'png'); + $resize = new ImageResize($image); + $filename = $this->getTempFile(); + $resize->save($filename, IMAGETYPE_BMP); + $this->assertEquals(IMAGETYPE_BMP, exif_imagetype($filename)); + } + public function testSaveChmod() { $image = $this->createImage(200, 100, 'png'); diff --git a/test/ressources/test_bmp.bmp b/test/ressources/test_bmp.bmp new file mode 100644 index 0000000000000000000000000000000000000000..17ac0f342d08d98cd271be9e1cd41b50e1be5f46 GIT binary patch literal 142 zcmZ?r?PGv|E+AC{#Eft(0hV9^lFE7z3>E+r{}~t{2+VVG4=P5;5yxUeQx+dIl>q?9 C@CbMS literal 0 HcmV?d00001 From 3ea5ad5cfa52bed062d6e464256b8f72c9f18675 Mon Sep 17 00:00:00 2001 From: Gabriele Olmi <42089195+GabrieleOlmi@users.noreply.github.com> Date: Sat, 2 Apr 2022 01:06:40 +0200 Subject: [PATCH 17/40] README: missing semicolon in "resize" section --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3c6c55c..15056b0 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ To scale an image, in this case to half it's size (scaling is percentage based): ```php $image = new ImageResize('image.jpg'); $image->scale(50); -$image->save('image2.jpg') +$image->save('image2.jpg'); ``` To resize an image according to one dimension (keeping aspect ratio): From 23d7a715d7901ccf91c60d6fd7a57934d2d1cea8 Mon Sep 17 00:00:00 2001 From: Diego Marty Date: Thu, 12 May 2022 12:22:27 +0200 Subject: [PATCH 18/40] Updated return type to avoid implicit float to int conversion --- lib/ImageResize.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ImageResize.php b/lib/ImageResize.php index 0eea1e6..e7babe4 100644 --- a/lib/ImageResize.php +++ b/lib/ImageResize.php @@ -740,7 +740,7 @@ public function getDestHeight() * * @param integer $expectedSize * @param integer $position - * @return float|integer + * @return integer */ protected function getCropPosition($expectedSize, $position = self::CROPCENTER) { @@ -758,7 +758,7 @@ protected function getCropPosition($expectedSize, $position = self::CROPCENTER) $size = $expectedSize / 4; break; } - return $size; + return (int) $size; } /** From b877eaf52acd5eab88f47e148ef710087cc21dfd Mon Sep 17 00:00:00 2001 From: Pier-Luc Lafleur Date: Tue, 21 Jun 2022 10:17:16 -0400 Subject: [PATCH 19/40] Replacing deprecated null parameter #3 of imagerotate() by 0 --- lib/ImageResize.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/ImageResize.php b/lib/ImageResize.php index e7babe4..3c179f0 100644 --- a/lib/ImageResize.php +++ b/lib/ImageResize.php @@ -213,11 +213,11 @@ public function imageCreateJpegfromExif($filename) $orientation = $exif['Orientation']; if ($orientation === 6 || $orientation === 5) { - $img = imagerotate($img, 270, null); + $img = imagerotate($img, 270, 0); } elseif ($orientation === 3 || $orientation === 4) { - $img = imagerotate($img, 180, null); + $img = imagerotate($img, 180, 0); } elseif ($orientation === 8 || $orientation === 7) { - $img = imagerotate($img, 90, null); + $img = imagerotate($img, 90, 0); } if ($orientation === 5 || $orientation === 4 || $orientation === 7) { From c98ce06e73ed0b26efeead5846ce888339ca47c8 Mon Sep 17 00:00:00 2001 From: Aditya Patadia Date: Mon, 21 Nov 2022 14:57:40 +0530 Subject: [PATCH 20/40] logo update --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 15056b0..8c37c96 100644 --- a/README.md +++ b/README.md @@ -380,4 +380,4 @@ Maintainer This library is maintained by Gumlet.com -[](https://www.gumlet.com) +[](https://www.gumlet.com) From f532ee4c7b901c27d6ee5520d3be1436cc693e80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Paczyn=CC=81ski?= Date: Sun, 25 Dec 2022 21:57:58 +0100 Subject: [PATCH 21/40] Round scaled values before integer conversion --- lib/ImageResize.php | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/ImageResize.php b/lib/ImageResize.php index 3c179f0..d016f1c 100644 --- a/lib/ImageResize.php +++ b/lib/ImageResize.php @@ -465,12 +465,12 @@ public function resizeToShortSide($max_short, $allow_enlarge = false) { if ($this->getSourceHeight() < $this->getSourceWidth()) { $ratio = $max_short / $this->getSourceHeight(); - $long = (int) ($this->getSourceWidth() * $ratio); + $long = (int) round($this->getSourceWidth() * $ratio); $this->resize($long, $max_short, $allow_enlarge); } else { $ratio = $max_short / $this->getSourceWidth(); - $long = (int) ($this->getSourceHeight() * $ratio); + $long = (int) round($this->getSourceHeight() * $ratio); $this->resize($max_short, $long, $allow_enlarge); } @@ -489,12 +489,12 @@ public function resizeToLongSide($max_long, $allow_enlarge = false) { if ($this->getSourceHeight() > $this->getSourceWidth()) { $ratio = $max_long / $this->getSourceHeight(); - $short = (int) ($this->getSourceWidth() * $ratio); + $short = (int) round($this->getSourceWidth() * $ratio); $this->resize($short, $max_long, $allow_enlarge); } else { $ratio = $max_long / $this->getSourceWidth(); - $short = (int) ($this->getSourceHeight() * $ratio); + $short = (int) round($this->getSourceHeight() * $ratio); $this->resize($max_long, $short, $allow_enlarge); } @@ -512,7 +512,7 @@ public function resizeToLongSide($max_long, $allow_enlarge = false) public function resizeToHeight($height, $allow_enlarge = false) { $ratio = $height / $this->getSourceHeight(); - $width = (int) ($this->getSourceWidth() * $ratio); + $width = (int) round($this->getSourceWidth() * $ratio); $this->resize($width, $height, $allow_enlarge); @@ -529,7 +529,7 @@ public function resizeToHeight($height, $allow_enlarge = false) public function resizeToWidth($width, $allow_enlarge = false) { $ratio = $width / $this->getSourceWidth(); - $height = (int) ($this->getSourceHeight() * $ratio); + $height = (int) round($this->getSourceHeight() * $ratio); $this->resize($width, $height, $allow_enlarge); @@ -552,11 +552,11 @@ public function resizeToBestFit($max_width, $max_height, $allow_enlarge = false) $ratio = $this->getSourceHeight() / $this->getSourceWidth(); $width = $max_width; - $height = (int) ($width * $ratio); + $height = (int) round($width * $ratio); if ($height > $max_height) { $height = $max_height; - $width = (int) ($height / $ratio); + $width = (int) round($height / $ratio); } return $this->resize($width, $height, $allow_enlarge); @@ -570,8 +570,8 @@ public function resizeToBestFit($max_width, $max_height, $allow_enlarge = false) */ public function scale($scale) { - $width = (int) ($this->getSourceWidth() * $scale / 100); - $height = (int) ($this->getSourceHeight() * $scale / 100); + $width = (int) round($this->getSourceWidth() * $scale / 100); + $height = (int) round($this->getSourceHeight() * $scale / 100); $this->resize($width, $height, true); @@ -642,7 +642,7 @@ public function crop($width, $height, $allow_enlarge = false, $position = self:: if ($ratio_dest < $ratio_source) { $this->resizeToHeight($height, $allow_enlarge); - $excess_width = (int) (($this->getDestWidth() - $width) * $this->getSourceWidth() / $this->getDestWidth()); + $excess_width = (int) round(($this->getDestWidth() - $width) * $this->getSourceWidth() / $this->getDestWidth()); $this->source_w = $this->getSourceWidth() - $excess_width; $this->source_x = $this->getCropPosition($excess_width, $position); @@ -651,7 +651,7 @@ public function crop($width, $height, $allow_enlarge = false, $position = self:: } else { $this->resizeToWidth($width, $allow_enlarge); - $excess_height = (int) (($this->getDestHeight() - $height) * $this->getSourceHeight() / $this->getDestHeight()); + $excess_height = (int) round(($this->getDestHeight() - $height) * $this->getSourceHeight() / $this->getDestHeight()); $this->source_h = $this->getSourceHeight() - $excess_height; $this->source_y = $this->getCropPosition($excess_height, $position); @@ -758,7 +758,7 @@ protected function getCropPosition($expectedSize, $position = self::CROPCENTER) $size = $expectedSize / 4; break; } - return (int) $size; + return (int) round($size); } /** From e3ea6e14a9312ae408c0c012e5b994a218a6fb3f Mon Sep 17 00:00:00 2001 From: Aditya Patadia Date: Wed, 11 Oct 2023 19:35:19 +0530 Subject: [PATCH 22/40] imageflip example updated --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8c37c96..9e487ed 100644 --- a/README.md +++ b/README.md @@ -352,7 +352,9 @@ Flips an image using a given mode and this method is only for PHP version 5.4. $flip = new ImageResize('image.png'); $image = imagecreatetruecolor(200, 100); -$flip->imageFlip($image, 0); +$image->addFilter(function ($image) { + imageflip($image, IMG_FLIP_HORIZONTAL); +}); ``` From 54165d97ebc3d4fc188761166b78e6702f605f59 Mon Sep 17 00:00:00 2001 From: Aditya Patadia Date: Wed, 11 Oct 2023 19:46:03 +0530 Subject: [PATCH 23/40] Update php-testing.yml --- .github/workflows/php-testing.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/php-testing.yml b/.github/workflows/php-testing.yml index 0ced5ec..9653053 100644 --- a/.github/workflows/php-testing.yml +++ b/.github/workflows/php-testing.yml @@ -8,12 +8,12 @@ jobs: strategy: fail-fast: false matrix: - operating-system: [ubuntu-20.04] - php-versions: ['7.2', '7.3', '7.4', '8.0', '8.1'] + operating-system: [ubuntu-22.04] + php-versions: ['7.2', '7.3', '7.4', '8.0', '8.1', '8.2'] name: PHP ${{ matrix.php-versions }} Test on ${{ matrix.operating-system }} steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Setup PHP uses: shivammathur/setup-php@v2 From d9fbaa2bbd4ea9abc36d1bd30eaa4369687cdfee Mon Sep 17 00:00:00 2001 From: Aditya Patadia Date: Wed, 23 Apr 2025 22:35:33 +0530 Subject: [PATCH 24/40] testing versions update --- .github/workflows/php-testing.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/php-testing.yml b/.github/workflows/php-testing.yml index 9653053..33781d9 100644 --- a/.github/workflows/php-testing.yml +++ b/.github/workflows/php-testing.yml @@ -8,8 +8,8 @@ jobs: strategy: fail-fast: false matrix: - operating-system: [ubuntu-22.04] - php-versions: ['7.2', '7.3', '7.4', '8.0', '8.1', '8.2'] + operating-system: [ubuntu-24.04] + php-versions: ['7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3', '8.4'] name: PHP ${{ matrix.php-versions }} Test on ${{ matrix.operating-system }} steps: - name: Checkout From 113437077da7c41b7a9b0eef60420495406e43b7 Mon Sep 17 00:00:00 2001 From: Aditya Patadia Date: Wed, 23 Apr 2025 23:20:26 +0530 Subject: [PATCH 25/40] os downgrade --- .github/workflows/php-testing.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/php-testing.yml b/.github/workflows/php-testing.yml index 33781d9..07b8f58 100644 --- a/.github/workflows/php-testing.yml +++ b/.github/workflows/php-testing.yml @@ -8,7 +8,7 @@ jobs: strategy: fail-fast: false matrix: - operating-system: [ubuntu-24.04] + operating-system: [ubuntu-22.04] php-versions: ['7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3', '8.4'] name: PHP ${{ matrix.php-versions }} Test on ${{ matrix.operating-system }} steps: From 64b7d41aed18cb145af6c8aa2a21b3e28f849700 Mon Sep 17 00:00:00 2001 From: Aditya Patadia Date: Thu, 24 Apr 2025 00:14:14 +0530 Subject: [PATCH 26/40] test image update --- test/ImageResizeTest.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/ImageResizeTest.php b/test/ImageResizeTest.php index 1647bc4..0ba1068 100644 --- a/test/ImageResizeTest.php +++ b/test/ImageResizeTest.php @@ -15,8 +15,8 @@ class ImageResizeTest extends TestCase ); private $unsupported_image = 'AAAKAAAAAAAAAAAAAQABABgAAF9SlQAAAAAAAAAAVFJVRVZJU0lPTi1YRklMRS4A'; - private $image_string = 'R0lGODlhAQABAIAAAAQCBP///yH5BAEAAAEALAAAAAABAAEAAAICRAEAOw=='; - private $data_url = 'data:image/gif;base64,R0lGODlhAQABAIAAAAQCBP///yH5BAEAAAEALAAAAAABAAEAAAICRAEAOw=='; + private $image_string = 'R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs='; + private $data_url = 'data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs='; /** @@ -435,14 +435,14 @@ public function testGetImageAsString() { $resize = ImageResize::createFromString(base64_decode($this->image_string)); $image = $resize->getImageAsString(); - $this->assertEquals(43, strlen($image)); + $this->assertEquals(35, strlen($image)); } public function testToString() { $resize = ImageResize::createFromString(base64_decode($this->image_string)); $image = (string)$resize; - $this->assertEquals(43, strlen($image)); + $this->assertEquals(35, strlen($image)); } From c3fd60a695bf9a5543870ac7ae87ec3ae5740e84 Mon Sep 17 00:00:00 2001 From: Aditya Patadia Date: Thu, 24 Apr 2025 00:41:20 +0530 Subject: [PATCH 27/40] avif support added --- README.md | 4 +- composer.json | 2 +- lib/ImageResize.php | 77 +++++++++++++++++---------------- test/ImageResizeTest.php | 10 +++++ test/ressources/test_avif.avif | Bin 0 -> 16781 bytes 5 files changed, 52 insertions(+), 41 deletions(-) create mode 100644 test/ressources/test_avif.avif diff --git a/README.md b/README.md index 9e487ed..344a097 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ If using [Composer](https://getcomposer.org/), in your `composer.json` file add: ```json { "require": { - "gumlet/php-image-resize": "2.0.*" + "gumlet/php-image-resize": "2.1.*" } } ``` @@ -31,7 +31,7 @@ If you are still using PHP 5.3, please install version ```1.7.0``` and if you ar WebP support is added with PHP `5.6.0` and current version of library supports that. If you are facing issues, please use `1.9.2` version of this library. -For PHP versions >= 7.2, `2.0.1` or above version of this library should be used. +For PHP versions >= 7.2 to 8.0, `2.0.x` or version of this library should be used. Otherwise: diff --git a/composer.json b/composer.json index 3e68112..9003297 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,7 @@ }], "require": { - "php": ">=5.6.0", + "php": ">=8.1.0", "ext-gd": "*", "ext-fileinfo": "*" }, diff --git a/lib/ImageResize.php b/lib/ImageResize.php index d016f1c..6065425 100644 --- a/lib/ImageResize.php +++ b/lib/ImageResize.php @@ -22,6 +22,7 @@ class ImageResize public $quality_jpg = 85; public $quality_webp = 85; + public $quality_avif = 60; public $quality_png = 6; public $quality_truecolor = true; public $gamma_correct = false; @@ -102,50 +103,28 @@ protected function applyFilter($image, $filterType = IMG_FILTER_NEGATE) */ public function __construct($filename) { - if (!defined('IMAGETYPE_WEBP')) { - define('IMAGETYPE_WEBP', 18); - } - - if (!defined('IMAGETYPE_BMP')) { - define('IMAGETYPE_BMP', 6); - } - if ($filename === null || empty($filename) || (substr($filename, 0, 5) !== 'data:' && !is_file($filename))) { throw new ImageResizeException('File does not exist'); } $finfo = finfo_open(FILEINFO_MIME_TYPE); - $checkWebp = false; - if (strstr(finfo_file($finfo, $filename), 'image') === false) { - if (version_compare(PHP_VERSION, '7.0.0', '<=') && strstr(file_get_contents($filename), 'WEBPVP8') !== false) { - $checkWebp = true; - $this->source_type = IMAGETYPE_WEBP; - } else { - throw new ImageResizeException('Unsupported file type'); - } - } elseif(strstr(finfo_file($finfo, $filename), 'image/webp') !== false) { - $checkWebp = true; - $this->source_type = IMAGETYPE_WEBP; - } if (!$image_info = getimagesize($filename, $this->source_info)) { $image_info = getimagesize($filename); } - if (!$checkWebp) { - if (!$image_info) { - if (strstr(finfo_file($finfo, $filename), 'image') !== false) { - throw new ImageResizeException('Unsupported image type'); - } - - throw new ImageResizeException('Could not read file'); + if (!$image_info) { + if (strstr(finfo_file($finfo, $filename), 'image') !== false) { + throw new ImageResizeException('Unsupported image type'); } - $this->original_w = $image_info[0]; - $this->original_h = $image_info[1]; - $this->source_type = $image_info[2]; + throw new ImageResizeException('Could not read file'); } + $this->original_w = $image_info[0]; + $this->original_h = $image_info[1]; + $this->source_type = $image_info[2]; + switch ($this->source_type) { case IMAGETYPE_GIF: $this->source_image = imagecreatefromgif($filename); @@ -171,10 +150,14 @@ public function __construct($filename) break; + case IMAGETYPE_AVIF: + $this->source_image = imagecreatefromavif($filename); + $this->original_w = imagesx($this->source_image); + $this->original_h = imagesy($this->source_image); + + break; + case IMAGETYPE_BMP: - if (version_compare(PHP_VERSION, '7.2.0', '<')) { - throw new ImageResizeException('For bmp support PHP >= 7.2.0 is required'); - } $this->source_image = imagecreatefrombmp($filename); break; @@ -269,9 +252,22 @@ public function save($filename, $image_type = null, $quality = null, $permission break; case IMAGETYPE_WEBP: - if (version_compare(PHP_VERSION, '5.5.0', '<')) { - throw new ImageResizeException('For WebP support PHP >= 5.5.0 is required'); + if( !empty($exact_size) && is_array($exact_size) ){ + $dest_image = imagecreatetruecolor($exact_size[0], $exact_size[1]); + $background = imagecolorallocate($dest_image, 255, 255, 255); + imagefilledrectangle($dest_image, 0, 0, $exact_size[0], $exact_size[1], $background); + } else{ + $dest_image = imagecreatetruecolor($this->getDestWidth(), $this->getDestHeight()); + $background = imagecolorallocate($dest_image, 255, 255, 255); + imagefilledrectangle($dest_image, 0, 0, $this->getDestWidth(), $this->getDestHeight(), $background); } + + imagealphablending($dest_image, false); + imagesavealpha($dest_image, true); + + break; + + case IMAGETYPE_AVIF: if( !empty($exact_size) && is_array($exact_size) ){ $dest_image = imagecreatetruecolor($exact_size[0], $exact_size[1]); $background = imagecolorallocate($dest_image, 255, 255, 255); @@ -378,9 +374,6 @@ public function save($filename, $image_type = null, $quality = null, $permission break; case IMAGETYPE_WEBP: - if (version_compare(PHP_VERSION, '5.5.0', '<')) { - throw new ImageResizeException('For WebP support PHP >= 5.5.0 is required'); - } if ($quality === null) { $quality = $this->quality_webp; } @@ -388,6 +381,14 @@ public function save($filename, $image_type = null, $quality = null, $permission imagewebp($dest_image, $filename, $quality); break; + case IMAGETYPE_AVIF: + if ($quality === null) { + $quality = $this->quality_avif; + } + + imageavif($dest_image, $filename, $quality); + break; + case IMAGETYPE_PNG: if ($quality === null || $quality > 9) { $quality = $this->quality_png; diff --git a/test/ImageResizeTest.php b/test/ImageResizeTest.php index 0ba1068..9f83f10 100644 --- a/test/ImageResizeTest.php +++ b/test/ImageResizeTest.php @@ -68,6 +68,16 @@ public function testLoadWebp() $this->assertInstanceOf('\Gumlet\ImageResize', $resize); } + public function testLoadAvif() + { + $image = __DIR__ . '/ressources/test_avif.avif'; + $resize = new ImageResize($image); + + $this->assertEquals(100, $resize->original_w); + $this->assertEquals(IMAGETYPE_AVIF, $resize->source_type); + $this->assertInstanceOf('\Gumlet\ImageResize', $resize); + } + public function testLoadBmp() { $image = __DIR__ . '/ressources/test_bmp.bmp'; diff --git a/test/ressources/test_avif.avif b/test/ressources/test_avif.avif new file mode 100644 index 0000000000000000000000000000000000000000..4255c0b1a422092ceb6189c6c3660d9b63549fba GIT binary patch literal 16781 zcmb`vV~{4>5-$9<&1u`VZQGo-ZJX1!r)}Hrp0>?t+qUk^-si-*KkoPM%ZRFc@~K=| zS!-ofR76!4006)-b@s3~aJ4W6{E@%f#=?}*#=_u_4Z>h!;%xAj|09Iv#@3GiLIA+t z!pQl*_`e$7-on}D9|P#mp2fo2&gictA^-pe{ABR21ZWy zf(i;Uf6w&)mdB-kGoGjY8|(k=^Z&_08=E-&os;)Jo34?)Cd$RP5i+EX8#v9{J-#j&ils&0Aj@S zSN;Dh&L-~vl!K%O0PuHC|Be2?x%wXmg7zl`=09su_&?4r|IgAt{NdyN#~G#r04*T^ z0LI$?IFeid03jFvXr4B5adiF96=40*<3OVzMqmk$Rxpo<{HTi9EQB|daZDK831VQ1 zZaNoM_MTwjbs6537Ck=mzfKswzW$6sv2e0C`A-bvKU(O|hG=i$Zt<4`frNzoqtGqv zZ4Ca}e*_2s1R4Mg0{RDHSvZ>fTc!X2ypi#rCH-6Ae~Oe((8k!n85sZ##erGZX8;5T zAYeN4{8Mim(rE&?dv99buabkYqdgWarLCv7AJcFB@l7i0?{O!&5OO1W40vh<^?2rj z``wFtP0x4;V)#pm4imHZ8_EXg?RU~B+Ts@BaimowRSZ$De;o0evMM@ciYfw;eG4R6 zS4>Jx;%>!k@`pV65U*?*Py)6KwN)Q3>w$q#Ga*-RSMYL$4&jdp$7 zZqi&uncnngtesj)Yfg(AQTUbSW(#S&V)-cH^NXB3BrpsGLE!k)?M&DaOKQ zUJTb}p6O<=G9pWmR+xP71nVdd%d5 z^+clicfEjG=4ZO66B!(Mmf8rHAi?{t#@J{d{z$PoS(7eE6S$8;NIQ%BC0Gc zk1jefCMtmwA#ZnzJ10gB-;*dLbmG-lwA!TGzb-(i`4uNqVoDC0RVzL8tsE0w8sXG& zBQDHWgLb+(;S)(;e$9Bz18=?{rLm=1pS1Iiv?N+SliFwO@f9t=BP%JS0(X3)SN!po zSU~mk7wKw#r+;eg1&*_>&0K;2*`x-^&T3XaD!5>Q2HGi;Q4CYhzMf1oB81u%4qbgxtA#M(~1VevCt;lDxL;#VmLZ?AQpiii;fnt5gtp=DV#q2VmO#`t zJ~aVYdv`=6N*QjGa2@&59~0@){WN);`&t#^3xfrZH()i4#7O}~!#Px~JSd#>r(S#LKJUwq9}^5+Vi&OC_FS&&Fq;7nXJq?(`E7b&IHa zZbkp3g|Rp+{AdN^TfigxnWN(v9hD_!+~h3%5O6Fsa__}LthZaMHd4Gd$!ziB-V`KGwoWmp&2gH45UY=teDO zo~=yZgh{T((ffEv;ol@+gS4xdv$otU?`J!jU5Bmj2|`< zc^fxMJiGJ{l7_n;K_k=Th^e;xe>}eLN+y4=ILIeEIo60MD|Dv`p4R{miNqJ1`^7nf zfcw>YgWu#~^NI)0olJC;j0*U2pyXLYXL}tJP4uoELJ(j)(0o|Kd9YhwMehS^!xG1! z&*UktW3>ev72=OwJPZF$LR3j#|HGGZtVUjVn;ix;oW?oDClUM_OgV{*@-VdWYHBn< zqzQ1wnAyn}*h)!k(Nj2K&n3RN6aakBg-a+NMqxDJwB2}(t>U?n#6xf-RdaU@Oh-Zc zk(Laa?j{6#`;-Cvns&M+%>E3c2xDKRT7Fv-Leh1rhQZ!*akg9Om9aumweCPH_WVFD zQdI$c!)%iF?C?@uHP=jvKYWGA(adE=j}(Vq^n>a1?s-xhxR_WI^IO=PrA#5LoEv62 z{)BLoiv49(Bke@pMZO)oI4kc>Zq5J|W|@2Z!-nW+D~b!TPFvR83?%$F(H{Xqg@}ft zZBb00x4C1P?P`MAC}hC4=`JpM(_R5gsut4(Wri?~#rNfj)=icTy$dn`$WGTe>HYeh zYlC5Pqham979@8I@o<@5h9A)@WO0GvHKNF?Q?vd2QOh}aS)Si48eB?&z7BeH#^kA! zQcOiz4`sU`3H&3+yuBUzpME_$>o@E*TZrTOF@}E?unOI-#jjHj2!wh~F*91iN)ufvk)blDg~T8#!2DsDa3^D}s3 zihM`R5gzffwPR&xIy=nNTzlXz0bMnhK=#}fBY5N3H&SQ<&$D~cp|$9>_EmetdG~tK z%S5Cl7vNUVj0WwuSWe5&91#k7@DlMRe*`L9jL_UimqjQzw0=>ZW{4FpOT4qizW7#> zQd`H@DyLyJ9^x4X=TM0CvF7C3D3W3?-!E}Oj8|9;(_NUG_^V?rBE@}Jc2xg+EGErb zn-{aQ(gK<>cBSVa#wkRYpL+=5+sn|MbT}C-Mas|cn`frZ-lU|TTMKh`^+;BVLQ2i@ zsNZt5P<3s_fi@_0E`&Lvairvzs~D->rNTMYPR4JqArXZQjh>NymC)@W72wdDDr48* z@&kc;7!p>jgyN}Eq`Gjd)jPKapT@3gDk~zlR$-DiO9Q)9p2`B z<4cwzoXTQZ-3A%!{t(A;r>}o*vnKRt2b9nZ&W(|FsXwUWL}}$g?f^zi+p&=`nL!)V zUzXXbg9G+w>NAWmt=6*jtx~?mLN9kel~*OZ&@%nw4+>tntEv<$69~|ka?QX;I@$7a zy?m6ppLUm5%_k6Z#I?49;D_58)_`wYOku8yTt&I%QBgq`8wlRM6ecMfn+(?^psOl3 z_Uc6appr$wxM{9i6tNKP0&{)xIu26?18{QtqE)U}o37dcmG@EKM7MrDupRde8e&&P z58v>X^GFuabB3zHe?`-2{JI}(B;V`AayOtnEw>@g_fG%92cFrkh1eQ69)v19iNimhfg4`Wstjy*pWd%Ql^D+;2~QKS7xG9sVub~~u< zKKQX1_PcfIJ=V@1*c_)-+-)0*96W>xT-x)S@tbh9W$_L5%{d)23E!bNF?>yi z`T$hB%%a-;s_(V|MpNg|qxKco*M3V{RSx-Y#;m4QWL}6`#Ld^S^B*;_uOX^+8Z~=( zvTFB|RZsBKS=4l>m%mFKgK;G%JGmzZvQ`_ux~tER}UxGq2j>r)D8G%ifG>k4$uGA zNoBXD8g!r2%LdA*y+y1=w}vn&iV)8Fm72i;T)`wiP>a~|P@bdPF*Do@!&OiyrsQSm zVS-$szQ%;W-!FnP|7fXMU>!3H3&tGX)<3%Ql_6%W7DRIUaE+8n?$j8Ly~s!!6=&yG zlNWG6Tw%y`N4@C5toMR5b2_-s?IV3j+Z(zv(OomMgUic{DWB>43sA-fY|6ETF8vF4 z0ji7a?G{FEM{%5>$|aL$sUmmJYdd>@(^K4M_;Xs7io8K>%6+`A=xN#b3{7ALL@0-o z-MNxkc{WgEmsE!Uy+fGo)>Pk=R}h@K;`xEbP{wZTcHJT_Vq^ zR9KUlq2w(lk&W_Tm(jkwn+ZiOv}OXaaxa68m!09g`=vgiE z9M*iqo6?;MUssAw*D+MQ-Ge9uCA=A-Iz|`89fADHYI2y~&^I6`gt^&r`EyIBTlL52 zeq~-gQS53|uDgSM9z&B3<=)Fin(=ke=Xfi1I^v33z@SPcJN&N`Bw;E0n?WW)ntDwA zZuB|o`wfb9pf0Y9N2XGt@|RQKk_H8-91n$P=cvcI%z3Y|szdkYukCnQ7ZiQx&h|fn z_CbUzAT^?^s}Q(NL}8>!rSe`KSf+;ZGjHj!vsQJ&zcISsWH)j)T<3Sh-e^a$Ehh_IUo5~g}pqK3KDNnrXy;trw_+dbw zJrOBE9nK(A+NwoD^5Z2MpF);*V$$re&5>es8em%bu#64&xU2A)Vp47va4z;$&?e`k zJOTdAyP>;6D}hYZZDv5Vh-y$$3F(unWmWF$BbcjmZu8{+CVXeuB#dh{l&EecV}d(@ zN9q?AR4)BoutGyaorulWk4mXj428|70BHR=t#*>6pmpo^gja3kIRP0VB?MZE61O$`7xlg|rI_-v4GC)B;UrO{fJo%= z)eZ{g>o8m=x6-ej%?_Se9HX9qG21amib5>(&w@pm6piUvB?UY&Gb0 zPn0l$ZPWY%;%anna#UQ2vs+Bf?R`Q>k!Dz9DaK2!rRs;r|& zb+y$C7z#agd+0+Q9Y=5@L8pAYl5mlV`B6zJ_%J4cyU8P zJCwqjW2w#g{<(Sd4RHf0OG+H4HTiIbuE!xN#c0MFv`JQcyjLq0O}``y@_sC)f5fvR z?a^PA#I)cO7GCMC97DqFf0aU}H&;&X+TspcJj(@PA64tR?Lpc=)!S$&dz4$Xc@orvFG`?9^#6aXKLQP=sIi?vd6U-V&X3Ys%-G+IgZF$DX-+C=T?eu8>5Ek zXSD5}$rzo6C`1O4f*ne6%8*RUTG>-GTMEHOTx)i4Z>l!_3h=q0+Yl)qSU%chDTF-v zZ}XnHzPr*$ga9g14Oq$8k zsl_Nd-r(m%h24o=`qft53AeQ%U}i!cu(kqBYrfZy!wP0h_Y|AJygZdbwoO%ohc~3| zB^HB|y6_ujU`TelvAbuzc%v2Fa0l!Lu#$5s$?BNHy&U6yuZ=d&oDmjts6l_&G)d3w zIQ!7P{X?Kbc8xjKJ2r$_*k@e)?2_La+bZVa+#lVAB9ekyCR! zwTtiC`knYX^0h|hs6J4aHtRY|E`ZhH_)r;YbMAii`)F=jwmcjZP=F!YFAu?88+M)S zkoWRDG9lEUHx3+HcmG$M*nDwG8f|zLU54APuRm27yM|d`+3q*8*w-gkWluPFEY`z$ z*pg1zc%o+8YftnYSB6mD#QI=^?1*aXQ4yz-{qt$eC;DWS60wn=-o5Jp4BQqS*GtfVeO+(C zOu<3r86I$H`f2w|HFRSTu?}=e^nBkS%8wHl>NFVSVk9Sp_~S9fL1~Mr=*=>4Wy8n8 zE|NyX!zzUEjY^l}L#vwlC}ElTv3oTwSU90@JtQaBw`IgDwf(!BP`uPVXy@d`Rw>zn zz?1N8_0RlW75ERdO#{o5b(|z@J~w}qyJ9J5qo9Q3MW&4H>Y3U*Wa?HA6rI{65jIGu zUaEF ze)&vF;e0sTTKA5sbs3K;L_C@F7?WLS3WYKB9WT9RJJ6pjH5=Nao8&5PbzBT@Ln{}Z zS%O9`KilTOLkBM&C7`7$pV%+Z^ksg7b96pXl0Ew zCUox|a=|(~Byq~f0E=ofJ#hqd-VzOuA=hcSOW_hq{N|mJwEZ5Q8D-SsqR)4(i6?e* z)lBoDtJ|CLr57vWTSWA5)I|p?^pchRT8Akj9v64wqxWS<{Aq5Awf>&NeE;Gt z7WOcPo9Ny>tYcUy;&p|BjZemA01ko)wlWfM9a-tNXGuf63_FuXV}LfL2@ErZNVgQb z)~bWdLzHLgue3_+Un3(q~PmeO|`zS-)-O})6 zzjY1q;K*2`F^`3GT~aYvnS*?JsI_;+^|yXzALV?;E23P$SApSxc{c0A1>To~aXWc= z*jcl_g7@c~R9fm&i#mK^Y4h5bRbA3*6s*vGwS(#KqY?t2Y?v}}+wn(w`l$6;X@vm4 zPRzg1MkXKneHS%YN`H5~1m|;-9rfSvBvmK`bM1=o_w^YV_b*4FVx3E5eBxgRI~h)% zLaW&@=+S%DV1e^aJlb!40}L#!7RH8fE@k{=^3Pl{2SC>1(DAfcc@SgwX)Nl1m}Q%d z4T3`;EF~WIzgP3@-Q-I1{2XxnDY9BK$e9h}zhslTqSAaDA1n)dGLfTYX%3#f5F5@d zVXiOz_3E7T~O;1*DR}M6CoNCgXON6LA!0U*v5=3K|-Ecf_g(j(r)}7gY#Z z3q?6zlo*)Rl~(j9QA&>nsGmcGm}$IjQ;d0w9p3eLCGi!<5N6hKoJD+M04~LB(`JXl zGqH+)LD^kqN-~~!;WeGkSmXDz6$Een4Rk?p4aDMQ>p4V z!6~Ng414{V;cz5d-MVhnP^(SLAE1J}c*+|Yni-5K1FYN`dF@edqz@6-uuLyl%64)M z{HH9OkD6}>pSK2rd0|gbL9Y}cxm=YWYV(QqkMZ9vv7)+HTZVVAMtI*LF~7+(nzn=S zY#~~c>gP-Yve#2qMRPsqoH<;-cUX*9@R)?hqUJ;JOWLM`$yxn!TYc zzPS;=@9uMrLHZ$40_!&|E+g$J6o`d)^V~;SF_PAJ zHWt)2V$2xkX47+a3cgg-!Z}C8pVEZLKb~s%@=v_(%znFW%LQ% z62tBXv5>NBn=x7K7OLEC(-H9w^`ZZaMZ^O8skVh)nJNme^yE2{Wfde<6KEhfN_UN& z@qOio1LGJtQk{Z8%pIyocl!FsDVU1?rqGr9J%Y3y^uzveeURgK9c%4RN<}HgzE*AN zUMs_%7!6P${JY5aAqdoLGgzI;h${!BM~_a7s&M01flM~m$rP+;UX?Q2#m$gQ85$L3 zGcU8qux5!K1Da=>HFfWd0o;-mqtj~`%?Uc?coI6{Xom}`;gF+GoW1@<1Rs8>=3gH3 zXHS*YjKJx+=t!t^h3lW)MZvKf37TLfzH#?rb*wLy>1Gf@m*m z^QPDQI=g9M%N9AexU`0F*U}A2Rnt@DmHvIfDiz5_W6(ykZt-ihlNjsyKZJc z%gLVe&a;0Cf`XWcjWC$g3k7f7%uuRi^~KF{jBvP>$s36%Z9)e_?|MDO+&4y2;55fT zN7_qhb|}6saAAr5r0W{kE||-{so(Y1+c2Q?$S(j*5t#O~Xhm@Oehc?Jv0Ddrc96>e zrN2#W1q|(Vka4-hov{pZ4X=&1`^t;@m>ofA7NGzw2sJU zvHIP3PAklbha!X=d+jY<3=xr5VdX)C8R-bx;MKRml71r|D9YTO^1i%v%*PJ|P)$0b z0v`5#w}2!l)~E3CO+ z^TkF25&gX6Yr-fp?Rtc+dfJybcyBOptD61MtmEUD0#*&Br|7EfxHRu?0)zQ0R>~i4 z1_g9hl7lk3q~*et&PPZQIe7xm<1M}NBExop5UWw0q(G`yA%^Ky>|T-~)d6E9?S^As zPHabPB_HZaBLw2OAdFXA*G9K2%dcHL9k#G&NcdZ)6S9vbFiSQ7=-FHs-FYPV9v@#Q zJkM3f_G9CR@sn0Y3|tK=yb9b0jElh6IX*~LFrBl+j?|eZbwYpT(7xpN_Bq=tId+CK?FhZK7h22*^bv(-( z2)Rshf&8Hj{C%$Ekl8W_fhKuF_v_x}r3S@h^xm`F8z&^HU1;9M>fQU93oSO)?|QYd z1Yd14ajjOLwK|$+dO@|oOjPtqRvV)i@+h?*mtRcyaCy0|KNO`+FxtP_mwtX<)tjAZ zjy%jU|L_DoAgp%Kk<+56n_TS~;~wTvqX~BiabMJ3+M9?K$oa(JIDJZi?6V!MqNpV2 zPn^xN`L;e}8(E;yuq?(zi47KVjJ3|nu9{#YLvp=aN_G|N$YxM8@yx<{2n83HC0&fV zNxDO$xD*EJPVm;fd1s(NI5~|MEf|yE?)K8=h*e2c%Cg^2pf|~Z$KaTJ0l)jR{4uNL z!lr!iTpB#DcfxjU6uu~F8ax*ROj&nXKQW$v^H(Msu;-&=if3Xe%GY=Qj$N!W`#UUl zVyvO4st;VSO0U7MAugQwK#UO`*E^|b>9=91Q{FnS{BKxs)%r~i&R*Dk+=JfdPJS}` zUUrQ9hoQmFejjU0V@R*%zpWH#kyRCQJBkr@UWD}efNft_EUV7@B?Q)iJHA{$Inux@ zQoH!eVD@>tuyD`X)1niyK8JrhtwhN-8?Z^q!Q%4fJGL-^?Je-Auw(i;X3QQKLVqxZ zsL6V~eRpMS*b<#Wcl6J3MKt@v;ZC8TFAA>2NV8P0x_L&z@Z?hqW~ zaNhvhWDG?7>C#KP9JB3?Ou=~zVUeJ4=@OxsrA&8AQT9urz9K_Hc~fuUtXM0UJVeoi zW+ic*(BPHZvIFB8*xey}(l`Aol4QmwT||F7C)@^-ru(o;yacFcE}kzsR0Ifr<`>f< zpaSlSLWo-q%pLS8Te!n-gupr{`poN@mLvp^qnBC=gQa+I1I~t)E$#PDa6kC6@qCn6 zqTPFjxd$WRSYNb{4awoRol|5u7MeG_Y+=HCch9`xX?CT8%aSaIA^3bYEGYB|T3y+g z)4{&|UcYthZjA?fJ#O!jZ7YiMUPs&*%@-CAm=2hz1or#6zs}mt8 zp&@OKGb+KG0Mn`C0ohC&=x}5o4gRc0+-+&|phwWNrg&J2Gk!*{NsU zo}N^HKrBHzBzVgp<`*-HPS^k;n^Gdxlfs(y76|MFnS#pf<^HDhRR^DvTKjhs{Vnx- z+bQ3|X*N?b?Q977rr=iSTffN~It?+P0DA=?5y*5;d=qEn;sYIV=>DNgq#jM2m1eac z7tF%DxdnC+Jza%U-NjJ?E2CJ3RUGi_m<=&SG$Qt|Et|QBsx(fdc`$QX=Fqp2K#A{n?HJd_ zp1eBQd6UrtuIV+O73^EAnoN!`i`igK&r!weKMJN<0o=5p(E#2q416RRXSDJoglZLr zA|sO&-vO*^lb>+SgTANB`kiH*Pt2O&j|xLWAYvaHw~sgk@1{GO7`+9yH|UK@g&x;n zv;o#6k?Ks;H%nKM6*UfAX;C7K&5=BU8uQTmvVLfI#0x`wNlaKOLYMcU_N??bjrrv!-{Pg$CU`bbsZX%62hh!vl=bMe(`z4g zGB-MhRu}r%a|F%A@~0n{f2=>KFcZ}lC8py5m7tdw-q~^Uf~3)Y`IF~X^xAR1s!~ul zD#vxNSdb1hszR424%?V9$C>@iEhIan@&u}K()$z?>K&@60hRVM^YmiasIMV}wT}W{ z`a#J|2z@dj(M(N1?aav@KN$()?_LnFx%QGgZ84Mbh*cWId&SMOu$1R;SkEnUekIr0 zD0y$~P7C^C;w}AMqH&pPp}Xe^`%q zw82E%xXd?iuP!8gVC7CtKu3!d7e^^86xC^?GQBH)@zI&V$vtzddTGC!yh{)2;&H2e zyqw3fE{4F}J<5(?Y=gF~ue5l}i786l!uB6gHde}-d7z#xVWKaP6p`w>Dv)o0a z;Ld{dTk#g?3KnlWm}di#b|FJtf&Soe=VOWPM7nQRU3^o-5XmLJlin+w3n9T+&SJNT zqB;Z#Qi)~=lDCjfWm{*YWc5$cV_0FnU6t18rJ0FpEtwrTuF<-VVFq*)n;BT#;N8NA zzwmOn8s z>CrL(Gah&7qT5s>Lsjw0CUp7a42y8QpPIl1SBv*{oQ)n_zY;mELSLrHT?-Caogsv+ zZlVVwc7xJ8Q9e_c`#2aZ!-W|G8(e|za6(@{*CW4e31sqrc+s|Li$y^c6C zt4?FukklC)7T)BQN_#Y8-c=r9?|1Z!G{~{878JU3?Xa|tiQcoTpwQ)me+8aGTVDik zF=YFkj^~hdV?g-@yh}B^EYpF++J6=`hiYXhVdt(&x1ZkoRmPTQ9)zS+4-E0EiG9g9 zr2vskkdv0Jrc*(jAJ6iIvEB-QP4&#%r^*V0i{PF}1_o=!a8CF%AKV9Rk$X&s{Nqx1 z`g0i!lQMDDz|CsEI_YPIsVdrSS8TpFlAo^bKn0j=U0 zr4iAItHbXuqEE2W-2N1t0d{0i!LlpBp zIj+}>9W0eS0@7_Qx5_7J^W>qH8eG{MTm@~SX~vJ49Czd<)|50BY3!A9 zbKZB{qvW3m;-HEiJ_{b5Z3Z%k2d0gmiTX!JU_Qk0ZoFaB_$% zil5-GZ4b<^8v3R;(AB8o9Z=7(!oQfafSNi*CkdZZjM{MVnkgk%!3!;#*@sHkF29gj z^`WgLt`uk@5UCMd`-3AxJ|K|$L>E~_J7uBr^{zCGhZ>tv7zQ%IgKc&qck(Q@>KkgR zg_ioVs=wyBXRN@@lqJKT^5qPoqEU&+4)k|Zr4NXqETU};2b zsAeN`7^Gi?l7BKCf=`h#E(*LYp97qasJ%eESF z8+^KjvjExSnTz^QBungmFR!3G9AzH|J-nu*2bCwnkkWm**KadE+^vbPw-l>xR9nk) zcJYRvcZO_QzvFIjy1gsRI-8|r>F?RPS}a`-5KQ}hH_})5VY|mQpRsu2n7^2J(KkoJ1!>wU<_iejpst zn=67VPe@?;IQ-j13dB8{DM4UEBcC~kcZm5X{`m)aOHnxzQ9#woydL<%UFnu3i(}^B zuRPpCBB?^rSr$ajtwfR&=%Vmwi*oGgd+@C|W9sW&%Ch}j(0Pbb8`mP!xWPcI&D4O6 zgX|G0s`7~yO|Z~L9vt+*Rn3B5RgDuXNVmUIpQmLBR=pUMaKCfXx9gR(!hZSK1eY`0 zzAk7S|tZ9`R|%|1y&{c`Yz`LHwTF28!t8KFaqhbJ{< zK8hbsjIQylez-#p{DQkgiotI~iEQ~aTJpnLlctTynC#jqNF=j^g$(#SXnWgK*Eija zw|vKag8D7^{qmgOCfC?Hhw~`Yx#a%6Oj!22BDjcX!cFV%!_zlBTCcq-D!hJ=?yw(H zx4MZJM=&#d$m!3pG?FB#B1`gR!~CBxLuHR9^4XiGd9_5Ojfy47K*;( z5r8O6n~iDrY5~~r?l!IPK|?5ID2_FpDZ0?7Vjq^!@8<~JREQCS3nbjXU0VH4#CFqq zgoc|UfkpOj3P^oAR56o+P^opa{oYpZ3x9o>u)5I&@~H8odPE^0YOFnMZ<#_`KP(}^ zU^FTOM{HknZ1OkNM+dM1g=S(6n+#j4W!zg1ZY{rpVX2l^-m&UD>5uomAwb`J8JA36 z7A3VTwf`ij)Yg+uHO+9dkLt9uCnvkqFE72}Ko=%!;`**EU3kwSllKnYDnxdcG%e^I zOZt6*w6Kt32^}2a!G;cNYGkI3wSrrdy{=k5x*`o!@LShZLxeb4586DY*i!d)S-0hg z!2Bafg1tP@B%W_Ot1D*^-*&u-G#w_zoGe?l4(&rw---Hl0Sw~R$WlqxP5Dq1$v7}> z?ECHJ_i4D=D9ntRpWTm>S|#UoUzx^Bt1>_i@qv+b@_~_iwR@2vuxZ3*U-QU6Ook76 z+{<({Km{&uBo3Y7%wi=Lmx-q-aX*W8L;P84g-yGxsC(X?=C8oJ$XLZFJzzGr8cK~|Efu+*if6ssu9O}2WvU)XZf7&(F=dSx&bfu_Dw}13 zsR&&J0vzprC|iIj#}n|b7@qkG8CF&uugDV)tC7^%W%^hy4-_ohLcfVn&JRcp270A* zb;|;HseuAHVOty&J#1!&QVe`VoQw+}Xu4kK3Ilwo$e={cVY zcFbq+gVA3b^BHU39_DXoGPS$>l*U^@^#y8Ugpz+Zh0+o zH&J{#5+-=p+vDZwIH|C5{+xvgNzR3Q^P=vmq}3m*b(yMyE$SvoP#ms%=u-nRwkyXn zA6VcfOw2#ze(#&6$U7b>pqdMwo9qKII?3~4cb73|1xVk`(e`&2D#9uyhLRTg8pQbE zJ(nl21}TjUpV|OiNLo&WPO|2fnG9=lH88J)H$9 zL+`Q7KpwMfGt#4{_WWp0c`8JDNZ^p!`7p zk{CU7iG5zORd5nh&MOX5=PyzvZ^!3?^=kylAi2+FpL8kxlzSK0T*K2CtA`*LR8x#x z56|g^a20Pf$Z=xphMs6Y#2IOqfL(jA3-stpF)^oNMF z{SGCXt{_;7T!hB;>8ua;i-|i5O}>sE-`Gj7iV@g3eb*QT@MP+jxR=*Hwkp5cB>+ux z`&{@qS0VeES7BUE#Iv{kQoAyFL22J>^${bqOt2da?g&q1Mf>T1EXi2Q%r;?$mo5XEcN%;w8&(_r9m6+Iv8D6cns;kKi?+74LD)PJL5Bgy zm=`AOxlXizgcbYr6(exuc7xu}7!mqqfBAvQYvo%%?{sL>DF{b^+V}?<{YvDi(39uz zM=3QmExWTFctM+joUDdli3p3}bxia2v{ z(hLQ(4!@wo%itF*NdCM2}Y}@Dn{;KptZ*-cAl>Up(kt zj^P^+t^^vuS_xJSH5+2BH52$v3#j+=65j1&cSeOlb!#>5T#N<_Kd`rrZaGw4OR= zYo`WHLN1r!gmdpWT_d>KMSwsj6I1zGu7xXY#~)fNxhin$`kow50c<31_avVAVMAUE z8Vt$6Fq^NV#IQDUB6QrLEqxQ;NyC!5%3fDheUn1_y#_ai-wsHLZU3;J=nkAtknmud z=F_Y9)5qJS24@~iu|EH(gfJ%K*WAupuSaGXm;?&Kz5d?5(!#x4I$ z3^J7BWP1Wi6-cx*jEm|W(O#`Wv?963wp_;g%TzLfP}jAUA&gzP6xQVL);Z8zqI5SX1l1H(#Oh zqZDgl^St5hkw!=XOVk7rX;%k)Ba~C>?}qIVeKD-WhPp1Ckh*T0fjmoBzvp&WXMb^oXys*{`v2(n>1{oX`Kb0EI1m|Ina~6FrW= zHX#B|n#~S%F%2$Z!D2AL-<0t{*g4F@2SM(#ETMMCpgp2+`fLe=X34W%!z0P%K3=gb z+9Yi{g;ODh!`SHl$57mrA$_*SEq3GSxvyq#Z3-r~C2(4O z2cg``gbErc#bgL34$eu}5F(h_obNu6z9PBF?<;YfwTlK#-QSU*zpASgsTJ9 zv#mk}I#HU2y}$AnnbXF~l+eF=9Vgwc@j8=oo~b0>z8q1KYBO&kX`Ydxv)UYKDGRe) zVOI&q36whcda64+L|Qap3~dwYS>a4@P0A)% zd&yFz<+i|jZpO=HlCBGAT3{`r)pCbRV_8(%YqNqf_?>YTZg?+CQcVmR5ZE-M18s=h3qAYPzfI3n zMzi5+8fyRDg>6ituF{&@v~3M`Bjs*`N$sYkd^?ACG zeSLmXE1~cD6giPJSsS+Ri1FrkdpOW4K$>>1^NckViwDYsGfIH>rihz3ST`D_vH2ca6TQcE zq%*!C+g)z3&#Bf=;?y81q~amZ9O6;LWrsC{(!u`D-}X;&ruW3B!_ftvR0sjn^0pf( zAO|MRWg{SdU`4W6?^WEUwan!+v&(KF@Wd=e3X2RR2~msweaSZ+1PhRSc?s+pcCQwq1kSQ0@Od4eznqh#`)>eAZ3f<_T4sN``)-6vnBx)sgN zc(H$M3Yt4Q&pdfw15ZPEI{(m%jIc{TG?w`QZXhMfWH(6Wff5&S3JIdoFhRlOd{2cf!86QV zZ<>#w47HM4ni_@!jtEgpIm}(GU4iVOmB<~wdQT0D>i+SKJAyj1IEBPKdeZB2>?chs znyTXBnhIvaacJ+rJxQo95AK|!)(PQWwklXZ#o#S2JTP~gR~2iq!m9a*f1A62C&_`HZnb|) z@*%$biNZj+#%`F-KFilT6VPJNOmAI2kD^Z_tX^@sX168K1}3Z2+C{fEF%x3=349%^ zaLeqA5yT(b#ju-v^9x6Od6~xt;(^=JH>hI1!4!%1fPP1}0XWZyt#Ow zL0A>hOiw{O^?(H;FDY3xvZKx1e1{L+C)l+ePs`E_BNJ3 z#49d$Y|tC`vGwiawn|?b-1G~6u*P6rAG!7T!##ewSm!?xO8EnSA5|w zmUAl&p@eq(bOeKhGb@@Z%|(OXTw~?H1HEnOh4P_KBH{c!mzW)?V&R8$a z(0EjqnEA>^W?Hb$fLX9{S|;vuhD~-&0jpQSb{j=2m?d+oyu|S`iOIEZ9-7?{vSso$ zybgzHn_?xLn|!0#4U;hqIX41tUe?EOO%HZb*EvZxYliD1y{MupX~>@jTAd&8X(F$k zU&l^8B{$-raVCXmW0fGI4)&5}Y|6tuenBqS^fBzWp4fucl7C%7$ z@&9kPx5S_0f8+dDg989@5P-iu;S5ZS3_$V!VxT_}0J;C+85tOWa{rC^x9=P{_uq(r PTh2lLga5Xk|CRp(nF>xN literal 0 HcmV?d00001 From 5c98762121bcba711c0e278e4c8f65f41e01cd5d Mon Sep 17 00:00:00 2001 From: Aditya Patadia Date: Thu, 24 Apr 2025 00:42:43 +0530 Subject: [PATCH 28/40] bug fix --- .github/workflows/php-testing.yml | 2 +- test/ImageResizeTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/php-testing.yml b/.github/workflows/php-testing.yml index 07b8f58..1e93db5 100644 --- a/.github/workflows/php-testing.yml +++ b/.github/workflows/php-testing.yml @@ -9,7 +9,7 @@ jobs: fail-fast: false matrix: operating-system: [ubuntu-22.04] - php-versions: ['7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3', '8.4'] + php-versions: ['8.1', '8.2', '8.3', '8.4'] name: PHP ${{ matrix.php-versions }} Test on ${{ matrix.operating-system }} steps: - name: Checkout diff --git a/test/ImageResizeTest.php b/test/ImageResizeTest.php index 9f83f10..c6a877a 100644 --- a/test/ImageResizeTest.php +++ b/test/ImageResizeTest.php @@ -64,7 +64,7 @@ public function testLoadWebp() $image = __DIR__ . '/ressources/test_webp.webp'; $resize = new ImageResize($image); - $this->assertEquals(IMAGETYPE_WEBP, $resize->source_type); + $this->assertEquals(IMAGETYPE_WEBP, $resize->getSourceWidth()); $this->assertInstanceOf('\Gumlet\ImageResize', $resize); } From 690472b12755ddc6ac0119547b33ebdf1186af20 Mon Sep 17 00:00:00 2001 From: Aditya Patadia Date: Thu, 24 Apr 2025 00:43:32 +0530 Subject: [PATCH 29/40] bug fix --- test/ImageResizeTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/ImageResizeTest.php b/test/ImageResizeTest.php index c6a877a..ebe126e 100644 --- a/test/ImageResizeTest.php +++ b/test/ImageResizeTest.php @@ -64,7 +64,7 @@ public function testLoadWebp() $image = __DIR__ . '/ressources/test_webp.webp'; $resize = new ImageResize($image); - $this->assertEquals(IMAGETYPE_WEBP, $resize->getSourceWidth()); + $this->assertEquals(IMAGETYPE_WEBP, $resize->source_type); $this->assertInstanceOf('\Gumlet\ImageResize', $resize); } @@ -73,7 +73,7 @@ public function testLoadAvif() $image = __DIR__ . '/ressources/test_avif.avif'; $resize = new ImageResize($image); - $this->assertEquals(100, $resize->original_w); + $this->assertEquals(100, $resize->getSourceWidth()); $this->assertEquals(IMAGETYPE_AVIF, $resize->source_type); $this->assertInstanceOf('\Gumlet\ImageResize', $resize); } From b7010cc0c4ce2c952b2e3b877de7912c36b56453 Mon Sep 17 00:00:00 2001 From: Aditya Patadia Date: Thu, 24 Apr 2025 00:47:05 +0530 Subject: [PATCH 30/40] checking if avif works now --- lib/ImageResize.php | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/lib/ImageResize.php b/lib/ImageResize.php index 6065425..e7d24ca 100644 --- a/lib/ImageResize.php +++ b/lib/ImageResize.php @@ -108,23 +108,37 @@ public function __construct($filename) } $finfo = finfo_open(FILEINFO_MIME_TYPE); + $checkWebp = false; + if (strstr(finfo_file($finfo, $filename), 'image') === false) { + if (version_compare(PHP_VERSION, '7.0.0', '<=') && strstr(file_get_contents($filename), 'WEBPVP8') !== false) { + $checkWebp = true; + $this->source_type = IMAGETYPE_WEBP; + } else { + throw new ImageResizeException('Unsupported file type'); + } + } elseif(strstr(finfo_file($finfo, $filename), 'image/webp') !== false) { + $checkWebp = true; + $this->source_type = IMAGETYPE_WEBP; + } if (!$image_info = getimagesize($filename, $this->source_info)) { $image_info = getimagesize($filename); } - if (!$image_info) { - if (strstr(finfo_file($finfo, $filename), 'image') !== false) { - throw new ImageResizeException('Unsupported image type'); + if (!$checkWebp) { + if (!$image_info) { + if (strstr(finfo_file($finfo, $filename), 'image') !== false) { + throw new ImageResizeException('Unsupported image type'); + } + + throw new ImageResizeException('Could not read file'); } - throw new ImageResizeException('Could not read file'); + $this->original_w = $image_info[0]; + $this->original_h = $image_info[1]; + $this->source_type = $image_info[2]; } - $this->original_w = $image_info[0]; - $this->original_h = $image_info[1]; - $this->source_type = $image_info[2]; - switch ($this->source_type) { case IMAGETYPE_GIF: $this->source_image = imagecreatefromgif($filename); @@ -152,12 +166,12 @@ public function __construct($filename) case IMAGETYPE_AVIF: $this->source_image = imagecreatefromavif($filename); - $this->original_w = imagesx($this->source_image); - $this->original_h = imagesy($this->source_image); - break; case IMAGETYPE_BMP: + if (version_compare(PHP_VERSION, '7.2.0', '<')) { + throw new ImageResizeException('For bmp support PHP >= 7.2.0 is required'); + } $this->source_image = imagecreatefrombmp($filename); break; From 33fab28748c7e62c19212db99896b8e9e4776b66 Mon Sep 17 00:00:00 2001 From: Aditya Patadia Date: Thu, 24 Apr 2025 00:47:52 +0530 Subject: [PATCH 31/40] fix in height/width for avif --- lib/ImageResize.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/ImageResize.php b/lib/ImageResize.php index e7d24ca..5289f96 100644 --- a/lib/ImageResize.php +++ b/lib/ImageResize.php @@ -166,6 +166,8 @@ public function __construct($filename) case IMAGETYPE_AVIF: $this->source_image = imagecreatefromavif($filename); + $this->original_w = imagesx($this->source_image); + $this->original_h = imagesy($this->source_image); break; case IMAGETYPE_BMP: From 1b514c8c3f999a2b119bec577b98b154a8af2310 Mon Sep 17 00:00:00 2001 From: Aditya Patadia Date: Thu, 24 Apr 2025 00:49:37 +0530 Subject: [PATCH 32/40] checking if webp is detected correctly --- lib/ImageResize.php | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/lib/ImageResize.php b/lib/ImageResize.php index 5289f96..16f4949 100644 --- a/lib/ImageResize.php +++ b/lib/ImageResize.php @@ -159,9 +159,6 @@ public function __construct($filename) case IMAGETYPE_WEBP: $this->source_image = imagecreatefromwebp($filename); - $this->original_w = imagesx($this->source_image); - $this->original_h = imagesy($this->source_image); - break; case IMAGETYPE_AVIF: @@ -171,9 +168,6 @@ public function __construct($filename) break; case IMAGETYPE_BMP: - if (version_compare(PHP_VERSION, '7.2.0', '<')) { - throw new ImageResizeException('For bmp support PHP >= 7.2.0 is required'); - } $this->source_image = imagecreatefrombmp($filename); break; @@ -323,10 +317,6 @@ public function save($filename, $image_type = null, $quality = null, $permission break; case IMAGETYPE_BMP: - if (version_compare(PHP_VERSION, '7.2.0', '<')) { - throw new ImageResizeException('For WebP support PHP >= 7.2.0 is required'); - } - if(!empty($exact_size) && is_array($exact_size)) { $dest_image = imagecreatetruecolor($exact_size[0], $exact_size[1]); $background = imagecolorallocate($dest_image, 255, 255, 255); From fefe38651007e4b7286d52b6d60eb7836020677f Mon Sep 17 00:00:00 2001 From: Aditya Patadia Date: Thu, 24 Apr 2025 00:55:10 +0530 Subject: [PATCH 33/40] phpunit upgrade --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 9003297..7a1fa1b 100644 --- a/composer.json +++ b/composer.json @@ -36,7 +36,7 @@ }, "require-dev": { - "phpunit/phpunit": "^8.5", + "phpunit/phpunit": "^12.0", "apigen/apigen": "^4.1", "php-coveralls/php-coveralls": "^2.1", "ext-exif": "*", From 5d93a16cbe43ed9b5d85a43d4d2acd398bc6bd0b Mon Sep 17 00:00:00 2001 From: Aditya Patadia Date: Thu, 24 Apr 2025 00:56:06 +0530 Subject: [PATCH 34/40] phpunit downgrade --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 7a1fa1b..08cee62 100644 --- a/composer.json +++ b/composer.json @@ -36,7 +36,7 @@ }, "require-dev": { - "phpunit/phpunit": "^12.0", + "phpunit/phpunit": "^10.0", "apigen/apigen": "^4.1", "php-coveralls/php-coveralls": "^2.1", "ext-exif": "*", From b2f352e2b26d95beef4a9bf9881b264d0416105d Mon Sep 17 00:00:00 2001 From: Aditya Patadia Date: Thu, 24 Apr 2025 00:56:59 +0530 Subject: [PATCH 35/40] test image upgrade --- .github/workflows/php-testing.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/php-testing.yml b/.github/workflows/php-testing.yml index 1e93db5..3fbfc6c 100644 --- a/.github/workflows/php-testing.yml +++ b/.github/workflows/php-testing.yml @@ -8,7 +8,7 @@ jobs: strategy: fail-fast: false matrix: - operating-system: [ubuntu-22.04] + operating-system: [ubuntu-24.04] php-versions: ['8.1', '8.2', '8.3', '8.4'] name: PHP ${{ matrix.php-versions }} Test on ${{ matrix.operating-system }} steps: From ecad2eaf59e14cae65d42bcc6143a7046784e6a4 Mon Sep 17 00:00:00 2001 From: Aditya Patadia Date: Thu, 24 Apr 2025 00:58:06 +0530 Subject: [PATCH 36/40] webp hack removed --- lib/ImageResize.php | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/lib/ImageResize.php b/lib/ImageResize.php index 16f4949..d3a9537 100644 --- a/lib/ImageResize.php +++ b/lib/ImageResize.php @@ -108,18 +108,7 @@ public function __construct($filename) } $finfo = finfo_open(FILEINFO_MIME_TYPE); - $checkWebp = false; - if (strstr(finfo_file($finfo, $filename), 'image') === false) { - if (version_compare(PHP_VERSION, '7.0.0', '<=') && strstr(file_get_contents($filename), 'WEBPVP8') !== false) { - $checkWebp = true; - $this->source_type = IMAGETYPE_WEBP; - } else { - throw new ImageResizeException('Unsupported file type'); - } - } elseif(strstr(finfo_file($finfo, $filename), 'image/webp') !== false) { - $checkWebp = true; - $this->source_type = IMAGETYPE_WEBP; - } + if (!$image_info = getimagesize($filename, $this->source_info)) { $image_info = getimagesize($filename); From ddb3b738198122477e1f9e7f3cd48aacc5ba406c Mon Sep 17 00:00:00 2001 From: Aditya Patadia Date: Thu, 24 Apr 2025 01:03:02 +0530 Subject: [PATCH 37/40] unsupported image update --- test/ImageResizeTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/ImageResizeTest.php b/test/ImageResizeTest.php index ebe126e..42b6b6a 100644 --- a/test/ImageResizeTest.php +++ b/test/ImageResizeTest.php @@ -14,7 +14,7 @@ class ImageResizeTest extends TestCase 'bmp', ); - private $unsupported_image = 'AAAKAAAAAAAAAAAAAQABABgAAF9SlQAAAAAAAAAAVFJVRVZJU0lPTi1YRklMRS4A'; + private $unsupported_image = 'AAAMJXgAAACGQpA0AAABAAEAGQAA'; // JPEG-XL image private $image_string = 'R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs='; private $data_url = 'data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs='; From 73915788742c30de4fdb8e54b25cd03a085a4459 Mon Sep 17 00:00:00 2001 From: Aditya Patadia Date: Thu, 24 Apr 2025 01:06:05 +0530 Subject: [PATCH 38/40] fixed error message --- lib/ImageResize.php | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/lib/ImageResize.php b/lib/ImageResize.php index d3a9537..795d0cb 100644 --- a/lib/ImageResize.php +++ b/lib/ImageResize.php @@ -109,25 +109,22 @@ public function __construct($filename) $finfo = finfo_open(FILEINFO_MIME_TYPE); - if (!$image_info = getimagesize($filename, $this->source_info)) { $image_info = getimagesize($filename); } - if (!$checkWebp) { - if (!$image_info) { - if (strstr(finfo_file($finfo, $filename), 'image') !== false) { - throw new ImageResizeException('Unsupported image type'); - } - - throw new ImageResizeException('Could not read file'); + if (!$image_info) { + if (strstr(finfo_file($finfo, $filename), 'image') !== false) { + throw new ImageResizeException('Unsupported image type'); } - $this->original_w = $image_info[0]; - $this->original_h = $image_info[1]; - $this->source_type = $image_info[2]; + throw new ImageResizeException('Unsupported file type'); } + $this->original_w = $image_info[0]; + $this->original_h = $image_info[1]; + $this->source_type = $image_info[2]; + switch ($this->source_type) { case IMAGETYPE_GIF: $this->source_image = imagecreatefromgif($filename); From 6da0f4661ad624bd60e86cff960e79144b781e36 Mon Sep 17 00:00:00 2001 From: Aditya Patadia Date: Thu, 24 Apr 2025 01:17:34 +0530 Subject: [PATCH 39/40] url updated --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 344a097..cccdce5 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ PHP library to resize, scale and crop images. Cloud Solution --------------- -If you don't want to crop, resize and store images on your server, Gumlet.com is a **free** service which can process images in real-time and serve worldwide through CDN. +If you don't want to crop, resize and store images on your server, Gumlet.com is a **free** service which can process images in real-time and serve worldwide through CDN. ------------------ @@ -382,4 +382,4 @@ Maintainer This library is maintained by Gumlet.com -[](https://www.gumlet.com) +[](https://www.gumlet.com) From d288347c489a4b922710629cd48d96d2001f94cd Mon Sep 17 00:00:00 2001 From: Aditya Patadia Date: Thu, 24 Apr 2025 10:13:51 +0530 Subject: [PATCH 40/40] Update README.md --- README.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/README.md b/README.md index cccdce5..e1b8e76 100644 --- a/README.md +++ b/README.md @@ -27,11 +27,7 @@ If using [Composer](https://getcomposer.org/), in your `composer.json` file add: } ``` -If you are still using PHP 5.3, please install version ```1.7.0``` and if you are using PHP 5.4, please install version ```1.8.0``` of this library. - -WebP support is added with PHP `5.6.0` and current version of library supports that. If you are facing issues, please use `1.9.2` version of this library. - -For PHP versions >= 7.2 to 8.0, `2.0.x` or version of this library should be used. +For PHP versions >= 7.2 to 8.0, `2.0.x` version of this library should be used. Otherwise: