diff --git a/composer.json b/composer.json index 02e2802d..11172885 100644 --- a/composer.json +++ b/composer.json @@ -6,6 +6,7 @@ "require": { "php": ">=8.2", "ext-ctype": "*", + "ext-exif": "*", "ext-gd": "*", "ext-iconv": "*", "ext-json": "*", @@ -18,6 +19,7 @@ "doctrine/orm": "^2.7", "nelmio/cors-bundle": "^2.1", "phpdocumentor/reflection-docblock": "^5.2", + "phpstan/phpdoc-parser": "^1", "symfony/asset": "^6", "symfony/console": "^6", "symfony/dotenv": "^6", diff --git a/composer.lock b/composer.lock index e4051af9..9ad0d33a 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "478b7a31a22d52fab52b1e9149b192c6", + "content-hash": "1469bcf51645f731c83256fd255cf08b", "packages": [ { "name": "api-platform/core", @@ -1836,16 +1836,16 @@ }, { "name": "monolog/monolog", - "version": "3.7.0", + "version": "3.8.0", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "f4393b648b78a5408747de94fca38beb5f7e9ef8" + "reference": "32e515fdc02cdafbe4593e30a9350d486b125b67" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/f4393b648b78a5408747de94fca38beb5f7e9ef8", - "reference": "f4393b648b78a5408747de94fca38beb5f7e9ef8", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/32e515fdc02cdafbe4593e30a9350d486b125b67", + "reference": "32e515fdc02cdafbe4593e30a9350d486b125b67", "shasum": "" }, "require": { @@ -1865,12 +1865,14 @@ "guzzlehttp/psr7": "^2.2", "mongodb/mongodb": "^1.8", "php-amqplib/php-amqplib": "~2.4 || ^3", - "phpstan/phpstan": "^1.9", - "phpstan/phpstan-deprecation-rules": "^1.0", - "phpstan/phpstan-strict-rules": "^1.4", - "phpunit/phpunit": "^10.5.17", + "php-console/php-console": "^3.1.8", + "phpstan/phpstan": "^2", + "phpstan/phpstan-deprecation-rules": "^2", + "phpstan/phpstan-strict-rules": "^2", + "phpunit/phpunit": "^10.5.17 || ^11.0.7", "predis/predis": "^1.1 || ^2", - "ruflin/elastica": "^7", + "rollbar/rollbar": "^4.0", + "ruflin/elastica": "^7 || ^8", "symfony/mailer": "^5.4 || ^6", "symfony/mime": "^5.4 || ^6" }, @@ -1921,7 +1923,7 @@ ], "support": { "issues": "https://github.com/Seldaek/monolog/issues", - "source": "https://github.com/Seldaek/monolog/tree/3.7.0" + "source": "https://github.com/Seldaek/monolog/tree/3.8.0" }, "funding": [ { @@ -1933,7 +1935,7 @@ "type": "tidelift" } ], - "time": "2024-06-28T09:40:51+00:00" + "time": "2024-11-12T13:57:08+00:00" }, { "name": "nelmio/cors-bundle", @@ -2052,16 +2054,16 @@ }, { "name": "phpdocumentor/reflection-docblock", - "version": "5.5.1", + "version": "5.6.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "0c70d2c566e899666f367ab7b80986beb3581e6f" + "reference": "f3558a4c23426d12bffeaab463f8a8d8b681193c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/0c70d2c566e899666f367ab7b80986beb3581e6f", - "reference": "0c70d2c566e899666f367ab7b80986beb3581e6f", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/f3558a4c23426d12bffeaab463f8a8d8b681193c", + "reference": "f3558a4c23426d12bffeaab463f8a8d8b681193c", "shasum": "" }, "require": { @@ -2070,7 +2072,7 @@ "php": "^7.4 || ^8.0", "phpdocumentor/reflection-common": "^2.2", "phpdocumentor/type-resolver": "^1.7", - "phpstan/phpdoc-parser": "^1.7", + "phpstan/phpdoc-parser": "^1.7|^2.0", "webmozart/assert": "^1.9.1" }, "require-dev": { @@ -2110,29 +2112,29 @@ "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", "support": { "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", - "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.5.1" + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.6.0" }, - "time": "2024-11-06T11:58:54+00:00" + "time": "2024-11-12T11:25:25+00:00" }, { "name": "phpdocumentor/type-resolver", - "version": "1.9.0", + "version": "1.10.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "1fb5ba8d045f5dd984ebded5b1cc66f29459422d" + "reference": "679e3ce485b99e84c775d28e2e96fade9a7fb50a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/1fb5ba8d045f5dd984ebded5b1cc66f29459422d", - "reference": "1fb5ba8d045f5dd984ebded5b1cc66f29459422d", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/679e3ce485b99e84c775d28e2e96fade9a7fb50a", + "reference": "679e3ce485b99e84c775d28e2e96fade9a7fb50a", "shasum": "" }, "require": { "doctrine/deprecations": "^1.0", "php": "^7.3 || ^8.0", "phpdocumentor/reflection-common": "^2.0", - "phpstan/phpdoc-parser": "^1.18" + "phpstan/phpdoc-parser": "^1.18|^2.0" }, "require-dev": { "ext-tokenizer": "*", @@ -2168,9 +2170,9 @@ "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", "support": { "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.9.0" + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.10.0" }, - "time": "2024-11-03T20:11:34+00:00" + "time": "2024-11-09T15:12:26+00:00" }, { "name": "phpstan/phpdoc-parser", @@ -8128,16 +8130,16 @@ }, { "name": "composer/pcre", - "version": "3.3.1", + "version": "3.3.2", "source": { "type": "git", "url": "https://github.com/composer/pcre.git", - "reference": "63aaeac21d7e775ff9bc9d45021e1745c97521c4" + "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/pcre/zipball/63aaeac21d7e775ff9bc9d45021e1745c97521c4", - "reference": "63aaeac21d7e775ff9bc9d45021e1745c97521c4", + "url": "https://api.github.com/repos/composer/pcre/zipball/b2bed4734f0cc156ee1fe9c0da2550420d99a21e", + "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e", "shasum": "" }, "require": { @@ -8147,8 +8149,8 @@ "phpstan/phpstan": "<1.11.10" }, "require-dev": { - "phpstan/phpstan": "^1.11.10", - "phpstan/phpstan-strict-rules": "^1.1", + "phpstan/phpstan": "^1.12 || ^2", + "phpstan/phpstan-strict-rules": "^1 || ^2", "phpunit/phpunit": "^8 || ^9" }, "type": "library", @@ -8187,7 +8189,7 @@ ], "support": { "issues": "https://github.com/composer/pcre/issues", - "source": "https://github.com/composer/pcre/tree/3.3.1" + "source": "https://github.com/composer/pcre/tree/3.3.2" }, "funding": [ { @@ -8203,7 +8205,7 @@ "type": "tidelift" } ], - "time": "2024-08-27T18:44:43+00:00" + "time": "2024-11-12T16:29:46+00:00" }, { "name": "composer/semver", @@ -9200,16 +9202,16 @@ }, { "name": "liip/test-fixtures-bundle", - "version": "2.9.1", + "version": "2.9.2", "source": { "type": "git", "url": "https://github.com/liip/LiipTestFixturesBundle.git", - "reference": "aa89bed82eda771483eae0bb043f10f827cd90b0" + "reference": "2b810cd0cc03f4f72a0265c911c03fc2553fb8de" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/liip/LiipTestFixturesBundle/zipball/aa89bed82eda771483eae0bb043f10f827cd90b0", - "reference": "aa89bed82eda771483eae0bb043f10f827cd90b0", + "url": "https://api.github.com/repos/liip/LiipTestFixturesBundle/zipball/2b810cd0cc03f4f72a0265c911c03fc2553fb8de", + "reference": "2b810cd0cc03f4f72a0265c911c03fc2553fb8de", "shasum": "" }, "require": { @@ -9288,9 +9290,9 @@ ], "support": { "issues": "https://github.com/liip/LiipTestFixturesBundle/issues", - "source": "https://github.com/liip/LiipTestFixturesBundle/tree/2.9.1" + "source": "https://github.com/liip/LiipTestFixturesBundle/tree/2.9.2" }, - "time": "2024-07-15T09:31:30+00:00" + "time": "2024-11-12T18:52:49+00:00" }, { "name": "masterminds/html5", @@ -9597,16 +9599,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.12.8", + "version": "1.12.10", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "f6a60a4d66142b8156c9da923f1972657bc4748c" + "reference": "fc463b5d0fe906dcf19689be692c65c50406a071" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/f6a60a4d66142b8156c9da923f1972657bc4748c", - "reference": "f6a60a4d66142b8156c9da923f1972657bc4748c", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/fc463b5d0fe906dcf19689be692c65c50406a071", + "reference": "fc463b5d0fe906dcf19689be692c65c50406a071", "shasum": "" }, "require": { @@ -9651,7 +9653,7 @@ "type": "github" } ], - "time": "2024-11-06T19:06:49+00:00" + "time": "2024-11-11T15:37:09+00:00" }, { "name": "phpunit/php-code-coverage", @@ -12548,6 +12550,7 @@ "platform": { "php": ">=8.2", "ext-ctype": "*", + "ext-exif": "*", "ext-gd": "*", "ext-iconv": "*", "ext-json": "*", diff --git a/src/Helper/ImageHelper.php b/src/Helper/ImageHelper.php index 5defc7a6..e55c67a8 100644 --- a/src/Helper/ImageHelper.php +++ b/src/Helper/ImageHelper.php @@ -25,6 +25,16 @@ public static function fitInBoundingBox(string $imgPath, mixed $boxWidth, mixed $imageWidth = $imageSizes[0]; $imageHeight = $imageSizes[1]; + return self::fitInBoundingBoxRaw($imageWidth, $imageHeight, $boxWidth, $boxHeight, $expand); + } + + /** + * gives back the width and height to be used. + * + * @return int[] + */ + public static function fitInBoundingBoxRaw(int $imageWidth, int $imageHeight, mixed $boxWidth, mixed $boxHeight, bool $expand = true): array + { // get ratios $widthRatio = (float) $boxWidth / $imageWidth; $heightRatio = (float) $boxHeight / $imageHeight; diff --git a/src/Service/Image/GdService.php b/src/Service/Image/GdService.php index 9669dcce..cac6af24 100644 --- a/src/Service/Image/GdService.php +++ b/src/Service/Image/GdService.php @@ -104,9 +104,30 @@ public function drawCrosshair(float $positionX, float $positionY, string $color, } } + private function getQuarterRotation(string $sourcePath): int + { + if (function_exists('exif_read_data')) { + $exif = exif_read_data($sourcePath); + if (!empty($exif['Orientation'])) { + return match ($exif['Orientation']) { + 3 => 2, + 6 => 3, + 8 => 1, + }; + } + } + + return 0; + } + public function resizeImage(string $sourcePath, string $targetPath, int $maxWidth, int $maxHeight): bool { - list($width, $height) = ImageHelper::fitInBoundingBox($sourcePath, $maxWidth, $maxHeight, false); + $rotation = $this->getQuarterRotation($sourcePath); + $imageSizes = getimagesize($sourcePath); + $imageWidth = $imageSizes[$rotation % 2]; + $imageHeight = $imageSizes[($rotation + 1) % 2]; + + list($width, $height) = ImageHelper::fitInBoundingBoxRaw($imageWidth, $imageHeight, $maxWidth, $maxHeight, false); $ending = strtolower(pathinfo($sourcePath, PATHINFO_EXTENSION)); // resize & save @@ -121,6 +142,10 @@ public function resizeImage(string $sourcePath, string $targetPath, int $maxWidt return false; } + if ($rotation > 0) { + $originalImage = imagerotate($originalImage, $rotation * 90, 0); + } + imagecopyresampled($newImage, $originalImage, 0, 0, 0, 0, $width, $height, imagesx($originalImage), imagesy($originalImage)); imagejpeg($newImage, $targetPath, 80); } elseif ('png' === $ending) { @@ -129,6 +154,10 @@ public function resizeImage(string $sourcePath, string $targetPath, int $maxWidt return false; } + if ($rotation > 0) { + $originalImage = imagerotate($originalImage, $rotation * 90, 0); + } + imagecopyresampled($newImage, $originalImage, 0, 0, 0, 0, $width, $height, imagesx($originalImage), imagesy($originalImage)); imagepng($newImage, $targetPath, 8); } elseif ('gif' === $ending) { @@ -137,6 +166,10 @@ public function resizeImage(string $sourcePath, string $targetPath, int $maxWidt return false; } + if ($rotation > 0) { + $originalImage = imagerotate($originalImage, $rotation * 90, 0); + } + imagecopyresampled($newImage, $originalImage, 0, 0, 0, 0, $width, $height, imagesx($originalImage), imagesy($originalImage)); imagegif($newImage, $targetPath); } else {