diff --git a/app/Commands/GlimpseCommand.php b/app/Commands/GlimpseCommand.php index ed86cad..e7bb1ab 100644 --- a/app/Commands/GlimpseCommand.php +++ b/app/Commands/GlimpseCommand.php @@ -152,14 +152,20 @@ protected function intOption(string $name): ?int protected function emit(ImageResult $result, string $path): void { if ($this->option('json')) { - $line = (string) json_encode([ + $payload = [ 'output' => $path, 'format' => $result->format, 'mime_type' => $result->mimeType, 'size' => $result->size, 'width' => $result->width, 'height' => $result->height, - ], JSON_UNESCAPED_SLASHES); + ]; + + if ($result->psnr !== null) { + $payload['psnr'] = $result->psnr; + } + + $line = (string) json_encode($payload, JSON_UNESCAPED_SLASHES); $path === '-' ? fwrite(STDERR, $line.PHP_EOL) : $this->line($line); @@ -167,12 +173,13 @@ protected function emit(ImageResult $result, string $path): void } $summary = sprintf( - 'Wrote %s (%s, %s, %dx%d)', + 'Wrote %s (%s, %s, %dx%d%s)', $path === '-' ? 'stdout' : $path, $result->mimeType, $this->humanSize($result->size), $result->width, $result->height, + $result->psnr === null ? '' : sprintf(', PSNR %.2F dB', $result->psnr), // %.2F is locale-independent; %.2f would print a comma under some locales ); $path === '-' ? fwrite(STDERR, $summary.PHP_EOL) : $this->info($summary); diff --git a/composer.json b/composer.json index 2b0bf17..dd7a684 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,7 @@ "laravel-zero/framework": "^12.0.2", "laravel-zero/phar-updater": "^1.4", "laravel/pint": "^1.29", - "mathiasgrimm/glimpse-php": "^3.0", + "mathiasgrimm/glimpse-php": "^3.1", "mockery/mockery": "^1.6.12", "pestphp/pest": "^3.8.4|^4.1.2", "phpstan/phpstan": "^2.2", diff --git a/composer.lock b/composer.lock index a993625..9ef9ad4 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": "c0baf0f8670301bca85bd060d55f1b96", + "content-hash": "245c3c68ddb5816cef23db720df6face", "packages": [], "packages-dev": [ { @@ -697,22 +697,22 @@ }, { "name": "guzzlehttp/guzzle", - "version": "7.13.3", + "version": "7.15.2", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "caa5491e1030fd120247f42fb3331ecf38da3b26" + "reference": "744101956d78b7c1384d0cbf379db13e859167bf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/caa5491e1030fd120247f42fb3331ecf38da3b26", - "reference": "caa5491e1030fd120247f42fb3331ecf38da3b26", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/744101956d78b7c1384d0cbf379db13e859167bf", + "reference": "744101956d78b7c1384d0cbf379db13e859167bf", "shasum": "" }, "require": { "ext-json": "*", "guzzlehttp/promises": "^2.5.1", - "guzzlehttp/psr7": "^2.12.4", + "guzzlehttp/psr7": "^2.13", "php": "^7.2.5 || ^8.0", "psr/http-client": "^1.0", "symfony/deprecation-contracts": "^2.5 || ^3.0", @@ -725,7 +725,7 @@ "bamarni/composer-bin-plugin": "^1.8.2", "ext-curl": "*", "guzzle/client-integration-tests": "3.0.3", - "guzzlehttp/test-server": "^0.6", + "guzzlehttp/test-server": "^0.7", "php-http/message-factory": "^1.1", "phpunit/phpunit": "^8.5.52 || ^9.6.34", "psr/log": "^1.1 || ^2.0 || ^3.0" @@ -805,7 +805,7 @@ ], "support": { "issues": "https://github.com/guzzle/guzzle/issues", - "source": "https://github.com/guzzle/guzzle/tree/7.13.3" + "source": "https://github.com/guzzle/guzzle/tree/7.15.2" }, "funding": [ { @@ -821,7 +821,7 @@ "type": "tidelift" } ], - "time": "2026-07-08T16:10:19+00:00" + "time": "2026-07-26T23:23:20+00:00" }, { "name": "guzzlehttp/promises", @@ -909,16 +909,16 @@ }, { "name": "guzzlehttp/psr7", - "version": "2.12.4", + "version": "2.13.0", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "51e27f9e2b332ab3e72f4520d5ff4f3c68c3577c" + "reference": "dad89620b7a6edb60c15858442eb2e408b45d8f4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/51e27f9e2b332ab3e72f4520d5ff4f3c68c3577c", - "reference": "51e27f9e2b332ab3e72f4520d5ff4f3c68c3577c", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/dad89620b7a6edb60c15858442eb2e408b45d8f4", + "reference": "dad89620b7a6edb60c15858442eb2e408b45d8f4", "shasum": "" }, "require": { @@ -1008,7 +1008,7 @@ ], "support": { "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/2.12.4" + "source": "https://github.com/guzzle/psr7/tree/2.13.0" }, "funding": [ { @@ -1024,20 +1024,20 @@ "type": "tidelift" } ], - "time": "2026-07-08T15:56:20+00:00" + "time": "2026-07-16T22:23:49+00:00" }, { "name": "guzzlehttp/uri-template", - "version": "v1.0.9", + "version": "v1.0.10", "source": { "type": "git", "url": "https://github.com/guzzle/uri-template.git", - "reference": "d7580af6d3f8384325d9cd3e99b21c3ed1848176" + "reference": "f6c24c21f42b990e9a58912b332d0874df6ba839" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/uri-template/zipball/d7580af6d3f8384325d9cd3e99b21c3ed1848176", - "reference": "d7580af6d3f8384325d9cd3e99b21c3ed1848176", + "url": "https://api.github.com/repos/guzzle/uri-template/zipball/f6c24c21f42b990e9a58912b332d0874df6ba839", + "reference": "f6c24c21f42b990e9a58912b332d0874df6ba839", "shasum": "" }, "require": { @@ -1094,7 +1094,7 @@ ], "support": { "issues": "https://github.com/guzzle/uri-template/issues", - "source": "https://github.com/guzzle/uri-template/tree/v1.0.9" + "source": "https://github.com/guzzle/uri-template/tree/v1.0.10" }, "funding": [ { @@ -1110,7 +1110,7 @@ "type": "tidelift" } ], - "time": "2026-07-08T16:19:22+00:00" + "time": "2026-07-17T13:53:03+00:00" }, { "name": "hamcrest/hamcrest-php", @@ -1165,7 +1165,7 @@ }, { "name": "illuminate/bus", - "version": "v12.63.0", + "version": "v12.64.0", "source": { "type": "git", "url": "https://github.com/illuminate/bus.git", @@ -1218,7 +1218,7 @@ }, { "name": "illuminate/cache", - "version": "v12.63.0", + "version": "v12.64.0", "source": { "type": "git", "url": "https://github.com/illuminate/cache.git", @@ -1280,7 +1280,7 @@ }, { "name": "illuminate/collections", - "version": "v12.63.0", + "version": "v12.64.0", "source": { "type": "git", "url": "https://github.com/illuminate/collections.git", @@ -1340,7 +1340,7 @@ }, { "name": "illuminate/conditionable", - "version": "v12.63.0", + "version": "v12.64.0", "source": { "type": "git", "url": "https://github.com/illuminate/conditionable.git", @@ -1386,7 +1386,7 @@ }, { "name": "illuminate/config", - "version": "v12.63.0", + "version": "v12.64.0", "source": { "type": "git", "url": "https://github.com/illuminate/config.git", @@ -1434,7 +1434,7 @@ }, { "name": "illuminate/console", - "version": "v12.63.0", + "version": "v12.64.0", "source": { "type": "git", "url": "https://github.com/illuminate/console.git", @@ -1500,7 +1500,7 @@ }, { "name": "illuminate/container", - "version": "v12.63.0", + "version": "v12.64.0", "source": { "type": "git", "url": "https://github.com/illuminate/container.git", @@ -1562,7 +1562,7 @@ }, { "name": "illuminate/contracts", - "version": "v12.63.0", + "version": "v12.64.0", "source": { "type": "git", "url": "https://github.com/illuminate/contracts.git", @@ -1610,7 +1610,7 @@ }, { "name": "illuminate/events", - "version": "v12.63.0", + "version": "v12.64.0", "source": { "type": "git", "url": "https://github.com/illuminate/events.git", @@ -1665,7 +1665,7 @@ }, { "name": "illuminate/filesystem", - "version": "v12.63.0", + "version": "v12.64.0", "source": { "type": "git", "url": "https://github.com/illuminate/filesystem.git", @@ -1794,7 +1794,7 @@ }, { "name": "illuminate/macroable", - "version": "v12.63.0", + "version": "v12.64.0", "source": { "type": "git", "url": "https://github.com/illuminate/macroable.git", @@ -1840,7 +1840,7 @@ }, { "name": "illuminate/pipeline", - "version": "v12.63.0", + "version": "v12.64.0", "source": { "type": "git", "url": "https://github.com/illuminate/pipeline.git", @@ -1892,7 +1892,7 @@ }, { "name": "illuminate/process", - "version": "v12.63.0", + "version": "v12.64.0", "source": { "type": "git", "url": "https://github.com/illuminate/process.git", @@ -1943,7 +1943,7 @@ }, { "name": "illuminate/reflection", - "version": "v12.63.0", + "version": "v12.64.0", "source": { "type": "git", "url": "https://github.com/illuminate/reflection.git", @@ -1994,7 +1994,7 @@ }, { "name": "illuminate/session", - "version": "v12.63.0", + "version": "v12.64.0", "source": { "type": "git", "url": "https://github.com/illuminate/session.git", @@ -2051,16 +2051,16 @@ }, { "name": "illuminate/support", - "version": "v12.63.0", + "version": "v12.64.0", "source": { "type": "git", "url": "https://github.com/illuminate/support.git", - "reference": "3a8772095ef7d6b1961a77f2f0b8921c056c48ea" + "reference": "bc7bc2db3e635697f81ea123511ae25b014a63fb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/support/zipball/3a8772095ef7d6b1961a77f2f0b8921c056c48ea", - "reference": "3a8772095ef7d6b1961a77f2f0b8921c056c48ea", + "url": "https://api.github.com/repos/illuminate/support/zipball/bc7bc2db3e635697f81ea123511ae25b014a63fb", + "reference": "bc7bc2db3e635697f81ea123511ae25b014a63fb", "shasum": "" }, "require": { @@ -2127,11 +2127,11 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2026-05-31T22:10:17+00:00" + "time": "2026-07-13T16:08:36+00:00" }, { "name": "illuminate/testing", - "version": "v12.63.0", + "version": "v12.64.0", "source": { "type": "git", "url": "https://github.com/illuminate/testing.git", @@ -2191,7 +2191,7 @@ }, { "name": "illuminate/view", - "version": "v12.63.0", + "version": "v12.64.0", "source": { "type": "git", "url": "https://github.com/illuminate/view.git", @@ -2658,16 +2658,16 @@ }, { "name": "laravel/pint", - "version": "v1.29.3", + "version": "v1.30.3", "source": { "type": "git", "url": "https://github.com/laravel/pint.git", - "reference": "da1d1111a6aa2e082d2a388b194afe1ba0a05d14" + "reference": "19ca6de4ce07869f61f09863e37e81562ebc0a9b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/pint/zipball/da1d1111a6aa2e082d2a388b194afe1ba0a05d14", - "reference": "da1d1111a6aa2e082d2a388b194afe1ba0a05d14", + "url": "https://api.github.com/repos/laravel/pint/zipball/19ca6de4ce07869f61f09863e37e81562ebc0a9b", + "reference": "19ca6de4ce07869f61f09863e37e81562ebc0a9b", "shasum": "" }, "require": { @@ -2678,14 +2678,16 @@ "php": "^8.2.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^3.95.8", - "illuminate/view": "^12.62.0", + "composer/semver": "^3.4.4", + "friendsofphp/php-cs-fixer": "^3.95.18", + "illuminate/view": "^12.64.0", "larastan/larastan": "^3.10.0", "laravel-zero/framework": "^12.1.0", "laravel/agent-detector": "^2.0.2", + "laravel/prompts": "^0.3.21", "mockery/mockery": "^1.6.12", "nunomaduro/termwind": "^2.4.0", - "pestphp/pest": "^3.8.6" + "pestphp/pest": "^3.8.7" }, "bin": [ "builds/pint" @@ -2722,7 +2724,7 @@ "issues": "https://github.com/laravel/pint/issues", "source": "https://github.com/laravel/pint" }, - "time": "2026-06-16T15:34:04+00:00" + "time": "2026-08-02T01:28:21+00:00" }, { "name": "laravel/prompts", @@ -2917,16 +2919,16 @@ }, { "name": "league/mime-type-detection", - "version": "1.16.0", + "version": "1.17.0", "source": { "type": "git", "url": "https://github.com/thephpleague/mime-type-detection.git", - "reference": "2d6702ff215bf922936ccc1ad31007edc76451b9" + "reference": "f5f47eff7c48ed1003069a2ca67f316fb4021c76" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/2d6702ff215bf922936ccc1ad31007edc76451b9", - "reference": "2d6702ff215bf922936ccc1ad31007edc76451b9", + "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/f5f47eff7c48ed1003069a2ca67f316fb4021c76", + "reference": "f5f47eff7c48ed1003069a2ca67f316fb4021c76", "shasum": "" }, "require": { @@ -2936,7 +2938,7 @@ "require-dev": { "friendsofphp/php-cs-fixer": "^3.2", "phpstan/phpstan": "^0.12.68", - "phpunit/phpunit": "^8.5.8 || ^9.3 || ^10.0" + "phpunit/phpunit": "^8.5.8 || ^9.3 || ^10.0 || ^11.0 || ^12.0" }, "type": "library", "autoload": { @@ -2957,7 +2959,7 @@ "description": "Mime-type detection for Flysystem", "support": { "issues": "https://github.com/thephpleague/mime-type-detection/issues", - "source": "https://github.com/thephpleague/mime-type-detection/tree/1.16.0" + "source": "https://github.com/thephpleague/mime-type-detection/tree/1.17.0" }, "funding": [ { @@ -2969,20 +2971,20 @@ "type": "tidelift" } ], - "time": "2024-09-21T08:32:55+00:00" + "time": "2026-07-09T11:49:27+00:00" }, { "name": "mathiasgrimm/glimpse-php", - "version": "v3.0.0", + "version": "v3.1.0", "source": { "type": "git", "url": "https://github.com/mathiasgrimm/glimpse-php.git", - "reference": "c4bd182e07fcdb52e65e44d8c4236dbb30213768" + "reference": "b5564728b07a5a1f950f23742b6e01c3559d9bab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mathiasgrimm/glimpse-php/zipball/c4bd182e07fcdb52e65e44d8c4236dbb30213768", - "reference": "c4bd182e07fcdb52e65e44d8c4236dbb30213768", + "url": "https://api.github.com/repos/mathiasgrimm/glimpse-php/zipball/b5564728b07a5a1f950f23742b6e01c3559d9bab", + "reference": "b5564728b07a5a1f950f23742b6e01c3559d9bab", "shasum": "" }, "require": { @@ -3036,7 +3038,7 @@ "issues": "https://github.com/mathiasgrimm/glimpse-php/issues", "source": "https://github.com/mathiasgrimm/glimpse-php" }, - "time": "2026-07-20T17:31:28+00:00" + "time": "2026-08-02T04:02:06+00:00" }, { "name": "mockery/mockery", @@ -3183,16 +3185,16 @@ }, { "name": "nesbot/carbon", - "version": "3.13.0", + "version": "3.13.1", "source": { "type": "git", "url": "https://github.com/CarbonPHP/carbon.git", - "reference": "40f6618f052df16b545f626fbf9a878e6497d16a" + "reference": "2937ad3d1d2c506fd2bc97d571438a95641f44e2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/40f6618f052df16b545f626fbf9a878e6497d16a", - "reference": "40f6618f052df16b545f626fbf9a878e6497d16a", + "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/2937ad3d1d2c506fd2bc97d571438a95641f44e2", + "reference": "2937ad3d1d2c506fd2bc97d571438a95641f44e2", "shasum": "" }, "require": { @@ -3284,7 +3286,7 @@ "type": "tidelift" } ], - "time": "2026-06-18T13:49:15+00:00" + "time": "2026-07-09T18:23:49+00:00" }, { "name": "nikic/php-parser", @@ -3345,23 +3347,23 @@ }, { "name": "nunomaduro/collision", - "version": "v8.9.4", + "version": "v8.9.5", "source": { "type": "git", "url": "https://github.com/nunomaduro/collision.git", - "reference": "716af8f95a470e9094cfca09ed897b023be191a5" + "reference": "fb53eacd509a1d303858e2d20cfebf2d630254ec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nunomaduro/collision/zipball/716af8f95a470e9094cfca09ed897b023be191a5", - "reference": "716af8f95a470e9094cfca09ed897b023be191a5", + "url": "https://api.github.com/repos/nunomaduro/collision/zipball/fb53eacd509a1d303858e2d20cfebf2d630254ec", + "reference": "fb53eacd509a1d303858e2d20cfebf2d630254ec", "shasum": "" }, "require": { "filp/whoops": "^2.18.4", "nunomaduro/termwind": "^2.4.0", "php": "^8.2.0", - "symfony/console": "^7.4.8 || ^8.0.8" + "symfony/console": "^7.4.14 || ^8.1.1" }, "conflict": { "laravel/framework": "<11.48.0 || >=14.0.0", @@ -3369,12 +3371,12 @@ }, "require-dev": { "brianium/paratest": "^7.8.5", - "larastan/larastan": "^3.9.6", - "laravel/framework": "^11.48.0 || ^12.56.0 || ^13.5.0", - "laravel/pint": "^1.29.1", - "orchestra/testbench-core": "^9.12.0 || ^10.12.1 || ^11.2.1", - "pestphp/pest": "^3.8.5 || ^4.4.3 || ^5.0.0", - "sebastian/environment": "^7.2.1 || ^8.0.4 || ^9.3.0" + "larastan/larastan": "^3.10.0", + "laravel/framework": "^11.48.0 || ^12.56.0 || ^13.20.0", + "laravel/pint": "^1.29.3", + "orchestra/testbench-core": "^9.12.0 || ^10.12.1 || ^11.3.5", + "pestphp/pest": "^3.8.5 || ^4.7.5 || ^5.0.0", + "sebastian/environment": "^7.2.1 || ^8.1.2 || ^9.3.2" }, "type": "library", "extra": { @@ -3437,7 +3439,7 @@ "type": "patreon" } ], - "time": "2026-04-21T14:04:20+00:00" + "time": "2026-07-15T19:09:14+00:00" }, { "name": "nunomaduro/laravel-console-summary", @@ -4462,11 +4464,11 @@ }, { "name": "phpstan/phpstan", - "version": "2.2.5", + "version": "2.2.7", "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/909c1e5fef7989ac0d0c1c5c42e32a5c4f6198a0", - "reference": "909c1e5fef7989ac0d0c1c5c42e32a5c4f6198a0", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/692db47b9dddb0487934e5236e77d48594aef921", + "reference": "692db47b9dddb0487934e5236e77d48594aef921", "shasum": "" }, "require": { @@ -4522,7 +4524,7 @@ "type": "github" } ], - "time": "2026-07-05T06:31:06+00:00" + "time": "2026-07-29T17:39:32+00:00" }, { "name": "phpunit/php-code-coverage", @@ -6693,16 +6695,16 @@ }, { "name": "symfony/console", - "version": "v7.4.14", + "version": "v7.4.15", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "92f58bc4bf97a92ed1b9f367f0cd44f20bde0e87" + "reference": "088ec6fe0ef6819cbc301174093b6bfa4ad26930" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/92f58bc4bf97a92ed1b9f367f0cd44f20bde0e87", - "reference": "92f58bc4bf97a92ed1b9f367f0cd44f20bde0e87", + "url": "https://api.github.com/repos/symfony/console/zipball/088ec6fe0ef6819cbc301174093b6bfa4ad26930", + "reference": "088ec6fe0ef6819cbc301174093b6bfa4ad26930", "shasum": "" }, "require": { @@ -6767,7 +6769,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.4.14" + "source": "https://github.com/symfony/console/tree/v7.4.15" }, "funding": [ { @@ -6787,7 +6789,7 @@ "type": "tidelift" } ], - "time": "2026-06-16T11:50:14+00:00" + "time": "2026-07-27T13:51:00+00:00" }, { "name": "symfony/deprecation-contracts", @@ -6862,16 +6864,16 @@ }, { "name": "symfony/error-handler", - "version": "v7.4.14", + "version": "v7.4.15", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "4e1a093b481f323e6e326451f9760c3868430673" + "reference": "d49f6a19f326db41ae7103bdc38e3eb35a791261" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/4e1a093b481f323e6e326451f9760c3868430673", - "reference": "4e1a093b481f323e6e326451f9760c3868430673", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/d49f6a19f326db41ae7103bdc38e3eb35a791261", + "reference": "d49f6a19f326db41ae7103bdc38e3eb35a791261", "shasum": "" }, "require": { @@ -6920,7 +6922,7 @@ "description": "Provides tools to manage errors and ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/error-handler/tree/v7.4.14" + "source": "https://github.com/symfony/error-handler/tree/v7.4.15" }, "funding": [ { @@ -6940,20 +6942,20 @@ "type": "tidelift" } ], - "time": "2026-06-05T06:22:21+00:00" + "time": "2026-07-21T15:13:06+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v7.4.14", + "version": "v7.4.15", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "51fe3d170227be8d1772214b82ae506e15ed78ff" + "reference": "336e7f3b9e95aba04f93ea9143920c2186abfbb9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/51fe3d170227be8d1772214b82ae506e15ed78ff", - "reference": "51fe3d170227be8d1772214b82ae506e15ed78ff", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/336e7f3b9e95aba04f93ea9143920c2186abfbb9", + "reference": "336e7f3b9e95aba04f93ea9143920c2186abfbb9", "shasum": "" }, "require": { @@ -7005,7 +7007,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v7.4.14" + "source": "https://github.com/symfony/event-dispatcher/tree/v7.4.15" }, "funding": [ { @@ -7025,7 +7027,7 @@ "type": "tidelift" } ], - "time": "2026-06-06T11:10:32+00:00" + "time": "2026-07-21T15:13:06+00:00" }, { "name": "symfony/event-dispatcher-contracts", @@ -7177,16 +7179,16 @@ }, { "name": "symfony/http-foundation", - "version": "v7.4.14", + "version": "v7.4.15", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "06db5ae1552177bf8572f8908839f12e3c06aed3" + "reference": "1f898ee8188adda9417fb52cf8425a8342c254e7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/06db5ae1552177bf8572f8908839f12e3c06aed3", - "reference": "06db5ae1552177bf8572f8908839f12e3c06aed3", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/1f898ee8188adda9417fb52cf8425a8342c254e7", + "reference": "1f898ee8188adda9417fb52cf8425a8342c254e7", "shasum": "" }, "require": { @@ -7235,7 +7237,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v7.4.14" + "source": "https://github.com/symfony/http-foundation/tree/v7.4.15" }, "funding": [ { @@ -7255,20 +7257,20 @@ "type": "tidelift" } ], - "time": "2026-06-11T07:31:44+00:00" + "time": "2026-07-29T07:12:33+00:00" }, { "name": "symfony/http-kernel", - "version": "v7.4.14", + "version": "v7.4.15", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "e99af79b1e776646eda0e1c23b7b45c184ff99be" + "reference": "403275d94f94d5626c3288c599b3b48093ba24f7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/e99af79b1e776646eda0e1c23b7b45c184ff99be", - "reference": "e99af79b1e776646eda0e1c23b7b45c184ff99be", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/403275d94f94d5626c3288c599b3b48093ba24f7", + "reference": "403275d94f94d5626c3288c599b3b48093ba24f7", "shasum": "" }, "require": { @@ -7326,7 +7328,7 @@ "symfony/validator": "^6.4|^7.0|^8.0", "symfony/var-dumper": "^6.4|^7.0|^8.0", "symfony/var-exporter": "^6.4|^7.0|^8.0", - "twig/twig": "^3.12" + "twig/twig": "^3.12|^4.0" }, "type": "library", "autoload": { @@ -7354,7 +7356,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v7.4.14" + "source": "https://github.com/symfony/http-kernel/tree/v7.4.15" }, "funding": [ { @@ -7374,20 +7376,20 @@ "type": "tidelift" } ], - "time": "2026-06-27T09:14:35+00:00" + "time": "2026-07-29T11:40:42+00:00" }, { "name": "symfony/mime", - "version": "v7.4.13", + "version": "v7.4.15", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "a845722765c4f6b2ce88beaf4f4479975b186770" + "reference": "0c1daf58bc931628df0bea26840d1fc8b9a3d34b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/a845722765c4f6b2ce88beaf4f4479975b186770", - "reference": "a845722765c4f6b2ce88beaf4f4479975b186770", + "url": "https://api.github.com/repos/symfony/mime/zipball/0c1daf58bc931628df0bea26840d1fc8b9a3d34b", + "reference": "0c1daf58bc931628df0bea26840d1fc8b9a3d34b", "shasum": "" }, "require": { @@ -7443,7 +7445,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v7.4.13" + "source": "https://github.com/symfony/mime/tree/v7.4.15" }, "funding": [ { @@ -7463,7 +7465,7 @@ "type": "tidelift" } ], - "time": "2026-05-23T16:22:37+00:00" + "time": "2026-07-29T07:59:49+00:00" }, { "name": "symfony/polyfill-ctype", @@ -7550,16 +7552,16 @@ }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.38.1", + "version": "v1.41.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "e9247d281d694a5120554d9afaf54e070e88a603" + "reference": "bb899c1db0aa8127dc3afe8cda4a67eb24915f8d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/e9247d281d694a5120554d9afaf54e070e88a603", - "reference": "e9247d281d694a5120554d9afaf54e070e88a603", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/bb899c1db0aa8127dc3afe8cda4a67eb24915f8d", + "reference": "bb899c1db0aa8127dc3afe8cda4a67eb24915f8d", "shasum": "" }, "require": { @@ -7608,7 +7610,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.38.1" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.41.0" }, "funding": [ { @@ -7628,7 +7630,7 @@ "type": "tidelift" } ], - "time": "2026-05-26T05:58:03+00:00" + "time": "2026-07-28T08:25:59+00:00" }, { "name": "symfony/polyfill-intl-idn", @@ -7973,16 +7975,16 @@ }, { "name": "symfony/polyfill-php83", - "version": "v1.38.2", + "version": "v1.41.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php83.git", - "reference": "796a26abb75ce49f3a84433cd81bf1009d73d5f8" + "reference": "5ea99087fb99c273a9b9236ed4c31e78b16103c6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/796a26abb75ce49f3a84433cd81bf1009d73d5f8", - "reference": "796a26abb75ce49f3a84433cd81bf1009d73d5f8", + "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/5ea99087fb99c273a9b9236ed4c31e78b16103c6", + "reference": "5ea99087fb99c273a9b9236ed4c31e78b16103c6", "shasum": "" }, "require": { @@ -8029,7 +8031,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php83/tree/v1.38.2" + "source": "https://github.com/symfony/polyfill-php83/tree/v1.41.0" }, "funding": [ { @@ -8049,7 +8051,7 @@ "type": "tidelift" } ], - "time": "2026-05-27T06:51:48+00:00" + "time": "2026-07-01T12:47:55+00:00" }, { "name": "symfony/polyfill-php84", @@ -8133,16 +8135,16 @@ }, { "name": "symfony/polyfill-php85", - "version": "v1.38.1", + "version": "v1.41.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php85.git", - "reference": "ba2ba04f3352cfa2dcbbcb90aee13ed967f505b1" + "reference": "255fab485aaa1006ed411040c42aecd7b5302d7a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php85/zipball/ba2ba04f3352cfa2dcbbcb90aee13ed967f505b1", - "reference": "ba2ba04f3352cfa2dcbbcb90aee13ed967f505b1", + "url": "https://api.github.com/repos/symfony/polyfill-php85/zipball/255fab485aaa1006ed411040c42aecd7b5302d7a", + "reference": "255fab485aaa1006ed411040c42aecd7b5302d7a", "shasum": "" }, "require": { @@ -8189,7 +8191,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php85/tree/v1.38.1" + "source": "https://github.com/symfony/polyfill-php85/tree/v1.41.0" }, "funding": [ { @@ -8209,7 +8211,7 @@ "type": "tidelift" } ], - "time": "2026-05-26T02:25:22+00:00" + "time": "2026-07-01T12:47:55+00:00" }, { "name": "symfony/process", @@ -8365,16 +8367,16 @@ }, { "name": "symfony/string", - "version": "v7.4.13", + "version": "v7.4.15", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "961683010db3b27ec6ebcd7308e6e1ee8fa7ffde" + "reference": "e394af32256bf9e7bf80849d95e589167c10097b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/961683010db3b27ec6ebcd7308e6e1ee8fa7ffde", - "reference": "961683010db3b27ec6ebcd7308e6e1ee8fa7ffde", + "url": "https://api.github.com/repos/symfony/string/zipball/e394af32256bf9e7bf80849d95e589167c10097b", + "reference": "e394af32256bf9e7bf80849d95e589167c10097b", "shasum": "" }, "require": { @@ -8432,7 +8434,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v7.4.13" + "source": "https://github.com/symfony/string/tree/v7.4.15" }, "funding": [ { @@ -8452,7 +8454,7 @@ "type": "tidelift" } ], - "time": "2026-05-23T15:23:29+00:00" + "time": "2026-07-28T07:33:02+00:00" }, { "name": "symfony/translation", @@ -8638,16 +8640,16 @@ }, { "name": "symfony/var-dumper", - "version": "v7.4.14", + "version": "v7.4.15", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "9a3a56a4a1e65a5cb4f8d13801fe8ab0a170e358" + "reference": "04ba4add636a95ff437af3a5a9499bb1d6c6d4bd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/9a3a56a4a1e65a5cb4f8d13801fe8ab0a170e358", - "reference": "9a3a56a4a1e65a5cb4f8d13801fe8ab0a170e358", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/04ba4add636a95ff437af3a5a9499bb1d6c6d4bd", + "reference": "04ba4add636a95ff437af3a5a9499bb1d6c6d4bd", "shasum": "" }, "require": { @@ -8663,7 +8665,7 @@ "symfony/http-kernel": "^6.4|^7.0|^8.0", "symfony/process": "^6.4|^7.0|^8.0", "symfony/uid": "^6.4|^7.0|^8.0", - "twig/twig": "^3.12" + "twig/twig": "^3.12|^4.0" }, "bin": [ "Resources/bin/var-dump-server" @@ -8701,7 +8703,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v7.4.14" + "source": "https://github.com/symfony/var-dumper/tree/v7.4.15" }, "funding": [ { @@ -8721,7 +8723,7 @@ "type": "tidelift" } ], - "time": "2026-06-08T20:24:16+00:00" + "time": "2026-07-21T15:13:06+00:00" }, { "name": "ta-tikoma/phpunit-architecture-test", diff --git a/tests/Feature/Commands/ConvertCommandTest.php b/tests/Feature/Commands/ConvertCommandTest.php index d1ae185..f1199ca 100644 --- a/tests/Feature/Commands/ConvertCommandTest.php +++ b/tests/Feature/Commands/ConvertCommandTest.php @@ -240,6 +240,59 @@ ]); }); +test('includes the psnr in the JSON output when the API reports one', function () { + fakeTransform('convert', 'webp', ['psnr' => 41.27]); + + $input = createImage('photo.png'); + $expectedOutput = dirname($input).'/photo.webp'; + + $exitCode = Artisan::call('convert', ['input' => $input, '--format' => 'webp', '--json' => true]); + + expect($exitCode)->toBe(0) + ->and(json_decode(Artisan::output(), true))->toBe([ + 'output' => $expectedOutput, + 'format' => 'webp', + 'mime_type' => 'image/webp', + 'size' => strlen(Images::jpg()), + 'width' => 1280, + 'height' => 720, + 'psnr' => 41.27, + ]); +}); + +test('omits the psnr from the JSON output when the API reports null', function () { + fakeTransform('convert', 'webp', ['psnr' => null]); + + $input = createImage('photo.png'); + + $exitCode = Artisan::call('convert', ['input' => $input, '--format' => 'webp', '--json' => true]); + + expect($exitCode)->toBe(0) + ->and(json_decode(Artisan::output(), true))->not->toHaveKey('psnr'); +}); + +test('leaves PSNR out of the human summary when the API reports null', function () { + fakeTransform('convert', 'webp', ['psnr' => null]); + + $input = createImage('photo.png'); + $expectedOutput = dirname($input).'/photo.webp'; + + $this->artisan('convert', ['input' => $input, '--format' => 'webp']) + ->expectsOutput("Wrote {$expectedOutput} (image/webp, ".strlen(Images::jpg()).' B, 1280x720)') + ->assertExitCode(0); +}); + +test('appends the psnr to the human summary when the API reports one', function () { + fakeTransform('convert', 'webp', ['psnr' => 41.27]); + + $input = createImage('photo.png'); + $expectedOutput = dirname($input).'/photo.webp'; + + $this->artisan('convert', ['input' => $input, '--format' => 'webp']) + ->expectsOutputToContain("Wrote {$expectedOutput} (image/webp, ".strlen(Images::jpg()).' B, 1280x720, PSNR 41.27 dB)') + ->assertExitCode(0); +}); + test('stdin input requires an explicit output path', function () { Http::fake(); diff --git a/tests/Feature/Commands/OptimizeCommandTest.php b/tests/Feature/Commands/OptimizeCommandTest.php index 3ca20a3..27226c7 100644 --- a/tests/Feature/Commands/OptimizeCommandTest.php +++ b/tests/Feature/Commands/OptimizeCommandTest.php @@ -23,6 +23,17 @@ Http::assertSent(fn (Request $request) => $request['quality'] === 70); }); +test('appends the psnr to the summary when the API reports one', function () { + fakeTransform('optimize', 'jpg', ['psnr' => 43.75]); + + $input = createImage('photo.png'); + $expectedOutput = dirname($input).'/photo.optimized.jpg'; + + $this->artisan('optimize', ['input' => $input]) + ->expectsOutputToContain("Wrote {$expectedOutput} (image/jpeg, ".strlen(Images::jpg()).' B, 1280x720, PSNR 43.75 dB)') + ->assertExitCode(0); +}); + test('--in-place overwrites the input file without --force', function () { fakeTransform('optimize', 'png'); diff --git a/tests/Feature/Commands/ResizeCommandTest.php b/tests/Feature/Commands/ResizeCommandTest.php index d0e15aa..1c1c0b5 100644 --- a/tests/Feature/Commands/ResizeCommandTest.php +++ b/tests/Feature/Commands/ResizeCommandTest.php @@ -1,6 +1,7 @@ data())); }); +test('never carries a psnr key, since the resize response has none', function () { + fakeTransform('resize'); + + $input = createImage('photo.png'); + $expectedOutput = dirname($input).'/photo.resized.jpg'; + + $exitCode = Artisan::call('resize', ['input' => $input, '--width' => '800', '--json' => true]); + + expect($exitCode)->toBe(0) + ->and(json_decode(Artisan::output(), true))->toBe([ + 'output' => $expectedOutput, + 'format' => 'jpg', + 'mime_type' => 'image/jpeg', + 'size' => strlen(Images::jpg()), + 'width' => 1280, + 'height' => 720, + ]); +}); + test('--in-place overwrites the input file without --force', function () { fakeTransform('resize', 'png'); diff --git a/tests/Pest.php b/tests/Pest.php index c35b8ab..f05e08a 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -190,11 +190,12 @@ function fakeAnalyzeResponse(): array /** * A canned successful transform-endpoint response envelope. * + * @param array $overrides * @return array{data: array} */ -function fakeTransformResponse(string $format = 'jpg', string $mimeType = 'image/jpeg'): array +function fakeTransformResponse(string $format = 'jpg', string $mimeType = 'image/jpeg', array $overrides = []): array { - return ['data' => [ + return ['data' => $overrides + [ 'output' => ['type' => 'BASE64', 'data' => Images::JPG_BASE64], 'format' => $format, 'mime_type' => $mimeType, @@ -207,8 +208,10 @@ function fakeTransformResponse(string $format = 'jpg', string $mimeType = 'image /** * Fake a transform endpoint (convert, optimize, resize, thumbnail) with a * canned successful response reporting the given output format. + * + * @param array $overrides */ -function fakeTransform(string $endpoint, string $format = 'jpg'): void +function fakeTransform(string $endpoint, string $format = 'jpg', array $overrides = []): void { $mimeType = [ 'jpg' => 'image/jpeg', @@ -218,5 +221,5 @@ function fakeTransform(string $endpoint, string $format = 'jpg'): void 'avif' => 'image/avif', ][$format]; - Http::fake(["*/v1/{$endpoint}" => Http::response(fakeTransformResponse($format, $mimeType))]); + Http::fake(["*/v1/{$endpoint}" => Http::response(fakeTransformResponse($format, $mimeType, $overrides))]); }