[
  {
    "path": ".editorconfig",
    "content": "# editorconfig.org\n\nroot = true\n\n[*.php]\nindent_size = 4\nindent_style = space\nindent_size = 4\nend_of_line = lf\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\n"
  },
  {
    "path": ".gitattributes",
    "content": "* text=auto\n\n/.editorconfig      export-ignore\n/.github            export-ignore\n/.well-known        export-ignore\n/CONTRIBUTING.md    export-ignore\n/tests              export-ignore\n/.gitattributes     export-ignore\n/.gitignore         export-ignore\n/phpcs.xml.dist     export-ignore\n/phpunit.dist.xml   export-ignore\n/phpstan.dist.neon  export-ignore\n/docker-compose.yml export-ignore\n/Dockerfile         export-ignore\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "github: [Intervention]\nko_fi: interventionphp\ncustom: https://paypal.me/interventionio\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: ''\nassignees: ''\n---\n\n## Describe the bug\nA clear and concise description of what the bug is.\n\n## Code Example\nCode example to reproduce the behavior.\n\n## Expected behavior\nA clear and concise description of what you expected to happen.\n\n## Images\nIf applicable, add problematic images or screenshots to help explain your problem.\n\n## Environment (please complete the following information):\n - PHP Version:\n - OS:\n - Intervention Image Version:\n - GD, Imagick or libvips:\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: ''\nassignees: ''\n---\n\n## Describe the feature you'd like\nA clear and concise description of what you want to happen.\n\n## Is your feature request related to a problem? Please describe.\nA clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n"
  },
  {
    "path": ".github/workflows/run-tests.yml",
    "content": "name: Tests\n\non: [ push, pull_request ]\n\njobs:\n  run:\n    runs-on: ubuntu-22.04\n    strategy:\n      fail-fast: false\n      matrix:\n        php: [ '8.1', '8.2', '8.3', '8.4', '8.5' ]\n        imagemagick: [ '6.9.13-25', '7.1.1-47' ]\n\n    name: PHP ${{ matrix.php }} - ImageMagick ${{ matrix.imagemagick }}\n\n    steps:\n      - name: Checkout project\n        uses: actions/checkout@v4\n\n      - name: Setup PHP\n        uses: shivammathur/setup-php@v2\n        with:\n          php-version: ${{ matrix.php }}\n          extensions: mbstring, gd\n          coverage: none\n\n      - name: Prepare environment for Imagemagick\n        run: |\n          sudo apt remove -y imagemagick imagemagick-6-common libmagic-dev\n          sudo apt update --allow-releaseinfo-change\n          sudo apt update\n          sudo apt install -y libjpeg-dev libgif-dev libtiff-dev libpng-dev libwebp-dev libavif-dev libheif-dev libraqm-dev libmagickwand-dev\n\n      - name: Cache ImageMagick\n        uses: actions/cache@v4\n        id: cache-imagemagick\n        with:\n          path: /home/runner/im/imagemagick-${{ matrix.imagemagick }}\n          key: ${{ runner.os }}-ImageMagick-${{ matrix.imagemagick }}-${{ hashFiles('**/composer.json') }}\n          restore-keys: ${{ runner.os }}-ImageMagick-${{ matrix.imagemagick }}-\n\n      - name: Check ImageMagick cache exists\n        uses: andstor/file-existence-action@v3\n        id: cache-imagemagick-exists\n        with:\n          files: /home/runner/im/imagemagick-${{ matrix.imagemagick }}\n\n      - name: Install ImageMagick\n        if: ( steps.cache-imagemagick.outputs.cache-hit != 'true' || steps.cache-imagemagick-exists.outputs.files_exists != 'true' )\n        run: |\n          curl -o /tmp/ImageMagick.tar.xz -sL https://imagemagick.org/archive/releases/ImageMagick-${{ matrix.imagemagick }}.tar.xz\n          (\n            cd /tmp || exit 1\n            tar xf ImageMagick.tar.xz\n            cd ImageMagick-${{ matrix.imagemagick }}\n            sudo ./configure --prefix=/home/runner/im/imagemagick-${{ matrix.imagemagick }}\n            sudo make -j$(nproc)\n            sudo make install\n          )\n\n      - name: Install Imagick PHP extension\n        run: |\n          git clone --depth=1 --single-branch --branch master https://github.com/Imagick/imagick /tmp/imagick\n          (\n            cd /tmp/imagick || exit 1\n            phpize\n            sudo ./configure --with-imagick=/home/runner/im/imagemagick-${{ matrix.imagemagick }}\n            sudo make -j$(nproc)\n            sudo make install\n          )\n          sudo bash -c 'echo \"extension=imagick.so\" >> /etc/php/${{ matrix.php }}/cli/php.ini'\n          php --ri imagick;\n\n      - name: Get composer cache directory\n        id: composer-cache\n        run: echo \"dir=$(composer config cache-files-dir)\" >> $GITHUB_OUTPUT\n\n      - name: Cache composer dependencies\n        uses: actions/cache@v4\n        with:\n          path: ${{ steps.composer-cache.outputs.dir }}\n          key: ${{ runner.os }}-php-${{ matrix.php }}-${{ hashFiles('**/composer.json') }}\n          restore-keys: ${{ runner.os }}-php-${{ matrix.php }}-\n\n      - name: Install dependencies\n        run: composer update --prefer-stable --prefer-dist --no-interaction\n\n      - name: GD Version\n        run: php -r 'var_dump(gd_info());'\n\n      - name: Imagick Version\n        run: php -r 'var_dump(Imagick::getVersion());'\n\n      - name: Supported Imagick Formats\n        run: php -r 'var_dump(Imagick::queryFormats());'\n\n      - name: Execute tests\n        run: vendor/bin/phpunit --no-coverage\n\n      - name: Run analyzer\n        run: vendor/bin/phpstan\n\n      - name: Validate coding standards\n        run: vendor/bin/phpcs\n"
  },
  {
    "path": ".gitignore",
    "content": "build/\nvendor/\n/.phpunit.cache\ncomposer.lock\nphpunit.xml\nphpcs.xml\nphpstan.neon\n"
  },
  {
    "path": ".well-known/funding-manifest-urls",
    "content": "https://intervention.io/funding.json\nhttps://image.intervention.io/funding.json\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing to Intervention Image\n\nThank you for your interest in contributing to the project. \n\nYou can read the full contribution guide on https://intervention.io/contributing/.\n"
  },
  {
    "path": "Dockerfile",
    "content": "FROM php:8.1-cli\n\n# install dependencies\nRUN apt update \\\n        && apt install -y \\\n            libmagickwand-dev \\\n            libwebp-dev \\\n            libpng-dev \\\n            libavif-dev \\\n            git \\\n            zip \\\n        && pecl install imagick \\\n        && pecl install xdebug \\\n        && docker-php-ext-configure gd --with-freetype --with-jpeg --with-webp --with-avif \\\n        && docker-php-ext-enable \\\n            imagick \\\n            xdebug \\\n        && docker-php-ext-install \\\n            gd \\\n            exif \\\n        && apt-get clean\n\n# install composer\nCOPY --from=composer /usr/bin/composer /usr/bin/composer\n\n# install composer dependencies\nCOPY composer.json composer.lock ./\nRUN composer install\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2013-present Oliver Vogel\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies\nof the Software, and to permit persons to whom the Software is furnished to do\nso, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "composer.json",
    "content": "{\n    \"name\": \"intervention/image\",\n    \"description\": \"PHP Image Processing\",\n    \"homepage\": \"https://image.intervention.io\",\n    \"keywords\": [\n        \"image\",\n        \"gd\",\n        \"imagick\",\n        \"watermark\",\n        \"thumbnail\",\n        \"resize\"\n    ],\n    \"license\": \"MIT\",\n    \"authors\": [\n        {\n            \"name\": \"Oliver Vogel\",\n            \"email\": \"oliver@intervention.io\",\n            \"homepage\": \"https://intervention.io\"\n        }\n    ],\n    \"require\": {\n        \"php\": \"^8.1\",\n        \"ext-mbstring\": \"*\",\n        \"intervention/gif\": \"^4.2\"\n    },\n    \"require-dev\": {\n        \"phpunit/phpunit\": \"^10.0 || ^11.0 || ^12.0\",\n        \"mockery/mockery\": \"^1.6\",\n        \"phpstan/phpstan\": \"^2.1\",\n        \"squizlabs/php_codesniffer\": \"^4\",\n        \"slevomat/coding-standard\": \"~8.0\"\n    },\n    \"suggest\": {\n        \"ext-exif\": \"Recommended to be able to read EXIF data properly.\"\n    },\n    \"autoload\": {\n        \"psr-4\": {\n            \"Intervention\\\\Image\\\\\": \"src\"\n        }\n    },\n    \"autoload-dev\": {\n        \"psr-4\": {\n            \"Intervention\\\\Image\\\\Tests\\\\\": \"tests\"\n        }\n    },\n    \"config\": {\n        \"allow-plugins\": {\n            \"dealerdirect/phpcodesniffer-composer-installer\": true\n        }\n    }\n}\n"
  },
  {
    "path": "docker-compose.yml",
    "content": "services:\n  tests:\n    build: ./\n    working_dir: /project\n    entrypoint: [\"./vendor/bin/phpunit\"]\n    volumes:\n      - ./:/project\n  coverage:\n    build: ./\n    working_dir: /project\n    entrypoint: [\"./vendor/bin/phpunit\", \"--coverage-text\"]\n    volumes:\n      - ./:/project\n    environment:\n      - XDEBUG_MODE=coverage\n  analysis:\n    build: ./\n    working_dir: /project\n    entrypoint: [\"./vendor/bin/phpstan\", \"analyze\", \"--memory-limit=512M\"]\n    volumes:\n      - ./:/project\n  standards:\n    build: ./\n    working_dir: /project\n    entrypoint: [\"./vendor/bin/phpcs\"]\n    volumes:\n      - ./:/project\n"
  },
  {
    "path": "phpcs.xml.dist",
    "content": "<?xml version=\"1.0\"?>\n<ruleset name=\"Intervention\">\n    <file>src/</file>\n    <file>tests/</file>\n    <arg name=\"colors\"/>\n    <arg value=\"p\"/>\n\n    <rule ref=\"PSR12\"/>\n    <rule ref=\"Generic.Arrays.ArrayIndent\"/>\n    <rule ref=\"Generic.ControlStructures.InlineControlStructure\"/>\n    <rule ref=\"Generic.Formatting.SpaceAfterCast\"/>\n    <rule ref=\"Generic.Formatting.SpaceAfterNot\">\n        <properties>\n            <property name=\"spacing\" value=\"0\" />\n        </properties>\n    </rule>\n    <rule ref=\"Generic.Metrics.NestingLevel\"/>\n    <rule ref=\"SlevomatCodingStandard.Arrays.SingleLineArrayWhitespace\"/>\n    <rule ref=\"SlevomatCodingStandard.Arrays.DisallowImplicitArrayCreation\"/>\n    <rule ref=\"SlevomatCodingStandard.Arrays.DisallowPartiallyKeyed\"/>\n    <rule ref=\"SlevomatCodingStandard.Arrays.MultiLineArrayEndBracketPlacement\"/>\n    <rule ref=\"SlevomatCodingStandard.Classes.ClassConstantVisibility\"/>\n    <rule ref=\"SlevomatCodingStandard.Classes.ClassMemberSpacing\"/>\n    <rule ref=\"SlevomatCodingStandard.Classes.ConstantSpacing\"/>\n    <rule ref=\"SlevomatCodingStandard.Classes.MethodSpacing\"/>\n    <rule ref=\"SlevomatCodingStandard.Classes.ModernClassNameReference\"/>\n    <rule ref=\"SlevomatCodingStandard.Classes.ParentCallSpacing\"/>\n    <rule ref=\"SlevomatCodingStandard.Classes.PropertyDeclaration\"/>\n    <rule ref=\"SlevomatCodingStandard.Classes.RequireSelfReference\"/>\n    <rule ref=\"SlevomatCodingStandard.Classes.TraitUseDeclaration\"/>\n    <rule ref=\"SlevomatCodingStandard.Classes.ClassStructure\">\n        <properties>\n            <property name=\"methodGroups\" type=\"array\">\n                <element key=\"phpunit\" value=\"setUp\"/>\n            </property>\n            <property name=\"groups\" type=\"array\">\n                <element value=\"uses\"/>\n                <element value=\"enum cases\"/>\n                <element value=\"public constants\"/>\n                <element value=\"constants\"/>\n                <element value=\"public static properties, protected static properties, private static properties\"/>\n                <element value=\"public properties, protected properties, private properties\"/>\n                <element value=\"abstract methods\"/>\n                <element value=\"constructor\"/>\n                <element value=\"phpunit\"/>\n                <element value=\"static constructors\"/>\n                <element value=\"methods\"/>\n                <element value=\"magic methods\"/>\n            </property>\n        </properties>\n    </rule>\n    <rule ref=\"SlevomatCodingStandard.Files.TypeNameMatchesFileName\">\n        <properties>\n            <property name=\"rootNamespaces\" type=\"array\">\n                <element key=\"src\" value=\"Intervention\\Image\"/>\n                <element key=\"tests\" value=\"Intervention\\Image\\Tests\"/>\n            </property>\n        </properties>\n    </rule>\n    <rule ref=\"SlevomatCodingStandard.Namespaces.DisallowGroupUse\"/>\n    <rule ref=\"SlevomatCodingStandard.Namespaces.MultipleUsesPerLine\"/>\n    <rule ref=\"SlevomatCodingStandard.Namespaces.UnusedUses\">\n        <properties>\n            <property name=\"searchAnnotations\" value=\"true\" />\n        </properties>\n    </rule>\n    <rule ref=\"SlevomatCodingStandard.Namespaces.UseDoesNotStartWithBackslash\"/>\n    <rule ref=\"SlevomatCodingStandard.Namespaces.UseFromSameNamespace\"/>\n    <rule ref=\"SlevomatCodingStandard.Namespaces.UseSpacing\"/>\n    <rule ref=\"SlevomatCodingStandard.Namespaces.UselessAlias\"/>\n    <rule ref=\"SlevomatCodingStandard.Strings.DisallowVariableParsing\"/>\n    <rule ref=\"SlevomatCodingStandard.TypeHints.DeclareStrictTypes\">\n        <properties>\n            <property name=\"spacesCountAroundEqualsSign\" value=\"0\" />\n        </properties>\n    </rule>\n    <rule ref=\"SlevomatCodingStandard.TypeHints.LongTypeHints\"/>\n    <rule ref=\"SlevomatCodingStandard.TypeHints.ParameterTypeHint\"/>\n    <rule ref=\"SlevomatCodingStandard.TypeHints.ReturnTypeHint\"/>\n    <rule ref=\"SlevomatCodingStandard.TypeHints.PropertyTypeHint\"/>\n    <rule ref=\"SlevomatCodingStandard.TypeHints.UselessConstantTypeHint\"/>\n    <rule ref=\"SlevomatCodingStandard.TypeHints.NullableTypeForNullDefaultValue\"/>\n    <rule ref=\"SlevomatCodingStandard.TypeHints.ParameterTypeHintSpacing\"/>\n    <rule ref=\"SlevomatCodingStandard.TypeHints.ReturnTypeHintSpacing\"/>\n    <rule ref=\"SlevomatCodingStandard.TypeHints.DNFTypeHintFormat\">\n        <properties>\n            <property name=\"withSpacesAroundOperators\" value=\"no\" />\n            <property name=\"nullPosition\" value=\"first\" />\n        </properties>\n    </rule>\n    <rule ref=\"SlevomatCodingStandard.PHP.UselessSemicolon\"/>\n    <rule ref=\"SlevomatCodingStandard.Whitespaces.DuplicateSpaces\"/>\n    <rule ref=\"SlevomatCodingStandard.Operators.SpreadOperatorSpacing\">\n        <properties>\n            <property name=\"spacesCountAfterOperator\" value=\"0\" />\n        </properties>\n    </rule>\n    <rule ref=\"SlevomatCodingStandard.PHP.ShortList\"/>\n    <rule ref=\"SlevomatCodingStandard.PHP.TypeCast\"/>\n    <rule ref=\"SlevomatCodingStandard.Variables.UnusedVariable\"/>\n    <rule ref=\"SlevomatCodingStandard.Variables.UselessVariable\"/>\n    <rule ref=\"SlevomatCodingStandard.Commenting.DocCommentSpacing\">\n        <properties>\n            <property name=\"linesCountBeforeFirstContent\" value=\"0\"/>\n            <property name=\"linesCountAfterLastContent\" value=\"0\"/>\n            <property name=\"linesCountBetweenDescriptionAndAnnotations\" value=\"1\"/>\n            <property name=\"linesCountBetweenAnnotationsGroups\" value=\"1\"/>\n            <property name=\"annotationsGroups\" type=\"array\">\n                <element value=\"\n                    @ORM\\,\n                    @ODM\\,\n                    \"/>\n                <element value=\"\n                    @link,\n                    @internal,\n                    @deprecated,\n                    @see,\n                    @uses,\n                    \"/>\n                <element value=\"\n                    @param,\n                    @throws,\n                    @return,\n                    \"/>\n            </property>\n        </properties>\n    </rule>\n</ruleset>\n"
  },
  {
    "path": "phpstan.dist.neon",
    "content": "parameters:\n    level: 6\n    paths:\n        - src\n    reportUnmatchedIgnoredErrors: false\n    ignoreErrors:\n        - \n            identifier: unset.possiblyHookedProperty\n    exceptions:\n        check:\n            missingCheckedExceptionInThrows: true\n        uncheckedExceptionClasses:\n            - ImagickException\n            - ImagickDrawException\n            - ImagickPixelException\n            - Error\n"
  },
  {
    "path": "phpunit.dist.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<phpunit \n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" \n    xsi:noNamespaceSchemaLocation=\"https://schema.phpunit.de/10.5/phpunit.xsd\" \n    backupGlobals=\"false\" \n    backupStaticProperties=\"false\" \n    beStrictAboutTestsThatDoNotTestAnything=\"false\" \n    bootstrap=\"vendor/autoload.php\" \n    cacheDirectory=\".phpunit.cache\" \n    colors=\"true\" \n    displayDetailsOnTestsThatTriggerNotices=\"true\"\n    processIsolation=\"false\" \n    stopOnFailure=\"false\">\n  <testsuites>\n    <testsuite name=\"Unit Tests\">\n      <directory suffix=\".php\">./tests/Unit</directory>\n    </testsuite>\n    <testsuite name=\"Feature Tests\">\n      <directory suffix=\".php\">./tests/Feature</directory>\n    </testsuite>\n  </testsuites>\n  <source>\n    <include>\n      <directory suffix=\".php\">src</directory>\n    </include>\n  </source>\n</phpunit>\n"
  },
  {
    "path": "readme.md",
    "content": "# Intervention Image\n## PHP Image Processing\n\n[![Latest Version](https://img.shields.io/packagist/v/intervention/image.svg)](https://packagist.org/packages/intervention/image)\n[![Build Status](https://github.com/Intervention/image/actions/workflows/run-tests.yml/badge.svg)](https://github.com/Intervention/image/actions)\n[![Monthly Downloads](https://img.shields.io/packagist/dm/intervention/image.svg)](https://packagist.org/packages/intervention/image/stats)\n[![Support me on Ko-fi](https://raw.githubusercontent.com/Intervention/image/develop/.github/images/support.svg)](https://ko-fi.com/interventionphp)\n\nIntervention Image is a **PHP image processing library** that provides a simple\nand expressive way to create, edit, and compose images. It comes with a universal\ninterface for the two most popular PHP image manipulation extensions. You can\nchoose between the GD library or Imagick as the base layer for all operations.\n\n- Simple interface for common image editing tasks\n- Interchangeable driver architecture\n- Support for animated images\n- Framework-agnostic\n- PSR-12 compliant\n\n## Installation\n\nYou can easily install this library using [Composer](https://getcomposer.org).\nSimply request the package with the following command:\n\n```bash\ncomposer require intervention/image\n```\n\n## Getting Started\n\nLearn the [basics](https://image.intervention.io/v3/basics/instantiation/) on\nhow to use Intervention Image and more with the [official\ndocumentation](https://image.intervention.io/v3/).\n\n## Code Examples\n\n```php\nuse Intervention\\Image\\ImageManager;\n\n// create image manager with desired driver\n$manager = new ImageManager(\n    new Intervention\\Image\\Drivers\\Gd\\Driver()\n);\n\n// open an image file\n$image = $manager->read('images/example.gif');\n\n// resize image instance\n$image->resize(height: 300);\n\n// insert a watermark\n$image->place('images/watermark.png');\n\n// encode edited image\n$encoded = $image->toJpg();\n\n// save encoded image\n$encoded->save('images/example.jpg');\n```\n\n## Requirements\n\nBefore you begin with the installation make sure that your server environment\nsupports the following requirements.\n\n- PHP >= 8.1\n- Mbstring PHP Extension\n- Image Processing PHP Extension\n\n## Supported Image Libraries\n\nDepending on your environment Intervention Image lets you choose between\ndifferent image processing extensions.\n\n- GD Library\n- Imagick PHP extension\n- [libvips](https://github.com/Intervention/image-driver-vips)\n\n## Security\n\nIf you discover any security related issues, please email oliver@intervention.io directly.\n\n## Authors\n\nThis library is developed and maintained by [Oliver Vogel](https://intervention.io)\n\nThanks to the community of [contributors](https://github.com/Intervention/image/graphs/contributors) who have helped to improve this project.\n\n## License\n\nIntervention Image is licensed under the [MIT License](LICENSE).\n"
  },
  {
    "path": "src/Analyzers/ColorspaceAnalyzer.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Analyzers;\n\nuse Intervention\\Image\\Drivers\\SpecializableAnalyzer;\n\nclass ColorspaceAnalyzer extends SpecializableAnalyzer\n{\n    //\n}\n"
  },
  {
    "path": "src/Analyzers/HeightAnalyzer.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Analyzers;\n\nuse Intervention\\Image\\Drivers\\SpecializableAnalyzer;\n\nclass HeightAnalyzer extends SpecializableAnalyzer\n{\n    //\n}\n"
  },
  {
    "path": "src/Analyzers/PixelColorAnalyzer.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Analyzers;\n\nuse Intervention\\Image\\Drivers\\SpecializableAnalyzer;\n\nclass PixelColorAnalyzer extends SpecializableAnalyzer\n{\n    public function __construct(\n        public int $x,\n        public int $y,\n        public int $frame_key = 0\n    ) {\n        //\n    }\n}\n"
  },
  {
    "path": "src/Analyzers/PixelColorsAnalyzer.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Analyzers;\n\nuse Intervention\\Image\\Drivers\\SpecializableAnalyzer;\n\nclass PixelColorsAnalyzer extends SpecializableAnalyzer\n{\n    public function __construct(\n        public int $x,\n        public int $y\n    ) {\n        //\n    }\n}\n"
  },
  {
    "path": "src/Analyzers/ProfileAnalyzer.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Analyzers;\n\nuse Intervention\\Image\\Drivers\\SpecializableAnalyzer;\n\nclass ProfileAnalyzer extends SpecializableAnalyzer\n{\n    //\n}\n"
  },
  {
    "path": "src/Analyzers/ResolutionAnalyzer.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Analyzers;\n\nuse Intervention\\Image\\Drivers\\SpecializableAnalyzer;\n\nclass ResolutionAnalyzer extends SpecializableAnalyzer\n{\n    //\n}\n"
  },
  {
    "path": "src/Analyzers/WidthAnalyzer.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Analyzers;\n\nuse Intervention\\Image\\Drivers\\SpecializableAnalyzer;\n\nclass WidthAnalyzer extends SpecializableAnalyzer\n{\n    //\n}\n"
  },
  {
    "path": "src/Collection.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image;\n\nuse Intervention\\Image\\Interfaces\\CollectionInterface;\nuse ArrayIterator;\nuse Countable;\nuse Traversable;\nuse IteratorAggregate;\n\n/**\n * @implements IteratorAggregate<int|string, mixed>\n */\nclass Collection implements CollectionInterface, IteratorAggregate, Countable\n{\n    /**\n     * Create new collection object\n     *\n     * @param array<int|string, mixed> $items\n     * @return void\n     */\n    public function __construct(protected array $items = [])\n    {\n        //\n    }\n\n    /**\n     * Static constructor\n     *\n     * @param array<int|string, mixed> $items\n     * @return self<int|string, mixed>\n     */\n    public static function create(array $items = []): self\n    {\n        return new self($items);\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see CollectionInterface::has()\n     */\n    public function has(int|string $key): bool\n    {\n        return array_key_exists($key, $this->items);\n    }\n\n    /**\n     * Returns Iterator\n     *\n     * @return Traversable<int|string, mixed>\n     */\n    public function getIterator(): Traversable\n    {\n        return new ArrayIterator($this->items);\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see CollectionInterface::toArray()\n     */\n    public function toArray(): array\n    {\n        return $this->items;\n    }\n\n    /**\n     * Count items in collection\n     */\n    public function count(): int\n    {\n        return count($this->items);\n    }\n\n    /**\n     * Append new item to collection\n     *\n     * @return CollectionInterface<int|string, mixed>\n     */\n    public function push(mixed $item): CollectionInterface\n    {\n        $this->items[] = $item;\n\n        return $this;\n    }\n\n    /**\n     * Return first item in collection\n     */\n    public function first(): mixed\n    {\n        if ($item = reset($this->items)) {\n            return $item;\n        }\n\n        return null;\n    }\n\n    /**\n     * Returns last item in collection\n     */\n    public function last(): mixed\n    {\n        if ($item = end($this->items)) {\n            return $item;\n        }\n\n        return null;\n    }\n\n    /**\n     * Return item at given position starting at 0\n     */\n    public function getAtPosition(int $key = 0, mixed $default = null): mixed\n    {\n        if ($this->count() == 0) {\n            return $default;\n        }\n\n        $positions = array_values($this->items);\n        if (!array_key_exists($key, $positions)) {\n            return $default;\n        }\n\n        return $positions[$key];\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see CollectionInterface::get()\n     */\n    public function get(int|string $query, mixed $default = null): mixed\n    {\n        if ($this->count() == 0) {\n            return $default;\n        }\n\n        if (is_int($query) && array_key_exists($query, $this->items)) {\n            return $this->items[$query];\n        }\n\n        if (is_string($query) && !str_contains($query, '.')) {\n            return array_key_exists($query, $this->items) ? $this->items[$query] : $default;\n        }\n\n        $query = explode('.', (string) $query);\n\n        $result = $default;\n        $items = $this->items;\n        foreach ($query as $key) {\n            if (!is_array($items) || !array_key_exists($key, $items)) {\n                $result = $default;\n                break;\n            }\n\n            $result = $items[$key];\n            $items = $result;\n        }\n\n        return $result;\n    }\n\n    /**\n     * Map each item of collection by given callback\n     */\n    public function map(callable $callback): self\n    {\n\n        return new self(\n            array_map(\n                fn(mixed $item) => $callback($item),\n                $this->items,\n            )\n        );\n    }\n\n    /**\n     * Run callback on each item of the collection an remove it if it does not return true\n     */\n    public function filter(callable $callback): self\n    {\n        return new self(\n            array_filter(\n                $this->items,\n                fn(mixed $item) => $callback($item),\n            )\n        );\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see CollectionInterface::empty()\n     */\n    public function empty(): CollectionInterface\n    {\n        $this->items = [];\n\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see CollectionInterface::slice()\n     */\n    public function slice(int $offset, ?int $length = null): CollectionInterface\n    {\n        $this->items = array_slice($this->items, $offset, $length);\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/Colors/AbstractColor.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Colors;\n\nuse Intervention\\Image\\Exceptions\\ColorException;\nuse Intervention\\Image\\Interfaces\\ColorChannelInterface;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Interfaces\\ColorspaceInterface;\nuse ReflectionClass;\nuse Stringable;\n\nabstract class AbstractColor implements ColorInterface, Stringable\n{\n    /**\n     * Color channels\n     *\n     * @var array<ColorChannelInterface>\n     */\n    protected array $channels;\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorInterface::channels()\n     */\n    public function channels(): array\n    {\n        return $this->channels;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorInterface::channel()\n     */\n    public function channel(string $classname): ColorChannelInterface\n    {\n        $channels = array_filter(\n            $this->channels(),\n            fn(ColorChannelInterface $channel): bool => $channel::class === $classname,\n        );\n\n        if (count($channels) == 0) {\n            throw new ColorException('Color channel ' . $classname . ' could not be found.');\n        }\n\n        return reset($channels);\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorInterface::normalize()\n     */\n    public function normalize(): array\n    {\n        return array_map(\n            fn(ColorChannelInterface $channel): float => $channel->normalize(),\n            $this->channels(),\n        );\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorInterface::toArray()\n     */\n    public function toArray(): array\n    {\n        return array_map(\n            fn(ColorChannelInterface $channel): int => $channel->value(),\n            $this->channels()\n        );\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorInterface::convertTo()\n     */\n    public function convertTo(string|ColorspaceInterface $colorspace): ColorInterface\n    {\n        $colorspace = match (true) {\n            is_object($colorspace) => $colorspace,\n            default => new $colorspace(),\n        };\n\n        return $colorspace->importColor($this);\n    }\n\n    /**\n     * Show debug info for the current color\n     *\n     * @return array<string, int>\n     */\n    public function __debugInfo(): array\n    {\n        return array_reduce($this->channels(), function (array $result, ColorChannelInterface $item) {\n            $key = strtolower((new ReflectionClass($item))->getShortName());\n            $result[$key] = $item->value();\n            return $result;\n        }, []);\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorInterface::__toString()\n     */\n    public function __toString(): string\n    {\n        return $this->toString();\n    }\n}\n"
  },
  {
    "path": "src/Colors/AbstractColorChannel.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Colors;\n\nuse Intervention\\Image\\Exceptions\\ColorException;\nuse Intervention\\Image\\Interfaces\\ColorChannelInterface;\nuse Stringable;\n\nabstract class AbstractColorChannel implements ColorChannelInterface, Stringable\n{\n    protected int $value;\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorChannelInterface::__construct()\n     */\n    public function __construct(?int $value = null, ?float $normalized = null)\n    {\n        $this->value = $this->validate(\n            match (true) {\n                is_null($value) && is_numeric($normalized) => intval(round($normalized * $this->max())),\n                is_numeric($value) && is_null($normalized) => $value,\n                default => throw new ColorException('Color channels must either have a value or a normalized value')\n            }\n        );\n    }\n\n    /**\n     * Alias of value()\n     */\n    public function toInt(): int\n    {\n        return $this->value;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorChannelInterface::value()\n     */\n    public function value(): int\n    {\n        return $this->value;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorChannelInterface::normalize()\n     */\n    public function normalize(int $precision = 32): float\n    {\n        return round(($this->value() - $this->min()) / ($this->max() - $this->min()), $precision);\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorChannelInterface::validate()\n     */\n    public function validate(mixed $value): mixed\n    {\n        if ($value < $this->min() || $value > $this->max()) {\n            throw new ColorException('Color channel value must be in range ' . $this->min() . ' to ' . $this->max());\n        }\n\n        return $value;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorChannelInterface::toString()\n     */\n    public function toString(): string\n    {\n        return (string) $this->value();\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorChannelInterface::__toString()\n     */\n    public function __toString(): string\n    {\n        return $this->toString();\n    }\n}\n"
  },
  {
    "path": "src/Colors/Cmyk/Channels/Cyan.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Colors\\Cmyk\\Channels;\n\nuse Intervention\\Image\\Colors\\AbstractColorChannel;\n\nclass Cyan extends AbstractColorChannel\n{\n    public function min(): int\n    {\n        return 0;\n    }\n\n    public function max(): int\n    {\n        return 100;\n    }\n}\n"
  },
  {
    "path": "src/Colors/Cmyk/Channels/Key.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Colors\\Cmyk\\Channels;\n\nclass Key extends Cyan\n{\n    //\n}\n"
  },
  {
    "path": "src/Colors/Cmyk/Channels/Magenta.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Colors\\Cmyk\\Channels;\n\nclass Magenta extends Cyan\n{\n    //\n}\n"
  },
  {
    "path": "src/Colors/Cmyk/Channels/Yellow.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Colors\\Cmyk\\Channels;\n\nclass Yellow extends Cyan\n{\n    //\n}\n"
  },
  {
    "path": "src/Colors/Cmyk/Color.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Colors\\Cmyk;\n\nuse Intervention\\Image\\Colors\\AbstractColor;\nuse Intervention\\Image\\Colors\\Cmyk\\Channels\\Cyan;\nuse Intervention\\Image\\Colors\\Cmyk\\Channels\\Magenta;\nuse Intervention\\Image\\Colors\\Cmyk\\Channels\\Yellow;\nuse Intervention\\Image\\Colors\\Cmyk\\Channels\\Key;\nuse Intervention\\Image\\Colors\\Rgb\\Colorspace as RgbColorspace;\nuse Intervention\\Image\\InputHandler;\nuse Intervention\\Image\\Interfaces\\ColorChannelInterface;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Interfaces\\ColorspaceInterface;\n\nclass Color extends AbstractColor\n{\n    /**\n     * Create new instance\n     *\n     * @return void\n     */\n    public function __construct(int $c, int $m, int $y, int $k)\n    {\n        /** @throws void */\n        $this->channels = [\n            new Cyan($c),\n            new Magenta($m),\n            new Yellow($y),\n            new Key($k),\n        ];\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorInterface::create()\n     */\n    public static function create(mixed $input): ColorInterface\n    {\n        return InputHandler::withDecoders([\n            Decoders\\StringColorDecoder::class,\n        ])->handle($input);\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorInterface::colorspace()\n     */\n    public function colorspace(): ColorspaceInterface\n    {\n        return new Colorspace();\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorInterface::toHex()\n     */\n    public function toHex(string $prefix = ''): string\n    {\n        return $this->convertTo(RgbColorspace::class)->toHex($prefix);\n    }\n\n    /**\n     * Return the CMYK cyan channel\n     */\n    public function cyan(): ColorChannelInterface\n    {\n        /** @throws void */\n        return $this->channel(Cyan::class);\n    }\n\n    /**\n     * Return the CMYK magenta channel\n     */\n    public function magenta(): ColorChannelInterface\n    {\n        /** @throws void */\n        return $this->channel(Magenta::class);\n    }\n\n    /**\n     * Return the CMYK yellow channel\n     */\n    public function yellow(): ColorChannelInterface\n    {\n        /** @throws void */\n        return $this->channel(Yellow::class);\n    }\n\n    /**\n     * Return the CMYK key channel\n     */\n    public function key(): ColorChannelInterface\n    {\n        /** @throws void */\n        return $this->channel(Key::class);\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorInterface::toString()\n     */\n    public function toString(): string\n    {\n        return sprintf(\n            'cmyk(%d%%, %d%%, %d%%, %d%%)',\n            $this->cyan()->value(),\n            $this->magenta()->value(),\n            $this->yellow()->value(),\n            $this->key()->value()\n        );\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorInterface::isGreyscale()\n     */\n    public function isGreyscale(): bool\n    {\n        return 0 === array_sum([\n            $this->cyan()->value(),\n            $this->magenta()->value(),\n            $this->yellow()->value(),\n        ]);\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorInterface::isTransparent()\n     */\n    public function isTransparent(): bool\n    {\n        return false;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorInterface::isClear()\n     */\n    public function isClear(): bool\n    {\n        return false;\n    }\n}\n"
  },
  {
    "path": "src/Colors/Cmyk/Colorspace.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Colors\\Cmyk;\n\nuse Intervention\\Image\\Colors\\Rgb\\Color as RgbColor;\nuse Intervention\\Image\\Colors\\Cmyk\\Color as CmykColor;\nuse Intervention\\Image\\Colors\\Hsv\\Color as HsvColor;\nuse Intervention\\Image\\Colors\\Hsl\\Color as HslColor;\nuse Intervention\\Image\\Colors\\Rgb\\Colorspace as RgbColorspace;\nuse Intervention\\Image\\Exceptions\\ColorException;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Interfaces\\ColorspaceInterface;\n\nclass Colorspace implements ColorspaceInterface\n{\n    /**\n     * Channel class names of colorspace\n     *\n     * @var array<string>\n     */\n    public static array $channels = [\n        Channels\\Cyan::class,\n        Channels\\Magenta::class,\n        Channels\\Yellow::class,\n        Channels\\Key::class\n    ];\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorspaceInterface::createColor()\n     */\n    public function colorFromNormalized(array $normalized): ColorInterface\n    {\n        return new Color(...array_map(\n            fn(string $classname, float $value_normalized) => (new $classname(normalized: $value_normalized))->value(),\n            self::$channels,\n            $normalized,\n        ));\n    }\n\n    /**\n     * @throws ColorException\n     */\n    public function importColor(ColorInterface $color): ColorInterface\n    {\n        return match ($color::class) {\n            RgbColor::class => $this->importRgbColor($color),\n            HsvColor::class => $this->importRgbColor($color->convertTo(RgbColorspace::class)),\n            HslColor::class => $this->importRgbColor($color->convertTo(RgbColorspace::class)),\n            default => $color,\n        };\n    }\n\n    /**\n     * @throws ColorException\n     */\n    protected function importRgbColor(ColorInterface $color): CmykColor\n    {\n        if (!($color instanceof RgbColor)) {\n            throw new ColorException('Unabled to import color of type ' . $color::class . '.');\n        }\n\n        $c = (255 - $color->red()->value()) / 255.0 * 100;\n        $m = (255 - $color->green()->value()) / 255.0 * 100;\n        $y = (255 - $color->blue()->value()) / 255.0 * 100;\n        $k = intval(round(min([$c, $m, $y])));\n\n        $c = intval(round($c - $k));\n        $m = intval(round($m - $k));\n        $y = intval(round($y - $k));\n\n        return new CmykColor($c, $m, $y, $k);\n    }\n}\n"
  },
  {
    "path": "src/Colors/Cmyk/Decoders/StringColorDecoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Colors\\Cmyk\\Decoders;\n\nuse Intervention\\Image\\Colors\\Cmyk\\Color;\nuse Intervention\\Image\\Drivers\\AbstractDecoder;\nuse Intervention\\Image\\Exceptions\\DecoderException;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Interfaces\\DecoderInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\n\nclass StringColorDecoder extends AbstractDecoder implements DecoderInterface\n{\n    /**\n     * Decode CMYK color strings\n     */\n    public function decode(mixed $input): ImageInterface|ColorInterface\n    {\n        if (!is_string($input)) {\n            throw new DecoderException('Unable to decode input');\n        }\n\n        $pattern = '/^cmyk\\((?P<c>[0-9\\.]+%?), ?(?P<m>[0-9\\.]+%?), ?(?P<y>[0-9\\.]+%?), ?(?P<k>[0-9\\.]+%?)\\)$/i';\n        if (preg_match($pattern, $input, $matches) != 1) {\n            throw new DecoderException('Unable to decode input');\n        }\n\n        $values = array_map(function (string $value): int {\n            return intval(round(floatval(trim(str_replace('%', '', $value)))));\n        }, [$matches['c'], $matches['m'], $matches['y'], $matches['k']]);\n\n        return new Color(...$values);\n    }\n}\n"
  },
  {
    "path": "src/Colors/Hsl/Channels/Hue.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Colors\\Hsl\\Channels;\n\nuse Intervention\\Image\\Colors\\AbstractColorChannel;\n\nclass Hue extends AbstractColorChannel\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorChannelInterface::min()\n     */\n    public function min(): int\n    {\n        return 0;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorChannelInterface::max()\n     */\n    public function max(): int\n    {\n        return 360;\n    }\n}\n"
  },
  {
    "path": "src/Colors/Hsl/Channels/Luminance.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Colors\\Hsl\\Channels;\n\nuse Intervention\\Image\\Colors\\AbstractColorChannel;\n\nclass Luminance extends AbstractColorChannel\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorChannelInterface::min()\n     */\n    public function min(): int\n    {\n        return 0;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorChannelInterface::max()\n     */\n    public function max(): int\n    {\n        return 100;\n    }\n}\n"
  },
  {
    "path": "src/Colors/Hsl/Channels/Saturation.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Colors\\Hsl\\Channels;\n\nuse Intervention\\Image\\Colors\\AbstractColorChannel;\n\nclass Saturation extends AbstractColorChannel\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorChannelInterface::min()\n     */\n    public function min(): int\n    {\n        return 0;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorChannelInterface::max()\n     */\n    public function max(): int\n    {\n        return 100;\n    }\n}\n"
  },
  {
    "path": "src/Colors/Hsl/Color.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Colors\\Hsl;\n\nuse Intervention\\Image\\Colors\\AbstractColor;\nuse Intervention\\Image\\Colors\\Hsl\\Channels\\Hue;\nuse Intervention\\Image\\Colors\\Hsl\\Channels\\Luminance;\nuse Intervention\\Image\\Colors\\Hsl\\Channels\\Saturation;\nuse Intervention\\Image\\Colors\\Rgb\\Colorspace as RgbColorspace;\nuse Intervention\\Image\\InputHandler;\nuse Intervention\\Image\\Interfaces\\ColorChannelInterface;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Interfaces\\ColorspaceInterface;\n\nclass Color extends AbstractColor\n{\n    /**\n     * Create new color object\n     *\n     * @return void\n     */\n    public function __construct(int $h, int $s, int $l)\n    {\n        /** @throws void */\n        $this->channels = [\n            new Hue($h),\n            new Saturation($s),\n            new Luminance($l),\n        ];\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorInterface::colorspace()\n     */\n    public function colorspace(): ColorspaceInterface\n    {\n        return new Colorspace();\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorInterface::create()\n     */\n    public static function create(mixed $input): ColorInterface\n    {\n        return InputHandler::withDecoders([\n            Decoders\\StringColorDecoder::class,\n        ])->handle($input);\n    }\n\n    /**\n     * Return the Hue channel\n     */\n    public function hue(): ColorChannelInterface\n    {\n        /** @throws void */\n        return $this->channel(Hue::class);\n    }\n\n    /**\n     * Return the Saturation channel\n     */\n    public function saturation(): ColorChannelInterface\n    {\n        /** @throws void */\n        return $this->channel(Saturation::class);\n    }\n\n    /**\n     * Return the Luminance channel\n     */\n    public function luminance(): ColorChannelInterface\n    {\n        /** @throws void */\n        return $this->channel(Luminance::class);\n    }\n\n    public function toHex(string $prefix = ''): string\n    {\n        return $this->convertTo(RgbColorspace::class)->toHex($prefix);\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorInterface::toString()\n     */\n    public function toString(): string\n    {\n        return sprintf(\n            'hsl(%d, %d%%, %d%%)',\n            $this->hue()->value(),\n            $this->saturation()->value(),\n            $this->luminance()->value()\n        );\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorInterface::isGreyscale()\n     */\n    public function isGreyscale(): bool\n    {\n        return $this->saturation()->value() == 0;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorInterface::isTransparent()\n     */\n    public function isTransparent(): bool\n    {\n        return false;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorInterface::isClear()\n     */\n    public function isClear(): bool\n    {\n        return false;\n    }\n}\n"
  },
  {
    "path": "src/Colors/Hsl/Colorspace.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Colors\\Hsl;\n\nuse Intervention\\Image\\Colors\\Cmyk\\Color as CmykColor;\nuse Intervention\\Image\\Colors\\Rgb\\Color as RgbColor;\nuse Intervention\\Image\\Colors\\Hsv\\Color as HsvColor;\nuse Intervention\\Image\\Colors\\Rgb\\Colorspace as RgbColorspace;\nuse Intervention\\Image\\Exceptions\\ColorException;\nuse Intervention\\Image\\Interfaces\\ColorChannelInterface;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Interfaces\\ColorspaceInterface;\n\nclass Colorspace implements ColorspaceInterface\n{\n    /**\n     * Channel class names of colorspace\n     *\n     * @var array<string>\n     */\n    public static array $channels = [\n        Channels\\Hue::class,\n        Channels\\Saturation::class,\n        Channels\\Luminance::class\n    ];\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorspaceInterface::colorFromNormalized()\n     */\n    public function colorFromNormalized(array $normalized): ColorInterface\n    {\n        return new Color(...array_map(\n            fn(string $classname, float $value_normalized) => (new $classname(normalized: $value_normalized))->value(),\n            self::$channels,\n            $normalized\n        ));\n    }\n\n    /**\n     * @throws ColorException\n     */\n    public function importColor(ColorInterface $color): ColorInterface\n    {\n        return match ($color::class) {\n            CmykColor::class => $this->importRgbColor($color->convertTo(RgbColorspace::class)),\n            RgbColor::class => $this->importRgbColor($color),\n            HsvColor::class => $this->importHsvColor($color),\n            default => $color,\n        };\n    }\n\n    /**\n     * @throws ColorException\n     */\n    protected function importRgbColor(ColorInterface $color): ColorInterface\n    {\n        if (!($color instanceof RgbColor)) {\n            throw new ColorException('Unabled to import color of type ' . $color::class . '.');\n        }\n\n        // normalized values of rgb channels\n        $values = array_map(\n            fn(ColorChannelInterface $channel): float => $channel->normalize(),\n            $color->channels(),\n        );\n\n        // take only RGB\n        $values = array_slice($values, 0, 3);\n\n        // calculate Luminance\n        $min = min(...$values);\n        $max = max(...$values);\n        $luminance = ($max + $min) / 2;\n        $delta = $max - $min;\n\n        // calculate saturation\n        $saturation = match (true) {\n            $delta == 0 => 0,\n            default => $delta / (1 - abs(2 * $luminance - 1)),\n        };\n\n        // calculate hue\n        [$r, $g, $b] = $values;\n        $hue = match (true) {\n            ($delta == 0) => 0,\n            ($max == $r) => 60 * fmod((($g - $b) / $delta), 6),\n            ($max == $g) => 60 * ((($b - $r) / $delta) + 2),\n            ($max == $b) => 60 * ((($r - $g) / $delta) + 4),\n            default => 0,\n        };\n\n        $hue = ($hue + 360) % 360; // normalize hue\n\n        return new Color(\n            intval(round($hue)),\n            intval(round($saturation * 100)),\n            intval(round($luminance * 100)),\n        );\n    }\n\n    /**\n     * @throws ColorException\n     */\n    protected function importHsvColor(ColorInterface $color): ColorInterface\n    {\n        if (!($color instanceof HsvColor)) {\n            throw new ColorException('Unabled to import color of type ' . $color::class . '.');\n        }\n\n        // normalized values of hsv channels\n        [$h, $s, $v] = array_map(\n            fn(ColorChannelInterface $channel): float => $channel->normalize(),\n            $color->channels(),\n        );\n\n        // calculate Luminance\n        $luminance = (2 - $s) * $v / 2;\n\n        // calculate Saturation\n        $saturation = match (true) {\n            $luminance == 0 => $s,\n            $luminance == 1 => 0,\n            $luminance < .5 => $s * $v / ($luminance * 2),\n            default => $s * $v / (2 - $luminance * 2),\n        };\n\n        return new Color(\n            intval(round($h * 360)),\n            intval(round($saturation * 100)),\n            intval(round($luminance * 100)),\n        );\n    }\n}\n"
  },
  {
    "path": "src/Colors/Hsl/Decoders/StringColorDecoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Colors\\Hsl\\Decoders;\n\nuse Intervention\\Image\\Colors\\Hsl\\Color;\nuse Intervention\\Image\\Drivers\\AbstractDecoder;\nuse Intervention\\Image\\Exceptions\\DecoderException;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Interfaces\\DecoderInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\n\nclass StringColorDecoder extends AbstractDecoder implements DecoderInterface\n{\n    /**\n     * Decode hsl color strings\n     */\n    public function decode(mixed $input): ImageInterface|ColorInterface\n    {\n        if (!is_string($input)) {\n            throw new DecoderException('Unable to decode input');\n        }\n\n        $pattern = '/^hsl\\((?P<h>[0-9\\.]+), ?(?P<s>[0-9\\.]+%?), ?(?P<l>[0-9\\.]+%?)\\)$/i';\n        if (preg_match($pattern, $input, $matches) != 1) {\n            throw new DecoderException('Unable to decode input');\n        }\n\n        $values = array_map(function (string $value): int {\n            return match (strpos($value, '%')) {\n                false => intval(trim($value)),\n                default => intval(trim(str_replace('%', '', $value))),\n            };\n        }, [$matches['h'], $matches['s'], $matches['l']]);\n\n        return new Color(...$values);\n    }\n}\n"
  },
  {
    "path": "src/Colors/Hsv/Channels/Hue.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Colors\\Hsv\\Channels;\n\nuse Intervention\\Image\\Colors\\AbstractColorChannel;\n\nclass Hue extends AbstractColorChannel\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorChannelInterface::min()\n     */\n    public function min(): int\n    {\n        return 0;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorChannelInterface::max()\n     */\n    public function max(): int\n    {\n        return 360;\n    }\n}\n"
  },
  {
    "path": "src/Colors/Hsv/Channels/Saturation.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Colors\\Hsv\\Channels;\n\nuse Intervention\\Image\\Colors\\AbstractColorChannel;\n\nclass Saturation extends AbstractColorChannel\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorChannelInterface::min()\n     */\n    public function min(): int\n    {\n        return 0;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorChannelInterface::max()\n     */\n    public function max(): int\n    {\n        return 100;\n    }\n}\n"
  },
  {
    "path": "src/Colors/Hsv/Channels/Value.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Colors\\Hsv\\Channels;\n\nuse Intervention\\Image\\Colors\\AbstractColorChannel;\n\nclass Value extends AbstractColorChannel\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorChannelInterface::min()\n     */\n    public function min(): int\n    {\n        return 0;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorChannelInterface::max()\n     */\n    public function max(): int\n    {\n        return 100;\n    }\n}\n"
  },
  {
    "path": "src/Colors/Hsv/Color.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Colors\\Hsv;\n\nuse Intervention\\Image\\Colors\\AbstractColor;\nuse Intervention\\Image\\Colors\\Hsv\\Channels\\Hue;\nuse Intervention\\Image\\Colors\\Hsv\\Channels\\Saturation;\nuse Intervention\\Image\\Colors\\Hsv\\Channels\\Value;\nuse Intervention\\Image\\Colors\\Rgb\\Colorspace as RgbColorspace;\nuse Intervention\\Image\\InputHandler;\nuse Intervention\\Image\\Interfaces\\ColorChannelInterface;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Interfaces\\ColorspaceInterface;\n\nclass Color extends AbstractColor\n{\n    /**\n     * Create new color object\n     *\n     * @return void\n     */\n    public function __construct(int $h, int $s, int $v)\n    {\n        /** @throws void */\n        $this->channels = [\n            new Hue($h),\n            new Saturation($s),\n            new Value($v),\n        ];\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorInterface::colorspace()\n     */\n    public function colorspace(): ColorspaceInterface\n    {\n        return new Colorspace();\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorInterface::create()\n     */\n    public static function create(mixed $input): ColorInterface\n    {\n        return InputHandler::withDecoders([\n            Decoders\\StringColorDecoder::class,\n        ])->handle($input);\n    }\n\n    /**\n     * Return the Hue channel\n     */\n    public function hue(): ColorChannelInterface\n    {\n        /** @throws void */\n        return $this->channel(Hue::class);\n    }\n\n    /**\n     * Return the Saturation channel\n     */\n    public function saturation(): ColorChannelInterface\n    {\n        /** @throws void */\n        return $this->channel(Saturation::class);\n    }\n\n    /**\n     * Return the Value channel\n     */\n    public function value(): ColorChannelInterface\n    {\n        /** @throws void */\n        return $this->channel(Value::class);\n    }\n\n    public function toHex(string $prefix = ''): string\n    {\n        return $this->convertTo(RgbColorspace::class)->toHex($prefix);\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorInterface::toString()\n     */\n    public function toString(): string\n    {\n        return sprintf(\n            'hsv(%d, %d%%, %d%%)',\n            $this->hue()->value(),\n            $this->saturation()->value(),\n            $this->value()->value()\n        );\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorInterface::isGreyscale()\n     */\n    public function isGreyscale(): bool\n    {\n        return $this->saturation()->value() == 0;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorInterface::isTransparent()\n     */\n    public function isTransparent(): bool\n    {\n        return false;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorInterface::isClear()\n     */\n    public function isClear(): bool\n    {\n        return false;\n    }\n}\n"
  },
  {
    "path": "src/Colors/Hsv/Colorspace.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Colors\\Hsv;\n\nuse Intervention\\Image\\Colors\\Cmyk\\Color as CmykColor;\nuse Intervention\\Image\\Colors\\Rgb\\Color as RgbColor;\nuse Intervention\\Image\\Colors\\Hsl\\Color as HslColor;\nuse Intervention\\Image\\Colors\\Rgb\\Colorspace as RgbColorspace;\nuse Intervention\\Image\\Exceptions\\ColorException;\nuse Intervention\\Image\\Interfaces\\ColorChannelInterface;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Interfaces\\ColorspaceInterface;\n\nclass Colorspace implements ColorspaceInterface\n{\n    /**\n     * Channel class names of colorspace\n     *\n     * @var array<string>\n     */\n    public static array $channels = [\n        Channels\\Hue::class,\n        Channels\\Saturation::class,\n        Channels\\Value::class\n    ];\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorspaceInterface::colorFromNormalized()\n     */\n    public function colorFromNormalized(array $normalized): ColorInterface\n    {\n        return new Color(...array_map(\n            fn(string $classname, float $value_normalized) => (new $classname(normalized: $value_normalized))->value(),\n            self::$channels,\n            $normalized\n        ));\n    }\n\n    /**\n     * @throws ColorException\n     */\n    public function importColor(ColorInterface $color): ColorInterface\n    {\n        return match ($color::class) {\n            CmykColor::class => $this->importRgbColor($color->convertTo(RgbColorspace::class)),\n            RgbColor::class => $this->importRgbColor($color),\n            HslColor::class => $this->importHslColor($color),\n            default => $color,\n        };\n    }\n\n    /**\n     * @throws ColorException\n     */\n    protected function importRgbColor(ColorInterface $color): ColorInterface\n    {\n        if (!($color instanceof RgbColor)) {\n            throw new ColorException('Unabled to import color of type ' . $color::class . '.');\n        }\n\n        // normalized values of rgb channels\n        $values = array_map(fn(ColorChannelInterface $channel): float => $channel->normalize(), $color->channels());\n\n        // take only RGB\n        $values = array_slice($values, 0, 3);\n\n        // calculate chroma\n        $min = min(...$values);\n        $max = max(...$values);\n        $chroma = $max - $min;\n\n        // calculate value\n        $v = 100 * $max;\n\n        if ($chroma == 0) {\n            // greyscale color\n            return new Color(0, 0, intval(round($v)));\n        }\n\n        // calculate saturation\n        $s = 100 * ($chroma / $max);\n\n        // calculate hue\n        [$r, $g, $b] = $values;\n        $h = match (true) {\n            ($r == $min) => 3 - (($g - $b) / $chroma),\n            ($b == $min) => 1 - (($r - $g) / $chroma),\n            default => 5 - (($b - $r) / $chroma),\n        } * 60;\n\n        return new Color(\n            intval(round($h)),\n            intval(round($s)),\n            intval(round($v))\n        );\n    }\n\n    /**\n     * @throws ColorException\n     */\n    protected function importHslColor(ColorInterface $color): ColorInterface\n    {\n        if (!($color instanceof HslColor)) {\n            throw new ColorException('Unabled to import color of type ' . $color::class . '.');\n        }\n\n        // normalized values of hsl channels\n        [$h, $s, $l] = array_map(\n            fn(ColorChannelInterface $channel): float => $channel->normalize(),\n            $color->channels()\n        );\n\n        $v = $l + $s * min($l, 1 - $l);\n        $s = ($v == 0) ? 0 : 2 * (1 - $l / $v);\n\n        return $this->colorFromNormalized([$h, $s, $v]);\n    }\n}\n"
  },
  {
    "path": "src/Colors/Hsv/Decoders/StringColorDecoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Colors\\Hsv\\Decoders;\n\nuse Intervention\\Image\\Colors\\Hsv\\Color;\nuse Intervention\\Image\\Drivers\\AbstractDecoder;\nuse Intervention\\Image\\Exceptions\\DecoderException;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Interfaces\\DecoderInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\n\nclass StringColorDecoder extends AbstractDecoder implements DecoderInterface\n{\n    /**\n     * Decode hsv/hsb color strings\n     */\n    public function decode(mixed $input): ImageInterface|ColorInterface\n    {\n        if (!is_string($input)) {\n            throw new DecoderException('Unable to decode input');\n        }\n\n        $pattern = '/^hs(v|b)\\((?P<h>[0-9\\.]+), ?(?P<s>[0-9\\.]+%?), ?(?P<v>[0-9\\.]+%?)\\)$/i';\n        if (preg_match($pattern, $input, $matches) != 1) {\n            throw new DecoderException('Unable to decode input');\n        }\n\n        $values = array_map(function (string $value): int {\n            return match (strpos($value, '%')) {\n                false => intval(trim($value)),\n                default => intval(trim(str_replace('%', '', $value))),\n            };\n        }, [$matches['h'], $matches['s'], $matches['v']]);\n\n        return new Color(...$values);\n    }\n}\n"
  },
  {
    "path": "src/Colors/Profile.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Colors;\n\nuse Intervention\\Image\\File;\nuse Intervention\\Image\\Exceptions\\RuntimeException;\nuse Intervention\\Image\\Interfaces\\ProfileInterface;\n\nclass Profile extends File implements ProfileInterface\n{\n    /**\n     * Create profile object from path in file system\n     *\n     * @throws RuntimeException\n     */\n    public static function fromPath(string $path): self\n    {\n        return new self(fopen($path, 'r'));\n    }\n}\n"
  },
  {
    "path": "src/Colors/Rgb/Channels/Alpha.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Colors\\Rgb\\Channels;\n\nclass Alpha extends Red\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorChannelInterface::toString()\n     */\n    public function toString(): string\n    {\n        return strval(round($this->normalize(), 6));\n    }\n}\n"
  },
  {
    "path": "src/Colors/Rgb/Channels/Blue.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Colors\\Rgb\\Channels;\n\nclass Blue extends Red\n{\n    //\n}\n"
  },
  {
    "path": "src/Colors/Rgb/Channels/Green.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Colors\\Rgb\\Channels;\n\nclass Green extends Red\n{\n    //\n}\n"
  },
  {
    "path": "src/Colors/Rgb/Channels/Red.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Colors\\Rgb\\Channels;\n\nuse Intervention\\Image\\Colors\\AbstractColorChannel;\n\nclass Red extends AbstractColorChannel\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorChannelInterface::min()\n     */\n    public function min(): int\n    {\n        return 0;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorChannelInterface::max()\n     */\n    public function max(): int\n    {\n        return 255;\n    }\n}\n"
  },
  {
    "path": "src/Colors/Rgb/Color.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Colors\\Rgb;\n\nuse Intervention\\Image\\Colors\\AbstractColor;\nuse Intervention\\Image\\Colors\\Rgb\\Channels\\Blue;\nuse Intervention\\Image\\Colors\\Rgb\\Channels\\Green;\nuse Intervention\\Image\\Colors\\Rgb\\Channels\\Red;\nuse Intervention\\Image\\Colors\\Rgb\\Channels\\Alpha;\nuse Intervention\\Image\\InputHandler;\nuse Intervention\\Image\\Interfaces\\ColorChannelInterface;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Interfaces\\ColorspaceInterface;\n\nclass Color extends AbstractColor\n{\n    /**\n     * Create new instance\n     *\n     * @return ColorInterface\n     */\n    public function __construct(int $r, int $g, int $b, int $a = 255)\n    {\n        /** @throws void */\n        $this->channels = [\n            new Red($r),\n            new Green($g),\n            new Blue($b),\n            new Alpha($a),\n        ];\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorInterface::colorspace()\n     */\n    public function colorspace(): ColorspaceInterface\n    {\n        return new Colorspace();\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorInterface::create()\n     */\n    public static function create(mixed $input): ColorInterface\n    {\n        return InputHandler::withDecoders([\n            Decoders\\HexColorDecoder::class,\n            Decoders\\StringColorDecoder::class,\n            Decoders\\TransparentColorDecoder::class,\n            Decoders\\HtmlColornameDecoder::class,\n        ])->handle($input);\n    }\n\n    /**\n     * Return the RGB red color channel\n     */\n    public function red(): ColorChannelInterface\n    {\n        /** @throws void */\n        return $this->channel(Red::class);\n    }\n\n    /**\n     * Return the RGB green color channel\n     */\n    public function green(): ColorChannelInterface\n    {\n        /** @throws void */\n        return $this->channel(Green::class);\n    }\n\n    /**\n     * Return the RGB blue color channel\n     */\n    public function blue(): ColorChannelInterface\n    {\n        /** @throws void */\n        return $this->channel(Blue::class);\n    }\n\n    /**\n     * Return the colors alpha channel\n     */\n    public function alpha(): ColorChannelInterface\n    {\n        /** @throws void */\n        return $this->channel(Alpha::class);\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorInterface::toHex()\n     */\n    public function toHex(string $prefix = ''): string\n    {\n        if ($this->isTransparent()) {\n            return sprintf(\n                '%s%02x%02x%02x%02x',\n                $prefix,\n                $this->red()->value(),\n                $this->green()->value(),\n                $this->blue()->value(),\n                $this->alpha()->value()\n            );\n        }\n\n        return sprintf(\n            '%s%02x%02x%02x',\n            $prefix,\n            $this->red()->value(),\n            $this->green()->value(),\n            $this->blue()->value()\n        );\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorInterface::toString()\n     */\n    public function toString(): string\n    {\n        if ($this->isTransparent()) {\n            return sprintf(\n                'rgba(%d, %d, %d, %.1F)',\n                $this->red()->value(),\n                $this->green()->value(),\n                $this->blue()->value(),\n                $this->alpha()->normalize(),\n            );\n        }\n\n        return sprintf(\n            'rgb(%d, %d, %d)',\n            $this->red()->value(),\n            $this->green()->value(),\n            $this->blue()->value()\n        );\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorInterface::isGreyscale()\n     */\n    public function isGreyscale(): bool\n    {\n        $values = [$this->red()->value(), $this->green()->value(), $this->blue()->value()];\n\n        return count(array_unique($values, SORT_REGULAR)) === 1;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorInterface::isTransparent()\n     */\n    public function isTransparent(): bool\n    {\n        return $this->alpha()->value() < $this->alpha()->max();\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorInterface::isClear()\n     */\n    public function isClear(): bool\n    {\n        return $this->alpha()->value() == 0;\n    }\n}\n"
  },
  {
    "path": "src/Colors/Rgb/Colorspace.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Colors\\Rgb;\n\nuse Intervention\\Image\\Colors\\Hsv\\Color as HsvColor;\nuse Intervention\\Image\\Colors\\Hsl\\Color as HslColor;\nuse Intervention\\Image\\Colors\\Cmyk\\Color as CmykColor;\nuse Intervention\\Image\\Exceptions\\ColorException;\nuse Intervention\\Image\\Interfaces\\ColorChannelInterface;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Interfaces\\ColorspaceInterface;\n\nclass Colorspace implements ColorspaceInterface\n{\n    /**\n     * Channel class names of colorspace\n     *\n     * @var array<string>\n     */\n    public static array $channels = [\n        Channels\\Red::class,\n        Channels\\Green::class,\n        Channels\\Blue::class,\n        Channels\\Alpha::class\n    ];\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorspaceInterface::colorFromNormalized()\n     */\n    public function colorFromNormalized(array $normalized): ColorInterface\n    {\n        return new Color(...array_map(\n            fn($classname, float $value_normalized) => (new $classname(normalized: $value_normalized))->value(),\n            self::$channels,\n            $normalized,\n        ));\n    }\n\n    /**\n     * @throws ColorException\n     */\n    public function importColor(ColorInterface $color): ColorInterface\n    {\n        return match ($color::class) {\n            CmykColor::class => $this->importCmykColor($color),\n            HsvColor::class => $this->importHsvColor($color),\n            HslColor::class => $this->importHslColor($color),\n            default => $color,\n        };\n    }\n\n    /**\n     * @throws ColorException\n     */\n    protected function importCmykColor(ColorInterface $color): ColorInterface\n    {\n        if (!($color instanceof CmykColor)) {\n            throw new ColorException('Unabled to import color of type ' . $color::class . '.');\n        }\n\n        return new Color(\n            (int) (255 * (1 - $color->cyan()->normalize()) * (1 - $color->key()->normalize())),\n            (int) (255 * (1 - $color->magenta()->normalize()) * (1 - $color->key()->normalize())),\n            (int) (255 * (1 - $color->yellow()->normalize()) * (1 - $color->key()->normalize())),\n        );\n    }\n\n    /**\n     * @throws ColorException\n     */\n    protected function importHsvColor(ColorInterface $color): ColorInterface\n    {\n        if (!($color instanceof HsvColor)) {\n            throw new ColorException('Unabled to import color of type ' . $color::class . '.');\n        }\n\n        $chroma = $color->value()->normalize() * $color->saturation()->normalize();\n        $hue = $color->hue()->normalize() * 6;\n        $x = $chroma * (1 - abs(fmod($hue, 2) - 1));\n\n        // connect channel values\n        $values = match (true) {\n            $hue < 1 => [$chroma, $x, 0],\n            $hue < 2 => [$x, $chroma, 0],\n            $hue < 3 => [0, $chroma, $x],\n            $hue < 4 => [0, $x, $chroma],\n            $hue < 5 => [$x, 0, $chroma],\n            default => [$chroma, 0, $x],\n        };\n\n        // add to each value\n        $values = array_map(fn(float|int $value): float => $value + $color->value()->normalize() - $chroma, $values);\n        $values[] = 1; // append alpha channel value\n\n        return $this->colorFromNormalized($values);\n    }\n\n    /**\n     * @throws ColorException\n     */\n    protected function importHslColor(ColorInterface $color): ColorInterface\n    {\n        if (!($color instanceof HslColor)) {\n            throw new ColorException('Unabled to import color of type ' . $color::class . '.');\n        }\n\n        // normalized values of hsl channels\n        [$h, $s, $l] = array_map(\n            fn(ColorChannelInterface $channel): float => $channel->normalize(),\n            $color->channels()\n        );\n\n        $c = (1 - abs(2 * $l - 1)) * $s;\n        $x = $c * (1 - abs(fmod($h * 6, 2) - 1));\n        $m = $l - $c / 2;\n\n        $values = match (true) {\n            $h < 1 / 6 => [$c, $x, 0],\n            $h < 2 / 6 => [$x, $c, 0],\n            $h < 3 / 6 => [0, $c, $x],\n            $h < 4 / 6 => [0, $x, $c],\n            $h < 5 / 6 => [$x, 0, $c],\n            default => [$c, 0, $x],\n        };\n\n        $values = array_map(fn(float|int $value): float => $value + $m, $values);\n        $values[] = 1; // append alpha channel value\n\n        return $this->colorFromNormalized($values);\n    }\n}\n"
  },
  {
    "path": "src/Colors/Rgb/Decoders/HexColorDecoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Colors\\Rgb\\Decoders;\n\nuse Intervention\\Image\\Colors\\Rgb\\Color;\nuse Intervention\\Image\\Drivers\\AbstractDecoder;\nuse Intervention\\Image\\Exceptions\\DecoderException;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Interfaces\\DecoderInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\n\nclass HexColorDecoder extends AbstractDecoder implements DecoderInterface\n{\n    /**\n     * Decode hexadecimal rgb colors with and without transparency\n     */\n    public function decode(mixed $input): ImageInterface|ColorInterface\n    {\n        if (!is_string($input)) {\n            throw new DecoderException('Unable to decode input');\n        }\n\n        $pattern = '/^#?(?P<hex>[a-f\\d]{3}(?:[a-f\\d]?|(?:[a-f\\d]{3}(?:[a-f\\d]{2})?)?)\\b)$/i';\n        if (preg_match($pattern, $input, $matches) != 1) {\n            throw new DecoderException('Unable to decode input');\n        }\n\n        $values = match (strlen($matches['hex'])) {\n            3, 4 => str_split($matches['hex']),\n            6, 8 => str_split($matches['hex'], 2),\n            default => throw new DecoderException('Unable to decode input'),\n        };\n\n        $values = array_map(function (string $value): float|int {\n            return match (strlen($value)) {\n                1 => hexdec($value . $value),\n                2 => hexdec($value),\n                default => throw new DecoderException('Unable to decode input'),\n            };\n        }, $values);\n\n        return new Color(...$values);\n    }\n}\n"
  },
  {
    "path": "src/Colors/Rgb/Decoders/HtmlColornameDecoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Colors\\Rgb\\Decoders;\n\nuse Intervention\\Image\\Exceptions\\DecoderException;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Interfaces\\DecoderInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\n\nclass HtmlColornameDecoder extends HexColorDecoder implements DecoderInterface\n{\n    /**\n     * Available color names and their corresponding hex codes\n     *\n     * @var array<string, string>\n     */\n    protected static array $names = [\n        'lightsalmon' => '#ffa07a',\n        'salmon' => '#fa8072',\n        'darksalmon' => '#e9967a',\n        'lightcoral' => '#f08080',\n        'indianred' => '#cd5c5c',\n        'crimson' => '#dc143c',\n        'firebrick' => '#b22222',\n        'red' => '#ff0000',\n        'darkred' => '#8b0000',\n        'coral' => '#ff7f50',\n        'tomato' => '#ff6347',\n        'orangered' => '#ff4500',\n        'gold' => '#ffd700',\n        'orange' => '#ffa500',\n        'darkorange' => '#ff8c00',\n        'lightyellow' => '#ffffe0',\n        'lemonchiffon' => '#fffacd',\n        'lightgoldenrodyellow' => '#fafad2',\n        'papayawhip' => '#ffefd5',\n        'moccasin' => '#ffe4b5',\n        'peachpuff' => '#ffdab9',\n        'palegoldenrod' => '#eee8aa',\n        'khaki' => '#f0e68c',\n        'darkkhaki' => '#bdb76b',\n        'yellow' => '#ffff00',\n        'lawngreen' => '#7cfc00',\n        'chartreuse' => '#7fff00',\n        'limegreen' => '#32cd32',\n        'lime' => '#00ff00',\n        'forestgreen' => '#228b22',\n        'green' => '#008000',\n        'darkgreen' => '#006400',\n        'greenyellow' => '#adff2f',\n        'yellowgreen' => '#9acd32',\n        'springgreen' => '#00ff7f',\n        'mediumspringgreen' => '#00fa9a',\n        'lightgreen' => '#90ee90',\n        'palegreen' => '#98fb98',\n        'darkseagreen' => '#8fbc8f',\n        'mediumseagre' => 'en #3cb371',\n        'seagreen' => '#2e8b57',\n        'olive' => '#808000',\n        'darkolivegreen' => '#556b2f',\n        'olivedrab' => '#6b8e23',\n        'lightcyan' => '#e0ffff',\n        'cyan' => '#00ffff',\n        'aqua' => '#00ffff',\n        'aquamarine' => '#7fffd4',\n        'mediumaquamarine' => '#66cdaa',\n        'paleturquoise' => '#afeeee',\n        'turquoise' => '#40e0d0',\n        'mediumturquoise' => '#48d1cc',\n        'darkturquoise' => '#00ced1',\n        'lightseagreen' => '#20b2aa',\n        'cadetblue' => '#5f9ea0',\n        'darkcyan' => '#008b8b',\n        'teal' => '#008080',\n        'powderblue' => '#b0e0e6',\n        'lightblue' => '#add8e6',\n        'lightskyblue' => '#87cefa',\n        'skyblue' => '#87ceeb',\n        'deepskyblue' => '#00bfff',\n        'lightsteelblue' => '#b0c4de',\n        'dodgerblue' => '#1e90ff',\n        'cornflowerblue' => '#6495ed',\n        'steelblue' => '#4682b4',\n        'royalblue' => '#4169e1',\n        'blue' => '#0000ff',\n        'mediumblue' => '#0000cd',\n        'darkblue' => '#00008b',\n        'navy' => '#000080',\n        'midnightblue' => '#191970',\n        'mediumslateblue' => '#7b68ee',\n        'slateblue' => '#6a5acd',\n        'darkslateblue' => '#483d8b',\n        'lavender' => '#e6e6fa',\n        'thistle' => '#d8bfd8',\n        'plum' => '#dda0dd',\n        'violet' => '#ee82ee',\n        'orchid' => '#da70d6',\n        'fuchsia' => '#ff00ff',\n        'magenta' => '#ff00ff',\n        'mediumorchid' => '#ba55d3',\n        'mediumpurple' => '#9370db',\n        'blueviolet' => '#8a2be2',\n        'darkviolet' => '#9400d3',\n        'darkorchid' => '#9932cc',\n        'darkmagenta' => '#8b008b',\n        'purple' => '#800080',\n        'indigo' => '#4b0082',\n        'pink' => '#ffc0cb',\n        'lightpink' => '#ffb6c1',\n        'hotpink' => '#ff69b4',\n        'deeppink' => '#ff1493',\n        'palevioletred' => '#db7093',\n        'mediumvioletred' => '#c71585',\n        'white' => '#ffffff',\n        'snow' => '#fffafa',\n        'honeydew' => '#f0fff0',\n        'mintcream' => '#f5fffa',\n        'azure' => '#f0ffff',\n        'aliceblue' => '#f0f8ff',\n        'ghostwhite' => '#f8f8ff',\n        'whitesmoke' => '#f5f5f5',\n        'seashell' => '#fff5ee',\n        'beige' => '#f5f5dc',\n        'oldlace' => '#fdf5e6',\n        'floralwhite' => '#fffaf0',\n        'ivory' => '#fffff0',\n        'antiquewhite' => '#faebd7',\n        'linen' => '#faf0e6',\n        'lavenderblush' => '#fff0f5',\n        'mistyrose' => '#ffe4e1',\n        'gainsboro' => '#dcdcdc',\n        'lightgray' => '#d3d3d3',\n        'silver' => '#c0c0c0',\n        'darkgray' => '#a9a9a9',\n        'gray' => '#808080',\n        'dimgray' => '#696969',\n        'lightslategray' => '#778899',\n        'slategray' => '#708090',\n        'darkslategray' => '#2f4f4f',\n        'black' => '#000000',\n        'cornsilk' => '#fff8dc',\n        'blanchedalmond' => '#ffebcd',\n        'bisque' => '#ffe4c4',\n        'navajowhite' => '#ffdead',\n        'wheat' => '#f5deb3',\n        'burlywood' => '#deb887',\n        'tan' => '#d2b48c',\n        'rosybrown' => '#bc8f8f',\n        'sandybrown' => '#f4a460',\n        'goldenrod' => '#daa520',\n        'peru' => '#cd853f',\n        'chocolate' => '#d2691e',\n        'saddlebrown' => '#8b4513',\n        'sienna' => '#a0522d',\n        'brown' => '#a52a2a',\n        'maroon' => '#800000',\n    ];\n\n    /**\n     * Decode html color names\n     */\n    public function decode(mixed $input): ImageInterface|ColorInterface\n    {\n        if (!is_string($input)) {\n            throw new DecoderException('Unable to decode input');\n        }\n\n        if (!array_key_exists(strtolower($input), static::$names)) {\n            throw new DecoderException('Unable to decode input');\n        }\n\n        return parent::decode(static::$names[strtolower($input)]);\n    }\n}\n"
  },
  {
    "path": "src/Colors/Rgb/Decoders/StringColorDecoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Colors\\Rgb\\Decoders;\n\nuse Intervention\\Image\\Colors\\Rgb\\Color;\nuse Intervention\\Image\\Drivers\\AbstractDecoder;\nuse Intervention\\Image\\Exceptions\\DecoderException;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Interfaces\\DecoderInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\n\nclass StringColorDecoder extends AbstractDecoder implements DecoderInterface\n{\n    /**\n     * Decode rgb color strings\n     */\n    public function decode(mixed $input): ImageInterface|ColorInterface\n    {\n        if (!is_string($input)) {\n            throw new DecoderException('Unable to decode input');\n        }\n\n        $pattern = '/^s?rgba?\\((?P<r>[0-9\\.]+%?), ?(?P<g>[0-9\\.]+%?), ?(?P<b>[0-9\\.]+%?)' .\n            '(?:, ?(?P<a>(?:1)|(?:1\\.0*)|(?:0)|(?:0?\\.\\d+%?)|(?:\\d{1,3}%)))?\\)$/i';\n        if (preg_match($pattern, $input, $matches) != 1) {\n            throw new DecoderException('Unable to decode input');\n        }\n\n        // rgb values\n        $values = array_map(function (string $value): int {\n            return match (strpos($value, '%')) {\n                false => intval(trim($value)),\n                default => intval(round(floatval(trim(str_replace('%', '', $value))) / 100 * 255)),\n            };\n        }, [$matches['r'], $matches['g'], $matches['b']]);\n\n        // alpha value\n        if (array_key_exists('a', $matches)) {\n            $values[] = match (true) {\n                strpos($matches['a'], '%') => round(intval(trim(str_replace('%', '', $matches['a']))) / 2.55),\n                default => intval(round(floatval(trim($matches['a'])) * 255)),\n            };\n        }\n\n        return new Color(...$values);\n    }\n}\n"
  },
  {
    "path": "src/Colors/Rgb/Decoders/TransparentColorDecoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Colors\\Rgb\\Decoders;\n\nuse Intervention\\Image\\Exceptions\\DecoderException;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\n\nclass TransparentColorDecoder extends HexColorDecoder\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see DecoderInterface::decode()\n     */\n    public function decode(mixed $input): ImageInterface|ColorInterface\n    {\n        if (!is_string($input)) {\n            throw new DecoderException('Unable to decode input');\n        }\n\n        if (strtolower($input) !== 'transparent') {\n            throw new DecoderException('Unable to decode input');\n        }\n\n        return parent::decode('#ffffff00');\n    }\n}\n"
  },
  {
    "path": "src/Config.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image;\n\nuse Intervention\\Image\\Exceptions\\InputException;\n\nclass Config\n{\n    /**\n     * Create config object instance\n     *\n     * @return void\n     */\n    public function __construct(\n        public bool $autoOrientation = true,\n        public bool $decodeAnimation = true,\n        public mixed $blendingColor = 'ffffff',\n        public bool $strip = false,\n    ) {\n        //\n    }\n\n    /**\n     * Set values of given config options\n     *\n     * @throws InputException\n     */\n    public function setOptions(mixed ...$options): self\n    {\n        foreach ($this->prepareOptions($options) as $name => $value) {\n            if (!property_exists($this, $name)) {\n                throw new InputException('Property ' . $name . ' does not exists for ' . $this::class . '.');\n            }\n\n            $this->{$name} = $value;\n        }\n\n        return $this;\n    }\n\n    /**\n     * This method makes it possible to call self::setOptions() with a single\n     * array instead of named parameters\n     *\n     * @param array<mixed> $options\n     * @return array<string, mixed>\n     */\n    private function prepareOptions(array $options): array\n    {\n        if ($options === []) {\n            return $options;\n        }\n\n        if (count($options) > 1) {\n            return $options;\n        }\n\n        if (!array_key_exists(0, $options)) {\n            return $options;\n        }\n\n        if (!is_array($options[0])) {\n            return $options;\n        }\n\n        return $options[0];\n    }\n}\n"
  },
  {
    "path": "src/Decoders/Base64ImageDecoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Decoders;\n\nuse Intervention\\Image\\Drivers\\SpecializableDecoder;\n\nclass Base64ImageDecoder extends SpecializableDecoder\n{\n    //\n}\n"
  },
  {
    "path": "src/Decoders/BinaryImageDecoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Decoders;\n\nuse Intervention\\Image\\Drivers\\SpecializableDecoder;\n\nclass BinaryImageDecoder extends SpecializableDecoder\n{\n    //\n}\n"
  },
  {
    "path": "src/Decoders/ColorObjectDecoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Decoders;\n\nuse Intervention\\Image\\Drivers\\AbstractDecoder;\nuse Intervention\\Image\\Exceptions\\DecoderException;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\n\nclass ColorObjectDecoder extends AbstractDecoder\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see DecoderInterface::decode()\n     */\n    public function decode(mixed $input): ImageInterface|ColorInterface\n    {\n        if (!is_a($input, ColorInterface::class)) {\n            throw new DecoderException('Unable to decode input');\n        }\n\n        return $input;\n    }\n}\n"
  },
  {
    "path": "src/Decoders/DataUriImageDecoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Decoders;\n\nuse Intervention\\Image\\Drivers\\SpecializableDecoder;\n\nclass DataUriImageDecoder extends SpecializableDecoder\n{\n    //\n}\n"
  },
  {
    "path": "src/Decoders/EncodedImageObjectDecoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Decoders;\n\nuse Intervention\\Image\\Drivers\\SpecializableDecoder;\n\nclass EncodedImageObjectDecoder extends SpecializableDecoder\n{\n    //\n}\n"
  },
  {
    "path": "src/Decoders/FilePathImageDecoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Decoders;\n\nuse Intervention\\Image\\Drivers\\SpecializableDecoder;\n\nclass FilePathImageDecoder extends SpecializableDecoder\n{\n    //\n}\n"
  },
  {
    "path": "src/Decoders/FilePointerImageDecoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Decoders;\n\nuse Intervention\\Image\\Drivers\\SpecializableDecoder;\n\nclass FilePointerImageDecoder extends SpecializableDecoder\n{\n    //\n}\n"
  },
  {
    "path": "src/Decoders/ImageObjectDecoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Decoders;\n\nuse Intervention\\Image\\Drivers\\AbstractDecoder;\nuse Intervention\\Image\\Exceptions\\DecoderException;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\n\nclass ImageObjectDecoder extends AbstractDecoder\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see DecoderInterface::decode()\n     */\n    public function decode(mixed $input): ImageInterface|ColorInterface\n    {\n        if (!is_a($input, ImageInterface::class)) {\n            throw new DecoderException('Unable to decode input');\n        }\n\n        return $input;\n    }\n}\n"
  },
  {
    "path": "src/Decoders/NativeObjectDecoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Decoders;\n\nuse Intervention\\Image\\Drivers\\SpecializableDecoder;\n\nclass NativeObjectDecoder extends SpecializableDecoder\n{\n    //\n}\n"
  },
  {
    "path": "src/Decoders/SplFileInfoImageDecoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Decoders;\n\nuse Intervention\\Image\\Drivers\\SpecializableDecoder;\n\nclass SplFileInfoImageDecoder extends SpecializableDecoder\n{\n    //\n}\n"
  },
  {
    "path": "src/Drivers/AbstractDecoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers;\n\nuse Exception;\nuse Intervention\\Image\\Collection;\nuse Intervention\\Image\\Interfaces\\CollectionInterface;\nuse Intervention\\Image\\Interfaces\\DecoderInterface;\nuse Intervention\\Image\\Traits\\CanBuildFilePointer;\n\nabstract class AbstractDecoder implements DecoderInterface\n{\n    use CanBuildFilePointer;\n\n    /**\n     * Determine if the given input is GIF data format\n     */\n    protected function isGifFormat(string $input): bool\n    {\n        return str_starts_with($input, 'GIF87a') || str_starts_with($input, 'GIF89a');\n    }\n\n    /**\n     * Determine if given input is a path to an existing regular file\n     */\n    protected function isFile(mixed $input): bool\n    {\n        if (!is_string($input)) {\n            return false;\n        }\n\n        if (strlen($input) > PHP_MAXPATHLEN) {\n            return false;\n        }\n\n        try {\n            if (!@is_file($input)) {\n                return false;\n            }\n        } catch (Exception) {\n            return false;\n        }\n\n        return true;\n    }\n\n    /**\n     * Extract and return EXIF data from given input which can be binary image\n     * data or a file path.\n     *\n     * @return CollectionInterface<string, mixed>\n     */\n    protected function extractExifData(string $path_or_data): CollectionInterface\n    {\n        if (!function_exists('exif_read_data')) {\n            return new Collection();\n        }\n\n        try {\n            $source = match (true) {\n                $this->isFile($path_or_data) => $path_or_data, // path\n                default => $this->buildFilePointer($path_or_data), // data\n            };\n\n            // extract exif data\n            $data = @exif_read_data($source, null, true);\n            if (is_resource($source)) {\n                fclose($source);\n            }\n        } catch (Exception) {\n            $data = [];\n        }\n\n        return new Collection(is_array($data) ? $data : []);\n    }\n\n    /**\n     * Determine if given input is base64 encoded data\n     */\n    protected function isValidBase64(mixed $input): bool\n    {\n        if (!is_string($input)) {\n            return false;\n        }\n\n        return base64_encode(base64_decode($input)) === str_replace([\"\\n\", \"\\r\"], '', $input);\n    }\n\n    /**\n     * Parse data uri\n     */\n    protected function parseDataUri(mixed $input): object\n    {\n        $pattern = \"/^data:(?P<mediatype>\\w+\\/[-+.\\w]+)?\" .\n            \"(?P<parameters>(;[-\\w]+=[-\\w]+)*)(?P<base64>;base64)?,(?P<data>.*)/\";\n\n        $result = preg_match($pattern, (string) $input, $matches);\n\n        return new class ($matches, $result)\n        {\n            /**\n             * @param array<mixed> $matches\n             * @return void\n             */\n            public function __construct(private array $matches, private int|false $result)\n            {\n                //\n            }\n\n            public function isValid(): bool\n            {\n                return (bool) $this->result;\n            }\n\n            public function mediaType(): ?string\n            {\n                if (isset($this->matches['mediatype']) && !empty($this->matches['mediatype'])) {\n                    return $this->matches['mediatype'];\n                }\n\n                return null;\n            }\n\n            public function hasMediaType(): bool\n            {\n                return !empty($this->mediaType());\n            }\n\n            public function isBase64Encoded(): bool\n            {\n                return isset($this->matches['base64']) && $this->matches['base64'] === ';base64';\n            }\n\n            public function data(): ?string\n            {\n                if (isset($this->matches['data']) && !empty($this->matches['data'])) {\n                    return $this->matches['data'];\n                }\n\n                return null;\n            }\n        };\n    }\n}\n"
  },
  {
    "path": "src/Drivers/AbstractDriver.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers;\n\nuse Intervention\\Image\\Config;\nuse Intervention\\Image\\Exceptions\\DriverException;\nuse Intervention\\Image\\Exceptions\\NotSupportedException;\nuse Intervention\\Image\\InputHandler;\nuse Intervention\\Image\\Interfaces\\AnalyzerInterface;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Interfaces\\DecoderInterface;\nuse Intervention\\Image\\Interfaces\\DriverInterface;\nuse Intervention\\Image\\Interfaces\\EncoderInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\ModifierInterface;\nuse Intervention\\Image\\Interfaces\\SpecializableInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse ReflectionClass;\n\nabstract class AbstractDriver implements DriverInterface\n{\n    /**\n     * Driver options\n     */\n    protected Config $config;\n\n    /**\n     * @throws DriverException\n     * @return void\n     */\n    public function __construct()\n    {\n        $this->config = new Config();\n        $this->checkHealth();\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DriverInterface::config()\n     */\n    public function config(): Config\n    {\n        return $this->config;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DriverInterface::handleInput()\n     */\n    public function handleInput(mixed $input, array $decoders = []): ImageInterface|ColorInterface\n    {\n        return InputHandler::withDecoders($decoders, $this)->handle($input);\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DriverInterface::specialize()\n     */\n    public function specialize(\n        ModifierInterface|AnalyzerInterface|EncoderInterface|DecoderInterface $object\n    ): ModifierInterface|AnalyzerInterface|EncoderInterface|DecoderInterface {\n        // return object directly if no specializing is possible\n        if (!($object instanceof SpecializableInterface)) {\n            return $object;\n        }\n\n        // return directly and only attach driver if object is already specialized\n        if ($object instanceof SpecializedInterface) {\n            $object->setDriver($this);\n\n            return $object;\n        }\n\n        // resolve classname for specializable object\n        $specialized_classname = implode(\"\\\\\", [\n            (new ReflectionClass($this))->getNamespaceName(), // driver's namespace\n            match (true) {\n                $object instanceof ModifierInterface => 'Modifiers',\n                $object instanceof AnalyzerInterface => 'Analyzers',\n                $object instanceof EncoderInterface => 'Encoders',\n                $object instanceof DecoderInterface => 'Decoders',\n            },\n            $object_shortname = (new ReflectionClass($object))->getShortName(),\n        ]);\n\n        // fail if driver specialized classname does not exists\n        if (!class_exists($specialized_classname)) {\n            throw new NotSupportedException(\n                \"Class '\" . $object_shortname . \"' is not supported by \" . $this->id() . \" driver.\"\n            );\n        }\n\n        // create a driver specialized object with the specializable properties of generic object\n        $specialized = new $specialized_classname(...$object->specializable());\n\n        // attach driver\n        return $specialized->setDriver($this);\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DriverInterface::specializeMultiple()\n     *\n     * @throws NotSupportedException\n     * @throws DriverException\n     */\n    public function specializeMultiple(array $objects): array\n    {\n        return array_map(\n            function (string|object $object): ModifierInterface|AnalyzerInterface|EncoderInterface|DecoderInterface {\n                return $this->specialize(\n                    match (true) {\n                        is_string($object) => new $object(),\n                        is_object($object) => $object,\n                    }\n                );\n            },\n            $objects\n        );\n    }\n}\n"
  },
  {
    "path": "src/Drivers/AbstractEncoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers;\n\nuse Intervention\\Image\\EncodedImage;\nuse Intervention\\Image\\Exceptions\\RuntimeException;\nuse Intervention\\Image\\Interfaces\\EncodedImageInterface;\nuse Intervention\\Image\\Interfaces\\EncoderInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Traits\\CanBuildFilePointer;\n\nabstract class AbstractEncoder implements EncoderInterface\n{\n    use CanBuildFilePointer;\n\n    public const DEFAULT_QUALITY = 75;\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see EncoderInterface::encode()\n     */\n    public function encode(ImageInterface $image): EncodedImageInterface\n    {\n        return $image->encode($this);\n    }\n\n    /**\n     * Build new file pointer, run callback with it and return result as encoded image\n     *\n     * @throws RuntimeException\n     */\n    protected function createEncodedImage(callable $callback, ?string $mediaType = null): EncodedImage\n    {\n        $pointer = $this->buildFilePointer();\n        $callback($pointer);\n\n        return is_string($mediaType) ? new EncodedImage($pointer, $mediaType) : new EncodedImage($pointer);\n    }\n}\n"
  },
  {
    "path": "src/Drivers/AbstractFontProcessor.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers;\n\nuse Intervention\\Image\\Exceptions\\FontException;\nuse Intervention\\Image\\Geometry\\Point;\nuse Intervention\\Image\\Geometry\\Rectangle;\nuse Intervention\\Image\\Interfaces\\FontInterface;\nuse Intervention\\Image\\Interfaces\\FontProcessorInterface;\nuse Intervention\\Image\\Interfaces\\PointInterface;\nuse Intervention\\Image\\Typography\\Line;\nuse Intervention\\Image\\Typography\\TextBlock;\n\nabstract class AbstractFontProcessor implements FontProcessorInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see FontProcessorInterface::textBlock()\n     */\n    public function textBlock(string $text, FontInterface $font, PointInterface $position): TextBlock\n    {\n        $lines = $this->wrapTextBlock(new TextBlock($text), $font);\n        $pivot = $this->buildPivot($lines, $font, $position);\n\n        $leading = $this->leading($font);\n        $blockWidth = $this->boxSize((string) $lines->longestLine(), $font)->width();\n\n        $x = $pivot->x();\n        $y = $font->hasFilename() ? $pivot->y() + $this->capHeight($font) : $pivot->y();\n        $xAdjustment = 0;\n\n        // adjust line positions according to alignment\n        foreach ($lines as $line) {\n            $lineBoxSize = $this->boxSize((string) $line, $font);\n            $lineWidth = $lineBoxSize->width() + $lineBoxSize->pivot()->x();\n            $xAdjustment = $font->alignment() === 'left' ? 0 : $blockWidth - $lineWidth;\n            $xAdjustment = $font->alignment() === 'right' ? intval(round($xAdjustment)) : $xAdjustment;\n            $xAdjustment = $font->alignment() === 'center' ? intval(round($xAdjustment / 2)) : $xAdjustment;\n            $position = new Point($x + $xAdjustment, $y);\n            $position->rotate($font->angle(), $pivot);\n            $line->setPosition($position);\n            $y += $leading;\n        }\n\n        return $lines;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see FontProcessorInterface::nativeFontSize()\n     */\n    public function nativeFontSize(FontInterface $font): float\n    {\n        return $font->size();\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see FontProcessorInterface::typographicalSize()\n     */\n    public function typographicalSize(FontInterface $font): int\n    {\n        return $this->boxSize('Hy', $font)->height();\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see FontProcessorInterface::capHeight()\n     */\n    public function capHeight(FontInterface $font): int\n    {\n        return $this->boxSize('T', $font)->height();\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see FontProcessorInterface::leading()\n     */\n    public function leading(FontInterface $font): int\n    {\n        return intval(round($this->typographicalSize($font) * $font->lineHeight()));\n    }\n\n    /**\n     * Reformat a text block by wrapping each line before the given maximum width\n     *\n     * @throws FontException\n     */\n    protected function wrapTextBlock(TextBlock $block, FontInterface $font): TextBlock\n    {\n        $newLines = [];\n        foreach ($block as $line) {\n            foreach ($this->wrapLine($line, $font) as $newLine) {\n                $newLines[] = $newLine;\n            }\n        }\n\n        return $block->setLines($newLines);\n    }\n\n    /**\n     * Check if a line exceeds the given maximum width and wrap it if necessary.\n     * The output will be an array of formatted lines that are all within the\n     * maximum width.\n     *\n     * @throws FontException\n     * @return array<Line>\n     */\n    protected function wrapLine(Line $line, FontInterface $font): array\n    {\n        // no wrap width - no wrapping\n        if (is_null($font->wrapWidth())) {\n            return [$line];\n        }\n\n        $wrapped = [];\n        $formattedLine = new Line();\n\n        foreach ($line as $word) {\n            // calculate width of newly formatted line\n            $lineWidth = $this->boxSize(match ($formattedLine->count()) {\n                0 => $word,\n                default => $formattedLine . ' ' . $word,\n            }, $font)->width();\n\n            // decide if word fits on current line or a new line must be created\n            if ($line->count() === 1 || $lineWidth <= $font->wrapWidth()) {\n                $formattedLine->add($word);\n            } else {\n                if ($formattedLine->count() !== 0) {\n                    $wrapped[] = $formattedLine;\n                }\n                $formattedLine = new Line($word);\n            }\n        }\n\n        $wrapped[] = $formattedLine;\n\n        return $wrapped;\n    }\n\n    /**\n     * Build pivot point of textblock according to the font settings and based on given position\n     *\n     * @throws FontException\n     */\n    protected function buildPivot(TextBlock $block, FontInterface $font, PointInterface $position): PointInterface\n    {\n        // bounding box\n        $box = new Rectangle(\n            $this->boxSize((string) $block->longestLine(), $font)->width(),\n            $this->leading($font) * ($block->count() - 1) + $this->capHeight($font)\n        );\n\n        // set position\n        $box->setPivot($position);\n\n        // alignment\n        $box->align($font->alignment());\n        $box->valign($font->valignment());\n        $box->rotate($font->angle());\n\n        return $box->last();\n    }\n}\n"
  },
  {
    "path": "src/Drivers/AbstractFrame.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers;\n\nuse Intervention\\Image\\Interfaces\\FrameInterface;\n\nabstract class AbstractFrame implements FrameInterface\n{\n    /**\n     * Show debug info for the current image\n     *\n     * @return array<string, mixed>\n     */\n    public function __debugInfo(): array\n    {\n        return [\n            'delay' => $this->delay(),\n            'left' => $this->offsetLeft(),\n            'top' => $this->offsetTop(),\n            'dispose' => $this->dispose(),\n        ];\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Analyzers/ColorspaceAnalyzer.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Analyzers;\n\nuse Intervention\\Image\\Analyzers\\ColorspaceAnalyzer as GenericColorspaceAnalyzer;\nuse Intervention\\Image\\Colors\\Rgb\\Colorspace;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\n\nclass ColorspaceAnalyzer extends GenericColorspaceAnalyzer implements SpecializedInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see AnalyzerInterface::analyze()\n     */\n    public function analyze(ImageInterface $image): mixed\n    {\n        return new Colorspace();\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Analyzers/HeightAnalyzer.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Analyzers;\n\nuse Intervention\\Image\\Analyzers\\HeightAnalyzer as GenericHeightAnalyzer;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\n\nclass HeightAnalyzer extends GenericHeightAnalyzer implements SpecializedInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see AnalyzerInterface::analyze()\n     */\n    public function analyze(ImageInterface $image): mixed\n    {\n        return imagesy($image->core()->native());\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Analyzers/PixelColorAnalyzer.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Analyzers;\n\nuse GdImage;\nuse Intervention\\Image\\Analyzers\\PixelColorAnalyzer as GenericPixelColorAnalyzer;\nuse Intervention\\Image\\Exceptions\\ColorException;\nuse Intervention\\Image\\Exceptions\\GeometryException;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Interfaces\\ColorspaceInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\n\nclass PixelColorAnalyzer extends GenericPixelColorAnalyzer implements SpecializedInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see AnalyzerInterface::analyze()\n     */\n    public function analyze(ImageInterface $image): mixed\n    {\n        return $this->colorAt(\n            $image->colorspace(),\n            $image->core()->frame($this->frame_key)->native()\n        );\n    }\n\n    /**\n     * @throws GeometryException\n     * @throws ColorException\n     */\n    protected function colorAt(ColorspaceInterface $colorspace, GdImage $gd): ColorInterface\n    {\n        $index = @imagecolorat($gd, $this->x, $this->y);\n\n        if (!imageistruecolor($gd)) {\n            $index = imagecolorsforindex($gd, $index);\n        }\n\n        if ($index === false) {\n            throw new GeometryException(\n                'The specified position is not in the valid image area.'\n            );\n        }\n\n        return $this->driver()->colorProcessor($colorspace)->nativeToColor($index);\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Analyzers/PixelColorsAnalyzer.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Analyzers;\n\nuse Intervention\\Image\\Collection;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\n\nclass PixelColorsAnalyzer extends PixelColorAnalyzer\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see AnalyzerInterface::analyze()\n     */\n    public function analyze(ImageInterface $image): mixed\n    {\n        $colors = new Collection();\n        $colorspace = $image->colorspace();\n\n        foreach ($image as $frame) {\n            $colors->push(\n                parent::colorAt($colorspace, $frame->native())\n            );\n        }\n\n        return $colors;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Analyzers/ResolutionAnalyzer.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Analyzers;\n\nuse Intervention\\Image\\Analyzers\\ResolutionAnalyzer as GenericResolutionAnalyzer;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Resolution;\n\nclass ResolutionAnalyzer extends GenericResolutionAnalyzer implements SpecializedInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see AnalyzerInterface::analyze()\n     */\n    public function analyze(ImageInterface $image): mixed\n    {\n        return new Resolution(...imageresolution($image->core()->native()));\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Analyzers/WidthAnalyzer.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Analyzers;\n\nuse Intervention\\Image\\Analyzers\\WidthAnalyzer as GenericWidthAnalyzer;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\n\nclass WidthAnalyzer extends GenericWidthAnalyzer implements SpecializedInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see AnalyzerInterface::analyze()\n     */\n    public function analyze(ImageInterface $image): mixed\n    {\n        return imagesx($image->core()->native());\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Cloner.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd;\n\nuse GdImage;\nuse Intervention\\Image\\Colors\\Rgb\\Channels\\Alpha;\nuse Intervention\\Image\\Colors\\Rgb\\Color;\nuse Intervention\\Image\\Exceptions\\ColorException;\nuse Intervention\\Image\\Geometry\\Rectangle;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Interfaces\\SizeInterface;\n\nclass Cloner\n{\n    /**\n     * Create a clone of the given GdImage\n     *\n     * @throws ColorException\n     */\n    public static function clone(GdImage $gd): GdImage\n    {\n        // create empty canvas with same size\n        $clone = static::cloneEmpty($gd);\n\n        // transfer actual image to clone\n        imagecopy($clone, $gd, 0, 0, 0, 0, imagesx($gd), imagesy($gd));\n\n        return $clone;\n    }\n\n    /**\n     * Create an \"empty\" clone of the given GdImage\n     *\n     * This only retains the basic data without transferring the actual image.\n     * It is optionally possible to change the size of the result and set a\n     * background color.\n     *\n     * @throws ColorException\n     */\n    public static function cloneEmpty(\n        GdImage $gd,\n        ?SizeInterface $size = null,\n        ColorInterface $background = new Color(255, 255, 255, 0)\n    ): GdImage {\n        // define size\n        $size = $size ?: new Rectangle(imagesx($gd), imagesy($gd));\n\n        // create new gd image with same size or new given size\n        $clone = imagecreatetruecolor($size->width(), $size->height());\n\n        // copy resolution to clone\n        $resolution = imageresolution($gd);\n        if (is_array($resolution) && array_key_exists(0, $resolution) && array_key_exists(1, $resolution)) {\n            imageresolution($clone, $resolution[0], $resolution[1]);\n        }\n\n        // fill with background\n        $processor = new ColorProcessor();\n        imagefill($clone, 0, 0, $processor->colorToNative($background));\n        imagealphablending($clone, true);\n        imagesavealpha($clone, true);\n\n        // set background image as transparent if alpha channel value if color is below .5\n        // comes into effect when the end format only supports binary transparency (like GIF)\n        if ($background->channel(Alpha::class)->value() < 128) {\n            imagecolortransparent($clone, $processor->colorToNative($background));\n        }\n\n        return $clone;\n    }\n\n    /**\n     * Create a clone of an GdImage that is positioned on the specified background color.\n     * Possible transparent areas are mixed with this color.\n     *\n     * @throws ColorException\n     */\n    public static function cloneBlended(GdImage $gd, ColorInterface $background): GdImage\n    {\n        // create empty canvas with same size\n        $clone = static::cloneEmpty($gd, background: $background);\n\n        // transfer actual image to clone\n        imagecopy($clone, $gd, 0, 0, 0, 0, imagesx($gd), imagesy($gd));\n\n        return $clone;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/ColorProcessor.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd;\n\nuse Intervention\\Image\\Colors\\Rgb\\Channels\\Alpha;\nuse Intervention\\Image\\Colors\\Rgb\\Channels\\Blue;\nuse Intervention\\Image\\Colors\\Rgb\\Channels\\Green;\nuse Intervention\\Image\\Colors\\Rgb\\Channels\\Red;\nuse Intervention\\Image\\Colors\\Rgb\\Color;\nuse Intervention\\Image\\Colors\\Rgb\\Colorspace;\nuse Intervention\\Image\\Exceptions\\ColorException;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Interfaces\\ColorProcessorInterface;\nuse Intervention\\Image\\Interfaces\\ColorspaceInterface;\n\nclass ColorProcessor implements ColorProcessorInterface\n{\n    /**\n     * Create new color processor object\n     *\n     * @return void\n     */\n    public function __construct(protected ColorspaceInterface $colorspace = new Colorspace())\n    {\n        //\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorProcessorInterface::colorToNative()\n     */\n    public function colorToNative(ColorInterface $color): int\n    {\n        // convert color to colorspace\n        $color = $color->convertTo($this->colorspace);\n\n        // gd only supports rgb so the channels can be accessed directly\n        $r = $color->channel(Red::class)->value();\n        $g = $color->channel(Green::class)->value();\n        $b = $color->channel(Blue::class)->value();\n        $a = $color->channel(Alpha::class)->value();\n\n        // convert alpha value to gd alpha\n        // ([opaque]255-0[transparent]) to ([opaque]0-127[transparent])\n        $a = (int) $this->convertRange($a, 0, 255, 127, 0);\n\n        return ($a << 24) + ($r << 16) + ($g << 8) + $b;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorProcessorInterface::nativeToColor()\n     */\n    public function nativeToColor(mixed $value): ColorInterface\n    {\n        if (!is_int($value) && !is_array($value)) {\n            throw new ColorException('GD driver can only decode colors in integer and array format.');\n        }\n\n        if (is_array($value)) {\n            // array conversion\n            if (!$this->isValidArrayColor($value)) {\n                throw new ColorException(\n                    'GD driver can only decode array color format array{red: int, green: int, blue: int, alpha: int}.',\n                );\n            }\n\n            $r = $value['red'];\n            $g = $value['green'];\n            $b = $value['blue'];\n            $a = $value['alpha'];\n        } else {\n            // integer conversion\n            $a = ($value >> 24) & 0xFF;\n            $r = ($value >> 16) & 0xFF;\n            $g = ($value >> 8) & 0xFF;\n            $b = $value & 0xFF;\n        }\n\n        // convert gd apha integer to intervention alpha integer\n        // ([opaque]0-127[transparent]) to ([opaque]255-0[transparent])\n        $a = (int) static::convertRange($a, 127, 0, 0, 255);\n\n        return new Color($r, $g, $b, $a);\n    }\n\n    /**\n     * Convert input in range (min) to (max) to the corresponding value\n     * in target range (targetMin) to (targetMax).\n     */\n    protected function convertRange(\n        float|int $input,\n        float|int $min,\n        float|int $max,\n        float|int $targetMin,\n        float|int $targetMax\n    ): float|int {\n        return ceil(((($input - $min) * ($targetMax - $targetMin)) / ($max - $min)) + $targetMin);\n    }\n\n    /**\n     * Check if given array is valid color format\n     * array{red: int, green: int, blue: int, alpha: int}\n     * i.e. result of imagecolorsforindex()\n     *\n     * @param array<mixed> $color\n     */\n    private function isValidArrayColor(array $color): bool\n    {\n        if (!array_key_exists('red', $color)) {\n            return false;\n        }\n\n        if (!array_key_exists('green', $color)) {\n            return false;\n        }\n\n        if (!array_key_exists('blue', $color)) {\n            return false;\n        }\n\n        if (!array_key_exists('alpha', $color)) {\n            return false;\n        }\n\n        if (!is_int($color['red'])) {\n            return false;\n        }\n\n        if (!is_int($color['green'])) {\n            return false;\n        }\n\n        if (!is_int($color['blue'])) {\n            return false;\n        }\n\n        if (!is_int($color['alpha'])) {\n            return false;\n        }\n\n        return true;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Core.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd;\n\nuse Intervention\\Image\\Collection;\nuse Intervention\\Image\\Exceptions\\AnimationException;\nuse Intervention\\Image\\Interfaces\\CoreInterface;\nuse Intervention\\Image\\Interfaces\\FrameInterface;\n\nclass Core extends Collection implements CoreInterface\n{\n    protected int $loops = 0;\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see CoreInterface::add()\n     */\n    public function add(FrameInterface $frame): CoreInterface\n    {\n        $this->push($frame);\n\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see CoreInterface::native()\n     */\n    public function native(): mixed\n    {\n        return $this->first()->native();\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see CoreInterface::setNative()\n     */\n    public function setNative(mixed $native): self\n    {\n        $this->empty()->push(new Frame($native));\n\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see CoreInterface::frame()\n     */\n    public function frame(int $position): FrameInterface\n    {\n        $frame = $this->getAtPosition($position);\n\n        if (!($frame instanceof FrameInterface)) {\n            throw new AnimationException('Frame #' . $position . ' could not be found in the image.');\n        }\n\n        return $frame;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see CoreInterface::loops()\n     */\n    public function loops(): int\n    {\n        return $this->loops;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see CoreInterface::setLoops()\n     */\n    public function setLoops(int $loops): self\n    {\n        $this->loops = $loops;\n\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see CollectionInterface::first()\n     */\n    public function first(): FrameInterface\n    {\n        return parent::first();\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see CollectionInterface::last()\n     */\n    public function last(): FrameInterface\n    {\n        return parent::last();\n    }\n\n    /**\n     * Clone instance\n     */\n    public function __clone(): void\n    {\n        foreach ($this->items as $key => $frame) {\n            $this->items[$key] = clone $frame;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Decoders/AbstractDecoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Decoders;\n\nuse Intervention\\Image\\Drivers\\SpecializableDecoder;\nuse Intervention\\Image\\Exceptions\\DecoderException;\nuse Intervention\\Image\\Exceptions\\NotSupportedException;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\MediaType;\nuse ValueError;\n\nabstract class AbstractDecoder extends SpecializableDecoder implements SpecializedInterface\n{\n    /**\n     * Return media (mime) type of the file at given file path\n     *\n     * @throws DecoderException\n     * @throws NotSupportedException\n     */\n    protected function getMediaTypeByFilePath(string $filepath): MediaType\n    {\n        if (function_exists('finfo_file') && function_exists('finfo_open')) {\n            $mediaType = finfo_file(finfo_open(FILEINFO_MIME_TYPE), $filepath);\n            if (is_string($mediaType)) {\n                try {\n                    return MediaType::from($mediaType);\n                } catch (ValueError) {\n                    throw new NotSupportedException('Unsupported media type (MIME) ' . $mediaType . '.');\n                }\n            }\n        }\n\n        $info = @getimagesize($filepath);\n\n        if (!is_array($info)) {\n            throw new DecoderException('Unable to detect media (MIME) from data in file path.');\n        }\n\n        try {\n            return MediaType::from($info['mime']);\n        } catch (ValueError) {\n            throw new NotSupportedException('Unsupported media type (MIME) ' . $info['mime'] . '.');\n        }\n    }\n\n    /**\n     * Return media (mime) type of the given image data\n     *\n     * @throws DecoderException\n     * @throws NotSupportedException\n     */\n    protected function getMediaTypeByBinary(string $data): MediaType\n    {\n        if (function_exists('finfo_buffer') && function_exists('finfo_open')) {\n            $mediaType = finfo_buffer(finfo_open(FILEINFO_MIME_TYPE), $data);\n            if (is_string($mediaType)) {\n                try {\n                    return MediaType::from($mediaType);\n                } catch (ValueError) {\n                    throw new NotSupportedException('Unsupported media type (MIME) ' . $mediaType . '.');\n                }\n            }\n        }\n\n        $info = @getimagesizefromstring($data);\n\n        if (!is_array($info)) {\n            throw new DecoderException('Unable to detect media (MIME) from binary data.');\n        }\n\n        try {\n            return MediaType::from($info['mime']);\n        } catch (ValueError) {\n            throw new NotSupportedException('Unsupported media type (MIME) ' . $info['mime'] . '.');\n        }\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Decoders/Base64ImageDecoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Decoders;\n\nuse Intervention\\Image\\Exceptions\\DecoderException;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Interfaces\\DecoderInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\n\nclass Base64ImageDecoder extends BinaryImageDecoder implements DecoderInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see DecoderInterface::decode()\n     */\n    public function decode(mixed $input): ImageInterface|ColorInterface\n    {\n        if (!$this->isValidBase64($input)) {\n            throw new DecoderException('Unable to decode input');\n        }\n\n        return parent::decode(base64_decode((string) $input));\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Decoders/BinaryImageDecoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Decoders;\n\nuse Intervention\\Image\\Exceptions\\RuntimeException;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Interfaces\\DecoderInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Exceptions\\DecoderException;\nuse Intervention\\Image\\Format;\nuse Intervention\\Image\\Modifiers\\AlignRotationModifier;\n\nclass BinaryImageDecoder extends NativeObjectDecoder implements DecoderInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see DecoderInterface::decode()\n     */\n    public function decode(mixed $input): ImageInterface|ColorInterface\n    {\n        if (!is_string($input)) {\n            throw new DecoderException('Unable to decode input');\n        }\n\n        return match ($this->isGifFormat($input)) {\n            true => $this->decodeGif($input),\n            default => $this->decodeBinary($input),\n        };\n    }\n\n    /**\n     * Decode image from given binary data\n     *\n     * @throws RuntimeException\n     */\n    private function decodeBinary(string $input): ImageInterface\n    {\n        $gd = @imagecreatefromstring($input);\n\n        if ($gd === false) {\n            throw new DecoderException('Unable to decode input');\n        }\n\n        // create image instance\n        $image = parent::decode($gd);\n\n        // get media type\n        $mediaType = $this->getMediaTypeByBinary($input);\n\n        // extract & set exif data for appropriate formats\n        if (in_array($mediaType->format(), [Format::JPEG, Format::TIFF])) {\n            $image->setExif($this->extractExifData($input));\n        }\n\n        // set mediaType on origin\n        $image->origin()->setMediaType($mediaType);\n\n        // adjust image orientation\n        if ($this->driver()->config()->autoOrientation) {\n            $image->modify(new AlignRotationModifier());\n        }\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Decoders/DataUriImageDecoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Decoders;\n\nuse Intervention\\Image\\Exceptions\\DecoderException;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Interfaces\\DecoderInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\n\nclass DataUriImageDecoder extends BinaryImageDecoder implements DecoderInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see DecoderInterface::decode()\n     */\n    public function decode(mixed $input): ImageInterface|ColorInterface\n    {\n        if (!is_string($input)) {\n            throw new DecoderException('Unable to decode input');\n        }\n\n        $uri = $this->parseDataUri($input);\n\n        if (!$uri->isValid()) {\n            throw new DecoderException('Unable to decode input');\n        }\n\n        if ($uri->isBase64Encoded()) {\n            return parent::decode(base64_decode($uri->data()));\n        }\n\n        return parent::decode(urldecode($uri->data()));\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Decoders/EncodedImageObjectDecoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Decoders;\n\nuse Intervention\\Image\\EncodedImage;\nuse Intervention\\Image\\Exceptions\\DecoderException;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\n\nclass EncodedImageObjectDecoder extends BinaryImageDecoder\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see DecoderInterface::decode()\n     */\n    public function decode(mixed $input): ImageInterface|ColorInterface\n    {\n        if (!is_a($input, EncodedImage::class)) {\n            throw new DecoderException('Unable to decode input');\n        }\n\n        return parent::decode($input->toString());\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Decoders/FilePathImageDecoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Decoders;\n\nuse Intervention\\Image\\Exceptions\\DecoderException;\nuse Intervention\\Image\\Format;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Interfaces\\DecoderInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Modifiers\\AlignRotationModifier;\n\nclass FilePathImageDecoder extends NativeObjectDecoder implements DecoderInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see DecoderInterface::decode()\n     */\n    public function decode(mixed $input): ImageInterface|ColorInterface\n    {\n        if (!$this->isFile($input)) {\n            throw new DecoderException('Unable to decode input');\n        }\n\n        // detect media (mime) type\n        $mediaType = $this->getMediaTypeByFilePath($input);\n\n        $image = match ($mediaType->format()) {\n            // gif files might be animated and therefore cannot\n            // be handled by the standard GD decoder.\n            Format::GIF => $this->decodeGif($input),\n            default => parent::decode(match ($mediaType->format()) {\n                Format::JPEG => @imagecreatefromjpeg($input),\n                Format::WEBP => @imagecreatefromwebp($input),\n                Format::PNG => @imagecreatefrompng($input),\n                Format::AVIF => @imagecreatefromavif($input),\n                Format::BMP => @imagecreatefrombmp($input),\n                default => throw new DecoderException('Unable to decode input'),\n            }),\n        };\n\n        // set file path & mediaType on origin\n        $image->origin()->setFilePath($input);\n        $image->origin()->setMediaType($mediaType);\n\n        // extract exif for the appropriate formats\n        if ($mediaType->format() === Format::JPEG) {\n            $image->setExif($this->extractExifData($input));\n        }\n\n        // adjust image orientation\n        if ($this->driver()->config()->autoOrientation) {\n            $image->modify(new AlignRotationModifier());\n        }\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Decoders/FilePointerImageDecoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Decoders;\n\nuse Intervention\\Image\\Exceptions\\DecoderException;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\n\nclass FilePointerImageDecoder extends BinaryImageDecoder\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see DecoderInterface::decode()\n     */\n    public function decode(mixed $input): ImageInterface|ColorInterface\n    {\n        if (!is_resource($input) || !in_array(get_resource_type($input), ['file', 'stream'])) {\n            throw new DecoderException('Unable to decode input');\n        }\n\n        $contents = '';\n        @rewind($input);\n        while (!feof($input)) {\n            $contents .= fread($input, 1024);\n        }\n\n        return parent::decode($contents);\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Decoders/NativeObjectDecoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Decoders;\n\nuse Exception;\nuse GdImage;\nuse Intervention\\Gif\\Decoder as GifDecoder;\nuse Intervention\\Gif\\Splitter as GifSplitter;\nuse Intervention\\Image\\Drivers\\Gd\\Core;\nuse Intervention\\Image\\Drivers\\Gd\\Frame;\nuse Intervention\\Image\\Exceptions\\DecoderException;\nuse Intervention\\Image\\Exceptions\\RuntimeException;\nuse Intervention\\Image\\Image;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\n\nclass NativeObjectDecoder extends AbstractDecoder\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see DecoderInterface::decode()\n     */\n    public function decode(mixed $input): ImageInterface|ColorInterface\n    {\n        if (!is_object($input)) {\n            throw new DecoderException('Unable to decode input');\n        }\n\n        if (!($input instanceof GdImage)) {\n            throw new DecoderException('Unable to decode input');\n        }\n\n        if (!imageistruecolor($input)) {\n            imagepalettetotruecolor($input);\n        }\n\n        imagesavealpha($input, true);\n\n        // build image instance\n        return new Image(\n            $this->driver(),\n            new Core([\n                new Frame($input)\n            ])\n        );\n    }\n\n    /**\n     * Decode image from given GIF source which can be either a file path or binary data\n     *\n     * Depending on the configuration, this is taken over by the native GD function\n     * or, if animations are required, by our own extended decoder.\n     *\n     * @throws RuntimeException\n     */\n    protected function decodeGif(mixed $input): ImageInterface\n    {\n        // create non-animated image depending on config\n        if (!$this->driver()->config()->decodeAnimation) {\n            $native = match (true) {\n                $this->isGifFormat($input) => @imagecreatefromstring($input),\n                default => @imagecreatefromgif($input),\n            };\n\n            if ($native === false) {\n                throw new DecoderException('Unable to decode input.');\n            }\n\n            $image = self::decode($native);\n            $image->origin()->setMediaType('image/gif');\n\n            return $image;\n        }\n\n        try {\n            // create empty core\n            $core = new Core();\n\n            $gif = GifDecoder::decode($input);\n            $splitter = GifSplitter::create($gif)->split();\n            $delays = $splitter->getDelays();\n\n            // set loops on core\n            if ($loops = $gif->getMainApplicationExtension()?->getLoops()) {\n                $core->setLoops($loops);\n            }\n\n            // add GDImage instances to core\n            foreach ($splitter->coalesceToResources() as $key => $native) {\n                $core->push(\n                    new Frame($native, $delays[$key] / 100)\n                );\n            }\n        } catch (Exception $e) {\n            throw new DecoderException($e->getMessage(), $e->getCode(), $e);\n        }\n\n        // create (possibly) animated image\n        $image = new Image($this->driver(), $core);\n\n        // set media type\n        $image->origin()->setMediaType('image/gif');\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Decoders/SplFileInfoImageDecoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Decoders;\n\nuse SplFileInfo;\nuse Intervention\\Image\\Exceptions\\DecoderException;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Interfaces\\DecoderInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\n\nclass SplFileInfoImageDecoder extends FilePathImageDecoder implements DecoderInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see DecoderInterface::decode()\n     */\n    public function decode(mixed $input): ImageInterface|ColorInterface\n    {\n        if (!is_a($input, SplFileInfo::class)) {\n            throw new DecoderException('Unable to decode input');\n        }\n\n        return parent::decode($input->getRealPath());\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Driver.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd;\n\nuse Intervention\\Image\\Drivers\\AbstractDriver;\nuse Intervention\\Image\\Exceptions\\DriverException;\nuse Intervention\\Image\\Exceptions\\RuntimeException;\nuse Intervention\\Image\\Format;\nuse Intervention\\Image\\FileExtension;\nuse Intervention\\Image\\Image;\nuse Intervention\\Image\\Interfaces\\ColorProcessorInterface;\nuse Intervention\\Image\\Interfaces\\ColorspaceInterface;\nuse Intervention\\Image\\Interfaces\\DriverInterface;\nuse Intervention\\Image\\Interfaces\\FontProcessorInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\MediaType;\n\nclass Driver extends AbstractDriver\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see DriverInterface::id()\n     */\n    public function id(): string\n    {\n        return 'GD';\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DriverInterface::checkHealth()\n     *\n     * @codeCoverageIgnore\n     */\n    public function checkHealth(): void\n    {\n        if (!extension_loaded('gd') || !function_exists('gd_info')) {\n            throw new DriverException(\n                'GD PHP extension must be installed to use this driver.'\n            );\n        }\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DriverInterface::createImage()\n     */\n    public function createImage(int $width, int $height): ImageInterface\n    {\n        // build new transparent GDImage\n        $data = imagecreatetruecolor($width, $height);\n        imagesavealpha($data, true);\n        $background = imagecolorallocatealpha($data, 255, 255, 255, 127);\n        imagealphablending($data, false);\n        imagefill($data, 0, 0, $background);\n        imagecolortransparent($data, $background);\n\n        return new Image(\n            $this,\n            new Core([\n                new Frame($data)\n            ])\n        );\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DriverInterface::createAnimation()\n     *\n     * @throws RuntimeException\n     */\n    public function createAnimation(callable $init): ImageInterface\n    {\n        $animation = new class ($this)\n        {\n            public function __construct(\n                protected DriverInterface $driver,\n                public Core $core = new Core()\n            ) {\n                //\n            }\n\n            /**\n             * @throws RuntimeException\n             */\n            public function add(mixed $source, float $delay = 1): self\n            {\n                $this->core->add(\n                    $this->driver->handleInput($source)->core()->first()->setDelay($delay)\n                );\n\n                return $this;\n            }\n\n            /**\n             * @throws RuntimeException\n             */\n            public function __invoke(): ImageInterface\n            {\n                return new Image(\n                    $this->driver,\n                    $this->core\n                );\n            }\n        };\n\n        $init($animation);\n\n        return call_user_func($animation);\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DriverInterface::colorProcessor()\n     */\n    public function colorProcessor(ColorspaceInterface $colorspace): ColorProcessorInterface\n    {\n        return new ColorProcessor($colorspace);\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DriverInterface::fontProcessor()\n     */\n    public function fontProcessor(): FontProcessorInterface\n    {\n        return new FontProcessor();\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DriverInterface::supports()\n     */\n    public function supports(string|Format|FileExtension|MediaType $identifier): bool\n    {\n        return match (Format::tryCreate($identifier)) {\n            Format::JPEG => boolval(imagetypes() & IMG_JPEG),\n            Format::WEBP => boolval(imagetypes() & IMG_WEBP),\n            Format::GIF => boolval(imagetypes() & IMG_GIF),\n            Format::PNG => boolval(imagetypes() & IMG_PNG),\n            Format::AVIF => boolval(imagetypes() & IMG_AVIF),\n            Format::BMP => boolval(imagetypes() & IMG_BMP),\n            default => false,\n        };\n    }\n\n    /**\n     * Return version of GD library\n     */\n    public static function version(): string\n    {\n        return gd_info()['GD Version'];\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Encoders/AvifEncoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Encoders;\n\nuse Intervention\\Image\\EncodedImage;\nuse Intervention\\Image\\Encoders\\AvifEncoder as GenericAvifEncoder;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\n\nclass AvifEncoder extends GenericAvifEncoder implements SpecializedInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see EncoderInterface::encode()\n     */\n    public function encode(ImageInterface $image): EncodedImage\n    {\n        return $this->createEncodedImage(function ($pointer) use ($image): void {\n            imageavif($image->core()->native(), $pointer, $this->quality);\n        }, 'image/avif');\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Encoders/BmpEncoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Encoders;\n\nuse Intervention\\Image\\EncodedImage;\nuse Intervention\\Image\\Encoders\\BmpEncoder as GenericBmpEncoder;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\n\nclass BmpEncoder extends GenericBmpEncoder implements SpecializedInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see EncoderInterface::encode()\n     */\n    public function encode(ImageInterface $image): EncodedImage\n    {\n        return $this->createEncodedImage(function ($pointer) use ($image): void {\n            imagebmp($image->core()->native(), $pointer, false);\n        }, 'image/bmp');\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Encoders/GifEncoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Encoders;\n\nuse Exception;\nuse Intervention\\Gif\\Builder as GifBuilder;\nuse Intervention\\Image\\Drivers\\Gd\\Cloner;\nuse Intervention\\Image\\EncodedImage;\nuse Intervention\\Image\\Encoders\\GifEncoder as GenericGifEncoder;\nuse Intervention\\Image\\Exceptions\\EncoderException;\nuse Intervention\\Image\\Exceptions\\RuntimeException;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\n\nclass GifEncoder extends GenericGifEncoder implements SpecializedInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see EncoderInterface::encode()\n     */\n    public function encode(ImageInterface $image): EncodedImage\n    {\n        if ($image->isAnimated()) {\n            return $this->encodeAnimated($image);\n        }\n\n        $gd = Cloner::clone($image->core()->native());\n\n        return $this->createEncodedImage(function ($pointer) use ($gd): void {\n            imageinterlace($gd, $this->interlaced);\n            imagegif($gd, $pointer);\n        }, 'image/gif');\n    }\n\n    /**\n     * @throws RuntimeException\n     */\n    protected function encodeAnimated(ImageInterface $image): EncodedImage\n    {\n        try {\n            $builder = GifBuilder::canvas(\n                $image->width(),\n                $image->height()\n            );\n\n            foreach ($image as $frame) {\n                $builder->addFrame(\n                    source: $this->encode($frame->toImage($image->driver()))->toFilePointer(),\n                    delay: $frame->delay(),\n                    interlaced: $this->interlaced\n                );\n            }\n\n            $builder->setLoops($image->loops());\n\n            return new EncodedImage($builder->encode(), 'image/gif');\n        } catch (Exception $e) {\n            throw new EncoderException($e->getMessage(), $e->getCode(), $e);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Encoders/JpegEncoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Encoders;\n\nuse Intervention\\Image\\Drivers\\Gd\\Cloner;\nuse Intervention\\Image\\Encoders\\JpegEncoder as GenericJpegEncoder;\nuse Intervention\\Image\\EncodedImage;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\n\nclass JpegEncoder extends GenericJpegEncoder implements SpecializedInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see EncoderInterface::encode()\n     */\n    public function encode(ImageInterface $image): EncodedImage\n    {\n        $blendingColor = $this->driver()->handleInput(\n            $this->driver()->config()->blendingColor\n        );\n\n        $output = Cloner::cloneBlended(\n            $image->core()->native(),\n            background: $blendingColor\n        );\n\n        return $this->createEncodedImage(function ($pointer) use ($output): void {\n            imageinterlace($output, $this->progressive);\n            imagejpeg($output, $pointer, $this->quality);\n        }, 'image/jpeg');\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Encoders/PngEncoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Encoders;\n\nuse GdImage;\nuse Intervention\\Image\\Drivers\\Gd\\Cloner;\nuse Intervention\\Image\\EncodedImage;\nuse Intervention\\Image\\Encoders\\PngEncoder as GenericPngEncoder;\nuse Intervention\\Image\\Exceptions\\AnimationException;\nuse Intervention\\Image\\Exceptions\\ColorException;\nuse Intervention\\Image\\Exceptions\\RuntimeException;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\n\nclass PngEncoder extends GenericPngEncoder implements SpecializedInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see EncoderInterface::encode()\n     */\n    public function encode(ImageInterface $image): EncodedImage\n    {\n        $output = $this->prepareOutput($image);\n\n        return $this->createEncodedImage(function ($pointer) use ($output): void {\n            imageinterlace($output, $this->interlaced);\n            imagepng($output, $pointer, -1);\n        }, 'image/png');\n    }\n\n    /**\n     * Prepare given image instance for PNG format output according to encoder settings\n     *\n     * @throws RuntimeException\n     * @throws ColorException\n     * @throws AnimationException\n     */\n    private function prepareOutput(ImageInterface $image): GdImage\n    {\n        if ($this->indexed) {\n            $output = clone $image;\n            $output->reduceColors(255);\n\n            return $output->core()->native();\n        }\n\n        return Cloner::clone($image->core()->native());\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Encoders/WebpEncoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Encoders;\n\nuse Intervention\\Image\\EncodedImage;\nuse Intervention\\Image\\Encoders\\WebpEncoder as GenericWebpEncoder;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\n\nclass WebpEncoder extends GenericWebpEncoder implements SpecializedInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see EncoderInterface::encode()\n     */\n    public function encode(ImageInterface $image): EncodedImage\n    {\n        $quality = $this->quality === 100 && defined('IMG_WEBP_LOSSLESS') ? IMG_WEBP_LOSSLESS : $this->quality;\n\n        return $this->createEncodedImage(function ($pointer) use ($image, $quality): void {\n            imagewebp($image->core()->native(), $pointer, $quality);\n        }, 'image/webp');\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/FontProcessor.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd;\n\nuse Intervention\\Image\\Drivers\\AbstractFontProcessor;\nuse Intervention\\Image\\Exceptions\\FontException;\nuse Intervention\\Image\\Geometry\\Point;\nuse Intervention\\Image\\Geometry\\Rectangle;\nuse Intervention\\Image\\Interfaces\\FontInterface;\nuse Intervention\\Image\\Interfaces\\SizeInterface;\n\nclass FontProcessor extends AbstractFontProcessor\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see FontProcessorInterface::boxSize()\n     */\n    public function boxSize(string $text, FontInterface $font): SizeInterface\n    {\n        // if the font has no ttf file the box size is calculated\n        // with gd's internal font system: integer values from 1-5\n        if (!$font->hasFilename()) {\n            // calculate box size from gd font\n            $box = new Rectangle(0, 0);\n            $chars = mb_strlen($text);\n            if ($chars > 0) {\n                $box->setWidth(\n                    $chars * $this->gdCharacterWidth((int) $font->filename())\n                );\n                $box->setHeight(\n                    $this->gdCharacterHeight((int) $font->filename())\n                );\n            }\n            return $box;\n        }\n\n        // build full path to font file to make sure to pass absolute path to imageftbbox()\n        // because of issues with different GD version behaving differently when passing\n        // relative paths to imageftbbox()\n        $fontPath = realpath($font->filename());\n        if ($fontPath === false) {\n            throw new FontException('Font file ' . $font->filename() . ' does not exist.');\n        }\n\n        // calculate box size from ttf font file with angle 0\n        $box = imageftbbox(\n            size: $this->nativeFontSize($font),\n            angle: 0,\n            font_filename: $fontPath,\n            string: $text,\n        );\n\n        if ($box === false) {\n            throw new FontException('Unable to calculate box size of font ' . $font->filename() . '.');\n        }\n\n        // build size from points\n        return new Rectangle(\n            width: intval(abs($box[6] - $box[4])), // difference of upper-left-x and upper-right-x\n            height: intval(abs($box[7] - $box[1])), // difference if upper-left-y and lower-left-y\n            pivot: new Point($box[6], $box[7]), // position of upper-left corner\n        );\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see FontProcessorInterface::nativeFontSize()\n     */\n    public function nativeFontSize(FontInterface $font): float\n    {\n        return floatval(round($font->size() * .76, 6));\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see FontProcessorInterface::leading()\n     */\n    public function leading(FontInterface $font): int\n    {\n        return (int) round(parent::leading($font) * .8);\n    }\n\n    /**\n     * Return width of a single character\n     */\n    protected function gdCharacterWidth(int $gdfont): int\n    {\n        return $gdfont + 4;\n    }\n\n    /**\n     * Return height of a single character\n     */\n    protected function gdCharacterHeight(int $gdfont): int\n    {\n        return match ($gdfont) {\n            2, 3 => 14,\n            4, 5 => 16,\n            default => 8,\n        };\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Frame.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd;\n\nuse GdImage;\nuse Intervention\\Image\\Drivers\\AbstractFrame;\nuse Intervention\\Image\\Exceptions\\ColorException;\nuse Intervention\\Image\\Exceptions\\InputException;\nuse Intervention\\Image\\Geometry\\Rectangle;\nuse Intervention\\Image\\Image;\nuse Intervention\\Image\\Interfaces\\DriverInterface;\nuse Intervention\\Image\\Interfaces\\FrameInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SizeInterface;\n\nclass Frame extends AbstractFrame implements FrameInterface\n{\n    /**\n     * Create new frame instance\n     *\n     * @return void\n     */\n    public function __construct(\n        protected GdImage $native,\n        protected float $delay = 0,\n        protected int $dispose = 1,\n        protected int $offset_left = 0,\n        protected int $offset_top = 0\n    ) {\n        //\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see FrameInterface::toImage()\n     */\n    public function toImage(DriverInterface $driver): ImageInterface\n    {\n        return new Image($driver, new Core([$this]));\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see FrameInterface::setNative()\n     */\n    public function setNative(mixed $native): FrameInterface\n    {\n        $this->native = $native;\n\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see FrameInterface::native()\n     */\n    public function native(): GdImage\n    {\n        return $this->native;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see FrameInterface::size()\n     */\n    public function size(): SizeInterface\n    {\n        return new Rectangle(imagesx($this->native), imagesy($this->native));\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see FrameInterface::delay()\n     */\n    public function delay(): float\n    {\n        return $this->delay;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see FrameInterface::setDelay()\n     */\n    public function setDelay(float $delay): FrameInterface\n    {\n        $this->delay = $delay;\n\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see FrameInterface::dispose()\n     */\n    public function dispose(): int\n    {\n        return $this->dispose;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see FrameInterface::setDispose()\n     *\n     * @throws InputException\n     */\n    public function setDispose(int $dispose): FrameInterface\n    {\n        if (!in_array($dispose, [0, 1, 2, 3])) {\n            throw new InputException('Value for argument $dispose must be 0, 1, 2 or 3.');\n        }\n\n        $this->dispose = $dispose;\n\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see FrameInterface::setOffset()\n     */\n    public function setOffset(int $left, int $top): FrameInterface\n    {\n        $this->offset_left = $left;\n        $this->offset_top = $top;\n\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see FrameInterface::offsetLeft()\n     */\n    public function offsetLeft(): int\n    {\n        return $this->offset_left;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see FrameInterface::setOffsetLeft()\n     */\n    public function setOffsetLeft(int $offset): FrameInterface\n    {\n        $this->offset_left = $offset;\n\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see FrameInterface::offsetTop()\n     */\n    public function offsetTop(): int\n    {\n        return $this->offset_top;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see FrameInterface::setOffsetTop()\n     */\n    public function setOffsetTop(int $offset): FrameInterface\n    {\n        $this->offset_top = $offset;\n\n        return $this;\n    }\n\n    /**\n     * This workaround helps cloning GdImages which is currently not possible.\n     *\n     * @throws ColorException\n     */\n    public function __clone(): void\n    {\n        $this->native = Cloner::clone($this->native);\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Modifiers/AlignRotationModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Modifiers;\n\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\AlignRotationModifier as GenericAlignRotationModifier;\n\nclass AlignRotationModifier extends GenericAlignRotationModifier implements SpecializedInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see ModifierInterface::apply()\n     */\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        $image = match ($image->exif('IFD0.Orientation')) {\n            2 => $image->flop(),\n            3 => $image->rotate(180),\n            4 => $image->rotate(180)->flop(),\n            5 => $image->rotate(270)->flop(),\n            6 => $image->rotate(270),\n            7 => $image->rotate(90)->flop(),\n            8 => $image->rotate(90),\n            default => $image\n        };\n\n        return $this->markAligned($image);\n    }\n\n    /**\n     * Set exif data of image to top-left orientation, marking the image as\n     * aligned and making sure the rotation correction process is not\n     * performed again.\n     */\n    private function markAligned(ImageInterface $image): ImageInterface\n    {\n        $exif = $image->exif()->map(function ($item) {\n            if (is_array($item) && array_key_exists('Orientation', $item)) {\n                $item['Orientation'] = 1;\n                return $item;\n            }\n\n            return $item;\n        });\n\n        return $image->setExif($exif);\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Modifiers/BlendTransparencyModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Modifiers;\n\nuse Intervention\\Image\\Drivers\\Gd\\Cloner;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\BlendTransparencyModifier as GenericBlendTransparencyModifier;\n\nclass BlendTransparencyModifier extends GenericBlendTransparencyModifier implements SpecializedInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see ModifierInterface::apply()\n     */\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        $blendingColor = $this->blendingColor($this->driver());\n\n        foreach ($image as $frame) {\n            // create new canvas with blending color as background\n            $modified = Cloner::cloneBlended(\n                $frame->native(),\n                background: $blendingColor\n            );\n\n            // set new gd image\n            $frame->setNative($modified);\n        }\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Modifiers/BlurModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Modifiers;\n\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\BlurModifier as GenericBlurModifier;\n\nclass BlurModifier extends GenericBlurModifier implements SpecializedInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see ModifierInterface::apply()\n     */\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        foreach ($image as $frame) {\n            for ($i = 0; $i < $this->amount; $i++) {\n                imagefilter($frame->native(), IMG_FILTER_GAUSSIAN_BLUR);\n            }\n        }\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Modifiers/BrightnessModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Modifiers;\n\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\BrightnessModifier as GenericBrightnessModifier;\n\nclass BrightnessModifier extends GenericBrightnessModifier implements SpecializedInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see ModifierInterface::apply()\n     */\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        foreach ($image as $frame) {\n            imagefilter($frame->native(), IMG_FILTER_BRIGHTNESS, intval($this->level * 2.55));\n        }\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Modifiers/ColorizeModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Modifiers;\n\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\ColorizeModifier as GenericColorizeModifier;\n\nclass ColorizeModifier extends GenericColorizeModifier implements SpecializedInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see ModifierInterface::apply()\n     */\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        // normalize colorize levels\n        $red = (int) round($this->red * 2.55);\n        $green = (int) round($this->green * 2.55);\n        $blue = (int) round($this->blue * 2.55);\n\n        foreach ($image as $frame) {\n            imagefilter($frame->native(), IMG_FILTER_COLORIZE, $red, $green, $blue);\n        }\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Modifiers/ColorspaceModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Modifiers;\n\nuse Intervention\\Image\\Colors\\Rgb\\Colorspace as RgbColorspace;\nuse Intervention\\Image\\Exceptions\\NotSupportedException;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\ColorspaceModifier as GenericColorspaceModifier;\n\nclass ColorspaceModifier extends GenericColorspaceModifier implements SpecializedInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see ModifierInterface::apply()\n     */\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        if (!($this->targetColorspace() instanceof RgbColorspace)) {\n            throw new NotSupportedException(\n                'Only RGB colorspace is supported by GD driver.'\n            );\n        }\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Modifiers/ContainModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Modifiers;\n\nuse Intervention\\Image\\Colors\\Rgb\\Channels\\Blue;\nuse Intervention\\Image\\Colors\\Rgb\\Channels\\Green;\nuse Intervention\\Image\\Colors\\Rgb\\Channels\\Red;\nuse Intervention\\Image\\Drivers\\Gd\\Cloner;\nuse Intervention\\Image\\Exceptions\\ColorException;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Interfaces\\FrameInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SizeInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\ContainModifier as GenericContainModifier;\n\nclass ContainModifier extends GenericContainModifier implements SpecializedInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see ModifierInterface::apply()\n     */\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        $crop = $this->getCropSize($image);\n        $resize = $this->getResizeSize($image);\n        $background = $this->driver()->handleInput($this->background);\n        $blendingColor = $this->driver()->handleInput(\n            $this->driver()->config()->blendingColor\n        );\n\n        foreach ($image as $frame) {\n            $this->modify($frame, $crop, $resize, $background, $blendingColor);\n        }\n\n        return $image;\n    }\n\n    /**\n     * @throws ColorException\n     */\n    protected function modify(\n        FrameInterface $frame,\n        SizeInterface $crop,\n        SizeInterface $resize,\n        ColorInterface $background,\n        ColorInterface $blendingColor\n    ): void {\n        // create new gd image\n        $modified = Cloner::cloneEmpty($frame->native(), $resize, $background);\n\n        // make image area transparent to keep transparency\n        // even if background-color is set\n        $transparent = imagecolorallocatealpha(\n            $modified,\n            $blendingColor->channel(Red::class)->value(),\n            $blendingColor->channel(Green::class)->value(),\n            $blendingColor->channel(Blue::class)->value(),\n            127,\n        );\n        imagealphablending($modified, false); // do not blend / just overwrite\n        imagecolortransparent($modified, $transparent);\n        imagefilledrectangle(\n            $modified,\n            $crop->pivot()->x(),\n            $crop->pivot()->y(),\n            $crop->pivot()->x() + $crop->width() - 1,\n            $crop->pivot()->y() + $crop->height() - 1,\n            $transparent\n        );\n\n        // copy image from original with blending alpha\n        imagealphablending($modified, true);\n        imagecopyresampled(\n            $modified,\n            $frame->native(),\n            $crop->pivot()->x(),\n            $crop->pivot()->y(),\n            0,\n            0,\n            $crop->width(),\n            $crop->height(),\n            $frame->size()->width(),\n            $frame->size()->height()\n        );\n\n        // set new content as resource\n        $frame->setNative($modified);\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Modifiers/ContrastModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Modifiers;\n\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\ContrastModifier as GenericContrastModifier;\n\nclass ContrastModifier extends GenericContrastModifier implements SpecializedInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see ModifierInterface::apply()\n     */\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        foreach ($image as $frame) {\n            imagefilter($frame->native(), IMG_FILTER_CONTRAST, ($this->level * -1));\n        }\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Modifiers/CoverDownModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Modifiers;\n\nuse Intervention\\Image\\Exceptions\\GeometryException;\nuse Intervention\\Image\\Interfaces\\SizeInterface;\n\nclass CoverDownModifier extends CoverModifier\n{\n    /**\n     * @throws GeometryException\n     */\n    public function getResizeSize(SizeInterface $size): SizeInterface\n    {\n        return $size->resizeDown($this->width, $this->height);\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Modifiers/CoverModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Modifiers;\n\nuse Intervention\\Image\\Drivers\\Gd\\Cloner;\nuse Intervention\\Image\\Exceptions\\ColorException;\nuse Intervention\\Image\\Interfaces\\FrameInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SizeInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\CoverModifier as GenericCoverModifier;\n\nclass CoverModifier extends GenericCoverModifier implements SpecializedInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see ModifierInterface::apply()\n     */\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        $crop = $this->getCropSize($image);\n        $resize = $this->getResizeSize($crop);\n\n        foreach ($image as $frame) {\n            $this->modifyFrame($frame, $crop, $resize);\n        }\n\n        return $image;\n    }\n\n    /**\n     * @throws ColorException\n     */\n    protected function modifyFrame(FrameInterface $frame, SizeInterface $crop, SizeInterface $resize): void\n    {\n        // create new image\n        $modified = Cloner::cloneEmpty($frame->native(), $resize);\n\n        // copy content from resource\n        imagecopyresampled(\n            $modified,\n            $frame->native(),\n            0,\n            0,\n            $crop->pivot()->x(),\n            $crop->pivot()->y(),\n            $resize->width(),\n            $resize->height(),\n            $crop->width(),\n            $crop->height()\n        );\n\n        // set new content as resource\n        $frame->setNative($modified);\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Modifiers/CropModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Modifiers;\n\nuse Intervention\\Image\\Drivers\\Gd\\Cloner;\nuse Intervention\\Image\\Exceptions\\ColorException;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Interfaces\\FrameInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SizeInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\CropModifier as GenericCropModifier;\n\nclass CropModifier extends GenericCropModifier implements SpecializedInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see ModifierInterface::apply()\n     */\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        $originalSize = $image->size();\n        $crop = $this->crop($image);\n        $background = $this->driver()->handleInput($this->background);\n\n        foreach ($image as $frame) {\n            $this->cropFrame($frame, $originalSize, $crop, $background);\n        }\n\n        return $image;\n    }\n\n    /**\n     * @throws ColorException\n     */\n    protected function cropFrame(\n        FrameInterface $frame,\n        SizeInterface $originalSize,\n        SizeInterface $resizeTo,\n        ColorInterface $background\n    ): void {\n        // create new image with transparent background\n        $modified = Cloner::cloneEmpty($frame->native(), $resizeTo, $background);\n\n        // define offset\n        $offset_x = $resizeTo->pivot()->x() + $this->offset_x;\n        $offset_y = $resizeTo->pivot()->y() + $this->offset_y;\n\n        // define target width & height\n        $targetWidth = min($resizeTo->width(), $originalSize->width());\n        $targetHeight = min($resizeTo->height(), $originalSize->height());\n        $targetWidth = $targetWidth < $originalSize->width() ? $targetWidth + $offset_x : $targetWidth;\n        $targetHeight = $targetHeight < $originalSize->height() ? $targetHeight + $offset_y : $targetHeight;\n\n        // don't alpha blend for copy operation to keep transparent areas of original image\n        imagealphablending($modified, false);\n\n        // copy content from resource\n        imagecopyresampled(\n            $modified,\n            $frame->native(),\n            $offset_x * -1,\n            $offset_y * -1,\n            0,\n            0,\n            $targetWidth,\n            $targetHeight,\n            $targetWidth,\n            $targetHeight\n        );\n\n        // set new content as resource\n        $frame->setNative($modified);\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Modifiers/DrawBezierModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Modifiers;\n\nuse RuntimeException;\nuse Intervention\\Image\\Exceptions\\GeometryException;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\DrawBezierModifier as GenericDrawBezierModifier;\n\nclass DrawBezierModifier extends GenericDrawBezierModifier implements SpecializedInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see ModifierInterface::apply()\n     *\n     * @throws RuntimeException\n     * @throws GeometryException\n     */\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        foreach ($image as $frame) {\n            if ($this->drawable->count() !== 3 && $this->drawable->count() !== 4) {\n                throw new GeometryException('You must specify either 3 or 4 points to create a bezier curve');\n            }\n\n            [$polygon, $polygon_border_segments] = $this->calculateBezierPoints();\n\n            if ($this->drawable->hasBackgroundColor() || $this->drawable->hasBorder()) {\n                imagealphablending($frame->native(), true);\n                imageantialias($frame->native(), true);\n            }\n\n            if ($this->drawable->hasBackgroundColor()) {\n                $background_color = $this->driver()->colorProcessor($image->colorspace())->colorToNative(\n                    $this->backgroundColor()\n                );\n\n                imagesetthickness($frame->native(), 0);\n                imagefilledpolygon(\n                    $frame->native(),\n                    $polygon,\n                    $background_color\n                );\n            }\n\n            if ($this->drawable->hasBorder() && $this->drawable->borderSize() > 0) {\n                $border_color = $this->driver()->colorProcessor($image->colorspace())->colorToNative(\n                    $this->borderColor()\n                );\n\n                if ($this->drawable->borderSize() === 1) {\n                    imagesetthickness($frame->native(), $this->drawable->borderSize());\n\n                    $count = count($polygon);\n                    for ($i = 0; $i < $count; $i += 2) {\n                        if (array_key_exists($i + 2, $polygon) && array_key_exists($i + 3, $polygon)) {\n                            imageline(\n                                $frame->native(),\n                                $polygon[$i],\n                                $polygon[$i + 1],\n                                $polygon[$i + 2],\n                                $polygon[$i + 3],\n                                $border_color\n                            );\n                        }\n                    }\n                } else {\n                    $polygon_border_segments_total = count($polygon_border_segments);\n\n                    for ($i = 0; $i < $polygon_border_segments_total; $i += 1) {\n                        imagefilledpolygon(\n                            $frame->native(),\n                            $polygon_border_segments[$i],\n                            $border_color\n                        );\n                    }\n                }\n            }\n        }\n\n        return $image;\n    }\n\n    /**\n     * Calculate interpolation points for quadratic beziers using the Bernstein polynomial form\n     *\n     * @return array{'x': float, 'y': float}\n     */\n    private function calculateQuadraticBezierInterpolationPoint(float $t = 0.05): array\n    {\n        $remainder = 1 - $t;\n        $control_point_1_multiplier = $remainder * $remainder;\n        $control_point_2_multiplier = $remainder * $t * 2;\n        $control_point_3_multiplier = $t * $t;\n\n        $x = (\n            $this->drawable->first()->x() * $control_point_1_multiplier +\n            $this->drawable->second()->x() * $control_point_2_multiplier +\n            $this->drawable->last()->x() * $control_point_3_multiplier\n        );\n        $y = (\n            $this->drawable->first()->y() * $control_point_1_multiplier +\n            $this->drawable->second()->y() * $control_point_2_multiplier +\n            $this->drawable->last()->y() * $control_point_3_multiplier\n        );\n\n        return ['x' => $x, 'y' => $y];\n    }\n\n    /**\n     * Calculate interpolation points for cubic beziers using the Bernstein polynomial form\n     *\n     * @return array{'x': float, 'y': float}\n     */\n    private function calculateCubicBezierInterpolationPoint(float $t = 0.05): array\n    {\n        $remainder = 1 - $t;\n        $t_squared = $t * $t;\n        $remainder_squared = $remainder * $remainder;\n        $control_point_1_multiplier = $remainder_squared * $remainder;\n        $control_point_2_multiplier = $remainder_squared * $t * 3;\n        $control_point_3_multiplier = $t_squared * $remainder * 3;\n        $control_point_4_multiplier = $t_squared * $t;\n\n        $x = (\n            $this->drawable->first()->x() * $control_point_1_multiplier +\n            $this->drawable->second()->x() * $control_point_2_multiplier +\n            $this->drawable->third()->x() * $control_point_3_multiplier +\n            $this->drawable->last()->x() * $control_point_4_multiplier\n        );\n        $y = (\n            $this->drawable->first()->y() * $control_point_1_multiplier +\n            $this->drawable->second()->y() * $control_point_2_multiplier +\n            $this->drawable->third()->y() * $control_point_3_multiplier +\n            $this->drawable->last()->y() * $control_point_4_multiplier\n        );\n\n        return ['x' => $x, 'y' => $y];\n    }\n\n    /**\n     * Calculate the points needed to draw a quadratic or cubic bezier with optional border/stroke\n     *\n     * @throws GeometryException\n     * @return array{0: array<mixed>, 1: array<mixed>}\n     */\n    private function calculateBezierPoints(): array\n    {\n        if ($this->drawable->count() !== 3 && $this->drawable->count() !== 4) {\n            throw new GeometryException('You must specify either 3 or 4 points to create a bezier curve');\n        }\n\n        $polygon = [];\n        $inner_polygon = [];\n        $outer_polygon = [];\n        $polygon_border_segments = [];\n\n        // define ratio t; equivalent to 5 percent distance along edge\n        $t = 0.05;\n\n        $polygon[] = $this->drawable->first()->x();\n        $polygon[] = $this->drawable->first()->y();\n        for ($i = $t; $i < 1; $i += $t) {\n            if ($this->drawable->count() === 3) {\n                $ip = $this->calculateQuadraticBezierInterpolationPoint($i);\n            } elseif ($this->drawable->count() === 4) {\n                $ip = $this->calculateCubicBezierInterpolationPoint($i);\n            }\n            $polygon[] = (int) $ip['x'];\n            $polygon[] = (int) $ip['y'];\n        }\n        $polygon[] = $this->drawable->last()->x();\n        $polygon[] = $this->drawable->last()->y();\n\n        if ($this->drawable->hasBorder() && $this->drawable->borderSize() > 1) {\n            // create the border/stroke effect by calculating two new curves with offset positions\n            // from the main polygon and then connecting the inner/outer curves to create separate\n            // 4-point polygon segments\n            $polygon_total_points = count($polygon);\n            $offset = ($this->drawable->borderSize() / 2);\n\n            for ($i = 0; $i < $polygon_total_points; $i += 2) {\n                if (array_key_exists($i + 2, $polygon) && array_key_exists($i + 3, $polygon)) {\n                    $dx = $polygon[$i + 2] - $polygon[$i];\n                    $dy = $polygon[$i + 3] - $polygon[$i + 1];\n                    $dxy_sqrt = ($dx * $dx + $dy * $dy) ** 0.5;\n\n                    // inner polygon\n                    $scale = $offset / $dxy_sqrt;\n                    $ox = -$dy * $scale;\n                    $oy = $dx * $scale;\n\n                    $inner_polygon[] = $ox + $polygon[$i];\n                    $inner_polygon[] = $oy + $polygon[$i + 1];\n                    $inner_polygon[] = $ox + $polygon[$i + 2];\n                    $inner_polygon[] = $oy + $polygon[$i + 3];\n\n                    // outer polygon\n                    $scale = -$offset / $dxy_sqrt;\n                    $ox = -$dy * $scale;\n                    $oy = $dx * $scale;\n\n                    $outer_polygon[] = $ox + $polygon[$i];\n                    $outer_polygon[] = $oy + $polygon[$i + 1];\n                    $outer_polygon[] = $ox + $polygon[$i + 2];\n                    $outer_polygon[] = $oy + $polygon[$i + 3];\n                }\n            }\n\n            $inner_polygon_total_points = count($inner_polygon);\n\n            for ($i = 0; $i < $inner_polygon_total_points; $i += 2) {\n                if (array_key_exists($i + 2, $inner_polygon) && array_key_exists($i + 3, $inner_polygon)) {\n                    $polygon_border_segments[] = [\n                        $inner_polygon[$i],\n                        $inner_polygon[$i + 1],\n                        $outer_polygon[$i],\n                        $outer_polygon[$i + 1],\n                        $outer_polygon[$i + 2],\n                        $outer_polygon[$i + 3],\n                        $inner_polygon[$i + 2],\n                        $inner_polygon[$i + 3],\n                    ];\n                }\n            }\n        }\n\n        return [$polygon, $polygon_border_segments];\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Modifiers/DrawEllipseModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Modifiers;\n\nuse RuntimeException;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\DrawEllipseModifier as GenericDrawEllipseModifier;\n\nclass DrawEllipseModifier extends GenericDrawEllipseModifier implements SpecializedInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see ModifierInterface::apply()\n     *\n     * @throws RuntimeException\n     */\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        foreach ($image as $frame) {\n            if ($this->drawable->hasBorder()) {\n                imagealphablending($frame->native(), true);\n\n                // slightly smaller ellipse to keep 1px bordered edges clean\n                if ($this->drawable->hasBackgroundColor()) {\n                    imagefilledellipse(\n                        $frame->native(),\n                        $this->drawable()->position()->x(),\n                        $this->drawable->position()->y(),\n                        $this->drawable->width() - 1,\n                        $this->drawable->height() - 1,\n                        $this->driver()->colorProcessor($image->colorspace())->colorToNative(\n                            $this->backgroundColor()\n                        )\n                    );\n                }\n\n                // gd's imageellipse ignores imagesetthickness\n                // so i use imagearc with 360 degrees instead.\n                imagesetthickness(\n                    $frame->native(),\n                    $this->drawable->borderSize(),\n                );\n\n                imagearc(\n                    $frame->native(),\n                    $this->drawable()->position()->x(),\n                    $this->drawable()->position()->y(),\n                    $this->drawable->width(),\n                    $this->drawable->height(),\n                    0,\n                    360,\n                    $this->driver()->colorProcessor($image->colorspace())->colorToNative(\n                        $this->borderColor()\n                    )\n                );\n            } else {\n                imagealphablending($frame->native(), true);\n                imagesetthickness($frame->native(), 0);\n                imagefilledellipse(\n                    $frame->native(),\n                    $this->drawable()->position()->x(),\n                    $this->drawable()->position()->y(),\n                    $this->drawable->width(),\n                    $this->drawable->height(),\n                    $this->driver()->colorProcessor($image->colorspace())->colorToNative(\n                        $this->backgroundColor()\n                    )\n                );\n            }\n        }\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Modifiers/DrawLineModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Modifiers;\n\nuse RuntimeException;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\DrawLineModifier as GenericDrawLineModifier;\n\nclass DrawLineModifier extends GenericDrawLineModifier implements SpecializedInterface\n{\n    /**\n     * @throws RuntimeException\n     */\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        $color = $this->driver()->colorProcessor($image->colorspace())->colorToNative(\n            $this->backgroundColor()\n        );\n\n        foreach ($image as $frame) {\n            imagealphablending($frame->native(), true);\n            imageantialias($frame->native(), true);\n            imagesetthickness($frame->native(), $this->drawable->width());\n            imageline(\n                $frame->native(),\n                $this->drawable->start()->x(),\n                $this->drawable->start()->y(),\n                $this->drawable->end()->x(),\n                $this->drawable->end()->y(),\n                $color\n            );\n        }\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Modifiers/DrawPixelModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Modifiers;\n\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\DrawPixelModifier as GenericDrawPixelModifier;\n\nclass DrawPixelModifier extends GenericDrawPixelModifier implements SpecializedInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see ModifierInterface::apply()\n     */\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        $color = $this->driver()->colorProcessor($image->colorspace())->colorToNative(\n            $this->driver()->handleInput($this->color)\n        );\n\n        foreach ($image as $frame) {\n            imagealphablending($frame->native(), true);\n            imagesetpixel(\n                $frame->native(),\n                $this->position->x(),\n                $this->position->y(),\n                $color\n            );\n        }\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Modifiers/DrawPolygonModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Modifiers;\n\nuse RuntimeException;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\DrawPolygonModifier as ModifiersDrawPolygonModifier;\n\nclass DrawPolygonModifier extends ModifiersDrawPolygonModifier implements SpecializedInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see ModifierInterface::apply()\n     *\n     * @throws RuntimeException\n     */\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        foreach ($image as $frame) {\n            if ($this->drawable->hasBackgroundColor()) {\n                imagealphablending($frame->native(), true);\n                imagesetthickness($frame->native(), 0);\n                imagefilledpolygon(\n                    $frame->native(),\n                    $this->drawable->toArray(),\n                    $this->driver()->colorProcessor($image->colorspace())->colorToNative(\n                        $this->backgroundColor()\n                    )\n                );\n            }\n\n            if ($this->drawable->hasBorder()) {\n                imagealphablending($frame->native(), true);\n                imagesetthickness($frame->native(), $this->drawable->borderSize());\n                imagepolygon(\n                    $frame->native(),\n                    $this->drawable->toArray(),\n                    $this->driver()->colorProcessor($image->colorspace())->colorToNative(\n                        $this->borderColor()\n                    )\n                );\n            }\n        }\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Modifiers/DrawRectangleModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Modifiers;\n\nuse RuntimeException;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\DrawRectangleModifier as GenericDrawRectangleModifier;\n\nclass DrawRectangleModifier extends GenericDrawRectangleModifier implements SpecializedInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see ModifierInterface::apply()\n     *\n     * @throws RuntimeException\n     */\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        $position = $this->drawable->position();\n\n        foreach ($image as $frame) {\n            // draw background\n            if ($this->drawable->hasBackgroundColor()) {\n                imagealphablending($frame->native(), true);\n                imagesetthickness($frame->native(), 0);\n                imagefilledrectangle(\n                    $frame->native(),\n                    $position->x(),\n                    $position->y(),\n                    $position->x() + $this->drawable->width(),\n                    $position->y() + $this->drawable->height(),\n                    $this->driver()->colorProcessor($image->colorspace())->colorToNative(\n                        $this->backgroundColor()\n                    )\n                );\n            }\n\n            // draw border\n            if ($this->drawable->hasBorder()) {\n                imagealphablending($frame->native(), true);\n                imagesetthickness($frame->native(), $this->drawable->borderSize());\n                imagerectangle(\n                    $frame->native(),\n                    $position->x(),\n                    $position->y(),\n                    $position->x() + $this->drawable->width(),\n                    $position->y() + $this->drawable->height(),\n                    $this->driver()->colorProcessor($image->colorspace())->colorToNative(\n                        $this->borderColor()\n                    )\n                );\n            }\n        }\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Modifiers/FillModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Modifiers;\n\nuse Intervention\\Image\\Exceptions\\RuntimeException;\nuse Intervention\\Image\\Interfaces\\FrameInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\FillModifier as GenericFillModifier;\n\nclass FillModifier extends GenericFillModifier implements SpecializedInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see ModifierInterface::apply()\n     */\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        $color = $this->color($image);\n\n        foreach ($image as $frame) {\n            if ($this->hasPosition()) {\n                $this->floodFillWithColor($frame, $color);\n            } else {\n                $this->fillAllWithColor($frame, $color);\n            }\n        }\n\n        return $image;\n    }\n\n    /**\n     * @throws RuntimeException\n     */\n    private function color(ImageInterface $image): int\n    {\n        return $this->driver()->colorProcessor($image->colorspace())->colorToNative(\n            $this->driver()->handleInput($this->color)\n        );\n    }\n\n    private function floodFillWithColor(FrameInterface $frame, int $color): void\n    {\n        imagefill(\n            $frame->native(),\n            $this->position->x(),\n            $this->position->y(),\n            $color\n        );\n    }\n\n    private function fillAllWithColor(FrameInterface $frame, int $color): void\n    {\n        imagealphablending($frame->native(), true);\n        imagefilledrectangle(\n            $frame->native(),\n            0,\n            0,\n            $frame->size()->width() - 1,\n            $frame->size()->height() - 1,\n            $color\n        );\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Modifiers/FlipModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Modifiers;\n\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\FlipModifier as GenericFlipModifier;\n\nclass FlipModifier extends GenericFlipModifier implements SpecializedInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see ModifierInterface::apply()\n     */\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        foreach ($image as $frame) {\n            imageflip($frame->native(), IMG_FLIP_VERTICAL);\n        }\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Modifiers/FlopModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Modifiers;\n\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\FlopModifier as GenericFlopModifier;\n\nclass FlopModifier extends GenericFlopModifier implements SpecializedInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see ModifierInterface::apply()\n     */\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        foreach ($image as $frame) {\n            imageflip($frame->native(), IMG_FLIP_HORIZONTAL);\n        }\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Modifiers/GammaModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Modifiers;\n\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\GammaModifier as GenericGammaModifier;\n\nclass GammaModifier extends GenericGammaModifier implements SpecializedInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see ModifierInterface::apply()\n     */\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        foreach ($image as $frame) {\n            imagegammacorrect($frame->native(), 1, $this->gamma);\n        }\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Modifiers/GreyscaleModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Modifiers;\n\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\GreyscaleModifier as GenericGreyscaleModifier;\n\nclass GreyscaleModifier extends GenericGreyscaleModifier implements SpecializedInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see ModifierInterface::apply()\n     */\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        foreach ($image as $frame) {\n            imagefilter($frame->native(), IMG_FILTER_GRAYSCALE);\n        }\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Modifiers/InvertModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Modifiers;\n\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\InvertModifier as GenericInvertModifier;\n\nclass InvertModifier extends GenericInvertModifier implements SpecializedInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see ModifierInterface::apply()\n     */\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        foreach ($image as $frame) {\n            imagefilter($frame->native(), IMG_FILTER_NEGATE);\n        }\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Modifiers/PadModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Modifiers;\n\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SizeInterface;\n\nclass PadModifier extends ContainModifier\n{\n    public function getCropSize(ImageInterface $image): SizeInterface\n    {\n        return $image->size()\n            ->containMax(\n                $this->width,\n                $this->height\n            )\n            ->alignPivotTo(\n                $this->getResizeSize($image),\n                $this->position\n            );\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Modifiers/PixelateModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Modifiers;\n\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\PixelateModifier as GenericPixelateModifier;\n\nclass PixelateModifier extends GenericPixelateModifier implements SpecializedInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see ModifierInterface::apply()\n     */\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        foreach ($image as $frame) {\n            imagefilter($frame->native(), IMG_FILTER_PIXELATE, $this->size, true);\n        }\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Modifiers/PlaceModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Modifiers;\n\nuse Intervention\\Image\\Exceptions\\RuntimeException;\nuse Intervention\\Image\\Interfaces\\FrameInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\PointInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\PlaceModifier as GenericPlaceModifier;\n\nclass PlaceModifier extends GenericPlaceModifier implements SpecializedInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see ModifierInterface::apply()\n     */\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        $watermark = $this->driver()->handleInput($this->element);\n        $position = $this->getPosition($image, $watermark);\n\n        foreach ($image as $frame) {\n            imagealphablending($frame->native(), true);\n\n            if ($this->opacity === 100) {\n                $this->placeOpaque($frame, $watermark, $position);\n            } else {\n                $this->placeTransparent($frame, $watermark, $position);\n            }\n        }\n\n        return $image;\n    }\n\n    /**\n     * Insert watermark with 100% opacity\n     *\n     * @throws RuntimeException\n     */\n    private function placeOpaque(FrameInterface $frame, ImageInterface $watermark, PointInterface $position): void\n    {\n        imagecopy(\n            $frame->native(),\n            $watermark->core()->native(),\n            $position->x(),\n            $position->y(),\n            0,\n            0,\n            $watermark->width(),\n            $watermark->height()\n        );\n    }\n\n    /**\n     * Insert watermark transparent with current opacity\n     *\n     * Unfortunately, the original PHP function imagecopymerge does not work reliably.\n     * For example, any transparency of the image to be inserted is not applied correctly.\n     * For this reason, a new GDImage is created into which the original image is inserted\n     * in the first step and the watermark is inserted with 100% opacity in the second\n     * step. This combination is then transferred to the original image again with the\n     * respective opacity.\n     *\n     * Please note: Unfortunately, there is still an edge case, when a transparent image\n     * is placed on a transparent background, the \"double\" transparent areas appear opaque!\n     *\n     * @throws RuntimeException\n     */\n    private function placeTransparent(FrameInterface $frame, ImageInterface $watermark, PointInterface $position): void\n    {\n        $cut = imagecreatetruecolor($watermark->width(), $watermark->height());\n\n        imagecopy(\n            $cut,\n            $frame->native(),\n            0,\n            0,\n            $position->x(),\n            $position->y(),\n            imagesx($cut),\n            imagesy($cut)\n        );\n\n        imagecopy(\n            $cut,\n            $watermark->core()->native(),\n            0,\n            0,\n            0,\n            0,\n            imagesx($cut),\n            imagesy($cut)\n        );\n\n        imagecopymerge(\n            $frame->native(),\n            $cut,\n            $position->x(),\n            $position->y(),\n            0,\n            0,\n            $watermark->width(),\n            $watermark->height(),\n            $this->opacity\n        );\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Modifiers/ProfileModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Modifiers;\n\nuse Intervention\\Image\\Exceptions\\NotSupportedException;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\ProfileModifier as GenericProfileModifier;\n\nclass ProfileModifier extends GenericProfileModifier implements SpecializedInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see ModifierInterface::apply()\n     */\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        throw new NotSupportedException(\n            'Color profiles are not supported by GD driver.'\n        );\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Modifiers/ProfileRemovalModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Modifiers;\n\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\ProfileRemovalModifier as GenericProfileRemovalModifier;\n\nclass ProfileRemovalModifier extends GenericProfileRemovalModifier implements SpecializedInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see ModifierInterface::apply()\n     */\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        // Color profiles are not supported by GD, so the decoded\n        // image is already free of profiles anyway.\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Modifiers/QuantizeColorsModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Modifiers;\n\nuse Intervention\\Image\\Drivers\\Gd\\Cloner;\nuse Intervention\\Image\\Exceptions\\InputException;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\QuantizeColorsModifier as GenericQuantizeColorsModifier;\n\nclass QuantizeColorsModifier extends GenericQuantizeColorsModifier implements SpecializedInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see ModifierInterface::apply()\n     */\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        if ($this->limit <= 0) {\n            throw new InputException('Quantization limit must be greater than 0.');\n        }\n\n        // no color reduction if the limit is higher than the colors in the img\n        $colorCount = imagecolorstotal($image->core()->native());\n        if ($colorCount > 0 && $this->limit > $colorCount) {\n            return $image;\n        }\n\n        $width = $image->width();\n        $height = $image->height();\n\n        $background = $this->driver()->colorProcessor($image->colorspace())->colorToNative(\n            $this->driver()->handleInput($this->background)\n        );\n\n        $blendingColor = $this->driver()->handleInput(\n            $this->driver()->config()->blendingColor\n        );\n\n        foreach ($image as $frame) {\n            // create new image for color quantization\n            $reduced = Cloner::cloneEmpty($frame->native(), background: $blendingColor);\n\n            // fill with background\n            imagefill($reduced, 0, 0, $background);\n\n            // set transparency\n            imagecolortransparent($reduced, $background);\n\n            // copy original image (colors are limited automatically in the copy process)\n            imagecopy($reduced, $frame->native(), 0, 0, 0, 0, $width, $height);\n\n            // gd library does not support color quantization directly therefore the\n            // colors are decrease by transforming the image to a palette version\n            imagetruecolortopalette($reduced, true, $this->limit);\n\n            $frame->setNative($reduced);\n        }\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Modifiers/RemoveAnimationModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Modifiers;\n\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\RemoveAnimationModifier as GenericRemoveAnimationModifier;\n\nclass RemoveAnimationModifier extends GenericRemoveAnimationModifier implements SpecializedInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see ModifierInterface::apply()\n     */\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        $image->core()->setNative(\n            $this->selectedFrame($image)->native()\n        );\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Modifiers/ResizeCanvasModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Modifiers;\n\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\ResizeCanvasModifier as GenericResizeCanvasModifier;\n\nclass ResizeCanvasModifier extends GenericResizeCanvasModifier implements SpecializedInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see ModifierInterface::apply()\n     */\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        $cropSize = $this->cropSize($image);\n\n        $image->modify(new CropModifier(\n            $cropSize->width(),\n            $cropSize->height(),\n            $cropSize->pivot()->x(),\n            $cropSize->pivot()->y(),\n            $this->background,\n        ));\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Modifiers/ResizeCanvasRelativeModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Modifiers;\n\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SizeInterface;\n\nclass ResizeCanvasRelativeModifier extends ResizeCanvasModifier\n{\n    protected function cropSize(ImageInterface $image, bool $relative = false): SizeInterface\n    {\n        return parent::cropSize($image, true);\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Modifiers/ResizeDownModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Modifiers;\n\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SizeInterface;\n\nclass ResizeDownModifier extends ResizeModifier\n{\n    protected function getAdjustedSize(ImageInterface $image): SizeInterface\n    {\n        return $image->size()->resizeDown($this->width, $this->height);\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Modifiers/ResizeModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Modifiers;\n\nuse Intervention\\Image\\Drivers\\Gd\\Cloner;\nuse Intervention\\Image\\Exceptions\\ColorException;\nuse Intervention\\Image\\Exceptions\\GeometryException;\nuse Intervention\\Image\\Exceptions\\RuntimeException;\nuse Intervention\\Image\\Interfaces\\FrameInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SizeInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\ResizeModifier as GenericResizeModifier;\n\nclass ResizeModifier extends GenericResizeModifier implements SpecializedInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see ModifierInterface::apply()\n     */\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        $resizeTo = $this->getAdjustedSize($image);\n        foreach ($image as $frame) {\n            $this->resizeFrame($frame, $resizeTo);\n        }\n\n        return $image;\n    }\n\n    /**\n     * @throws ColorException\n     */\n    private function resizeFrame(FrameInterface $frame, SizeInterface $resizeTo): void\n    {\n        // create empty canvas in target size\n        $modified = Cloner::cloneEmpty($frame->native(), $resizeTo);\n\n        // copy content from resource\n        imagecopyresampled(\n            $modified,\n            $frame->native(),\n            $resizeTo->pivot()->x(),\n            $resizeTo->pivot()->y(),\n            0,\n            0,\n            $resizeTo->width(),\n            $resizeTo->height(),\n            $frame->size()->width(),\n            $frame->size()->height()\n        );\n\n        // set new content as resource\n        $frame->setNative($modified);\n    }\n\n    /**\n     * Return the size the modifier will resize to\n     *\n     * @throws RuntimeException\n     * @throws GeometryException\n     */\n    protected function getAdjustedSize(ImageInterface $image): SizeInterface\n    {\n        return $image->size()->resize($this->width, $this->height);\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Modifiers/ResolutionModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Modifiers;\n\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\ResolutionModifier as GenericResolutionModifier;\n\nclass ResolutionModifier extends GenericResolutionModifier implements SpecializedInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see ModifierInterface::apply()\n     */\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        $x = intval(round($this->x));\n        $y = intval(round($this->y));\n\n        foreach ($image as $frame) {\n            imageresolution($frame->native(), $x, $y);\n        }\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Modifiers/RotateModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Modifiers;\n\nuse Intervention\\Image\\Colors\\Rgb\\Channels\\Blue;\nuse Intervention\\Image\\Colors\\Rgb\\Channels\\Green;\nuse Intervention\\Image\\Colors\\Rgb\\Channels\\Red;\nuse Intervention\\Image\\Drivers\\Gd\\Cloner;\nuse Intervention\\Image\\Exceptions\\ColorException;\nuse Intervention\\Image\\Geometry\\Rectangle;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Interfaces\\FrameInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\RotateModifier as GenericRotateModifier;\n\nclass RotateModifier extends GenericRotateModifier implements SpecializedInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see ModifierInterface::apply()\n     */\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        $background = $this->driver()->handleInput($this->background);\n\n        foreach ($image as $frame) {\n            $this->modifyFrame($frame, $background);\n        }\n\n        return $image;\n    }\n\n    /**\n     * Apply rotation modification on given frame, given background\n     * color is used for newly create image areas\n     *\n     * @throws ColorException\n     */\n    protected function modifyFrame(FrameInterface $frame, ColorInterface $background): void\n    {\n        // get transparent color from frame core\n        $transparent = match ($transparent = imagecolortransparent($frame->native())) {\n            -1 => imagecolorallocatealpha(\n                $frame->native(),\n                $background->channel(Red::class)->value(),\n                $background->channel(Green::class)->value(),\n                $background->channel(Blue::class)->value(),\n                127\n            ),\n            default => $transparent,\n        };\n\n        // rotate original image against transparent background\n        $rotated = imagerotate(\n            $frame->native(),\n            $this->rotationAngle(),\n            $transparent\n        );\n\n        // create size from original after rotation\n        $container = (new Rectangle(\n            imagesx($rotated),\n            imagesy($rotated),\n        ))->movePivot('center');\n\n        // create size from original and rotate points\n        $cutout = (new Rectangle(\n            imagesx($frame->native()),\n            imagesy($frame->native()),\n            $container->pivot()\n        ))->align('center')\n            ->valign('center')\n            ->rotate($this->rotationAngle() * -1);\n\n        // create new gd image\n        $modified = Cloner::cloneEmpty($frame->native(), $container, $background);\n\n        // draw the cutout on new gd image to have a transparent\n        // background where the rotated image will be placed\n        imagealphablending($modified, false);\n        imagefilledpolygon(\n            $modified,\n            $cutout->toArray(),\n            imagecolortransparent($modified)\n        );\n\n        // place rotated image on new gd image\n        imagealphablending($modified, true);\n        imagecopy(\n            $modified,\n            $rotated,\n            0,\n            0,\n            0,\n            0,\n            imagesx($rotated),\n            imagesy($rotated)\n        );\n\n        $frame->setNative($modified);\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Modifiers/ScaleDownModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Modifiers;\n\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SizeInterface;\n\nclass ScaleDownModifier extends ResizeModifier\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see ResizeModifier::getAdjustedSize()\n     */\n    protected function getAdjustedSize(ImageInterface $image): SizeInterface\n    {\n        return $image->size()->scaleDown($this->width, $this->height);\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Modifiers/ScaleModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Modifiers;\n\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SizeInterface;\n\nclass ScaleModifier extends ResizeModifier\n{\n    protected function getAdjustedSize(ImageInterface $image): SizeInterface\n    {\n        return $image->size()->scale($this->width, $this->height);\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Modifiers/SharpenModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Modifiers;\n\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\SharpenModifier as GenericSharpenModifier;\n\nclass SharpenModifier extends GenericSharpenModifier implements SpecializedInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see ModifierInterface::apply()\n     */\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        $matrix = $this->matrix();\n        foreach ($image as $frame) {\n            imageconvolution($frame->native(), $matrix, 1, 0);\n        }\n\n        return $image;\n    }\n\n    /**\n     * Create matrix to be used by imageconvolution()\n     *\n     * @return array<array<float>>\n     */\n    private function matrix(): array\n    {\n        $min = $this->amount >= 10 ? $this->amount * -0.01 : 0;\n        $max = $this->amount * -0.025;\n        $abs = ((4 * $min + 4 * $max) * -1) + 1;\n\n        return [\n            [$min, $max, $min],\n            [$max, $abs, $max],\n            [$min, $max, $min]\n        ];\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Modifiers/SliceAnimationModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Modifiers;\n\nuse Intervention\\Image\\Exceptions\\AnimationException;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\SliceAnimationModifier as GenericSliceAnimationModifier;\n\nclass SliceAnimationModifier extends GenericSliceAnimationModifier implements SpecializedInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see ModifierInterface::apply()\n     */\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        if ($this->offset >= $image->count()) {\n            throw new AnimationException('Offset is not in the range of frames.');\n        }\n\n        $image->core()->slice($this->offset, $this->length);\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Modifiers/TextModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Modifiers;\n\nuse Intervention\\Image\\Exceptions\\ColorException;\nuse Intervention\\Image\\Exceptions\\FontException;\nuse Intervention\\Image\\Exceptions\\RuntimeException;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\TextModifier as GenericTextModifier;\n\nclass TextModifier extends GenericTextModifier implements SpecializedInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see ModifierInterface::apply()\n     */\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        $fontProcessor = $this->driver()->fontProcessor();\n        $lines = $fontProcessor->textBlock($this->text, $this->font, $this->position);\n\n        // decode text colors\n        $textColor = $this->gdTextColor($image);\n        $strokeColor = $this->gdStrokeColor($image);\n\n        // build full path to font file to make sure to pass absolute path to imageftbbox()\n        // because of issues with different GD version behaving differently when passing\n        // relative paths to imagettftext()\n        $fontPath = $this->font->hasFilename() ? realpath($this->font->filename()) : false;\n        if ($this->font->hasFilename() && $fontPath === false) {\n            throw new FontException('Font file ' . $this->font->filename() . ' does not exist.');\n        }\n\n        foreach ($image as $frame) {\n            imagealphablending($frame->native(), true);\n            if ($this->font->hasFilename()) {\n                foreach ($lines as $line) {\n                    foreach ($this->strokeOffsets($this->font) as $offset) {\n                        imagettftext(\n                            image: $frame->native(),\n                            size: $fontProcessor->nativeFontSize($this->font),\n                            angle: $this->font->angle() * -1,\n                            x: $line->position()->x() + $offset->x(),\n                            y: $line->position()->y() + $offset->y(),\n                            color: $strokeColor,\n                            font_filename: $fontPath,\n                            text: (string) $line\n                        );\n                    }\n\n                    imagettftext(\n                        image: $frame->native(),\n                        size: $fontProcessor->nativeFontSize($this->font),\n                        angle: $this->font->angle() * -1,\n                        x: $line->position()->x(),\n                        y: $line->position()->y(),\n                        color: $textColor,\n                        font_filename: $fontPath,\n                        text: (string) $line\n                    );\n                }\n            } else {\n                foreach ($lines as $line) {\n                    foreach ($this->strokeOffsets($this->font) as $offset) {\n                        imagestring(\n                            $frame->native(),\n                            $this->gdFont(),\n                            $line->position()->x() + $offset->x(),\n                            $line->position()->y() + $offset->y(),\n                            (string) $line,\n                            $strokeColor\n                        );\n                    }\n\n                    imagestring(\n                        $frame->native(),\n                        $this->gdFont(),\n                        $line->position()->x(),\n                        $line->position()->y(),\n                        (string) $line,\n                        $textColor\n                    );\n                }\n            }\n        }\n\n        return $image;\n    }\n\n    /**\n     * Decode text color in GD compatible format\n     *\n     * @throws RuntimeException\n     * @throws ColorException\n     */\n    protected function gdTextColor(ImageInterface $image): int\n    {\n        return $this\n            ->driver()\n            ->colorProcessor($image->colorspace())\n            ->colorToNative(parent::textColor());\n    }\n\n    /**\n     * Decode color for stroke (outline) effect in GD compatible format\n     *\n     * @throws RuntimeException\n     * @throws ColorException\n     */\n    protected function gdStrokeColor(ImageInterface $image): int\n    {\n        if (!$this->font->hasStrokeEffect()) {\n            return 0;\n        }\n\n        $color = parent::strokeColor();\n\n        if ($color->isTransparent()) {\n            throw new ColorException(\n                'The stroke color must be fully opaque.'\n            );\n        }\n\n        return $this\n            ->driver()\n            ->colorProcessor($image->colorspace())\n            ->colorToNative($color);\n    }\n\n    /**\n     * Return GD's internal font size (if no ttf file is set)\n     */\n    private function gdFont(): int\n    {\n        if (is_numeric($this->font->filename())) {\n            return intval($this->font->filename());\n        }\n\n        return 1;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Gd/Modifiers/TrimModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Gd\\Modifiers;\n\nuse Intervention\\Image\\Exceptions\\AnimationException;\nuse Intervention\\Image\\Exceptions\\NotSupportedException;\nuse Intervention\\Image\\Exceptions\\RuntimeException;\nuse Intervention\\Image\\Geometry\\Point;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\TrimModifier as GenericTrimModifier;\n\nclass TrimModifier extends GenericTrimModifier implements SpecializedInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see ModifierInterface::apply()\n     */\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        if ($image->isAnimated()) {\n            throw new NotSupportedException('Trim modifier cannot be applied to animated images.');\n        }\n\n        // apply tolerance with a min. value of .5 because the default tolerance of '0' should\n        // already trim away similar colors which is not the case with imagecropauto.\n        $trimmed = imagecropauto(\n            $image->core()->native(),\n            IMG_CROP_THRESHOLD,\n            max([.5, $this->tolerance / 10]),\n            $this->trimColor($image)\n        );\n\n        // if the tolerance is very high, it is possible that no image is left.\n        // imagick returns a 1x1 pixel image in this case. this does the same.\n        if ($trimmed === false) {\n            $trimmed = $this->driver()->createImage(1, 1)->core()->native();\n        }\n\n        $image->core()->setNative($trimmed);\n\n        return $image;\n    }\n\n    /**\n     * Create an average color from the colors of the four corner points of the given image\n     *\n     * @throws RuntimeException\n     * @throws AnimationException\n     */\n    private function trimColor(ImageInterface $image): int\n    {\n        // trim color base\n        $red = 0;\n        $green = 0;\n        $blue = 0;\n\n        // corner coordinates\n        $size = $image->size();\n        $cornerPoints = [\n            new Point(0, 0),\n            new Point($size->width() - 1, 0),\n            new Point(0, $size->height() - 1),\n            new Point($size->width() - 1, $size->height() - 1),\n        ];\n\n        // create an average color to be used in trim operation\n        foreach ($cornerPoints as $pos) {\n            $cornerColor = imagecolorat($image->core()->native(), $pos->x(), $pos->y());\n            $rgb = imagecolorsforindex($image->core()->native(), $cornerColor);\n            $red += round(round(($rgb['red'] / 51)) * 51);\n            $green += round(round(($rgb['green'] / 51)) * 51);\n            $blue += round(round(($rgb['blue'] / 51)) * 51);\n        }\n\n        $red = (int) round($red / 4);\n        $green = (int) round($green / 4);\n        $blue = (int) round($blue / 4);\n\n        return imagecolorallocate($image->core()->native(), $red, $green, $blue);\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Analyzers/ColorspaceAnalyzer.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Analyzers;\n\nuse Imagick;\nuse Intervention\\Image\\Analyzers\\ColorspaceAnalyzer as GenericColorspaceAnalyzer;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Colors\\Cmyk\\Colorspace as CmykColorspace;\nuse Intervention\\Image\\Colors\\Rgb\\Colorspace as RgbColorspace;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\n\nclass ColorspaceAnalyzer extends GenericColorspaceAnalyzer implements SpecializedInterface\n{\n    public function analyze(ImageInterface $image): mixed\n    {\n        return match ($image->core()->native()->getImageColorspace()) {\n            Imagick::COLORSPACE_CMYK => new CmykColorspace(),\n            default => new RgbColorspace(),\n        };\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Analyzers/HeightAnalyzer.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Analyzers;\n\nuse Intervention\\Image\\Analyzers\\HeightAnalyzer as GenericHeightAnalyzer;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\n\nclass HeightAnalyzer extends GenericHeightAnalyzer implements SpecializedInterface\n{\n    public function analyze(ImageInterface $image): mixed\n    {\n        return $image->core()->native()->getImageHeight();\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Analyzers/PixelColorAnalyzer.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Analyzers;\n\nuse Imagick;\nuse Intervention\\Image\\Analyzers\\PixelColorAnalyzer as GenericPixelColorAnalyzer;\nuse Intervention\\Image\\Exceptions\\ColorException;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Interfaces\\ColorspaceInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\n\nclass PixelColorAnalyzer extends GenericPixelColorAnalyzer implements SpecializedInterface\n{\n    public function analyze(ImageInterface $image): mixed\n    {\n        return $this->colorAt(\n            $image->colorspace(),\n            $image->core()->frame($this->frame_key)->native()\n        );\n    }\n\n    /**\n     * @throws ColorException\n     */\n    protected function colorAt(ColorspaceInterface $colorspace, Imagick $imagick): ColorInterface\n    {\n        return $this->driver()\n            ->colorProcessor($colorspace)\n            ->nativeToColor(\n                $imagick->getImagePixelColor($this->x, $this->y)\n            );\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Analyzers/PixelColorsAnalyzer.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Analyzers;\n\nuse Intervention\\Image\\Collection;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\n\nclass PixelColorsAnalyzer extends PixelColorAnalyzer\n{\n    public function analyze(ImageInterface $image): mixed\n    {\n        $colors = new Collection();\n        $colorspace = $image->colorspace();\n\n        foreach ($image as $frame) {\n            $colors->push(\n                parent::colorAt($colorspace, $frame->native())\n            );\n        }\n\n        return $colors;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Analyzers/ProfileAnalyzer.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Analyzers;\n\nuse Intervention\\Image\\Analyzers\\ProfileAnalyzer as GenericProfileAnalyzer;\nuse Intervention\\Image\\Colors\\Profile;\nuse Intervention\\Image\\Exceptions\\ColorException;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\n\nclass ProfileAnalyzer extends GenericProfileAnalyzer implements SpecializedInterface\n{\n    public function analyze(ImageInterface $image): mixed\n    {\n        $profiles = $image->core()->native()->getImageProfiles('icc');\n\n        if (!array_key_exists('icc', $profiles)) {\n            throw new ColorException('No ICC profile found in image.');\n        }\n\n        return new Profile($profiles['icc']);\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Analyzers/ResolutionAnalyzer.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Analyzers;\n\nuse Intervention\\Image\\Analyzers\\ResolutionAnalyzer as GenericResolutionAnalyzer;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Resolution;\n\nclass ResolutionAnalyzer extends GenericResolutionAnalyzer implements SpecializedInterface\n{\n    public function analyze(ImageInterface $image): mixed\n    {\n        $imagick = $image->core()->native();\n        $imageResolution = $imagick->getImageResolution();\n\n        return new Resolution(\n            $imageResolution['x'],\n            $imageResolution['y'],\n            $imagick->getImageUnits(),\n        );\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Analyzers/WidthAnalyzer.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Analyzers;\n\nuse Intervention\\Image\\Analyzers\\WidthAnalyzer as GenericWidthAnalyzer;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\n\nclass WidthAnalyzer extends GenericWidthAnalyzer implements SpecializedInterface\n{\n    public function analyze(ImageInterface $image): mixed\n    {\n        return $image->core()->native()->getImageWidth();\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/ColorProcessor.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick;\n\nuse Imagick;\nuse ImagickPixel;\nuse Intervention\\Image\\Colors\\Cmyk\\Colorspace as CmykColorspace;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Interfaces\\ColorProcessorInterface;\nuse Intervention\\Image\\Interfaces\\ColorspaceInterface;\n\nclass ColorProcessor implements ColorProcessorInterface\n{\n    public function __construct(protected ColorspaceInterface $colorspace)\n    {\n        //\n    }\n\n    public function colorToNative(ColorInterface $color): ImagickPixel\n    {\n        return new ImagickPixel(\n            (string) $color->convertTo($this->colorspace)\n        );\n    }\n\n    public function nativeToColor(mixed $native): ColorInterface\n    {\n        return match ($this->colorspace::class) {\n            CmykColorspace::class => $this->colorspace->colorFromNormalized([\n                $native->getColorValue(Imagick::COLOR_CYAN),\n                $native->getColorValue(Imagick::COLOR_MAGENTA),\n                $native->getColorValue(Imagick::COLOR_YELLOW),\n                $native->getColorValue(Imagick::COLOR_BLACK),\n            ]),\n            default => $this->colorspace->colorFromNormalized([\n                $native->getColorValue(Imagick::COLOR_RED),\n                $native->getColorValue(Imagick::COLOR_GREEN),\n                $native->getColorValue(Imagick::COLOR_BLUE),\n                $native->getColorValue(Imagick::COLOR_ALPHA),\n            ]),\n        };\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Core.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick;\n\nuse Imagick;\nuse ImagickException;\nuse Iterator;\nuse Intervention\\Image\\Interfaces\\CoreInterface;\nuse Intervention\\Image\\Exceptions\\AnimationException;\nuse Intervention\\Image\\Interfaces\\CollectionInterface;\nuse Intervention\\Image\\Interfaces\\FrameInterface;\n\n/**\n * @implements Iterator<FrameInterface>\n */\nclass Core implements CoreInterface, Iterator\n{\n    protected int $iteratorIndex = 0;\n\n    /**\n     * Create new core instance\n     *\n     * @return void\n     */\n    public function __construct(protected Imagick $imagick)\n    {\n        //\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see CollectionInterface::has()\n     */\n    public function has(int|string $key): bool\n    {\n        try {\n            $result = $this->imagick->setIteratorIndex($key);\n        } catch (ImagickException) {\n            return false;\n        }\n\n        return $result;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see CollectionInterface::push()\n     */\n    public function push(mixed $item): CollectionInterface\n    {\n        return $this->add($item);\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see CollectionInterface::get()\n     */\n    public function get(int|string $key, mixed $default = null): mixed\n    {\n        try {\n            $this->imagick->setIteratorIndex($key);\n        } catch (ImagickException) {\n            return $default;\n        }\n\n        return new Frame($this->imagick->current());\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see CollectionInterface::getAtPosition()\n     */\n    public function getAtPosition(int $key = 0, mixed $default = null): mixed\n    {\n        return $this->get($key, $default);\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see CollectionInterface::empty()\n     */\n    public function empty(): CollectionInterface\n    {\n        $this->imagick->clear();\n\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see CollectionInterface::slice()\n     */\n    public function slice(int $offset, ?int $length = null): CollectionInterface\n    {\n        $allowed_indexes = [];\n        $length = is_null($length) ? $this->count() : $length;\n        for ($i = $offset; $i < $offset + $length; $i++) {\n            $allowed_indexes[] = $i;\n        }\n\n        $sliced = new Imagick();\n        foreach ($this->imagick as $key => $native) {\n            if (in_array($key, $allowed_indexes)) {\n                $sliced->addImage($native->getImage());\n            }\n        }\n\n        $sliced = $sliced->coalesceImages();\n        $sliced->setImageIterations($this->imagick->getImageIterations());\n\n        $this->imagick = $sliced;\n\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see CoreInterface::add()\n     */\n    public function add(FrameInterface $frame): CoreInterface\n    {\n        $imagick = $frame->native();\n\n        $imagick->setImageDelay(\n            (int) round($frame->delay() * 100)\n        );\n\n        $imagick->setImageDispose($frame->dispose());\n\n        $size = $frame->size();\n        $imagick->setImagePage(\n            $size->width(),\n            $size->height(),\n            $frame->offsetLeft(),\n            $frame->offsetTop()\n        );\n\n        $this->imagick->addImage($imagick);\n\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see CoreInterface::count()\n     */\n    public function count(): int\n    {\n        return $this->imagick->getNumberImages();\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see Iterator::rewind()\n     */\n    public function current(): mixed\n    {\n        $this->imagick->setIteratorIndex($this->iteratorIndex);\n\n        return new Frame($this->imagick->current());\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see Iterator::rewind()\n     */\n    public function next(): void\n    {\n        $this->iteratorIndex += 1;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see Iterator::rewind()\n     */\n    public function key(): mixed\n    {\n        return $this->iteratorIndex;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see Iterator::rewind()\n     */\n    public function valid(): bool\n    {\n        try {\n            $result = $this->imagick->setIteratorIndex($this->iteratorIndex);\n        } catch (ImagickException) {\n            return false;\n        }\n\n        return $result;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see Iterator::rewind()\n     */\n    public function rewind(): void\n    {\n        $this->iteratorIndex = 0;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see CoreInterface::native()\n     */\n    public function native(): mixed\n    {\n        return $this->imagick;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see CoreInterface::setNative()\n     */\n    public function setNative(mixed $native): CoreInterface\n    {\n        $this->imagick = $native;\n\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see CoreInterface::frame()\n     */\n    public function frame(int $position): FrameInterface\n    {\n        foreach ($this->imagick as $core) {\n            if ($core->getIteratorIndex() === $position) {\n                return new Frame($core);\n            }\n        }\n\n        throw new AnimationException('Frame #' . $position . ' could not be found in the image.');\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see CoreInterface::loops()\n     */\n    public function loops(): int\n    {\n        return $this->imagick->getImageIterations();\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see CoreInterface::setLoops()\n     */\n    public function setLoops(int $loops): CoreInterface\n    {\n        $this->imagick = $this->imagick->coalesceImages();\n        $this->imagick->setImageIterations($loops);\n\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see CollectionInterface::first()\n     */\n    public function first(): FrameInterface\n    {\n        return $this->frame(0);\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see CollectableInterface::last()\n     */\n    public function last(): FrameInterface\n    {\n        return $this->frame($this->count() - 1);\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see CollectionInterface::toArray()\n     */\n    public function toArray(): array\n    {\n        $frames = [];\n\n        foreach ($this as $frame) {\n            $frames[] = $frame;\n        }\n\n        return $frames;\n    }\n\n    /**\n     * Clone instance\n     */\n    public function __clone(): void\n    {\n        $this->imagick = clone $this->imagick;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Decoders/Base64ImageDecoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Decoders;\n\nuse Intervention\\Image\\Exceptions\\DecoderException;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\n\nclass Base64ImageDecoder extends BinaryImageDecoder\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see DecoderInterface::decode()\n     */\n    public function decode(mixed $input): ImageInterface|ColorInterface\n    {\n        if (!$this->isValidBase64($input)) {\n            throw new DecoderException('Unable to decode input');\n        }\n\n        return parent::decode(base64_decode((string) $input));\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Decoders/BinaryImageDecoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Decoders;\n\nuse Imagick;\nuse ImagickException;\nuse Intervention\\Image\\Exceptions\\DecoderException;\nuse Intervention\\Image\\Format;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\n\nclass BinaryImageDecoder extends NativeObjectDecoder\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see DecoderInterface::decode()\n     */\n    public function decode(mixed $input): ImageInterface|ColorInterface\n    {\n        if (!is_string($input)) {\n            throw new DecoderException('Unable to decode input');\n        }\n\n        try {\n            $imagick = new Imagick();\n            $imagick->readImageBlob($input);\n        } catch (ImagickException) {\n            throw new DecoderException('Unable to decode input');\n        }\n\n        // decode image\n        $image = parent::decode($imagick);\n\n        // get media type enum from string media type\n        $format = Format::tryCreate($image->origin()->mediaType());\n\n        // extract exif data for appropriate formats\n        if (in_array($format, [Format::JPEG, Format::TIFF])) {\n            $image->setExif($this->extractExifData($input));\n        }\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Decoders/DataUriImageDecoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Decoders;\n\nuse Intervention\\Image\\Exceptions\\DecoderException;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\n\nclass DataUriImageDecoder extends BinaryImageDecoder\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see DecoderInterface::decode()\n     */\n    public function decode(mixed $input): ImageInterface|ColorInterface\n    {\n        if (!is_string($input)) {\n            throw new DecoderException('Unable to decode input');\n        }\n\n        $uri = $this->parseDataUri($input);\n\n        if (!$uri->isValid()) {\n            throw new DecoderException('Unable to decode input');\n        }\n\n        if ($uri->isBase64Encoded()) {\n            return parent::decode(base64_decode($uri->data()));\n        }\n\n        return parent::decode(urldecode($uri->data()));\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Decoders/EncodedImageObjectDecoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Decoders;\n\nuse Intervention\\Image\\EncodedImage;\nuse Intervention\\Image\\Exceptions\\DecoderException;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\n\nclass EncodedImageObjectDecoder extends BinaryImageDecoder\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see DecoderInterface::decode()\n     */\n    public function decode(mixed $input): ImageInterface|ColorInterface\n    {\n        if (!is_a($input, EncodedImage::class)) {\n            throw new DecoderException('Unable to decode input');\n        }\n\n        return parent::decode($input->toString());\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Decoders/FilePathImageDecoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Decoders;\n\nuse Imagick;\nuse ImagickException;\nuse Intervention\\Image\\Exceptions\\DecoderException;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\n\nclass FilePathImageDecoder extends NativeObjectDecoder\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see DecoderInterface::decode()\n     */\n    public function decode(mixed $input): ImageInterface|ColorInterface\n    {\n        if (!$this->isFile($input)) {\n            throw new DecoderException('Unable to decode input');\n        }\n\n        try {\n            $imagick = new Imagick();\n            $imagick->readImage($input);\n        } catch (ImagickException) {\n            throw new DecoderException('Unable to decode input');\n        }\n\n        // decode image\n        $image = parent::decode($imagick);\n\n        // set file path on origin\n        $image->origin()->setFilePath($input);\n\n        // extract exif data for the appropriate formats\n        if (in_array($imagick->getImageFormat(), ['JPEG', 'TIFF', 'TIF'])) {\n            $image->setExif($this->extractExifData($input));\n        }\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Decoders/FilePointerImageDecoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Decoders;\n\nuse Intervention\\Image\\Exceptions\\DecoderException;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\n\nclass FilePointerImageDecoder extends BinaryImageDecoder\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see DecoderInterface::decode()\n     */\n    public function decode(mixed $input): ImageInterface|ColorInterface\n    {\n        if (!is_resource($input) || !in_array(get_resource_type($input), ['file', 'stream'])) {\n            throw new DecoderException('Unable to decode input');\n        }\n\n        $contents = '';\n        @rewind($input);\n        while (!feof($input)) {\n            $contents .= fread($input, 1024);\n        }\n\n        return parent::decode($contents);\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Decoders/NativeObjectDecoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Decoders;\n\nuse Imagick;\nuse Intervention\\Image\\Drivers\\Imagick\\Core;\nuse Intervention\\Image\\Drivers\\SpecializableDecoder;\nuse Intervention\\Image\\Exceptions\\DecoderException;\nuse Intervention\\Image\\Image;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\AlignRotationModifier;\nuse Intervention\\Image\\Modifiers\\RemoveAnimationModifier;\n\nclass NativeObjectDecoder extends SpecializableDecoder implements SpecializedInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see DecoderInterface::decode()\n     */\n    public function decode(mixed $input): ImageInterface|ColorInterface\n    {\n        if (!is_object($input)) {\n            throw new DecoderException('Unable to decode input');\n        }\n\n        if (!($input instanceof Imagick)) {\n            throw new DecoderException('Unable to decode input');\n        }\n\n        // For some JPEG formats, the \"coalesceImages()\" call leads to an image\n        // completely filled with background color. The logic behind this is\n        // incomprehensible for me; could be an imagick bug.\n        if ($input->getImageFormat() !== 'JPEG') {\n            $input = $input->coalesceImages();\n        }\n\n        // turn images with colorspace 'GRAY' into 'SRGB' to avoid working on\n        // greyscale colorspace images as this results images loosing color\n        // information when placed into this image.\n        if ($input->getImageColorspace() == Imagick::COLORSPACE_GRAY) {\n            $input->setImageColorspace(Imagick::COLORSPACE_SRGB);\n        }\n\n        // create image object\n        $image = new Image(\n            $this->driver(),\n            new Core($input)\n        );\n\n        // discard animation depending on config\n        if (!$this->driver()->config()->decodeAnimation) {\n            $image->modify(new RemoveAnimationModifier());\n        }\n\n        // adjust image rotatation\n        if ($this->driver()->config()->autoOrientation) {\n            $image->modify(new AlignRotationModifier());\n        }\n\n        // set media type on origin\n        $image->origin()->setMediaType($input->getImageMimeType());\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Decoders/SplFileInfoImageDecoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Decoders;\n\nuse SplFileInfo;\nuse Intervention\\Image\\Exceptions\\DecoderException;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\n\nclass SplFileInfoImageDecoder extends FilePathImageDecoder\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see DecoderInterface::decode()\n     */\n    public function decode(mixed $input): ImageInterface|ColorInterface\n    {\n        if (!is_a($input, SplFileInfo::class)) {\n            throw new DecoderException('Unable to decode input');\n        }\n\n        return parent::decode($input->getRealPath());\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Driver.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick;\n\nuse Imagick;\nuse ImagickPixel;\nuse Intervention\\Image\\Drivers\\AbstractDriver;\nuse Intervention\\Image\\Exceptions\\DriverException;\nuse Intervention\\Image\\Exceptions\\NotSupportedException;\nuse Intervention\\Image\\Exceptions\\RuntimeException;\nuse Intervention\\Image\\Format;\nuse Intervention\\Image\\FileExtension;\nuse Intervention\\Image\\Image;\nuse Intervention\\Image\\Interfaces\\ColorProcessorInterface;\nuse Intervention\\Image\\Interfaces\\ColorspaceInterface;\nuse Intervention\\Image\\Interfaces\\DriverInterface;\nuse Intervention\\Image\\Interfaces\\FontProcessorInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\MediaType;\n\nclass Driver extends AbstractDriver\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see DriverInterface::id()\n     */\n    public function id(): string\n    {\n        return 'Imagick';\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DriverInterface::checkHealth()\n     *\n     * @codeCoverageIgnore\n     */\n    public function checkHealth(): void\n    {\n        if (!extension_loaded('imagick') || !class_exists('Imagick')) {\n            throw new DriverException(\n                'Imagick PHP extension must be installed to use this driver.'\n            );\n        }\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DriverInterface::createImage()\n     */\n    public function createImage(int $width, int $height): ImageInterface\n    {\n        $background = new ImagickPixel('rgba(255, 255, 255, 0)');\n\n        $imagick = new Imagick();\n        $imagick->newImage($width, $height, $background, 'png');\n        $imagick->setType(Imagick::IMGTYPE_UNDEFINED);\n        $imagick->setImageType(Imagick::IMGTYPE_UNDEFINED);\n        $imagick->setColorspace(Imagick::COLORSPACE_SRGB);\n        $imagick->setImageResolution(96, 96);\n        $imagick->setImageBackgroundColor($background);\n\n        return new Image($this, new Core($imagick));\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DriverInterface::createAnimation()\n     *\n     * @throws RuntimeException\n     */\n    public function createAnimation(callable $init): ImageInterface\n    {\n        $imagick = new Imagick();\n        $imagick->setFormat('gif');\n\n        $animation = new class ($this, $imagick)\n        {\n            public function __construct(\n                protected DriverInterface $driver,\n                public Imagick $imagick\n            ) {\n                //\n            }\n\n            /**\n             * @throws RuntimeException\n             */\n            public function add(mixed $source, float $delay = 1): self\n            {\n                $native = $this->driver->handleInput($source)->core()->native();\n                $native->setImageDelay(intval(round($delay * 100)));\n\n                $this->imagick->addImage($native);\n\n                return $this;\n            }\n\n            /**\n             * @throws RuntimeException\n             */\n            public function __invoke(): ImageInterface\n            {\n                return new Image(\n                    $this->driver,\n                    new Core($this->imagick)\n                );\n            }\n        };\n\n        $init($animation);\n\n        return call_user_func($animation);\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DriverInterface::colorProcessor()\n     */\n    public function colorProcessor(ColorspaceInterface $colorspace): ColorProcessorInterface\n    {\n        return new ColorProcessor($colorspace);\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DriverInterface::fontProcessor()\n     */\n    public function fontProcessor(): FontProcessorInterface\n    {\n        return new FontProcessor();\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DriverInterface::supports()\n     */\n    public function supports(string|Format|FileExtension|MediaType $identifier): bool\n    {\n        try {\n            $format = Format::create($identifier);\n        } catch (NotSupportedException) {\n            return false;\n        }\n\n        return count(Imagick::queryFormats($format->name)) >= 1;\n    }\n\n    /**\n     * Return version of ImageMagick library\n     *\n     * @throws DriverException\n     */\n    public static function version(): string\n    {\n        $pattern = '/^ImageMagick (?P<version>(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)' .\n            '(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?' .\n            '(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?)/';\n\n        if (preg_match($pattern, Imagick::getVersion()['versionString'], $matches) !== 1) {\n            throw new DriverException('Unable to read ImageMagick version number.');\n        }\n\n        return $matches['version'];\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Encoders/AvifEncoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Encoders;\n\nuse Imagick;\nuse Intervention\\Image\\Drivers\\Imagick\\Modifiers\\StripMetaModifier;\nuse Intervention\\Image\\EncodedImage;\nuse Intervention\\Image\\Encoders\\AvifEncoder as GenericAvifEncoder;\nuse Intervention\\Image\\Interfaces\\EncodedImageInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\n\nclass AvifEncoder extends GenericAvifEncoder implements SpecializedInterface\n{\n    public function encode(ImageInterface $image): EncodedImageInterface\n    {\n        $format = 'AVIF';\n        $compression = Imagick::COMPRESSION_ZIP;\n\n        // strip meta data\n        if ($this->strip || (is_null($this->strip) && $this->driver()->config()->strip)) {\n            $image->modify(new StripMetaModifier());\n        }\n\n        $imagick = $image->core()->native();\n        $imagick->setFormat($format);\n        $imagick->setImageFormat($format);\n        $imagick->setCompression($compression);\n        $imagick->setImageCompression($compression);\n        $imagick->setCompressionQuality($this->quality);\n        $imagick->setImageCompressionQuality($this->quality);\n\n        return new EncodedImage($imagick->getImagesBlob(), 'image/avif');\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Encoders/BmpEncoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Encoders;\n\nuse Imagick;\nuse Intervention\\Image\\EncodedImage;\nuse Intervention\\Image\\Encoders\\BmpEncoder as GenericBmpEncoder;\nuse Intervention\\Image\\Interfaces\\EncodedImageInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\n\nclass BmpEncoder extends GenericBmpEncoder implements SpecializedInterface\n{\n    public function encode(ImageInterface $image): EncodedImageInterface\n    {\n        $format = 'BMP';\n        $compression = Imagick::COMPRESSION_NO;\n\n        $imagick = $image->core()->native();\n        $imagick->setFormat($format);\n        $imagick->setImageFormat($format);\n        $imagick->setCompression($compression);\n        $imagick->setImageCompression($compression);\n\n        return new EncodedImage($imagick->getImagesBlob(), 'image/bmp');\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Encoders/GifEncoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Encoders;\n\nuse Imagick;\nuse Intervention\\Image\\EncodedImage;\nuse Intervention\\Image\\Encoders\\GifEncoder as GenericGifEncoder;\nuse Intervention\\Image\\Interfaces\\EncodedImageInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\n\nclass GifEncoder extends GenericGifEncoder implements SpecializedInterface\n{\n    public function encode(ImageInterface $image): EncodedImageInterface\n    {\n        $format = 'GIF';\n        $compression = Imagick::COMPRESSION_LZW;\n\n        $imagick = $image->core()->native();\n\n        $imagick->setFormat($format);\n        $imagick->setImageFormat($format);\n        $imagick->setCompression($compression);\n        $imagick->setImageCompression($compression);\n\n        if ($this->interlaced) {\n            $imagick->setInterlaceScheme(Imagick::INTERLACE_LINE);\n        }\n\n        return new EncodedImage($imagick->getImagesBlob(), 'image/gif');\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Encoders/HeicEncoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Encoders;\n\nuse Intervention\\Image\\Drivers\\Imagick\\Modifiers\\StripMetaModifier;\nuse Intervention\\Image\\EncodedImage;\nuse Intervention\\Image\\Encoders\\HeicEncoder as GenericHeicEncoder;\nuse Intervention\\Image\\Interfaces\\EncodedImageInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\n\nclass HeicEncoder extends GenericHeicEncoder implements SpecializedInterface\n{\n    public function encode(ImageInterface $image): EncodedImageInterface\n    {\n        $format = 'HEIC';\n\n        // strip meta data\n        if ($this->strip || (is_null($this->strip) && $this->driver()->config()->strip)) {\n            $image->modify(new StripMetaModifier());\n        }\n\n        $imagick = $image->core()->native();\n        $imagick->setFormat($format);\n        $imagick->setImageFormat($format);\n        $imagick->setCompressionQuality($this->quality);\n        $imagick->setImageCompressionQuality($this->quality);\n\n        return new EncodedImage($imagick->getImagesBlob(), 'image/heic');\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Encoders/Jpeg2000Encoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Encoders;\n\nuse Imagick;\nuse Intervention\\Image\\Drivers\\Imagick\\Modifiers\\StripMetaModifier;\nuse Intervention\\Image\\EncodedImage;\nuse Intervention\\Image\\Encoders\\Jpeg2000Encoder as GenericJpeg2000Encoder;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\EncodedImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\n\nclass Jpeg2000Encoder extends GenericJpeg2000Encoder implements SpecializedInterface\n{\n    public function encode(ImageInterface $image): EncodedImageInterface\n    {\n        $format = 'JP2';\n        $compression = Imagick::COMPRESSION_JPEG;\n\n        // strip meta data\n        if ($this->strip || (is_null($this->strip) && $this->driver()->config()->strip)) {\n            $image->modify(new StripMetaModifier());\n        }\n\n        $imagick = $image->core()->native();\n        $imagick->setImageBackgroundColor('white');\n        $imagick->setBackgroundColor('white');\n        $imagick->setFormat($format);\n        $imagick->setImageFormat($format);\n        $imagick->setCompression($compression);\n        $imagick->setImageCompression($compression);\n        $imagick->setCompressionQuality($this->quality);\n        $imagick->setImageCompressionQuality($this->quality);\n\n        return new EncodedImage($imagick->getImagesBlob(), 'image/jp2');\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Encoders/JpegEncoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Encoders;\n\nuse Imagick;\nuse Intervention\\Image\\Drivers\\Imagick\\Modifiers\\StripMetaModifier;\nuse Intervention\\Image\\EncodedImage;\nuse Intervention\\Image\\Encoders\\JpegEncoder as GenericJpegEncoder;\nuse Intervention\\Image\\Interfaces\\EncodedImageInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\n\nclass JpegEncoder extends GenericJpegEncoder implements SpecializedInterface\n{\n    public function encode(ImageInterface $image): EncodedImageInterface\n    {\n        $format = 'JPEG';\n        $compression = Imagick::COMPRESSION_JPEG;\n        $blendingColor = $this->driver()->handleInput(\n            $this->driver()->config()->blendingColor\n        );\n\n        // resolve blending color because jpeg has no transparency\n        $background = $this->driver()\n            ->colorProcessor($image->colorspace())\n            ->colorToNative($blendingColor);\n\n        // set alpha value to 1 because Imagick renders\n        // possible full transparent colors as black\n        $background->setColorValue(Imagick::COLOR_ALPHA, 1);\n\n        // strip meta data\n        if ($this->strip || (is_null($this->strip) && $this->driver()->config()->strip)) {\n            $image->modify(new StripMetaModifier());\n        }\n\n        /** @var Imagick $imagick */\n        $imagick = $image->core()->native();\n        $imagick->setImageBackgroundColor($background);\n        $imagick->setBackgroundColor($background);\n        $imagick->setFormat($format);\n        $imagick->setImageFormat($format);\n        $imagick->setCompression($compression);\n        $imagick->setImageCompression($compression);\n        $imagick->setCompressionQuality($this->quality);\n        $imagick->setImageCompressionQuality($this->quality);\n        $imagick->setImageAlphaChannel(Imagick::ALPHACHANNEL_REMOVE);\n\n        if ($this->progressive) {\n            $imagick->setInterlaceScheme(Imagick::INTERLACE_PLANE);\n        }\n\n        return new EncodedImage($imagick->getImagesBlob(), 'image/jpeg');\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Encoders/PngEncoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Encoders;\n\nuse Imagick;\nuse Intervention\\Image\\EncodedImage;\nuse Intervention\\Image\\Encoders\\PngEncoder as GenericPngEncoder;\nuse Intervention\\Image\\Interfaces\\EncodedImageInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\n\nclass PngEncoder extends GenericPngEncoder implements SpecializedInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see EncoderInterface::encode()\n     */\n    public function encode(ImageInterface $image): EncodedImageInterface\n    {\n        if ($this->indexed) {\n            // reduce colors\n            $output = clone $image;\n            $output->reduceColors(256);\n\n            $output = $output->core()->native();\n            $output->setFormat('PNG');\n            $output->setImageFormat('PNG');\n        } else {\n            $output = clone $image->core()->native();\n            $output->setFormat('PNG32');\n            $output->setImageFormat('PNG32');\n        }\n\n        $output->setCompression(Imagick::COMPRESSION_ZIP);\n        $output->setImageCompression(Imagick::COMPRESSION_ZIP);\n\n        if ($this->interlaced) {\n            $output->setInterlaceScheme(Imagick::INTERLACE_LINE);\n        }\n\n        return new EncodedImage($output->getImagesBlob(), 'image/png');\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Encoders/TiffEncoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Encoders;\n\nuse Intervention\\Image\\Drivers\\Imagick\\Modifiers\\StripMetaModifier;\nuse Intervention\\Image\\EncodedImage;\nuse Intervention\\Image\\Encoders\\TiffEncoder as GenericTiffEncoder;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\EncodedImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\n\nclass TiffEncoder extends GenericTiffEncoder implements SpecializedInterface\n{\n    public function encode(ImageInterface $image): EncodedImageInterface\n    {\n        $format = 'TIFF';\n\n        // strip meta data\n        if ($this->strip || (is_null($this->strip) && $this->driver()->config()->strip)) {\n            $image->modify(new StripMetaModifier());\n        }\n\n        $imagick = $image->core()->native();\n        $imagick->setFormat($format);\n        $imagick->setImageFormat($format);\n        $imagick->setCompression($imagick->getImageCompression());\n        $imagick->setImageCompression($imagick->getImageCompression());\n        $imagick->setCompressionQuality($this->quality);\n        $imagick->setImageCompressionQuality($this->quality);\n\n        return new EncodedImage($imagick->getImagesBlob(), 'image/tiff');\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Encoders/WebpEncoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Encoders;\n\nuse Imagick;\nuse ImagickPixel;\nuse Intervention\\Image\\Drivers\\Imagick\\Modifiers\\StripMetaModifier;\nuse Intervention\\Image\\EncodedImage;\nuse Intervention\\Image\\Encoders\\WebpEncoder as GenericWebpEncoder;\nuse Intervention\\Image\\Interfaces\\EncodedImageInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\n\nclass WebpEncoder extends GenericWebpEncoder implements SpecializedInterface\n{\n    public function encode(ImageInterface $image): EncodedImageInterface\n    {\n        $format = 'WEBP';\n        $compression = Imagick::COMPRESSION_ZIP;\n\n        // strip meta data\n        if ($this->strip || (is_null($this->strip) && $this->driver()->config()->strip)) {\n            $image->modify(new StripMetaModifier());\n        }\n\n        $imagick = $image->core()->native();\n        $imagick->setImageBackgroundColor(new ImagickPixel('transparent'));\n\n        if (!$image->isAnimated()) {\n            $imagick = $imagick->mergeImageLayers(Imagick::LAYERMETHOD_MERGE);\n        }\n\n        $imagick->setFormat($format);\n        $imagick->setImageFormat($format);\n        $imagick->setCompression($compression);\n        $imagick->setImageCompression($compression);\n        $imagick->setImageCompressionQuality($this->quality);\n\n        if ($this->quality === 100) {\n            $imagick->setOption('webp:lossless', 'true');\n        }\n\n        return new EncodedImage($imagick->getImagesBlob(), 'image/webp');\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/FontProcessor.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick;\n\nuse Imagick;\nuse ImagickDraw;\nuse ImagickDrawException;\nuse ImagickException;\nuse ImagickPixel;\nuse Intervention\\Image\\Drivers\\AbstractFontProcessor;\nuse Intervention\\Image\\Exceptions\\FontException;\nuse Intervention\\Image\\Geometry\\Rectangle;\nuse Intervention\\Image\\Interfaces\\FontInterface;\nuse Intervention\\Image\\Interfaces\\SizeInterface;\n\nclass FontProcessor extends AbstractFontProcessor\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see FontProcessorInterface::boxSize()\n     */\n    public function boxSize(string $text, FontInterface $font): SizeInterface\n    {\n        // no text - no box size\n        if (mb_strlen($text) === 0) {\n            return new Rectangle(0, 0);\n        }\n\n        $draw = $this->toImagickDraw($font);\n        $dimensions = (new Imagick())->queryFontMetrics($draw, $text);\n\n        return new Rectangle(\n            intval(round($dimensions['textWidth'])),\n            intval(round($dimensions['ascender'] + $dimensions['descender'])),\n        );\n    }\n\n    /**\n     * Imagick::annotateImage() needs an ImagickDraw object - this method takes\n     * the font object as the base and adds an optional passed color to the new\n     * ImagickDraw object.\n     *\n     * @throws FontException\n     * @throws ImagickDrawException\n     * @throws ImagickException\n     */\n    public function toImagickDraw(FontInterface $font, ?ImagickPixel $color = null): ImagickDraw\n    {\n        if (!$font->hasFilename()) {\n            throw new FontException('No font file specified.');\n        }\n\n        $draw = new ImagickDraw();\n        $draw->setStrokeAntialias(true);\n        $draw->setTextAntialias(true);\n        $draw->setFont($font->filename());\n        $draw->setFontSize($this->nativeFontSize($font));\n        $draw->setTextAlignment(Imagick::ALIGN_LEFT);\n\n        if ($color instanceof ImagickPixel) {\n            $draw->setFillColor($color);\n        }\n\n        return $draw;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Frame.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick;\n\nuse Imagick;\nuse ImagickException;\nuse ImagickPixel;\nuse Intervention\\Image\\Drivers\\AbstractFrame;\nuse Intervention\\Image\\Exceptions\\InputException;\nuse Intervention\\Image\\Geometry\\Rectangle;\nuse Intervention\\Image\\Image;\nuse Intervention\\Image\\Interfaces\\DriverInterface;\nuse Intervention\\Image\\Interfaces\\FrameInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SizeInterface;\n\nclass Frame extends AbstractFrame implements FrameInterface\n{\n    /**\n     * Create new frame object\n     *\n     * @throws ImagickException\n     * @return void\n     */\n    public function __construct(protected Imagick $native)\n    {\n        $background = new ImagickPixel('rgba(255, 255, 255, 0)');\n        $this->native->setImageBackgroundColor($background);\n        $this->native->setBackgroundColor($background);\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DriverInterface::toImage()\n     */\n    public function toImage(DriverInterface $driver): ImageInterface\n    {\n        return new Image($driver, new Core($this->native()));\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DriverInterface::setNative()\n     */\n    public function setNative(mixed $native): FrameInterface\n    {\n        $this->native = $native;\n\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DriverInterface::native()\n     */\n    public function native(): Imagick\n    {\n        return $this->native;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DriverInterface::size()\n     */\n    public function size(): SizeInterface\n    {\n        return new Rectangle(\n            $this->native->getImageWidth(),\n            $this->native->getImageHeight()\n        );\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DriverInterface::delay()\n     */\n    public function delay(): float\n    {\n        return $this->native->getImageDelay() / 100;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DriverInterface::setDelay()\n     */\n    public function setDelay(float $delay): FrameInterface\n    {\n        $this->native->setImageDelay(intval(round($delay * 100)));\n\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DriverInterface::dispose()\n     */\n    public function dispose(): int\n    {\n        return $this->native->getImageDispose();\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DriverInterface::setDispose()\n     *\n     * @throws InputException\n     */\n    public function setDispose(int $dispose): FrameInterface\n    {\n        if (!in_array($dispose, [0, 1, 2, 3])) {\n            throw new InputException('Value for argument $dispose must be 0, 1, 2 or 3.');\n        }\n\n        $this->native->setImageDispose($dispose);\n\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DriverInterface::setOffset()\n     */\n    public function setOffset(int $left, int $top): FrameInterface\n    {\n        $this->native->setImagePage(\n            $this->native->getImageWidth(),\n            $this->native->getImageHeight(),\n            $left,\n            $top\n        );\n\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DriverInterface::offsetLeft()\n     */\n    public function offsetLeft(): int\n    {\n        return $this->native->getImagePage()['x'];\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DriverInterface::setOffsetLeft()\n     */\n    public function setOffsetLeft(int $offset): FrameInterface\n    {\n        return $this->setOffset($offset, $this->offsetTop());\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DriverInterface::offsetTop()\n     */\n    public function offsetTop(): int\n    {\n        return $this->native->getImagePage()['y'];\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DriverInterface::setOffsetTop()\n     */\n    public function setOffsetTop(int $offset): FrameInterface\n    {\n        return $this->setOffset($this->offsetLeft(), $offset);\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Modifiers/AlignRotationModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Modifiers;\n\nuse Imagick;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\AlignRotationModifier as GenericAlignRotationModifier;\n\nclass AlignRotationModifier extends GenericAlignRotationModifier implements SpecializedInterface\n{\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        switch ($image->core()->native()->getImageOrientation()) {\n            case Imagick::ORIENTATION_TOPRIGHT: // 2\n                $image->core()->native()->flopImage();\n                break;\n\n            case Imagick::ORIENTATION_BOTTOMRIGHT: // 3\n                $image->core()->native()->rotateImage(\"#000\", 180);\n                break;\n\n            case Imagick::ORIENTATION_BOTTOMLEFT: // 4\n                $image->core()->native()->rotateImage(\"#000\", 180);\n                $image->core()->native()->flopImage();\n                break;\n\n            case Imagick::ORIENTATION_LEFTTOP: // 5\n                $image->core()->native()->rotateImage(\"#000\", -270);\n                $image->core()->native()->flopImage();\n                break;\n\n            case Imagick::ORIENTATION_RIGHTTOP: // 6\n                $image->core()->native()->rotateImage(\"#000\", -270);\n                break;\n\n            case Imagick::ORIENTATION_RIGHTBOTTOM: // 7\n                $image->core()->native()->rotateImage(\"#000\", -90);\n                $image->core()->native()->flopImage();\n                break;\n\n            case Imagick::ORIENTATION_LEFTBOTTOM: // 8\n                $image->core()->native()->rotateImage(\"#000\", -90);\n                break;\n        }\n\n        // set new orientation in image\n        $image->core()->native()->setImageOrientation(Imagick::ORIENTATION_TOPLEFT);\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Modifiers/BlendTransparencyModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Modifiers;\n\nuse Imagick;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\BlendTransparencyModifier as GenericBlendTransparencyModifier;\n\nclass BlendTransparencyModifier extends GenericBlendTransparencyModifier implements SpecializedInterface\n{\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        $blendingColor = $this->blendingColor($this->driver());\n\n        // get imagickpixel from blending color\n        $pixel = $this->driver()\n            ->colorProcessor($image->colorspace())\n            ->colorToNative($blendingColor);\n\n        // merge transparent areas with the background color\n        foreach ($image as $frame) {\n            $frame->native()->setImageBackgroundColor($pixel);\n            $frame->native()->setImageAlphaChannel(Imagick::ALPHACHANNEL_REMOVE);\n            $frame->native()->mergeImageLayers(Imagick::LAYERMETHOD_FLATTEN);\n        }\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Modifiers/BlurModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Modifiers;\n\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\BlurModifier as GenericBlurModifier;\n\nclass BlurModifier extends GenericBlurModifier implements SpecializedInterface\n{\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        foreach ($image as $frame) {\n            $frame->native()->blurImage($this->amount, 0.5 * $this->amount);\n        }\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Modifiers/BrightnessModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Modifiers;\n\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\BrightnessModifier as GenericBrightnessModifier;\n\nclass BrightnessModifier extends GenericBrightnessModifier implements SpecializedInterface\n{\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        foreach ($image as $frame) {\n            $frame->native()->modulateImage(100 + $this->level, 100, 100);\n        }\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Modifiers/ColorizeModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Modifiers;\n\nuse Imagick;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\ColorizeModifier as GenericColorizeModifier;\n\nclass ColorizeModifier extends GenericColorizeModifier implements SpecializedInterface\n{\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        $red = $this->normalizeLevel($this->red);\n        $green = $this->normalizeLevel($this->green);\n        $blue = $this->normalizeLevel($this->blue);\n\n        foreach ($image as $frame) {\n            $qrange = $frame->native()->getQuantumRange();\n            $frame->native()->levelImage(0, $red, $qrange['quantumRangeLong'], Imagick::CHANNEL_RED);\n            $frame->native()->levelImage(0, $green, $qrange['quantumRangeLong'], Imagick::CHANNEL_GREEN);\n            $frame->native()->levelImage(0, $blue, $qrange['quantumRangeLong'], Imagick::CHANNEL_BLUE);\n        }\n\n        return $image;\n    }\n\n    private function normalizeLevel(int $level): int\n    {\n        return $level > 0 ? intval(round($level / 5)) : intval(round(($level + 100) / 100));\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Modifiers/ColorspaceModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Modifiers;\n\nuse Imagick;\nuse Intervention\\Image\\Exceptions\\NotSupportedException;\nuse Intervention\\Image\\Interfaces\\ColorspaceInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Colors\\Cmyk\\Colorspace as CmykColorspace;\nuse Intervention\\Image\\Colors\\Rgb\\Colorspace as RgbColorspace;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\ColorspaceModifier as GenericColorspaceModifier;\n\nclass ColorspaceModifier extends GenericColorspaceModifier implements SpecializedInterface\n{\n    /**\n     * Map own colorspace classname to Imagick classnames\n     *\n     * @var array<string, int>\n     */\n    protected static array $mapping = [\n        RgbColorspace::class => Imagick::COLORSPACE_SRGB,\n        CmykColorspace::class => Imagick::COLORSPACE_CMYK,\n    ];\n\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        $colorspace = $this->targetColorspace();\n\n        $imagick = $image->core()->native();\n        $imagick->transformImageColorspace(\n            $this->getImagickColorspace($colorspace)\n        );\n\n        return $image;\n    }\n\n    /**\n     * @throws NotSupportedException\n     */\n    private function getImagickColorspace(ColorspaceInterface $colorspace): int\n    {\n        if (!array_key_exists($colorspace::class, self::$mapping)) {\n            throw new NotSupportedException('Given colorspace is not supported.');\n        }\n\n        return self::$mapping[$colorspace::class];\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Modifiers/ContainModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Modifiers;\n\nuse ImagickDraw;\nuse ImagickPixel;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\ContainModifier as GenericContainModifier;\n\nclass ContainModifier extends GenericContainModifier implements SpecializedInterface\n{\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        $crop = $this->getCropSize($image);\n        $resize = $this->getResizeSize($image);\n        $transparent = new ImagickPixel('transparent');\n        $background = $this->driver()->colorProcessor($image->colorspace())->colorToNative(\n            $this->driver()->handleInput($this->background)\n        );\n\n        foreach ($image as $frame) {\n            $frame->native()->scaleImage(\n                $crop->width(),\n                $crop->height(),\n            );\n\n            $frame->native()->setBackgroundColor($transparent);\n            $frame->native()->setImageBackgroundColor($transparent);\n\n            $frame->native()->extentImage(\n                $resize->width(),\n                $resize->height(),\n                $crop->pivot()->x() * -1,\n                $crop->pivot()->y() * -1\n            );\n\n            if ($resize->width() > $crop->width()) {\n                // fill new emerged background\n                $draw = new ImagickDraw();\n                $draw->setFillColor($background);\n\n                $delta = abs($crop->pivot()->x());\n\n                if ($delta > 0) {\n                    $draw->rectangle(\n                        0,\n                        0,\n                        $delta - 1,\n                        $resize->height()\n                    );\n                }\n\n                $draw->rectangle(\n                    $crop->width() + $delta,\n                    0,\n                    $resize->width(),\n                    $resize->height()\n                );\n\n                $frame->native()->drawImage($draw);\n            }\n\n            if ($resize->height() > $crop->height()) {\n                // fill new emerged background\n                $draw = new ImagickDraw();\n                $draw->setFillColor($background);\n\n                $delta = abs($crop->pivot()->y());\n\n                if ($delta > 0) {\n                    $draw->rectangle(\n                        0,\n                        0,\n                        $resize->width(),\n                        $delta - 1\n                    );\n                }\n\n                $draw->rectangle(\n                    0,\n                    $crop->height() + $delta,\n                    $resize->width(),\n                    $resize->height()\n                );\n\n                $frame->native()->drawImage($draw);\n            }\n        }\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Modifiers/ContrastModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Modifiers;\n\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\ContrastModifier as GenericContrastModifier;\n\nclass ContrastModifier extends GenericContrastModifier implements SpecializedInterface\n{\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        foreach ($image as $frame) {\n            $frame->native()->sigmoidalContrastImage($this->level > 0, abs($this->level / 4), 0);\n        }\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Modifiers/CoverDownModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Modifiers;\n\nuse Intervention\\Image\\Exceptions\\GeometryException;\nuse Intervention\\Image\\Interfaces\\SizeInterface;\n\nclass CoverDownModifier extends CoverModifier\n{\n    /**\n     * @throws GeometryException\n     */\n    public function getResizeSize(SizeInterface $size): SizeInterface\n    {\n        return $size->resizeDown($this->width, $this->height);\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Modifiers/CoverModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Modifiers;\n\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\CoverModifier as GenericCoverModifier;\n\nclass CoverModifier extends GenericCoverModifier implements SpecializedInterface\n{\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        $crop = $this->getCropSize($image);\n        $resize = $this->getResizeSize($crop);\n\n        foreach ($image as $frame) {\n            $frame->native()->cropImage(\n                $crop->width(),\n                $crop->height(),\n                $crop->pivot()->x(),\n                $crop->pivot()->y()\n            );\n\n            $frame->native()->scaleImage(\n                $resize->width(),\n                $resize->height()\n            );\n\n            $frame->native()->setImagePage(0, 0, 0, 0);\n        }\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Modifiers/CropModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Modifiers;\n\nuse Imagick;\nuse ImagickPixel;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\CropModifier as GenericCropModifier;\n\nclass CropModifier extends GenericCropModifier implements SpecializedInterface\n{\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        // decode background color\n        $background = $this->driver()->colorProcessor($image->colorspace())->colorToNative(\n            $this->driver()->handleInput($this->background)\n        );\n\n        // create empty container imagick to rebuild core\n        $imagick = new Imagick();\n\n        // save resolution to add it later\n        $resolution = $image->resolution()->perInch();\n\n        // define position of the image on the new canvas\n        $crop = $this->crop($image);\n        $position = [\n            ($crop->pivot()->x() + $this->offset_x) * -1,\n            ($crop->pivot()->y() + $this->offset_y) * -1,\n        ];\n\n        foreach ($image as $frame) {\n            // create new frame canvas with modifiers background\n            $canvas = new Imagick();\n            $canvas->newImage($crop->width(), $crop->height(), $background, 'png');\n            $canvas->setImageResolution($resolution->x(), $resolution->y());\n            $canvas->setImageAlphaChannel(Imagick::ALPHACHANNEL_SET); // or ALPHACHANNEL_ACTIVATE?\n\n            // set animation details\n            if ($image->isAnimated()) {\n                $canvas->setImageDelay($frame->native()->getImageDelay());\n                $canvas->setImageIterations($frame->native()->getImageIterations());\n                $canvas->setImageDispose($frame->native()->getImageDispose());\n            }\n\n            // make the rectangular position of the original image transparent\n            // so that we can later place the original on top. this preserves\n            // the transparency of the original and shows the background color\n            // of the modifier in the other areas. if the original image has no\n            // transparent area the rectangular transparency will be covered by\n            // the original.\n            $clearer = new Imagick();\n            $clearer->newImage(\n                $frame->native()->getImageWidth(),\n                $frame->native()->getImageHeight(),\n                new ImagickPixel('black'),\n            );\n            $canvas->compositeImage($clearer, Imagick::COMPOSITE_DSTOUT, ...$position);\n\n            // place original frame content onto prepared frame canvas\n            $canvas->compositeImage($frame->native(), Imagick::COMPOSITE_DEFAULT, ...$position);\n\n            // add newly built frame to container imagick\n            $imagick->addImage($canvas);\n        }\n\n        // replace imagick in the original image\n        $image->core()->setNative($imagick);\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Modifiers/DrawBezierModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Modifiers;\n\nuse ImagickDraw;\nuse RuntimeException;\nuse Intervention\\Image\\Exceptions\\GeometryException;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\DrawBezierModifier as GenericDrawBezierModifier;\n\nclass DrawBezierModifier extends GenericDrawBezierModifier implements SpecializedInterface\n{\n    /**\n     * @throws RuntimeException\n     * @throws GeometryException\n     */\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        if ($this->drawable->count() !== 3 && $this->drawable->count() !== 4) {\n            throw new GeometryException('You must specify either 3 or 4 points to create a bezier curve');\n        }\n\n        $drawing = new ImagickDraw();\n\n        if ($this->drawable->hasBackgroundColor()) {\n            $background_color = $this->driver()->colorProcessor($image->colorspace())->colorToNative(\n                $this->backgroundColor()\n            );\n        } else {\n            $background_color = 'transparent';\n        }\n\n        $drawing->setFillColor($background_color);\n\n        if ($this->drawable->hasBorder() && $this->drawable->borderSize() > 0) {\n            $border_color = $this->driver()->colorProcessor($image->colorspace())->colorToNative(\n                $this->borderColor()\n            );\n\n            $drawing->setStrokeColor($border_color);\n            $drawing->setStrokeWidth($this->drawable->borderSize());\n        }\n\n        $drawing->pathStart();\n        $drawing->pathMoveToAbsolute(\n            $this->drawable->first()->x(),\n            $this->drawable->first()->y()\n        );\n        if ($this->drawable->count() === 3) {\n            $drawing->pathCurveToQuadraticBezierAbsolute(\n                $this->drawable->second()->x(),\n                $this->drawable->second()->y(),\n                $this->drawable->last()->x(),\n                $this->drawable->last()->y()\n            );\n        } elseif ($this->drawable->count() === 4) {\n            $drawing->pathCurveToAbsolute(\n                $this->drawable->second()->x(),\n                $this->drawable->second()->y(),\n                $this->drawable->third()->x(),\n                $this->drawable->third()->y(),\n                $this->drawable->last()->x(),\n                $this->drawable->last()->y()\n            );\n        }\n        $drawing->pathFinish();\n\n        foreach ($image as $frame) {\n            $frame->native()->drawImage($drawing);\n        }\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Modifiers/DrawEllipseModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Modifiers;\n\nuse ImagickDraw;\nuse RuntimeException;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\DrawEllipseModifier as GenericDrawEllipseModifier;\n\nclass DrawEllipseModifier extends GenericDrawEllipseModifier implements SpecializedInterface\n{\n    /**\n     * @throws RuntimeException\n     */\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        $background_color = $this->driver()->colorProcessor($image->colorspace())->colorToNative(\n            $this->backgroundColor()\n        );\n\n        $border_color = $this->driver()->colorProcessor($image->colorspace())->colorToNative(\n            $this->borderColor()\n        );\n\n        foreach ($image as $frame) {\n            $drawing = new ImagickDraw();\n            $drawing->setFillColor($background_color);\n\n            if ($this->drawable->hasBorder()) {\n                $drawing->setStrokeWidth($this->drawable->borderSize());\n                $drawing->setStrokeColor($border_color);\n            }\n\n            $drawing->ellipse(\n                $this->drawable->position()->x(),\n                $this->drawable->position()->y(),\n                $this->drawable->width() / 2,\n                $this->drawable->height() / 2,\n                0,\n                360\n            );\n\n            $frame->native()->drawImage($drawing);\n        }\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Modifiers/DrawLineModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Modifiers;\n\nuse ImagickDraw;\nuse RuntimeException;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\DrawLineModifier as GenericDrawLineModifier;\n\nclass DrawLineModifier extends GenericDrawLineModifier implements SpecializedInterface\n{\n    /**\n     * @throws RuntimeException\n     */\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        $drawing = new ImagickDraw();\n        $drawing->setStrokeWidth($this->drawable->width());\n        $drawing->setFillOpacity(0);\n        $drawing->setStrokeColor(\n            $this->driver()->colorProcessor($image->colorspace())->colorToNative(\n                $this->backgroundColor()\n            )\n        );\n\n        $drawing->line(\n            $this->drawable->start()->x(),\n            $this->drawable->start()->y(),\n            $this->drawable->end()->x(),\n            $this->drawable->end()->y(),\n        );\n\n        foreach ($image as $frame) {\n            $frame->native()->drawImage($drawing);\n        }\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Modifiers/DrawPixelModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Modifiers;\n\nuse ImagickDraw;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\DrawPixelModifier as GenericDrawPixelModifier;\n\nclass DrawPixelModifier extends GenericDrawPixelModifier implements SpecializedInterface\n{\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        $color = $this->driver()->colorProcessor($image->colorspace())->colorToNative(\n            $this->driver()->handleInput($this->color)\n        );\n\n        $pixel = new ImagickDraw();\n        $pixel->setFillColor($color);\n        $pixel->point($this->position->x(), $this->position->y());\n\n        foreach ($image as $frame) {\n            $frame->native()->drawImage($pixel);\n        }\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Modifiers/DrawPolygonModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Modifiers;\n\nuse ImagickDraw;\nuse ImagickPixel;\nuse RuntimeException;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\DrawPolygonModifier as GenericDrawPolygonModifier;\n\nclass DrawPolygonModifier extends GenericDrawPolygonModifier implements SpecializedInterface\n{\n    /**\n     * @throws RuntimeException\n     */\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        $drawing = new ImagickDraw();\n        $drawing->setFillColor(new ImagickPixel('transparent')); // defaults to no backgroundColor\n\n        if ($this->drawable->hasBackgroundColor()) {\n            $background_color = $this->driver()->colorProcessor($image->colorspace())->colorToNative(\n                $this->backgroundColor()\n            );\n\n            $drawing->setFillColor($background_color);\n        }\n\n        if ($this->drawable->hasBorder()) {\n            $border_color = $this->driver()->colorProcessor($image->colorspace())->colorToNative(\n                $this->borderColor()\n            );\n\n            $drawing->setStrokeColor($border_color);\n            $drawing->setStrokeWidth($this->drawable->borderSize());\n        }\n\n        $drawing->polygon($this->points());\n\n        foreach ($image as $frame) {\n            $frame->native()->drawImage($drawing);\n        }\n\n        return $image;\n    }\n\n    /**\n     * Return points of drawable in processable form for ImagickDraw\n     *\n     * @return array<array<string, int>>\n     */\n    private function points(): array\n    {\n        $points = [];\n        foreach ($this->drawable as $point) {\n            $points[] = ['x' => $point->x(), 'y' => $point->y()];\n        }\n\n        return $points;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Modifiers/DrawRectangleModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Modifiers;\n\nuse ImagickDraw;\nuse RuntimeException;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\DrawRectangleModifier as GenericDrawRectangleModifier;\n\nclass DrawRectangleModifier extends GenericDrawRectangleModifier implements SpecializedInterface\n{\n    /**\n     * @throws RuntimeException\n     */\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        $drawing = new ImagickDraw();\n\n        $background_color = $this->driver()->colorProcessor($image->colorspace())->colorToNative(\n            $this->backgroundColor()\n        );\n\n        $border_color = $this->driver()->colorProcessor($image->colorspace())->colorToNative(\n            $this->borderColor()\n        );\n\n        $drawing->setFillColor($background_color);\n        if ($this->drawable->hasBorder()) {\n            $drawing->setStrokeColor($border_color);\n            $drawing->setStrokeWidth($this->drawable->borderSize());\n        }\n\n        // build rectangle\n        $drawing->rectangle(\n            $this->drawable->position()->x(),\n            $this->drawable->position()->y(),\n            $this->drawable->position()->x() + $this->drawable->width(),\n            $this->drawable->position()->y() + $this->drawable->height()\n        );\n\n        foreach ($image as $frame) {\n            $frame->native()->drawImage($drawing);\n        }\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Modifiers/FillModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Modifiers;\n\nuse Imagick;\nuse ImagickDraw;\nuse ImagickPixel;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\FillModifier as ModifiersFillModifier;\n\nclass FillModifier extends ModifiersFillModifier implements SpecializedInterface\n{\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        $pixel = $this->driver()->colorProcessor($image->colorspace())->colorToNative(\n            $this->driver()->handleInput($this->color)\n        );\n\n        foreach ($image->core()->native() as $frame) {\n            if ($this->hasPosition()) {\n                $this->floodFillWithColor($frame, $pixel);\n            } else {\n                $this->fillAllWithColor($frame, $pixel);\n            }\n        }\n\n        return $image;\n    }\n\n    private function floodFillWithColor(Imagick $frame, ImagickPixel $pixel): void\n    {\n        $target = $frame->getImagePixelColor(\n            $this->position->x(),\n            $this->position->y()\n        );\n\n        $frame->floodfillPaintImage(\n            $pixel,\n            100,\n            $target,\n            $this->position->x(),\n            $this->position->y(),\n            false,\n            Imagick::CHANNEL_ALL\n        );\n    }\n\n    private function fillAllWithColor(Imagick $frame, ImagickPixel $pixel): void\n    {\n        $draw = new ImagickDraw();\n        $draw->setFillColor($pixel);\n        $draw->rectangle(0, 0, $frame->getImageWidth(), $frame->getImageHeight());\n        $frame->drawImage($draw);\n\n        // deactive alpha channel when image was filled with opaque color\n        if ($pixel->getColorValue(Imagick::COLOR_ALPHA) == 1) {\n            $frame->setImageAlphaChannel(Imagick::ALPHACHANNEL_DEACTIVATE);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Modifiers/FlipModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Modifiers;\n\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\FlipModifier as GenericFlipModifier;\n\nclass FlipModifier extends GenericFlipModifier implements SpecializedInterface\n{\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        foreach ($image as $frame) {\n            $frame->native()->flipImage();\n        }\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Modifiers/FlopModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Modifiers;\n\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\FlopModifier as ModifiersFlopModifier;\n\nclass FlopModifier extends ModifiersFlopModifier implements SpecializedInterface\n{\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        foreach ($image as $frame) {\n            $frame->native()->flopImage();\n        }\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Modifiers/GammaModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Modifiers;\n\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\GammaModifier as GenericGammaModifier;\n\nclass GammaModifier extends GenericGammaModifier implements SpecializedInterface\n{\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        foreach ($image as $frame) {\n            $frame->native()->gammaImage($this->gamma);\n        }\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Modifiers/GreyscaleModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Modifiers;\n\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\GreyscaleModifier as GenericGreyscaleModifier;\n\nclass GreyscaleModifier extends GenericGreyscaleModifier implements SpecializedInterface\n{\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        foreach ($image as $frame) {\n            $frame->native()->modulateImage(100, 0, 100);\n        }\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Modifiers/InvertModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Modifiers;\n\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\InvertModifier as GenericInvertModifier;\n\nclass InvertModifier extends GenericInvertModifier implements SpecializedInterface\n{\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        foreach ($image as $frame) {\n            $frame->native()->negateImage(false);\n        }\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Modifiers/PadModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Modifiers;\n\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SizeInterface;\n\nclass PadModifier extends ContainModifier\n{\n    public function getCropSize(ImageInterface $image): SizeInterface\n    {\n        return $image->size()\n            ->containMax(\n                $this->width,\n                $this->height\n            )\n            ->alignPivotTo(\n                $this->getResizeSize($image),\n                $this->position\n            );\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Modifiers/PixelateModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Modifiers;\n\nuse Intervention\\Image\\Interfaces\\FrameInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\PixelateModifier as GenericPixelateModifier;\n\nclass PixelateModifier extends GenericPixelateModifier implements SpecializedInterface\n{\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        foreach ($image as $frame) {\n            $this->pixelateFrame($frame);\n        }\n\n        return $image;\n    }\n\n    protected function pixelateFrame(FrameInterface $frame): void\n    {\n        $size = $frame->size();\n\n        $frame->native()->scaleImage(\n            (int) round(max(1, $size->width() / $this->size)),\n            (int) round(max(1, $size->height() / $this->size))\n        );\n\n        $frame->native()->scaleImage($size->width(), $size->height());\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Modifiers/PlaceModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Modifiers;\n\nuse Imagick;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\PlaceModifier as GenericPlaceModifier;\n\nclass PlaceModifier extends GenericPlaceModifier implements SpecializedInterface\n{\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        $watermark = $this->driver()->handleInput($this->element);\n        $position = $this->getPosition($image, $watermark);\n\n        // set opacity of watermark\n        if ($this->opacity < 100) {\n            $watermark->core()->native()->setImageAlphaChannel(Imagick::ALPHACHANNEL_SET);\n            $watermark->core()->native()->evaluateImage(\n                Imagick::EVALUATE_DIVIDE,\n                $this->opacity > 0 ? 100 / $this->opacity : 1000,\n                Imagick::CHANNEL_ALPHA,\n            );\n        }\n\n        foreach ($image as $frame) {\n            $frame->native()->compositeImage(\n                $watermark->core()->native(),\n                Imagick::COMPOSITE_DEFAULT,\n                $position->x(),\n                $position->y()\n            );\n        }\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Modifiers/ProfileModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Modifiers;\n\nuse Intervention\\Image\\Exceptions\\ColorException;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\ProfileModifier as GenericProfileModifier;\n\nclass ProfileModifier extends GenericProfileModifier implements SpecializedInterface\n{\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        $imagick = $image->core()->native();\n        $result = $imagick->profileImage('icc', (string) $this->profile);\n\n        if ($result === false) {\n            throw new ColorException('ICC color profile could not be set.');\n        }\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Modifiers/ProfileRemovalModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Modifiers;\n\nuse Intervention\\Image\\Exceptions\\ColorException;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\ProfileRemovalModifier as GenericProfileRemovalModifier;\n\nclass ProfileRemovalModifier extends GenericProfileRemovalModifier implements SpecializedInterface\n{\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        $imagick = $image->core()->native();\n        $result = $imagick->profileImage('icc', null);\n\n        if ($result === false) {\n            throw new ColorException('ICC color profile could not be removed.');\n        }\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Modifiers/QuantizeColorsModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Modifiers;\n\nuse Intervention\\Image\\Exceptions\\InputException;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\QuantizeColorsModifier as GenericQuantizeColorsModifier;\n\nclass QuantizeColorsModifier extends GenericQuantizeColorsModifier implements SpecializedInterface\n{\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        if ($this->limit <= 0) {\n            throw new InputException('Quantization limit must be greater than 0.');\n        }\n\n        // no color reduction if the limit is higher than the colors in the img\n        if ($this->limit > $image->core()->native()->getImageColors()) {\n            return $image;\n        }\n\n        foreach ($image as $frame) {\n            $frame->native()->quantizeImage(\n                $this->limit,\n                $frame->native()->getImageColorspace(),\n                0,\n                false,\n                false\n            );\n        }\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Modifiers/RemoveAnimationModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Modifiers;\n\nuse Imagick;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\RemoveAnimationModifier as GenericRemoveAnimationModifier;\n\nclass RemoveAnimationModifier extends GenericRemoveAnimationModifier implements SpecializedInterface\n{\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        // create new imagick with just one image\n        $imagick = new Imagick();\n        $frame = $this->selectedFrame($image);\n        $imagick->addImage($frame->native()->getImage());\n\n        // set new imagick to image\n        $image->core()->setNative($imagick);\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Modifiers/ResizeCanvasModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Modifiers;\n\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\ResizeCanvasModifier as GenericResizeCanvasModifier;\n\nclass ResizeCanvasModifier extends GenericResizeCanvasModifier implements SpecializedInterface\n{\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        $cropSize = $this->cropSize($image);\n\n        $image->modify(new CropModifier(\n            $cropSize->width(),\n            $cropSize->height(),\n            $cropSize->pivot()->x(),\n            $cropSize->pivot()->y(),\n            $this->background,\n        ));\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Modifiers/ResizeCanvasRelativeModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Modifiers;\n\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SizeInterface;\n\nclass ResizeCanvasRelativeModifier extends ResizeCanvasModifier\n{\n    protected function cropSize(ImageInterface $image, bool $relative = false): SizeInterface\n    {\n        return parent::cropSize($image, true);\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Modifiers/ResizeDownModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Modifiers;\n\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SizeInterface;\n\nclass ResizeDownModifier extends ResizeModifier\n{\n    protected function getAdjustedSize(ImageInterface $image): SizeInterface\n    {\n        return $image->size()->resizeDown($this->width, $this->height);\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Modifiers/ResizeModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Modifiers;\n\nuse Intervention\\Image\\Exceptions\\RuntimeException;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SizeInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\ResizeModifier as GenericResizeModifier;\n\nclass ResizeModifier extends GenericResizeModifier implements SpecializedInterface\n{\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        $resizeTo = $this->getAdjustedSize($image);\n\n        foreach ($image as $frame) {\n            $frame->native()->scaleImage(\n                $resizeTo->width(),\n                $resizeTo->height()\n            );\n        }\n\n        return $image;\n    }\n\n    /**\n     * @throws RuntimeException\n     */\n    protected function getAdjustedSize(ImageInterface $image): SizeInterface\n    {\n        return $image->size()->resize($this->width, $this->height);\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Modifiers/ResolutionModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Modifiers;\n\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\ResolutionModifier as GenericResolutionModifier;\n\nclass ResolutionModifier extends GenericResolutionModifier implements SpecializedInterface\n{\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        $imagick = $image->core()->native();\n        $imagick->setImageResolution($this->x, $this->y);\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Modifiers/RotateModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Modifiers;\n\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\RotateModifier as GenericRotateModifier;\n\nclass RotateModifier extends GenericRotateModifier implements SpecializedInterface\n{\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        $background = $this->driver()->colorProcessor($image->colorspace())->colorToNative(\n            $this->driver()->handleInput($this->background)\n        );\n\n        foreach ($image as $frame) {\n            $frame->native()->rotateImage(\n                $background,\n                $this->rotationAngle() * -1\n            );\n        }\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Modifiers/ScaleDownModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Modifiers;\n\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SizeInterface;\n\nclass ScaleDownModifier extends ResizeModifier\n{\n    protected function getAdjustedSize(ImageInterface $image): SizeInterface\n    {\n        return $image->size()->scaleDown($this->width, $this->height);\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Modifiers/ScaleModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Modifiers;\n\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SizeInterface;\n\nclass ScaleModifier extends ResizeModifier\n{\n    protected function getAdjustedSize(ImageInterface $image): SizeInterface\n    {\n        return $image->size()->scale($this->width, $this->height);\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Modifiers/SharpenModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Modifiers;\n\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\SharpenModifier as GenericSharpenModifier;\n\nclass SharpenModifier extends GenericSharpenModifier implements SpecializedInterface\n{\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        foreach ($image as $frame) {\n            $frame->native()->unsharpMaskImage(1, 1, $this->amount / 6.25, 0);\n        }\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Modifiers/SliceAnimationModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Modifiers;\n\nuse Intervention\\Image\\Exceptions\\AnimationException;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\SliceAnimationModifier as GenericSliceAnimationModifier;\n\nclass SliceAnimationModifier extends GenericSliceAnimationModifier implements SpecializedInterface\n{\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        if ($this->offset >= $image->count()) {\n            throw new AnimationException('Offset is not in the range of frames.');\n        }\n\n        $image->core()->slice($this->offset, $this->length);\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Modifiers/StripMetaModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Modifiers;\n\nuse Intervention\\Image\\Collection;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\ModifierInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\n\nclass StripMetaModifier implements ModifierInterface, SpecializedInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see Intervention\\Image\\Interfaces\\ModifierInterface::apply()\n     */\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        // preserve icc profiles\n        $profiles = $image->core()->native()->getImageProfiles('icc');\n\n        // remove meta data\n        $image->core()->native()->stripImage();\n        $image->setExif(new Collection());\n\n        if ($profiles !== []) {\n            // re-apply icc profiles\n            $image->core()->native()->profileImage(\"icc\", $profiles['icc']);\n        }\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Modifiers/TextModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Modifiers;\n\nuse ImagickDraw;\nuse ImagickDrawException;\nuse ImagickException;\nuse Intervention\\Image\\Drivers\\Imagick\\FontProcessor;\nuse Intervention\\Image\\Exceptions\\ColorException;\nuse Intervention\\Image\\Exceptions\\FontException;\nuse Intervention\\Image\\Exceptions\\RuntimeException;\nuse Intervention\\Image\\Geometry\\Point;\nuse Intervention\\Image\\Interfaces\\FontInterface;\nuse Intervention\\Image\\Interfaces\\FrameInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\PointInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\TextModifier as GenericTextModifier;\nuse Intervention\\Image\\Typography\\Line;\n\nclass TextModifier extends GenericTextModifier implements SpecializedInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see ModifierInterface::apply()\n     */\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        $lines = $this->processor()->textBlock($this->text, $this->font, $this->position);\n        $drawText = $this->imagickDrawText($image, $this->font);\n        $drawStroke = $this->imagickDrawStroke($image, $this->font);\n\n        foreach ($image as $frame) {\n            foreach ($lines as $line) {\n                foreach ($this->strokeOffsets($this->font) as $offset) {\n                    // Draw the stroke outline under the actual text\n                    $this->maybeDrawTextline($frame, $line, $drawStroke, $offset);\n                }\n\n                // Draw the actual text\n                $this->maybeDrawTextline($frame, $line, $drawText);\n            }\n        }\n\n        return $image;\n    }\n\n    /**\n     * Create an ImagickDraw object to draw text on the image\n     *\n     * @throws RuntimeException\n     * @throws ColorException\n     * @throws FontException\n     * @throws ImagickDrawException\n     * @throws ImagickException\n     */\n    private function imagickDrawText(ImageInterface $image, FontInterface $font): ImagickDraw\n    {\n        $color = $this->driver()->handleInput($font->color());\n\n        if ($font->hasStrokeEffect() && $color->isTransparent()) {\n            throw new ColorException(\n                'The text color must be fully opaque when using the stroke effect.'\n            );\n        }\n\n        $color = $this->driver()->colorProcessor($image->colorspace())->colorToNative($color);\n\n        return $this->processor()->toImagickDraw($font, $color);\n    }\n\n    /**\n     * Create a ImagickDraw object to draw the outline stroke effect on the Image\n     *\n     * @throws RuntimeException\n     * @throws ColorException\n     * @throws FontException\n     * @throws ImagickDrawException\n     * @throws ImagickException\n     */\n    private function imagickDrawStroke(ImageInterface $image, FontInterface $font): ?ImagickDraw\n    {\n        if (!$font->hasStrokeEffect()) {\n            return null;\n        }\n\n        $color = $this->driver()->handleInput($font->strokeColor());\n\n        if ($color->isTransparent()) {\n            throw new ColorException(\n                'The stroke color must be fully opaque.'\n            );\n        }\n\n        $color = $this->driver()->colorProcessor($image->colorspace())->colorToNative($color);\n\n        return $this->processor()->toImagickDraw($font, $color);\n    }\n\n    /**\n     * Maybe draw given line of text on frame instance depending on given\n     * ImageDraw instance. Optionally move line position by given offset.\n     */\n    private function maybeDrawTextline(\n        FrameInterface $frame,\n        Line $textline,\n        ?ImagickDraw $draw = null,\n        PointInterface $offset = new Point(),\n    ): void {\n        if ($draw instanceof ImagickDraw) {\n            $frame->native()->annotateImage(\n                $draw,\n                $textline->position()->x() + $offset->x(),\n                $textline->position()->y() + $offset->y(),\n                $this->font->angle(),\n                (string) $textline\n            );\n        }\n    }\n\n    /**\n     * Return imagick font processor\n     *\n     * @throws FontException\n     */\n    private function processor(): FontProcessor\n    {\n        $processor = $this->driver()->fontProcessor();\n\n        if (!($processor instanceof FontProcessor)) {\n            throw new FontException('Font processor does not match the driver.');\n        }\n\n        return $processor;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Imagick/Modifiers/TrimModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers\\Imagick\\Modifiers;\n\nuse Intervention\\Image\\Exceptions\\NotSupportedException;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\TrimModifier as GenericTrimModifier;\n\nclass TrimModifier extends GenericTrimModifier implements SpecializedInterface\n{\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        if ($image->isAnimated()) {\n            throw new NotSupportedException('Trim modifier cannot be applied to animated images.');\n        }\n\n        $imagick = $image->core()->native();\n        $imagick->trimImage(($this->tolerance / 100 * $imagick->getQuantum()) / 1.5);\n        $imagick->setImagePage(0, 0, 0, 0);\n\n        return $image;\n    }\n}\n"
  },
  {
    "path": "src/Drivers/Specializable.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers;\n\nuse Intervention\\Image\\Interfaces\\SpecializableInterface;\nuse Intervention\\Image\\Traits\\CanBeDriverSpecialized;\n\nabstract class Specializable implements SpecializableInterface\n{\n    use CanBeDriverSpecialized;\n}\n"
  },
  {
    "path": "src/Drivers/SpecializableAnalyzer.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers;\n\nuse Intervention\\Image\\Interfaces\\AnalyzerInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\n\nabstract class SpecializableAnalyzer extends Specializable implements AnalyzerInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see AnalyzerInterface::analyze()\n     */\n    public function analyze(ImageInterface $image): mixed\n    {\n        return $image->analyze($this);\n    }\n}\n"
  },
  {
    "path": "src/Drivers/SpecializableDecoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers;\n\nuse Intervention\\Image\\Exceptions\\DecoderException;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializableInterface;\nuse Intervention\\Image\\Traits\\CanBeDriverSpecialized;\n\nabstract class SpecializableDecoder extends AbstractDecoder implements SpecializableInterface\n{\n    use CanBeDriverSpecialized;\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DecoderInterface::decode()\n     */\n    public function decode(mixed $input): ImageInterface|ColorInterface\n    {\n        throw new DecoderException('Decoder must be specialized by the driver first.');\n    }\n}\n"
  },
  {
    "path": "src/Drivers/SpecializableEncoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers;\n\nuse Intervention\\Image\\Interfaces\\SpecializableInterface;\nuse Intervention\\Image\\Traits\\CanBeDriverSpecialized;\n\nabstract class SpecializableEncoder extends AbstractEncoder implements SpecializableInterface\n{\n    use CanBeDriverSpecialized;\n}\n"
  },
  {
    "path": "src/Drivers/SpecializableModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Drivers;\n\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\ModifierInterface;\n\nabstract class SpecializableModifier extends Specializable implements ModifierInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see ModifierInterface::apply()\n     */\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        return $image->modify($this);\n    }\n}\n"
  },
  {
    "path": "src/EncodedImage.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image;\n\nuse Intervention\\Image\\Interfaces\\EncodedImageInterface;\n\nclass EncodedImage extends File implements EncodedImageInterface\n{\n    /**\n     * Create new instance\n     *\n     * @param string|resource $data\n     */\n    public function __construct(\n        mixed $data,\n        protected string $mediaType = 'application/octet-stream'\n    ) {\n        parent::__construct($data);\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see EncodedImageInterface::mediaType()\n     */\n    public function mediaType(): string\n    {\n        return $this->mediaType;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see EncodedImageInterface::mimetype()\n     */\n    public function mimetype(): string\n    {\n        return $this->mediaType();\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see EncodedImageInterface::toDataUri()\n     */\n    public function toDataUri(): string\n    {\n        return sprintf('data:%s;base64,%s', $this->mediaType(), base64_encode((string) $this));\n    }\n\n    /**\n     * Show debug info for the current image\n     *\n     * @return array<string, mixed>\n     */\n    public function __debugInfo(): array\n    {\n        return [\n            'mediaType' => $this->mediaType(),\n            'size' => $this->size(),\n        ];\n    }\n}\n"
  },
  {
    "path": "src/Encoders/AutoEncoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Encoders;\n\nuse Intervention\\Image\\Interfaces\\EncodedImageInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\n\nclass AutoEncoder extends MediaTypeEncoder\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see EncoderInterface::encode()\n     */\n    public function encode(ImageInterface $image): EncodedImageInterface\n    {\n        return $image->encode(\n            $this->encoderByMediaType(\n                $image->origin()->mediaType()\n            )\n        );\n    }\n}\n"
  },
  {
    "path": "src/Encoders/AvifEncoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Encoders;\n\nuse Intervention\\Image\\Drivers\\SpecializableEncoder;\n\nclass AvifEncoder extends SpecializableEncoder\n{\n    /**\n     * Create new encoder object\n     *\n     * @param null|bool $strip Strip EXIF metadata\n     * @return void\n     */\n    public function __construct(\n        public int $quality = self::DEFAULT_QUALITY,\n        public ?bool $strip = null\n    ) {\n        //\n    }\n}\n"
  },
  {
    "path": "src/Encoders/BmpEncoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Encoders;\n\nuse Intervention\\Image\\Drivers\\SpecializableEncoder;\n\nclass BmpEncoder extends SpecializableEncoder\n{\n    public function __construct()\n    {\n        //\n    }\n}\n"
  },
  {
    "path": "src/Encoders/FileExtensionEncoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Encoders;\n\nuse Error;\nuse Intervention\\Image\\Exceptions\\EncoderException;\nuse Intervention\\Image\\FileExtension;\nuse Intervention\\Image\\Interfaces\\EncodedImageInterface;\nuse Intervention\\Image\\Interfaces\\EncoderInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\n\nclass FileExtensionEncoder extends AutoEncoder\n{\n    /**\n     * Encoder options\n     *\n     * @var array<string, mixed>\n     */\n    protected array $options = [];\n\n    /**\n     * Create new encoder instance to encode to format of given file extension\n     *\n     * @param null|string|FileExtension $extension Target file extension for example \"png\"\n     * @return void\n     */\n    public function __construct(public null|string|FileExtension $extension = null, mixed ...$options)\n    {\n        $this->options = $options;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see EncoderInterface::encode()\n     */\n    public function encode(ImageInterface $image): EncodedImageInterface\n    {\n        $extension = is_null($this->extension) ? $image->origin()->fileExtension() : $this->extension;\n\n        return $image->encode(\n            $this->encoderByFileExtension(\n                $extension\n            )\n        );\n    }\n\n    /**\n     * Create matching encoder for given file extension\n     *\n     * @throws EncoderException\n     */\n    protected function encoderByFileExtension(null|string|FileExtension $extension): EncoderInterface\n    {\n        if (empty($extension)) {\n            throw new EncoderException('No encoder found for empty file extension.');\n        }\n\n        try {\n            $extension = is_string($extension) ? FileExtension::from(strtolower($extension)) : $extension;\n        } catch (Error) {\n            throw new EncoderException('No encoder found for file extension (' . $extension . ').');\n        }\n\n        return $extension->format()->encoder(...$this->options);\n    }\n}\n"
  },
  {
    "path": "src/Encoders/FilePathEncoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Encoders;\n\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\EncodedImageInterface;\n\nclass FilePathEncoder extends FileExtensionEncoder\n{\n    /**\n     * Create new encoder instance to encode to format of file extension in given path\n     *\n     * @return void\n     */\n    public function __construct(protected ?string $path = null, mixed ...$options)\n    {\n        parent::__construct(\n            is_null($path) ? $path : pathinfo($path, PATHINFO_EXTENSION),\n            ...$options\n        );\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see EncoderInterface::encode()\n     */\n    public function encode(ImageInterface $image): EncodedImageInterface\n    {\n        return $image->encode(\n            $this->encoderByFileExtension(\n                is_null($this->path) ? $image->origin()->fileExtension() : pathinfo($this->path, PATHINFO_EXTENSION)\n            )\n        );\n    }\n}\n"
  },
  {
    "path": "src/Encoders/GifEncoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Encoders;\n\nuse Intervention\\Image\\Drivers\\SpecializableEncoder;\n\nclass GifEncoder extends SpecializableEncoder\n{\n    /**\n     * Create new encoder object\n     *\n     * @return void\n     */\n    public function __construct(public bool $interlaced = false)\n    {\n        //\n    }\n}\n"
  },
  {
    "path": "src/Encoders/HeicEncoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Encoders;\n\nuse Intervention\\Image\\Drivers\\SpecializableEncoder;\n\nclass HeicEncoder extends SpecializableEncoder\n{\n    /**\n     * Create new encoder object\n     *\n     * @param null|bool $strip Strip EXIF metadata\n     * @return void\n     */\n    public function __construct(\n        public int $quality = self::DEFAULT_QUALITY,\n        public ?bool $strip = null\n    ) {\n        //\n    }\n}\n"
  },
  {
    "path": "src/Encoders/Jpeg2000Encoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Encoders;\n\nuse Intervention\\Image\\Drivers\\SpecializableEncoder;\n\nclass Jpeg2000Encoder extends SpecializableEncoder\n{\n    /**\n     * Create new encoder object\n     *\n     * @param null|bool $strip Strip EXIF metadata\n     * @return void\n     */\n    public function __construct(\n        public int $quality = self::DEFAULT_QUALITY,\n        public ?bool $strip = null\n    ) {\n        //\n    }\n}\n"
  },
  {
    "path": "src/Encoders/JpegEncoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Encoders;\n\nuse Intervention\\Image\\Drivers\\SpecializableEncoder;\n\nclass JpegEncoder extends SpecializableEncoder\n{\n    /**\n     * Create new encoder object\n     *\n     * @param null|bool $strip Strip EXIF metadata\n     * @return void\n     */\n    public function __construct(\n        public int $quality = self::DEFAULT_QUALITY,\n        public bool $progressive = false,\n        public ?bool $strip = null\n    ) {\n        //\n    }\n}\n"
  },
  {
    "path": "src/Encoders/MediaTypeEncoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Encoders;\n\nuse Error;\nuse Intervention\\Image\\Drivers\\AbstractEncoder;\nuse Intervention\\Image\\Exceptions\\EncoderException;\nuse Intervention\\Image\\Interfaces\\EncodedImageInterface;\nuse Intervention\\Image\\Interfaces\\EncoderInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\MediaType;\n\nclass MediaTypeEncoder extends AbstractEncoder\n{\n    /**\n     * Encoder options\n     *\n     * @var array<string, mixed>\n     */\n    protected array $options = [];\n\n    /**\n     * Create new encoder instance\n     *\n     * @param null|string|MediaType $mediaType Target media type for example \"image/jpeg\"\n     * @return void\n     */\n    public function __construct(public null|string|MediaType $mediaType = null, mixed ...$options)\n    {\n        $this->options = $options;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see EncoderInterface::encode()\n     */\n    public function encode(ImageInterface $image): EncodedImageInterface\n    {\n        $mediaType = is_null($this->mediaType) ? $image->origin()->mediaType() : $this->mediaType;\n\n        return $image->encode(\n            $this->encoderByMediaType($mediaType)\n        );\n    }\n\n    /**\n     * Return new encoder by given media (MIME) type\n     *\n     * @throws EncoderException\n     */\n    protected function encoderByMediaType(string|MediaType $mediaType): EncoderInterface\n    {\n        try {\n            $mediaType = is_string($mediaType) ? MediaType::from($mediaType) : $mediaType;\n        } catch (Error) {\n            throw new EncoderException('No encoder found for media type (' . $mediaType . ').');\n        }\n\n        return $mediaType->format()->encoder(...$this->options);\n    }\n}\n"
  },
  {
    "path": "src/Encoders/PngEncoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Encoders;\n\nuse Intervention\\Image\\Drivers\\SpecializableEncoder;\n\nclass PngEncoder extends SpecializableEncoder\n{\n    /**\n     * Create new encoder object\n     *\n     * @return void\n     */\n    public function __construct(public bool $interlaced = false, public bool $indexed = false)\n    {\n        //\n    }\n}\n"
  },
  {
    "path": "src/Encoders/TiffEncoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Encoders;\n\nuse Intervention\\Image\\Drivers\\SpecializableEncoder;\n\nclass TiffEncoder extends SpecializableEncoder\n{\n    /**\n     * Create new encoder object\n     *\n     * @param null|bool $strip Strip EXIF metadata\n     * @return void\n     */\n    public function __construct(\n        public int $quality = self::DEFAULT_QUALITY,\n        public ?bool $strip = null\n    ) {\n        //\n    }\n}\n"
  },
  {
    "path": "src/Encoders/WebpEncoder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Encoders;\n\nuse Intervention\\Image\\Drivers\\SpecializableEncoder;\n\nclass WebpEncoder extends SpecializableEncoder\n{\n    /**\n     * Create new encoder object\n     *\n     * @param null|bool $strip Strip EXIF metadata\n     * @return void\n     */\n    public function __construct(\n        public int $quality = self::DEFAULT_QUALITY,\n        public ?bool $strip = null\n    ) {\n        //\n    }\n}\n"
  },
  {
    "path": "src/Exceptions/AnimationException.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Exceptions;\n\nclass AnimationException extends RuntimeException\n{\n    //\n}\n"
  },
  {
    "path": "src/Exceptions/ColorException.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Exceptions;\n\nclass ColorException extends RuntimeException\n{\n    //\n}\n"
  },
  {
    "path": "src/Exceptions/DecoderException.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Exceptions;\n\nclass DecoderException extends RuntimeException\n{\n    //\n}\n"
  },
  {
    "path": "src/Exceptions/DriverException.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Exceptions;\n\nclass DriverException extends RuntimeException\n{\n    //\n}\n"
  },
  {
    "path": "src/Exceptions/EncoderException.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Exceptions;\n\nclass EncoderException extends RuntimeException\n{\n    //\n}\n"
  },
  {
    "path": "src/Exceptions/FontException.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Exceptions;\n\nclass FontException extends RuntimeException\n{\n    //\n}\n"
  },
  {
    "path": "src/Exceptions/GeometryException.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Exceptions;\n\nclass GeometryException extends RuntimeException\n{\n    //\n}\n"
  },
  {
    "path": "src/Exceptions/InputException.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Exceptions;\n\nclass InputException extends RuntimeException\n{\n    //\n}\n"
  },
  {
    "path": "src/Exceptions/NotSupportedException.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Exceptions;\n\nclass NotSupportedException extends RuntimeException\n{\n    //\n}\n"
  },
  {
    "path": "src/Exceptions/NotWritableException.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Exceptions;\n\nclass NotWritableException extends RuntimeException\n{\n    //\n}\n"
  },
  {
    "path": "src/Exceptions/RuntimeException.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Exceptions;\n\nclass RuntimeException extends \\RuntimeException\n{\n    //\n}\n"
  },
  {
    "path": "src/File.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image;\n\nuse Intervention\\Image\\Exceptions\\NotWritableException;\nuse Intervention\\Image\\Exceptions\\RuntimeException;\nuse Intervention\\Image\\Interfaces\\FileInterface;\nuse Intervention\\Image\\Traits\\CanBuildFilePointer;\nuse Stringable;\n\nclass File implements FileInterface, Stringable\n{\n    use CanBuildFilePointer;\n\n    /**\n     * @var resource\n     */\n    protected $pointer;\n\n    /**\n     * Create new instance\n     *\n     * @param string|resource|null $data\n     * @throws RuntimeException\n     */\n    public function __construct(mixed $data = null)\n    {\n        $this->pointer = $this->buildFilePointer($data);\n    }\n\n    /**\n     * Create file object from path in file system\n     *\n     * @throws RuntimeException\n     */\n    public static function fromPath(string $path): self\n    {\n        return new self(fopen($path, 'r'));\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see FileInterface::save()\n     */\n    public function save(string $filepath): void\n    {\n        $dir = pathinfo($filepath, PATHINFO_DIRNAME);\n\n        if (!is_dir($dir)) {\n            throw new NotWritableException(\n                \"Can't write image to path. Directory does not exist.\"\n            );\n        }\n\n        if (!is_writable($dir)) {\n            throw new NotWritableException(\n                \"Can't write image to path. Directory is not writable.\"\n            );\n        }\n\n        if (is_file($filepath) && !is_writable($filepath)) {\n            throw new NotWritableException(\n                sprintf(\"Can't write image. Path (%s) is not writable.\", $filepath)\n            );\n        }\n\n        // write data\n        $saved = @file_put_contents($filepath, $this->toFilePointer());\n        if ($saved === false) {\n            throw new NotWritableException(\n                sprintf(\"Can't write image data to path (%s).\", $filepath)\n            );\n        }\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see FileInterface::toString()\n     */\n    public function toString(): string\n    {\n        return stream_get_contents($this->toFilePointer(), offset: 0);\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see FileInterface::toFilePointer()\n     */\n    public function toFilePointer()\n    {\n        rewind($this->pointer);\n\n        return $this->pointer;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see FileInterface::size()\n     */\n    public function size(): int\n    {\n        $info = fstat($this->toFilePointer());\n\n        return intval($info['size']);\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see FileInterface::__toString()\n     */\n    public function __toString(): string\n    {\n        return $this->toString();\n    }\n}\n"
  },
  {
    "path": "src/FileExtension.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image;\n\nuse Error;\nuse Intervention\\Image\\Exceptions\\NotSupportedException;\n\nenum FileExtension: string\n{\n    case JPG = 'jpg';\n    case JPEG = 'jpeg';\n    case WEBP = 'webp';\n    case AVIF = 'avif';\n    case BMP = 'bmp';\n    case GIF = 'gif';\n    case PNG = 'png';\n    case TIF = 'tif';\n    case TIFF = 'tiff';\n    case JP2 = 'jp2';\n    case J2K = 'j2k';\n    case JP2K = 'jp2k';\n    case JPF = 'jpf';\n    case JPM = 'jpm';\n    case JPG2 = 'jpg2';\n    case J2C = 'j2c';\n    case JPC = 'jpc';\n    case JPX = 'jpx';\n    case HEIC = 'heic';\n    case HEIF = 'heif';\n\n    /**\n     * Create file extension from given identifier\n     *\n     * @param string|Format|MediaType|FileExtension $identifier\n     * @throws NotSupportedException\n     */\n    public static function create(string|self|Format|MediaType $identifier): self\n    {\n        if ($identifier instanceof self) {\n            return $identifier;\n        }\n\n        if ($identifier instanceof Format) {\n            return $identifier->fileExtension();\n        }\n\n        if ($identifier instanceof MediaType) {\n            return $identifier->fileExtension();\n        }\n\n        try {\n            $extension = self::from(strtolower($identifier));\n        } catch (Error) {\n            try {\n                $extension = MediaType::from(strtolower($identifier))->fileExtension();\n            } catch (Error) {\n                throw new NotSupportedException('Unable to create file extension from \"' . $identifier . '\".');\n            }\n        }\n\n        return $extension;\n    }\n\n    /**\n     * Try to create media type from given identifier and return null on failure\n     *\n     * @param string|Format|MediaType|FileExtension $identifier\n     * @return FileExtension|null\n     */\n    public static function tryCreate(string|self|Format|MediaType $identifier): ?self\n    {\n        try {\n            return self::create($identifier);\n        } catch (NotSupportedException) {\n            return null;\n        }\n    }\n\n    /**\n     * Return the matching format for the current file extension\n     */\n    public function format(): Format\n    {\n        return match ($this) {\n            self::JPEG,\n            self::JPG => Format::JPEG,\n            self::WEBP => Format::WEBP,\n            self::GIF => Format::GIF,\n            self::PNG => Format::PNG,\n            self::AVIF => Format::AVIF,\n            self::BMP => Format::BMP,\n            self::TIF,\n            self::TIFF => Format::TIFF,\n            self::JP2,\n            self::JP2K,\n            self::J2K,\n            self::JPF,\n            self::JPM,\n            self::JPG2,\n            self::J2C,\n            self::JPC,\n            self::JPX => Format::JP2,\n            self::HEIC,\n            self::HEIF => Format::HEIC,\n        };\n    }\n\n    /**\n     * Return media types for the current format\n     *\n     * @return array<MediaType>\n     */\n    public function mediaTypes(): array\n    {\n        return $this->format()->mediaTypes();\n    }\n\n    /**\n     * Return the first found media type for the current format\n     */\n    public function mediaType(): MediaType\n    {\n        return $this->format()->mediaType();\n    }\n}\n"
  },
  {
    "path": "src/Format.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image;\n\nuse Error;\nuse Intervention\\Image\\Encoders\\AvifEncoder;\nuse Intervention\\Image\\Encoders\\BmpEncoder;\nuse Intervention\\Image\\Encoders\\GifEncoder;\nuse Intervention\\Image\\Encoders\\HeicEncoder;\nuse Intervention\\Image\\Encoders\\Jpeg2000Encoder;\nuse Intervention\\Image\\Encoders\\JpegEncoder;\nuse Intervention\\Image\\Encoders\\PngEncoder;\nuse Intervention\\Image\\Encoders\\TiffEncoder;\nuse Intervention\\Image\\Encoders\\WebpEncoder;\nuse Intervention\\Image\\Exceptions\\NotSupportedException;\nuse Intervention\\Image\\Interfaces\\EncoderInterface;\nuse ReflectionClass;\nuse ReflectionParameter;\n\nenum Format\n{\n    case AVIF;\n    case BMP;\n    case GIF;\n    case HEIC;\n    case JP2;\n    case JPEG;\n    case PNG;\n    case TIFF;\n    case WEBP;\n\n    /**\n     * Create format from given identifier\n     *\n     * @param string|Format|MediaType|FileExtension $identifier\n     * @throws NotSupportedException\n     */\n    public static function create(string|self|MediaType|FileExtension $identifier): self\n    {\n        if ($identifier instanceof self) {\n            return $identifier;\n        }\n\n        if ($identifier instanceof MediaType) {\n            return $identifier->format();\n        }\n\n        if ($identifier instanceof FileExtension) {\n            return $identifier->format();\n        }\n\n        try {\n            $format = MediaType::from(strtolower($identifier))->format();\n        } catch (Error) {\n            try {\n                $format = FileExtension::from(strtolower($identifier))->format();\n            } catch (Error) {\n                throw new NotSupportedException('Unable to create format from \"' . $identifier . '\".');\n            }\n        }\n\n        return $format;\n    }\n\n    /**\n     * Try to create format from given identifier and return null on failure\n     *\n     * @param string|Format|MediaType|FileExtension $identifier\n     * @return Format|null\n     */\n    public static function tryCreate(string|self|MediaType|FileExtension $identifier): ?self\n    {\n        try {\n            return self::create($identifier);\n        } catch (NotSupportedException) {\n            return null;\n        }\n    }\n\n    /**\n     * Return the possible media (MIME) types for the current format\n     *\n     * @return array<MediaType>\n     */\n    public function mediaTypes(): array\n    {\n        return array_filter(\n            MediaType::cases(),\n            fn(MediaType $mediaType): bool => $mediaType->format() === $this\n        );\n    }\n\n    /**\n     * Return the first found media type for the current format\n     */\n    public function mediaType(): MediaType\n    {\n        $types = $this->mediaTypes();\n\n        return reset($types);\n    }\n\n    /**\n     * Return the possible file extension for the current format\n     *\n     * @return array<FileExtension>\n     */\n    public function fileExtensions(): array\n    {\n        return array_filter(\n            FileExtension::cases(),\n            fn(FileExtension $fileExtension): bool => $fileExtension->format() === $this\n        );\n    }\n\n    /**\n     * Return the first found file extension for the current format\n     */\n    public function fileExtension(): FileExtension\n    {\n        $extensions = $this->fileExtensions();\n\n        return reset($extensions);\n    }\n\n    /**\n     * Create an encoder instance with given options that matches the format\n     */\n    public function encoder(mixed ...$options): EncoderInterface\n    {\n        // get classname of target encoder from current format\n        $classname = match ($this) {\n            self::AVIF => AvifEncoder::class,\n            self::BMP => BmpEncoder::class,\n            self::GIF => GifEncoder::class,\n            self::HEIC => HeicEncoder::class,\n            self::JP2 => Jpeg2000Encoder::class,\n            self::JPEG => JpegEncoder::class,\n            self::PNG => PngEncoder::class,\n            self::TIFF => TiffEncoder::class,\n            self::WEBP => WebpEncoder::class,\n        };\n\n        // get parameters of target encoder\n        $parameters = [];\n        $reflectionClass = new ReflectionClass($classname);\n        if ($constructor = $reflectionClass->getConstructor()) {\n            $parameters = array_map(\n                fn(ReflectionParameter $parameter): string => $parameter->getName(),\n                $constructor->getParameters(),\n            );\n        }\n\n        // filter out unavailable options of target encoder\n        $options = array_filter(\n            $options,\n            fn(mixed $key): bool => in_array($key, $parameters),\n            ARRAY_FILTER_USE_KEY,\n        );\n\n        return new $classname(...$options);\n    }\n}\n"
  },
  {
    "path": "src/Geometry/Bezier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Geometry;\n\nuse ArrayAccess;\nuse ArrayIterator;\nuse Countable;\nuse Traversable;\nuse IteratorAggregate;\nuse Intervention\\Image\\Geometry\\Traits\\HasBackgroundColor;\nuse Intervention\\Image\\Geometry\\Traits\\HasBorder;\nuse Intervention\\Image\\Interfaces\\DrawableInterface;\nuse Intervention\\Image\\Interfaces\\PointInterface;\n\n/**\n * @implements IteratorAggregate<PointInterface>\n * @implements ArrayAccess<int, PointInterface>\n */\nclass Bezier implements IteratorAggregate, Countable, ArrayAccess, DrawableInterface\n{\n    use HasBorder;\n    use HasBackgroundColor;\n\n    /**\n     * Create new bezier instance\n     *\n     * @param array<PointInterface> $points\n     * @return void\n     */\n    public function __construct(\n        protected array $points = [],\n        protected PointInterface $pivot = new Point()\n    ) {\n        //\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DrawableInterface::position()\n     */\n    public function position(): PointInterface\n    {\n        return $this->pivot;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DrawableInterface::setPosition()\n     */\n    public function setPosition(PointInterface $position): DrawableInterface\n    {\n        $this->pivot = $position;\n\n        return $this;\n    }\n\n    /**\n     * Implement iteration through all points of bezier\n     *\n     * @return Traversable<PointInterface>\n     */\n    public function getIterator(): Traversable\n    {\n        return new ArrayIterator($this->points);\n    }\n\n    /**\n     * Return current pivot point\n     */\n    public function pivot(): PointInterface\n    {\n        return $this->pivot;\n    }\n\n    /**\n     * Change pivot point to given point\n     */\n    public function setPivot(PointInterface $pivot): self\n    {\n        $this->pivot = $pivot;\n\n        return $this;\n    }\n\n    /**\n     * Return first control point of bezier\n     */\n    public function first(): ?PointInterface\n    {\n        if ($point = reset($this->points)) {\n            return $point;\n        }\n\n        return null;\n    }\n\n    /**\n     * Return second control point of bezier\n     */\n    public function second(): ?PointInterface\n    {\n        if (array_key_exists(1, $this->points)) {\n            return $this->points[1];\n        }\n\n        return null;\n    }\n\n    /**\n     * Return third control point of bezier\n     */\n    public function third(): ?PointInterface\n    {\n        if (array_key_exists(2, $this->points)) {\n            return $this->points[2];\n        }\n\n        return null;\n    }\n\n    /**\n     * Return last control point of bezier\n     */\n    public function last(): ?PointInterface\n    {\n        if ($point = end($this->points)) {\n            return $point;\n        }\n\n        return null;\n    }\n\n    /**\n     * Return bezier's point count\n     */\n    public function count(): int\n    {\n        return count($this->points);\n    }\n\n    /**\n     * Determine if point exists at given offset\n     */\n    public function offsetExists(mixed $offset): bool\n    {\n        return array_key_exists($offset, $this->points);\n    }\n\n    /**\n     * Return point at given offset\n     */\n    public function offsetGet(mixed $offset): mixed\n    {\n        return $this->points[$offset];\n    }\n\n    /**\n     * Set point at given offset\n     */\n    public function offsetSet(mixed $offset, mixed $value): void\n    {\n        $this->points[$offset] = $value;\n    }\n\n    /**\n     * Unset offset at given offset\n     */\n    public function offsetUnset(mixed $offset): void\n    {\n        unset($this->points[$offset]);\n    }\n\n    /**\n     * Add given point to bezier\n     */\n    public function addPoint(PointInterface $point): self\n    {\n        $this->points[] = $point;\n\n        return $this;\n    }\n\n    /**\n     * Return array of all x/y values of all points of bezier\n     *\n     * @return array<int>\n     */\n    public function toArray(): array\n    {\n        $coordinates = [];\n        foreach ($this->points as $point) {\n            $coordinates[] = $point->x();\n            $coordinates[] = $point->y();\n        }\n\n        return $coordinates;\n    }\n}\n"
  },
  {
    "path": "src/Geometry/Circle.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Geometry;\n\nuse Intervention\\Image\\Interfaces\\PointInterface;\n\nclass Circle extends Ellipse\n{\n    /**\n     * Create new Circle instance\n     *\n     * @return void\n     */\n    public function __construct(\n        int $diameter,\n        PointInterface $pivot = new Point()\n    ) {\n        parent::__construct($diameter, $diameter, $pivot);\n    }\n\n    /**\n     * Set diameter of circle\n     */\n    public function setDiameter(int $diameter): self\n    {\n        $this->setWidth($diameter);\n        $this->setHeight($diameter);\n\n        return $this;\n    }\n\n    /**\n     * Get diameter of circle\n     */\n    public function diameter(): int\n    {\n        return $this->width();\n    }\n\n    /**\n     * Set radius of circle\n     */\n    public function setRadius(int $radius): self\n    {\n        return $this->setDiameter(intval($radius * 2));\n    }\n\n    /**\n     * Get radius of circle\n     */\n    public function radius(): int\n    {\n        return intval(round($this->diameter() / 2));\n    }\n}\n"
  },
  {
    "path": "src/Geometry/Ellipse.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Geometry;\n\nuse Intervention\\Image\\Geometry\\Traits\\HasBackgroundColor;\nuse Intervention\\Image\\Geometry\\Traits\\HasBorder;\nuse Intervention\\Image\\Interfaces\\DrawableInterface;\nuse Intervention\\Image\\Interfaces\\PointInterface;\n\nclass Ellipse implements DrawableInterface\n{\n    use HasBorder;\n    use HasBackgroundColor;\n\n    /**\n     * Create new Ellipse\n     *\n     * @return void\n     */\n    public function __construct(\n        protected int $width,\n        protected int $height,\n        protected PointInterface $pivot = new Point()\n    ) {\n        //\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DrawableInterface::position()\n     */\n    public function position(): PointInterface\n    {\n        return $this->pivot;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DrawableInterface::setPosition()\n     */\n    public function setPosition(PointInterface $position): self\n    {\n        $this->pivot = $position;\n\n        return $this;\n    }\n\n    /**\n     * Return pivot point of Ellipse\n     */\n    public function pivot(): PointInterface\n    {\n        return $this->pivot;\n    }\n\n    /**\n     * Set size of Ellipse\n     */\n    public function setSize(int $width, int $height): self\n    {\n        return $this->setWidth($width)->setHeight($height);\n    }\n\n    /**\n     * Set width of Ellipse\n     */\n    public function setWidth(int $width): self\n    {\n        $this->width = $width;\n\n        return $this;\n    }\n\n    /**\n     * Set height of Ellipse\n     */\n    public function setHeight(int $height): self\n    {\n        $this->height = $height;\n\n        return $this;\n    }\n\n    /**\n     * Get width of Ellipse\n     */\n    public function width(): int\n    {\n        return $this->width;\n    }\n\n    /**\n     * Get height of Ellipse\n     */\n    public function height(): int\n    {\n        return $this->height;\n    }\n}\n"
  },
  {
    "path": "src/Geometry/Factories/BezierFactory.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Geometry\\Factories;\n\nuse Closure;\nuse Intervention\\Image\\Geometry\\Point;\nuse Intervention\\Image\\Geometry\\Bezier;\nuse Intervention\\Image\\Interfaces\\DrawableFactoryInterface;\nuse Intervention\\Image\\Interfaces\\DrawableInterface;\n\nclass BezierFactory implements DrawableFactoryInterface\n{\n    protected Bezier $bezier;\n\n    /**\n     * Create new factory instance\n     *\n     * @return void\n     */\n    public function __construct(null|Closure|Bezier $init = null)\n    {\n        $this->bezier = is_a($init, Bezier::class) ? $init : new Bezier([]);\n\n        if (is_callable($init)) {\n            $init($this);\n        }\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DrawableFactoryInterface::init()\n     */\n    public static function init(null|Closure|DrawableInterface $init = null): self\n    {\n        return new self($init);\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DrawableFactoryInterface::create()\n     */\n    public function create(): DrawableInterface\n    {\n        return $this->bezier;\n    }\n\n    /**\n     * Add a point to the bezier to be produced\n     */\n    public function point(int $x, int $y): self\n    {\n        $this->bezier->addPoint(new Point($x, $y));\n\n        return $this;\n    }\n\n    /**\n     * Set the background color of the bezier to be produced\n     */\n    public function background(mixed $color): self\n    {\n        $this->bezier->setBackgroundColor($color);\n\n        return $this;\n    }\n\n    /**\n     * Set the border color & border size of the bezier to be produced\n     */\n    public function border(mixed $color, int $size = 1): self\n    {\n        $this->bezier->setBorder($color, $size);\n\n        return $this;\n    }\n\n    /**\n     * Produce the bezier\n     */\n    public function __invoke(): Bezier\n    {\n        return $this->bezier;\n    }\n}\n"
  },
  {
    "path": "src/Geometry/Factories/CircleFactory.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Geometry\\Factories;\n\nuse Closure;\nuse Intervention\\Image\\Geometry\\Circle;\nuse Intervention\\Image\\Geometry\\Point;\nuse Intervention\\Image\\Interfaces\\DrawableFactoryInterface;\nuse Intervention\\Image\\Interfaces\\DrawableInterface;\nuse Intervention\\Image\\Interfaces\\PointInterface;\n\nclass CircleFactory implements DrawableFactoryInterface\n{\n    protected Circle $circle;\n\n    /**\n     * Create new factory instance\n     *\n     * @return void\n     */\n    public function __construct(\n        protected PointInterface $pivot = new Point(),\n        null|Closure|Circle $init = null,\n    ) {\n        $this->circle = is_a($init, Circle::class) ? $init : new Circle(0);\n        $this->circle->setPosition($pivot);\n\n        if (is_callable($init)) {\n            $init($this);\n        }\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DrawableFactoryInterface::init()\n     */\n    public static function init(null|Closure|DrawableInterface $init = null): self\n    {\n        return new self(init: $init);\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DrawableFactoryInterface::create()\n     */\n    public function create(): DrawableInterface\n    {\n        return $this->circle;\n    }\n\n    /**\n     * Set the radius of the circle to be produced\n     */\n    public function radius(int $radius): self\n    {\n        $this->circle->setSize($radius * 2, $radius * 2);\n\n        return $this;\n    }\n\n    /**\n     * Set the diameter of the circle to be produced\n     */\n    public function diameter(int $diameter): self\n    {\n        $this->circle->setSize($diameter, $diameter);\n\n        return $this;\n    }\n\n    /**\n     * Set the background color of the circle to be produced\n     */\n    public function background(mixed $color): self\n    {\n        $this->circle->setBackgroundColor($color);\n\n        return $this;\n    }\n\n    /**\n     * Set the border color & border size of the ellipse to be produced\n     */\n    public function border(mixed $color, int $size = 1): self\n    {\n        $this->circle->setBorder($color, $size);\n\n        return $this;\n    }\n\n    /**\n     * Produce the circle\n     */\n    public function __invoke(): Circle\n    {\n        return $this->circle;\n    }\n}\n"
  },
  {
    "path": "src/Geometry/Factories/Drawable.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Geometry\\Factories;\n\nclass Drawable\n{\n    /**\n     * Creeate BezierFactory statically\n     */\n    public static function bezier(): BezierFactory\n    {\n        return new BezierFactory();\n    }\n\n    /**\n     * Creeate CircleFactory statically\n     */\n    public static function circle(): CircleFactory\n    {\n        return new CircleFactory();\n    }\n\n    /**\n     * Create EllipseFactory statically\n     */\n    public static function ellipse(): EllipseFactory\n    {\n        return new EllipseFactory();\n    }\n\n    /**\n     * Creeate LineFactory statically\n     */\n    public static function line(): LineFactory\n    {\n        return new LineFactory();\n    }\n\n    /**\n     * Creeate PolygonFactory statically\n     */\n    public static function polygon(): PolygonFactory\n    {\n        return new PolygonFactory();\n    }\n\n    /**\n     * Creeate RectangleFactory statically\n     */\n    public static function rectangle(): RectangleFactory\n    {\n        return new RectangleFactory();\n    }\n}\n"
  },
  {
    "path": "src/Geometry/Factories/EllipseFactory.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Geometry\\Factories;\n\nuse Closure;\nuse Intervention\\Image\\Geometry\\Ellipse;\nuse Intervention\\Image\\Geometry\\Point;\nuse Intervention\\Image\\Interfaces\\DrawableFactoryInterface;\nuse Intervention\\Image\\Interfaces\\DrawableInterface;\nuse Intervention\\Image\\Interfaces\\PointInterface;\n\nclass EllipseFactory implements DrawableFactoryInterface\n{\n    protected Ellipse $ellipse;\n\n    /**\n     * Create new factory instance\n     *\n     * @return void\n     */\n    public function __construct(\n        protected PointInterface $pivot = new Point(),\n        null|Closure|Ellipse $init = null,\n    ) {\n        $this->ellipse = is_a($init, Ellipse::class) ? $init : new Ellipse(0, 0);\n        $this->ellipse->setPosition($pivot);\n\n        if (is_callable($init)) {\n            $init($this);\n        }\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DrawableFactoryInterface::init()\n     */\n    public static function init(null|Closure|DrawableInterface $init = null): self\n    {\n        return new self(init: $init);\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DrawableFactoryInterface::create()\n     */\n    public function create(): DrawableInterface\n    {\n        return $this->ellipse;\n    }\n\n    /**\n     * Set the size of the ellipse to be produced\n     */\n    public function size(int $width, int $height): self\n    {\n        $this->ellipse->setSize($width, $height);\n\n        return $this;\n    }\n\n    /**\n     * Set the width of the ellipse to be produced\n     */\n    public function width(int $width): self\n    {\n        $this->ellipse->setWidth($width);\n\n        return $this;\n    }\n\n    /**\n     * Set the height of the ellipse to be produced\n     */\n    public function height(int $height): self\n    {\n        $this->ellipse->setHeight($height);\n\n        return $this;\n    }\n\n    /**\n     * Set the background color of the ellipse to be produced\n     */\n    public function background(mixed $color): self\n    {\n        $this->ellipse->setBackgroundColor($color);\n\n        return $this;\n    }\n\n    /**\n     * Set the border color & border size of the ellipse to be produced\n     */\n    public function border(mixed $color, int $size = 1): self\n    {\n        $this->ellipse->setBorder($color, $size);\n\n        return $this;\n    }\n\n    /**\n     * Produce the ellipse\n     */\n    public function __invoke(): Ellipse\n    {\n        return $this->ellipse;\n    }\n}\n"
  },
  {
    "path": "src/Geometry/Factories/LineFactory.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Geometry\\Factories;\n\nuse Closure;\nuse Intervention\\Image\\Geometry\\Point;\nuse Intervention\\Image\\Geometry\\Line;\nuse Intervention\\Image\\Interfaces\\DrawableFactoryInterface;\nuse Intervention\\Image\\Interfaces\\DrawableInterface;\n\nclass LineFactory implements DrawableFactoryInterface\n{\n    protected Line $line;\n\n    /**\n     * Create the factory instance\n     *\n     * @return void\n     */\n    public function __construct(null|Closure|Line $init = null)\n    {\n        $this->line = is_a($init, Line::class) ? $init : new Line(new Point(), new Point());\n\n        if (is_callable($init)) {\n            $init($this);\n        }\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DrawableFactoryInterface::init()\n     */\n    public static function init(null|Closure|DrawableInterface $init = null): self\n    {\n        return new self($init);\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DrawableFactoryInterface::create()\n     */\n    public function create(): DrawableInterface\n    {\n        return $this->line;\n    }\n\n    /**\n     * Set the color of the line to be produced\n     */\n    public function color(mixed $color): self\n    {\n        $this->line->setBackgroundColor($color);\n        $this->line->setBorderColor($color);\n\n        return $this;\n    }\n\n    /**\n     * Set the (background) color of the line to be produced\n     */\n    public function background(mixed $color): self\n    {\n        $this->line->setBackgroundColor($color);\n        $this->line->setBorderColor($color);\n\n        return $this;\n    }\n\n    /**\n     * Set the border size & border color of the line to be produced\n     */\n    public function border(mixed $color, int $size = 1): self\n    {\n        $this->line->setBackgroundColor($color);\n        $this->line->setBorderColor($color);\n        $this->line->setWidth($size);\n\n        return $this;\n    }\n\n    /**\n     * Set the width of the line to be produced\n     */\n    public function width(int $size): self\n    {\n        $this->line->setWidth($size);\n\n        return $this;\n    }\n\n    /**\n     * Set the coordinates of the starting point of the line to be produced\n     */\n    public function from(int $x, int $y): self\n    {\n        $this->line->setStart(new Point($x, $y));\n\n        return $this;\n    }\n\n    /**\n     * Set the coordinates of the end point of the line to be produced\n     */\n    public function to(int $x, int $y): self\n    {\n        $this->line->setEnd(new Point($x, $y));\n\n        return $this;\n    }\n\n    /**\n     * Produce the line\n     */\n    public function __invoke(): Line\n    {\n        return $this->line;\n    }\n}\n"
  },
  {
    "path": "src/Geometry/Factories/PolygonFactory.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Geometry\\Factories;\n\nuse Closure;\nuse Intervention\\Image\\Geometry\\Point;\nuse Intervention\\Image\\Geometry\\Polygon;\nuse Intervention\\Image\\Interfaces\\DrawableFactoryInterface;\nuse Intervention\\Image\\Interfaces\\DrawableInterface;\n\nclass PolygonFactory implements DrawableFactoryInterface\n{\n    protected Polygon $polygon;\n\n    /**\n     * Create new factory instance\n     *\n     * @return void\n     */\n    public function __construct(null|Closure|Polygon $init = null)\n    {\n        $this->polygon = is_a($init, Polygon::class) ? $init : new Polygon([]);\n\n        if (is_callable($init)) {\n            $init($this);\n        }\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DrawableFactoryInterface::init()\n     */\n    public static function init(null|Closure|DrawableInterface $init = null): self\n    {\n        return new self($init);\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DrawableFactoryInterface::create()\n     */\n    public function create(): DrawableInterface\n    {\n        return $this->polygon;\n    }\n\n    /**\n     * Add a point to the polygon to be produced\n     */\n    public function point(int $x, int $y): self\n    {\n        $this->polygon->addPoint(new Point($x, $y));\n\n        return $this;\n    }\n\n    /**\n     * Set the background color of the polygon to be produced\n     */\n    public function background(mixed $color): self\n    {\n        $this->polygon->setBackgroundColor($color);\n\n        return $this;\n    }\n\n    /**\n     * Set the border color & border size of the polygon to be produced\n     */\n    public function border(mixed $color, int $size = 1): self\n    {\n        $this->polygon->setBorder($color, $size);\n\n        return $this;\n    }\n\n    /**\n     * Produce the polygon\n     */\n    public function __invoke(): Polygon\n    {\n        return $this->polygon;\n    }\n}\n"
  },
  {
    "path": "src/Geometry/Factories/RectangleFactory.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Geometry\\Factories;\n\nuse Closure;\nuse Intervention\\Image\\Geometry\\Point;\nuse Intervention\\Image\\Geometry\\Rectangle;\nuse Intervention\\Image\\Interfaces\\DrawableFactoryInterface;\nuse Intervention\\Image\\Interfaces\\DrawableInterface;\nuse Intervention\\Image\\Interfaces\\PointInterface;\n\nclass RectangleFactory implements DrawableFactoryInterface\n{\n    protected Rectangle $rectangle;\n\n    /**\n     * Create new instance\n     *\n     * @return void\n     */\n    public function __construct(\n        protected PointInterface $pivot = new Point(),\n        null|Closure|Rectangle $init = null,\n    ) {\n        $this->rectangle = is_a($init, Rectangle::class) ? $init : new Rectangle(0, 0, $pivot);\n        $this->rectangle->setPosition($pivot);\n\n        if (is_callable($init)) {\n            $init($this);\n        }\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DrawableFactoryInterface::init()\n     */\n    public static function init(null|Closure|DrawableInterface $init = null): self\n    {\n        return new self(init: $init);\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DrawableFactoryInterface::create()\n     */\n    public function create(): DrawableInterface\n    {\n        return $this->rectangle;\n    }\n\n    /**\n     * Set the size of the rectangle to be produced\n     */\n    public function size(int $width, int $height): self\n    {\n        $this->rectangle->setSize($width, $height);\n\n        return $this;\n    }\n\n    /**\n     * Set the width of the rectangle to be produced\n     */\n    public function width(int $width): self\n    {\n        $this->rectangle->setWidth($width);\n\n        return $this;\n    }\n\n    /**\n     * Set the height of the rectangle to be produced\n     */\n    public function height(int $height): self\n    {\n        $this->rectangle->setHeight($height);\n\n        return $this;\n    }\n\n    /**\n     * Set the background color of the rectangle to be produced\n     */\n    public function background(mixed $color): self\n    {\n        $this->rectangle->setBackgroundColor($color);\n\n        return $this;\n    }\n\n    /**\n     * Set the border color & border size of the rectangle to be produced\n     */\n    public function border(mixed $color, int $size = 1): self\n    {\n        $this->rectangle->setBorder($color, $size);\n\n        return $this;\n    }\n\n    /**\n     * Produce the rectangle\n     */\n    public function __invoke(): Rectangle\n    {\n        return $this->rectangle;\n    }\n}\n"
  },
  {
    "path": "src/Geometry/Line.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Geometry;\n\nuse Intervention\\Image\\Geometry\\Traits\\HasBackgroundColor;\nuse Intervention\\Image\\Geometry\\Traits\\HasBorder;\nuse Intervention\\Image\\Interfaces\\DrawableInterface;\nuse Intervention\\Image\\Interfaces\\PointInterface;\n\nclass Line implements DrawableInterface\n{\n    use HasBorder;\n    use HasBackgroundColor;\n\n    /**\n     * Create new line instance\n     *\n     * @return void\n     */\n    public function __construct(\n        protected PointInterface $start,\n        protected PointInterface $end,\n        protected int $width = 1\n    ) {\n        //\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DrawableInterface::position()\n     */\n    public function position(): PointInterface\n    {\n        return $this->start;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DrawableInterface::setPosition()\n     */\n    public function setPosition(PointInterface $position): DrawableInterface\n    {\n        $this->start = $position;\n\n        return $this;\n    }\n\n    /**\n     * Return line width\n     */\n    public function width(): int\n    {\n        return $this->width;\n    }\n\n    /**\n     * Set line width\n     */\n    public function setWidth(int $width): self\n    {\n        $this->width = $width;\n\n        return $this;\n    }\n\n    /**\n     * Get starting point of line\n     */\n    public function start(): PointInterface\n    {\n        return $this->start;\n    }\n\n    /**\n     * get end point of line\n     */\n    public function end(): PointInterface\n    {\n        return $this->end;\n    }\n\n    /**\n     * Set starting point of line\n     */\n    public function setStart(PointInterface $start): self\n    {\n        $this->start = $start;\n\n        return $this;\n    }\n\n    /**\n     * Set starting point of line by coordinates\n     */\n    public function from(int $x, int $y): self\n    {\n        $this->start()->setX($x);\n        $this->start()->setY($y);\n\n        return $this;\n    }\n\n    /**\n     * Set end point of line by coordinates\n     */\n    public function to(int $x, int $y): self\n    {\n        $this->end()->setX($x);\n        $this->end()->setY($y);\n\n        return $this;\n    }\n\n    /**\n     * Set end point of line\n     */\n    public function setEnd(PointInterface $end): self\n    {\n        $this->end = $end;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/Geometry/Pixel.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Geometry;\n\nuse Intervention\\Image\\Interfaces\\ColorInterface;\n\nclass Pixel extends Point\n{\n    /**\n     * Create new pixel instance\n     *\n     * @return void\n     */\n    public function __construct(\n        protected ColorInterface $background,\n        protected int $x,\n        protected int $y\n    ) {\n        //\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DrawableInterface::setBackgroundColor()\n     */\n    public function setBackgroundColor(ColorInterface $background): self\n    {\n        $this->background = $background;\n\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DrawableInterface::backgroundColor()\n     */\n    public function backgroundColor(): ColorInterface\n    {\n        return $this->background;\n    }\n}\n"
  },
  {
    "path": "src/Geometry/Point.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Geometry;\n\nuse ArrayIterator;\nuse Intervention\\Image\\Interfaces\\PointInterface;\nuse IteratorAggregate;\nuse Traversable;\n\n/**\n * @implements IteratorAggregate<int>\n */\nclass Point implements PointInterface, IteratorAggregate\n{\n    /**\n     * Create new point instance\n     *\n     * @return void\n     */\n    public function __construct(\n        protected int $x = 0,\n        protected int $y = 0\n    ) {\n        //\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see IteratorAggregate::getIterator()\n     */\n    public function getIterator(): Traversable\n    {\n        return new ArrayIterator([$this->x, $this->y]);\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see PointInterface::setX()\n     */\n    public function setX(int $x): self\n    {\n        $this->x = $x;\n\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see PointInterface::x()\n     */\n    public function x(): int\n    {\n        return $this->x;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see PointInterface::setY()\n     */\n    public function setY(int $y): self\n    {\n        $this->y = $y;\n\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see PointInterface::y()\n     */\n    public function y(): int\n    {\n        return $this->y;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see PointInterface::moveX()\n     */\n    public function moveX(int $value): self\n    {\n        $this->x += $value;\n\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see PointInterface::moveY()\n     */\n    public function moveY(int $value): self\n    {\n        $this->y += $value;\n\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see PointInterface::move()\n     */\n    public function move(int $x, int $y): self\n    {\n        return $this->moveX($x)->moveY($y);\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see PointInterface::setPosition()\n     */\n    public function setPosition(int $x, int $y): self\n    {\n        $this->setX($x);\n        $this->setY($y);\n\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see PointInterface::rotate()\n     */\n    public function rotate(float $angle, PointInterface $pivot): self\n    {\n        $sin = round(sin(deg2rad($angle)), 6);\n        $cos = round(cos(deg2rad($angle)), 6);\n\n        return $this->setPosition(\n            intval($cos * ($this->x() - $pivot->x()) - $sin * ($this->y() - $pivot->y()) + $pivot->x()),\n            intval($sin * ($this->x() - $pivot->x()) + $cos * ($this->y() - $pivot->y()) + $pivot->y())\n        );\n    }\n}\n"
  },
  {
    "path": "src/Geometry/Polygon.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Geometry;\n\nuse ArrayAccess;\nuse ArrayIterator;\nuse Countable;\nuse Traversable;\nuse IteratorAggregate;\nuse Intervention\\Image\\Geometry\\Traits\\HasBackgroundColor;\nuse Intervention\\Image\\Geometry\\Traits\\HasBorder;\nuse Intervention\\Image\\Interfaces\\DrawableInterface;\nuse Intervention\\Image\\Interfaces\\PointInterface;\n\n/**\n * @implements IteratorAggregate<PointInterface>\n * @implements ArrayAccess<int, PointInterface>\n */\nclass Polygon implements IteratorAggregate, Countable, ArrayAccess, DrawableInterface\n{\n    use HasBorder;\n    use HasBackgroundColor;\n\n    /**\n     * Create new polygon instance\n     *\n     * @param array<PointInterface> $points\n     * @return void\n     */\n    public function __construct(\n        protected array $points = [],\n        protected PointInterface $pivot = new Point()\n    ) {\n        //\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DrawableInterface::position()\n     */\n    public function position(): PointInterface\n    {\n        return $this->pivot;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DrawableInterface::setPosition()\n     */\n    public function setPosition(PointInterface $position): self\n    {\n        $this->pivot = $position;\n\n        return $this;\n    }\n\n    /**\n     * Implement iteration through all points of polygon\n     *\n     * @return Traversable<PointInterface>\n     */\n    public function getIterator(): Traversable\n    {\n        return new ArrayIterator($this->points);\n    }\n\n    /**\n     * Return current pivot point\n     */\n    public function pivot(): PointInterface\n    {\n        return $this->pivot;\n    }\n\n    /**\n     * Change pivot point to given point\n     */\n    public function setPivot(PointInterface $pivot): self\n    {\n        $this->pivot = $pivot;\n\n        return $this;\n    }\n\n    /**\n     * Return first point of polygon\n     */\n    public function first(): ?PointInterface\n    {\n        if ($point = reset($this->points)) {\n            return $point;\n        }\n\n        return null;\n    }\n\n    /**\n     * Return last point of polygon\n     */\n    public function last(): ?PointInterface\n    {\n        if ($point = end($this->points)) {\n            return $point;\n        }\n\n        return null;\n    }\n\n    /**\n     * Return polygon's point count\n     */\n    public function count(): int\n    {\n        return count($this->points);\n    }\n\n    /**\n     * Determine if point exists at given offset\n     */\n    public function offsetExists(mixed $offset): bool\n    {\n        return array_key_exists($offset, $this->points);\n    }\n\n    /**\n     * Return point at given offset\n     */\n    public function offsetGet(mixed $offset): mixed\n    {\n        return $this->points[$offset];\n    }\n\n    /**\n     * Set point at given offset\n     */\n    public function offsetSet(mixed $offset, mixed $value): void\n    {\n        $this->points[$offset] = $value;\n    }\n\n    /**\n     * Unset offset at given offset\n     */\n    public function offsetUnset(mixed $offset): void\n    {\n        unset($this->points[$offset]);\n    }\n\n    /**\n     * Add given point to polygon\n     */\n    public function addPoint(PointInterface $point): self\n    {\n        $this->points[] = $point;\n\n        return $this;\n    }\n\n    /**\n     * Calculate total horizontal span of polygon\n     */\n    public function width(): int\n    {\n        return abs($this->mostLeftPoint()->x() - $this->mostRightPoint()->x());\n    }\n\n    /**\n     * Calculate total vertical span of polygon\n     */\n    public function height(): int\n    {\n        return abs($this->mostBottomPoint()->y() - $this->mostTopPoint()->y());\n    }\n\n    /**\n     * Return most left point of all points in polygon\n     */\n    public function mostLeftPoint(): PointInterface\n    {\n        $points = $this->points;\n\n        usort($points, function (PointInterface $a, PointInterface $b): int {\n            if ($a->x() === $b->x()) {\n                return 0;\n            }\n            return $a->x() < $b->x() ? -1 : 1;\n        });\n\n        return $points[0];\n    }\n\n    /**\n     * Return most right point in polygon\n     */\n    public function mostRightPoint(): PointInterface\n    {\n        $points = $this->points;\n\n        usort($points, function (PointInterface $a, PointInterface $b): int {\n            if ($a->x() === $b->x()) {\n                return 0;\n            }\n            return $a->x() > $b->x() ? -1 : 1;\n        });\n\n        return $points[0];\n    }\n\n    /**\n     * Return most top point in polygon\n     */\n    public function mostTopPoint(): PointInterface\n    {\n        $points = $this->points;\n\n        usort($points, function (PointInterface $a, PointInterface $b): int {\n            if ($a->y() === $b->y()) {\n                return 0;\n            }\n            return $a->y() > $b->y() ? -1 : 1;\n        });\n\n        return $points[0];\n    }\n\n    /**\n     * Return most bottom point in polygon\n     */\n    public function mostBottomPoint(): PointInterface\n    {\n        $points = $this->points;\n\n        usort($points, function (PointInterface $a, PointInterface $b): int {\n            if ($a->y() === $b->y()) {\n                return 0;\n            }\n            return $a->y() < $b->y() ? -1 : 1;\n        });\n\n        return $points[0];\n    }\n\n    /**\n     * Return point in absolute center of the polygon\n     */\n    public function centerPoint(): PointInterface\n    {\n        return new Point(\n            $this->mostRightPoint()->x() - (intval(round($this->width() / 2))),\n            $this->mostTopPoint()->y() - (intval(round($this->height() / 2)))\n        );\n    }\n\n    /**\n     * Align all points of polygon horizontally to given position around pivot point\n     */\n    public function align(string $position): self\n    {\n        switch (strtolower($position)) {\n            case 'center':\n            case 'middle':\n                $diff = $this->centerPoint()->x() - $this->pivot()->x();\n                break;\n\n            case 'right':\n                $diff = $this->mostRightPoint()->x() - $this->pivot()->x();\n                break;\n\n            default:\n            case 'left':\n                $diff = $this->mostLeftPoint()->x() - $this->pivot()->x();\n                break;\n        }\n\n        foreach ($this->points as $point) {\n            $point->setX(\n                intval($point->x() - $diff)\n            );\n        }\n\n        return $this;\n    }\n\n    /**\n     * Align all points of polygon vertically to given position around pivot point\n     */\n    public function valign(string $position): self\n    {\n        switch (strtolower($position)) {\n            case 'center':\n            case 'middle':\n                $diff = $this->centerPoint()->y() - $this->pivot()->y();\n                break;\n\n            case 'top':\n                $diff = $this->mostTopPoint()->y() - $this->pivot()->y() - $this->height();\n                break;\n\n            default:\n            case 'bottom':\n                $diff = $this->mostBottomPoint()->y() - $this->pivot()->y() + $this->height();\n                break;\n        }\n\n        foreach ($this->points as $point) {\n            $point->setY(\n                intval($point->y() - $diff),\n            );\n        }\n\n        return $this;\n    }\n\n    /**\n     * Rotate points of polygon around pivot point with given angle\n     */\n    public function rotate(float $angle): self\n    {\n        $sin = sin(deg2rad($angle));\n        $cos = cos(deg2rad($angle));\n\n        foreach ($this->points as $point) {\n            // translate point to pivot\n            $point->setX(\n                intval($point->x() - $this->pivot()->x()),\n            );\n            $point->setY(\n                intval($point->y() - $this->pivot()->y()),\n            );\n\n            // rotate point\n            $x = $point->x() * $cos - $point->y() * $sin;\n            $y = $point->x() * $sin + $point->y() * $cos;\n\n            // translate point back\n            $point->setX(\n                intval($x + $this->pivot()->x()),\n            );\n            $point->setY(\n                intval($y + $this->pivot()->y()),\n            );\n        }\n\n        return $this;\n    }\n\n    /**\n     * Move all points by given amount on the x-axis\n     */\n    public function movePointsX(int $amount): self\n    {\n        foreach ($this->points as $point) {\n            $point->moveX($amount);\n        }\n\n        return $this;\n    }\n\n    /**\n     * Move all points by given amount on the y-axis\n     */\n    public function movePointsY(int $amount): self\n    {\n        foreach ($this->points as $point) {\n            $point->moveY($amount);\n        }\n\n        return $this;\n    }\n\n    /**\n     * Return array of all x/y values of all points of polygon\n     *\n     * @return array<int>\n     */\n    public function toArray(): array\n    {\n        $coordinates = [];\n        foreach ($this->points as $point) {\n            $coordinates[] = $point->x();\n            $coordinates[] = $point->y();\n        }\n\n        return $coordinates;\n    }\n}\n"
  },
  {
    "path": "src/Geometry/Rectangle.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Geometry;\n\nuse Intervention\\Image\\Exceptions\\GeometryException;\nuse Intervention\\Image\\Geometry\\Tools\\RectangleResizer;\nuse Intervention\\Image\\Interfaces\\PointInterface;\nuse Intervention\\Image\\Interfaces\\SizeInterface;\n\nclass Rectangle extends Polygon implements SizeInterface\n{\n    /**\n     * Create new rectangle instance\n     *\n     * @return void\n     */\n    public function __construct(\n        int $width,\n        int $height,\n        protected PointInterface $pivot = new Point()\n    ) {\n        $this->addPoint(new Point($this->pivot->x(), $this->pivot->y()));\n        $this->addPoint(new Point($this->pivot->x() + $width, $this->pivot->y()));\n        $this->addPoint(new Point($this->pivot->x() + $width, $this->pivot->y() - $height));\n        $this->addPoint(new Point($this->pivot->x(), $this->pivot->y() - $height));\n    }\n\n    /**\n     * Set size of rectangle\n     */\n    public function setSize(int $width, int $height): self\n    {\n        return $this->setWidth($width)->setHeight($height);\n    }\n\n    /**\n     * Set width of rectangle\n     */\n    public function setWidth(int $width): self\n    {\n        $this[1]->setX($this[0]->x() + $width);\n        $this[2]->setX($this[3]->x() + $width);\n\n        return $this;\n    }\n\n    /**\n     * Set height of rectangle\n     */\n    public function setHeight(int $height): self\n    {\n        $this[2]->setY($this[1]->y() + $height);\n        $this[3]->setY($this[0]->y() + $height);\n\n        return $this;\n    }\n\n    /**\n     * Return pivot point of rectangle\n     */\n    public function pivot(): PointInterface\n    {\n        return $this->pivot;\n    }\n\n    /**\n     * Set pivot point of rectangle\n     */\n    public function setPivot(PointInterface $pivot): self\n    {\n        $this->pivot = $pivot;\n\n        return $this;\n    }\n\n    /**\n     * Move pivot to the given position in the rectangle and adjust the new\n     * position by given offset values.\n     */\n    public function movePivot(string $position, int $offset_x = 0, int $offset_y = 0): self\n    {\n        switch (strtolower($position)) {\n            case 'top':\n            case 'top-center':\n            case 'top-middle':\n            case 'center-top':\n            case 'middle-top':\n                $x = intval(round($this->width() / 2)) + $offset_x;\n                $y = $offset_y;\n                break;\n\n            case 'top-right':\n            case 'right-top':\n                $x = $this->width() - $offset_x;\n                $y = $offset_y;\n                break;\n\n            case 'left':\n            case 'left-center':\n            case 'left-middle':\n            case 'center-left':\n            case 'middle-left':\n                $x = $offset_x;\n                $y = intval(round($this->height() / 2)) + $offset_y;\n                break;\n\n            case 'right':\n            case 'right-center':\n            case 'right-middle':\n            case 'center-right':\n            case 'middle-right':\n                $x = $this->width() - $offset_x;\n                $y = intval(round($this->height() / 2)) + $offset_y;\n                break;\n\n            case 'bottom-left':\n            case 'left-bottom':\n                $x = $offset_x;\n                $y = $this->height() - $offset_y;\n                break;\n\n            case 'bottom':\n            case 'bottom-center':\n            case 'bottom-middle':\n            case 'center-bottom':\n            case 'middle-bottom':\n                $x = intval(round($this->width() / 2)) + $offset_x;\n                $y = $this->height() - $offset_y;\n                break;\n\n            case 'bottom-right':\n            case 'right-bottom':\n                $x = $this->width() - $offset_x;\n                $y = $this->height() - $offset_y;\n                break;\n\n            case 'center':\n            case 'middle':\n            case 'center-center':\n            case 'middle-middle':\n                $x = intval(round($this->width() / 2)) + $offset_x;\n                $y = intval(round($this->height() / 2)) + $offset_y;\n                break;\n\n            default:\n            case 'top-left':\n            case 'left-top':\n                $x = $offset_x;\n                $y = $offset_y;\n                break;\n        }\n\n        $this->pivot->setPosition($x, $y);\n\n        return $this;\n    }\n\n    /**\n     * Align pivot relative to given size at given position\n     */\n    public function alignPivotTo(SizeInterface $size, string $position): self\n    {\n        $reference = new self($size->width(), $size->height());\n        $reference->movePivot($position);\n\n        $this->movePivot($position)->setPivot(\n            $reference->relativePositionTo($this)\n        );\n\n        return $this;\n    }\n\n    /**\n     * Return relative position to given rectangle\n     */\n    public function relativePositionTo(SizeInterface $rectangle): PointInterface\n    {\n        return new Point(\n            $this->pivot()->x() - $rectangle->pivot()->x(),\n            $this->pivot()->y() - $rectangle->pivot()->y()\n        );\n    }\n\n    /**\n     * Return aspect ration of rectangle\n     */\n    public function aspectRatio(): float\n    {\n        return $this->width() / $this->height();\n    }\n\n    /**\n     * Determine if rectangle fits into given rectangle\n     */\n    public function fitsInto(SizeInterface $size): bool\n    {\n        if ($this->width() > $size->width()) {\n            return false;\n        }\n\n        if ($this->height() > $size->height()) {\n            return false;\n        }\n\n        return true;\n    }\n\n    /**\n     * Determine if rectangle has landscape format\n     */\n    public function isLandscape(): bool\n    {\n        return $this->width() > $this->height();\n    }\n\n    /**\n     * Determine if rectangle has landscape format\n     */\n    public function isPortrait(): bool\n    {\n        return $this->width() < $this->height();\n    }\n\n    /**\n     * Return most top left point of rectangle\n     */\n    public function topLeftPoint(): PointInterface\n    {\n        return $this->points[0];\n    }\n\n    /**\n     * Return bottom right point of rectangle\n     */\n    public function bottomRightPoint(): PointInterface\n    {\n        return $this->points[2];\n    }\n\n    /**\n     * @see SizeInterface::resize()\n     *\n     * @throws GeometryException\n     */\n    public function resize(?int $width = null, ?int $height = null): SizeInterface\n    {\n        return $this->resizer($width, $height)->resize($this);\n    }\n\n    /**\n     * @see SizeInterface::resizeDown()\n     *\n     * @throws GeometryException\n     */\n    public function resizeDown(?int $width = null, ?int $height = null): SizeInterface\n    {\n        return $this->resizer($width, $height)->resizeDown($this);\n    }\n\n    /**\n     * @see SizeInterface::scale()\n     *\n     * @throws GeometryException\n     */\n    public function scale(?int $width = null, ?int $height = null): SizeInterface\n    {\n        return $this->resizer($width, $height)->scale($this);\n    }\n\n    /**\n     * @see SizeInterface::scaleDown()\n     *\n     * @throws GeometryException\n     */\n    public function scaleDown(?int $width = null, ?int $height = null): SizeInterface\n    {\n        return $this->resizer($width, $height)->scaleDown($this);\n    }\n\n    /**\n     * @see SizeInterface::cover()\n     *\n     * @throws GeometryException\n     */\n    public function cover(int $width, int $height): SizeInterface\n    {\n        return $this->resizer($width, $height)->cover($this);\n    }\n\n    /**\n     * @see SizeInterface::contain()\n     *\n     * @throws GeometryException\n     */\n    public function contain(int $width, int $height): SizeInterface\n    {\n        return $this->resizer($width, $height)->contain($this);\n    }\n\n    /**\n     * @see SizeInterface::containMax()\n     *\n     * @throws GeometryException\n     */\n    public function containMax(int $width, int $height): SizeInterface\n    {\n        return $this->resizer($width, $height)->containDown($this);\n    }\n\n    /**\n     * Create resizer instance with given target size\n     *\n     * @throws GeometryException\n     */\n    protected function resizer(?int $width = null, ?int $height = null): RectangleResizer\n    {\n        return new RectangleResizer($width, $height);\n    }\n\n    /**\n     * Show debug info for the current rectangle\n     *\n     * @return array<string, int|object>\n     */\n    public function __debugInfo(): array\n    {\n        return [\n            'width' => $this->width(),\n            'height' => $this->height(),\n            'pivot' => $this->pivot,\n        ];\n    }\n}\n"
  },
  {
    "path": "src/Geometry/Tools/RectangleResizer.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Geometry\\Tools;\n\nuse Intervention\\Image\\Exceptions\\GeometryException;\nuse Intervention\\Image\\Geometry\\Rectangle;\nuse Intervention\\Image\\Interfaces\\SizeInterface;\n\nclass RectangleResizer\n{\n    /**\n     * @throws GeometryException\n     * @return void\n     */\n    public function __construct(\n        protected ?int $width = null,\n        protected ?int $height = null,\n    ) {\n        if (is_int($width) && $width < 1) {\n            throw new GeometryException(\n                'The width you specify must be greater than or equal to 1.'\n            );\n        }\n\n        if (is_int($height) && $height < 1) {\n            throw new GeometryException(\n                'The height you specify must be greater than or equal to 1.'\n            );\n        }\n    }\n\n    /**\n     * Static factory method to create resizer with given target size\n     *\n     * @throws GeometryException\n     */\n    public static function to(mixed ...$arguments): self\n    {\n        return new self(...$arguments);\n    }\n\n    /**\n     * Determine if resize has target width\n     */\n    protected function hasTargetWidth(): bool\n    {\n        return is_int($this->width);\n    }\n\n    /**\n     * Return target width of resizer if available\n     */\n    protected function getTargetWidth(): ?int\n    {\n        return $this->hasTargetWidth() ? $this->width : null;\n    }\n\n    /**\n     * Determine if resize has target height\n     */\n    protected function hasTargetHeight(): bool\n    {\n        return is_int($this->height);\n    }\n\n    /**\n     * Return target width of resizer if available\n     */\n    protected function getTargetHeight(): ?int\n    {\n        return $this->hasTargetHeight() ? $this->height : null;\n    }\n\n    /**\n     * Return target size object\n     *\n     * @throws GeometryException\n     */\n    protected function getTargetSize(): SizeInterface\n    {\n        if (!$this->hasTargetWidth() || !$this->hasTargetHeight()) {\n            throw new GeometryException('Target size needs width and height.');\n        }\n\n        return new Rectangle($this->width, $this->height);\n    }\n\n    /**\n     * Set target width of resizer\n     */\n    public function toWidth(int $width): self\n    {\n        $this->width = $width;\n\n        return $this;\n    }\n\n    /**\n     * Set target height of resizer\n     */\n    public function toHeight(int $height): self\n    {\n        $this->height = $height;\n\n        return $this;\n    }\n\n    /**\n     * Set target size to given size object\n     */\n    public function toSize(SizeInterface $size): self\n    {\n        $this->width = $size->width();\n        $this->height = $size->height();\n\n        return $this;\n    }\n\n    /**\n     * Get proportinal width\n     */\n    protected function getProportionalWidth(SizeInterface $size): int\n    {\n        if (!$this->hasTargetHeight()) {\n            return $size->width();\n        }\n\n        return max([1, (int) round($this->height * $size->aspectRatio())]);\n    }\n\n    /**\n     * Get proportinal height\n     */\n    protected function getProportionalHeight(SizeInterface $size): int\n    {\n        if (!$this->hasTargetWidth()) {\n            return $size->height();\n        }\n\n        return max([1, (int) round($this->width / $size->aspectRatio())]);\n    }\n\n    /**\n     * Resize given size to target size of the resizer\n     */\n    public function resize(SizeInterface $size): SizeInterface\n    {\n        $resized = new Rectangle($size->width(), $size->height());\n\n        if ($width = $this->getTargetWidth()) {\n            $resized->setWidth($width);\n        }\n\n        if ($height = $this->getTargetHeight()) {\n            $resized->setHeight($height);\n        }\n\n        return $resized;\n    }\n\n    /**\n     * Resize given size to target size of the resizer but do not exceed original size\n     */\n    public function resizeDown(SizeInterface $size): SizeInterface\n    {\n        $resized = new Rectangle($size->width(), $size->height());\n\n        if ($width = $this->getTargetWidth()) {\n            $resized->setWidth(\n                min($width, $size->width())\n            );\n        }\n\n        if ($height = $this->getTargetHeight()) {\n            $resized->setHeight(\n                min($height, $size->height())\n            );\n        }\n\n        return $resized;\n    }\n\n    /**\n     * Resize given size to target size proportinally\n     */\n    public function scale(SizeInterface $size): SizeInterface\n    {\n        $resized = new Rectangle($size->width(), $size->height());\n\n        if ($this->hasTargetWidth() && $this->hasTargetHeight()) {\n            $resized->setWidth(min(\n                $this->getProportionalWidth($size),\n                $this->getTargetWidth()\n            ));\n            $resized->setHeight(min(\n                $this->getProportionalHeight($size),\n                $this->getTargetHeight()\n            ));\n        } elseif ($this->hasTargetWidth()) {\n            $resized->setWidth($this->getTargetWidth());\n            $resized->setHeight($this->getProportionalHeight($size));\n        } elseif ($this->hasTargetHeight()) {\n            $resized->setWidth($this->getProportionalWidth($size));\n            $resized->setHeight($this->getTargetHeight());\n        }\n\n        return $resized;\n    }\n\n    /**\n     * Resize given size to target size proportinally but do not exceed original size\n     */\n    public function scaleDown(SizeInterface $size): SizeInterface\n    {\n        $resized = new Rectangle($size->width(), $size->height());\n\n        if ($this->hasTargetWidth() && $this->hasTargetHeight()) {\n            $resized->setWidth(min(\n                $this->getProportionalWidth($size),\n                $this->getTargetWidth(),\n                $size->width()\n            ));\n            $resized->setHeight(min(\n                $this->getProportionalHeight($size),\n                $this->getTargetHeight(),\n                $size->height()\n            ));\n        } elseif ($this->hasTargetWidth()) {\n            $resized->setWidth(min(\n                $this->getTargetWidth(),\n                $size->width()\n            ));\n            $resized->setHeight(min(\n                $this->getProportionalHeight($size),\n                $size->height()\n            ));\n        } elseif ($this->hasTargetHeight()) {\n            $resized->setWidth(min(\n                $this->getProportionalWidth($size),\n                $size->width()\n            ));\n            $resized->setHeight(min(\n                $this->getTargetHeight(),\n                $size->height()\n            ));\n        }\n\n        return $resized;\n    }\n\n    /**\n     * Scale given size to cover target size\n     *\n     * @param SizeInterface $size Size to be resized\n     * @throws GeometryException\n     */\n    public function cover(SizeInterface $size): SizeInterface\n    {\n        $resized = new Rectangle($size->width(), $size->height());\n\n        // auto height\n        $resized->setWidth($this->getTargetWidth());\n        $resized->setHeight($this->getProportionalHeight($size));\n\n        if ($resized->fitsInto($this->getTargetSize())) {\n            // auto width\n            $resized->setWidth($this->getProportionalWidth($size));\n            $resized->setHeight($this->getTargetHeight());\n        }\n\n        return $resized;\n    }\n\n    /**\n     * Scale given size to contain target size\n     *\n     * @param SizeInterface $size Size to be resized\n     * @throws GeometryException\n     */\n    public function contain(SizeInterface $size): SizeInterface\n    {\n        $resized = new Rectangle($size->width(), $size->height());\n\n        // auto height\n        $resized->setWidth($this->getTargetWidth());\n        $resized->setHeight($this->getProportionalHeight($size));\n\n        if (!$resized->fitsInto($this->getTargetSize())) {\n            // auto width\n            $resized->setWidth($this->getProportionalWidth($size));\n            $resized->setHeight($this->getTargetHeight());\n        }\n\n        return $resized;\n    }\n\n    /**\n     * Scale given size to contain target size but prevent upsizing\n     *\n     * @param SizeInterface $size Size to be resized\n     * @throws GeometryException\n     */\n    public function containDown(SizeInterface $size): SizeInterface\n    {\n        $resized = new Rectangle($size->width(), $size->height());\n\n        // auto height\n        $resized->setWidth(\n            min($size->width(), $this->getTargetWidth())\n        );\n\n        $resized->setHeight(\n            min($size->height(), $this->getProportionalHeight($size))\n        );\n\n        if (!$resized->fitsInto($this->getTargetSize())) {\n            // auto width\n            $resized->setWidth(\n                min($size->width(), $this->getProportionalWidth($size))\n            );\n            $resized->setHeight(\n                min($size->height(), $this->getTargetHeight())\n            );\n        }\n\n        return $resized;\n    }\n\n    /**\n     * Crop target size out of given size at given position (i.e. move the pivot point)\n     */\n    public function crop(SizeInterface $size, string $position = 'top-left'): SizeInterface\n    {\n        return $this->resize($size)->alignPivotTo(\n            $size->movePivot($position),\n            $position\n        );\n    }\n}\n"
  },
  {
    "path": "src/Geometry/Traits/HasBackgroundColor.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Geometry\\Traits;\n\ntrait HasBackgroundColor\n{\n    protected mixed $backgroundColor = null;\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DrawableInterface::setBackgroundColor()\n     */\n    public function setBackgroundColor(mixed $color): self\n    {\n        $this->backgroundColor = $color;\n\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DrawableInterface::backgroundColor()\n     */\n    public function backgroundColor(): mixed\n    {\n        return $this->backgroundColor;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DrawableInterface::hasBackgroundColor()\n     */\n    public function hasBackgroundColor(): bool\n    {\n        return !empty($this->backgroundColor);\n    }\n}\n"
  },
  {
    "path": "src/Geometry/Traits/HasBorder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Geometry\\Traits;\n\ntrait HasBorder\n{\n    protected mixed $borderColor = null;\n    protected int $borderSize = 0;\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DrawableInterface::setBorder()\n     */\n    public function setBorder(mixed $color, int $size = 1): self\n    {\n        return $this->setBorderSize($size)->setBorderColor($color);\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DrawableInterface::setBorderSize()\n     */\n    public function setBorderSize(int $size): self\n    {\n        $this->borderSize = $size;\n\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DrawableInterface::borderSize()\n     */\n    public function borderSize(): int\n    {\n        return $this->borderSize;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DrawableInterface::setBorderColor()\n     */\n    public function setBorderColor(mixed $color): self\n    {\n        $this->borderColor = $color;\n\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DrawableInterface::borderColor()\n     */\n    public function borderColor(): mixed\n    {\n        return $this->borderColor;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DrawableInterface::hasBorder()\n     */\n    public function hasBorder(): bool\n    {\n        return $this->borderSize > 0 && !is_null($this->borderColor);\n    }\n}\n"
  },
  {
    "path": "src/Image.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image;\n\nuse Closure;\nuse Intervention\\Image\\Exceptions\\RuntimeException;\nuse Traversable;\nuse Intervention\\Image\\Analyzers\\ColorspaceAnalyzer;\nuse Intervention\\Image\\Analyzers\\HeightAnalyzer;\nuse Intervention\\Image\\Analyzers\\PixelColorAnalyzer;\nuse Intervention\\Image\\Analyzers\\PixelColorsAnalyzer;\nuse Intervention\\Image\\Analyzers\\ProfileAnalyzer;\nuse Intervention\\Image\\Analyzers\\ResolutionAnalyzer;\nuse Intervention\\Image\\Analyzers\\WidthAnalyzer;\nuse Intervention\\Image\\Encoders\\AutoEncoder;\nuse Intervention\\Image\\Encoders\\AvifEncoder;\nuse Intervention\\Image\\Encoders\\BmpEncoder;\nuse Intervention\\Image\\Encoders\\FileExtensionEncoder;\nuse Intervention\\Image\\Encoders\\FilePathEncoder;\nuse Intervention\\Image\\Encoders\\GifEncoder;\nuse Intervention\\Image\\Encoders\\HeicEncoder;\nuse Intervention\\Image\\Encoders\\Jpeg2000Encoder;\nuse Intervention\\Image\\Encoders\\JpegEncoder;\nuse Intervention\\Image\\Encoders\\MediaTypeEncoder;\nuse Intervention\\Image\\Encoders\\PngEncoder;\nuse Intervention\\Image\\Encoders\\TiffEncoder;\nuse Intervention\\Image\\Encoders\\WebpEncoder;\nuse Intervention\\Image\\Exceptions\\EncoderException;\nuse Intervention\\Image\\Geometry\\Bezier;\nuse Intervention\\Image\\Geometry\\Circle;\nuse Intervention\\Image\\Geometry\\Ellipse;\nuse Intervention\\Image\\Geometry\\Factories\\BezierFactory;\nuse Intervention\\Image\\Geometry\\Factories\\CircleFactory;\nuse Intervention\\Image\\Geometry\\Factories\\EllipseFactory;\nuse Intervention\\Image\\Geometry\\Factories\\LineFactory;\nuse Intervention\\Image\\Geometry\\Factories\\PolygonFactory;\nuse Intervention\\Image\\Geometry\\Factories\\RectangleFactory;\nuse Intervention\\Image\\Geometry\\Line;\nuse Intervention\\Image\\Geometry\\Point;\nuse Intervention\\Image\\Geometry\\Polygon;\nuse Intervention\\Image\\Geometry\\Rectangle;\nuse Intervention\\Image\\Interfaces\\AnalyzerInterface;\nuse Intervention\\Image\\Interfaces\\CollectionInterface;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Interfaces\\ColorspaceInterface;\nuse Intervention\\Image\\Interfaces\\CoreInterface;\nuse Intervention\\Image\\Interfaces\\DriverInterface;\nuse Intervention\\Image\\Interfaces\\EncodedImageInterface;\nuse Intervention\\Image\\Interfaces\\EncoderInterface;\nuse Intervention\\Image\\Interfaces\\FontInterface;\nuse Intervention\\Image\\Interfaces\\FrameInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\ModifierInterface;\nuse Intervention\\Image\\Interfaces\\ProfileInterface;\nuse Intervention\\Image\\Interfaces\\ResolutionInterface;\nuse Intervention\\Image\\Interfaces\\SizeInterface;\nuse Intervention\\Image\\Modifiers\\AlignRotationModifier;\nuse Intervention\\Image\\Modifiers\\BlendTransparencyModifier;\nuse Intervention\\Image\\Modifiers\\BlurModifier;\nuse Intervention\\Image\\Modifiers\\BrightnessModifier;\nuse Intervention\\Image\\Modifiers\\ColorizeModifier;\nuse Intervention\\Image\\Modifiers\\ColorspaceModifier;\nuse Intervention\\Image\\Modifiers\\ContainModifier;\nuse Intervention\\Image\\Modifiers\\ContrastModifier;\nuse Intervention\\Image\\Modifiers\\CropModifier;\nuse Intervention\\Image\\Modifiers\\DrawBezierModifier;\nuse Intervention\\Image\\Modifiers\\DrawEllipseModifier;\nuse Intervention\\Image\\Modifiers\\DrawLineModifier;\nuse Intervention\\Image\\Modifiers\\DrawPixelModifier;\nuse Intervention\\Image\\Modifiers\\DrawPolygonModifier;\nuse Intervention\\Image\\Modifiers\\DrawRectangleModifier;\nuse Intervention\\Image\\Modifiers\\FillModifier;\nuse Intervention\\Image\\Modifiers\\CoverDownModifier;\nuse Intervention\\Image\\Modifiers\\CoverModifier;\nuse Intervention\\Image\\Modifiers\\FlipModifier;\nuse Intervention\\Image\\Modifiers\\FlopModifier;\nuse Intervention\\Image\\Modifiers\\GammaModifier;\nuse Intervention\\Image\\Modifiers\\GreyscaleModifier;\nuse Intervention\\Image\\Modifiers\\InvertModifier;\nuse Intervention\\Image\\Modifiers\\PadModifier;\nuse Intervention\\Image\\Modifiers\\PixelateModifier;\nuse Intervention\\Image\\Modifiers\\PlaceModifier;\nuse Intervention\\Image\\Modifiers\\ProfileModifier;\nuse Intervention\\Image\\Modifiers\\ProfileRemovalModifier;\nuse Intervention\\Image\\Modifiers\\QuantizeColorsModifier;\nuse Intervention\\Image\\Modifiers\\RemoveAnimationModifier;\nuse Intervention\\Image\\Modifiers\\ResizeCanvasModifier;\nuse Intervention\\Image\\Modifiers\\ResizeCanvasRelativeModifier;\nuse Intervention\\Image\\Modifiers\\ResizeDownModifier;\nuse Intervention\\Image\\Modifiers\\ResizeModifier;\nuse Intervention\\Image\\Modifiers\\ResolutionModifier;\nuse Intervention\\Image\\Modifiers\\RotateModifier;\nuse Intervention\\Image\\Modifiers\\ScaleDownModifier;\nuse Intervention\\Image\\Modifiers\\ScaleModifier;\nuse Intervention\\Image\\Modifiers\\SharpenModifier;\nuse Intervention\\Image\\Modifiers\\SliceAnimationModifier;\nuse Intervention\\Image\\Modifiers\\TextModifier;\nuse Intervention\\Image\\Modifiers\\TrimModifier;\nuse Intervention\\Image\\Typography\\FontFactory;\n\nfinal class Image implements ImageInterface\n{\n    /**\n     * The origin from which the image was created\n     */\n    private Origin $origin;\n\n    /**\n     * Create new instance\n     *\n     * @throws RuntimeException\n     * @return void\n     */\n    public function __construct(\n        private DriverInterface $driver,\n        private CoreInterface $core,\n        private CollectionInterface $exif = new Collection()\n    ) {\n        $this->origin = new Origin();\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::driver()\n     */\n    public function driver(): DriverInterface\n    {\n        return $this->driver;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::core()\n     */\n    public function core(): CoreInterface\n    {\n        return $this->core;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::origin()\n     */\n    public function origin(): Origin\n    {\n        return $this->origin;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::setOrigin()\n     */\n    public function setOrigin(Origin $origin): ImageInterface\n    {\n        $this->origin = $origin;\n\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::count()\n     */\n    public function count(): int\n    {\n        return $this->core->count();\n    }\n\n    /**\n     * Implementation of IteratorAggregate\n     *\n     * @return Traversable<FrameInterface>\n     */\n    public function getIterator(): Traversable\n    {\n        return $this->core;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::isAnimated()\n     */\n    public function isAnimated(): bool\n    {\n        return $this->count() > 1;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::removeAnimation(\n     */\n    public function removeAnimation(int|string $position = 0): ImageInterface\n    {\n        return $this->modify(new RemoveAnimationModifier($position));\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::sliceAnimation()\n     */\n    public function sliceAnimation(int $offset = 0, ?int $length = null): ImageInterface\n    {\n        return $this->modify(new SliceAnimationModifier($offset, $length));\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::loops()\n     */\n    public function loops(): int\n    {\n        return $this->core->loops();\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::setLoops()\n     */\n    public function setLoops(int $loops): ImageInterface\n    {\n        $this->core->setLoops($loops);\n\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::exif()\n     */\n    public function exif(?string $query = null): mixed\n    {\n        return is_null($query) ? $this->exif : $this->exif->get($query);\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::setExif()\n     */\n    public function setExif(CollectionInterface $exif): ImageInterface\n    {\n        $this->exif = $exif;\n\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::modify()\n     */\n    public function modify(ModifierInterface $modifier): ImageInterface\n    {\n        return $this->driver->specialize($modifier)->apply($this);\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::analyze()\n     */\n    public function analyze(AnalyzerInterface $analyzer): mixed\n    {\n        return $this->driver->specialize($analyzer)->analyze($this);\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::encode()\n     */\n    public function encode(EncoderInterface $encoder = new AutoEncoder()): EncodedImageInterface\n    {\n        return $this->driver->specialize($encoder)->encode($this);\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::save()\n     */\n    public function save(?string $path = null, mixed ...$options): ImageInterface\n    {\n        $path = is_null($path) ? $this->origin()->filePath() : $path;\n\n        if (is_null($path)) {\n            throw new EncoderException('Could not determine file path to save.');\n        }\n\n        try {\n            // try to determine encoding format by file extension of the path\n            $encoded = $this->encodeByPath($path, ...$options);\n        } catch (EncoderException) {\n            // fallback to encoding format by media type\n            $encoded = $this->encodeByMediaType(null, ...$options);\n        }\n\n        $encoded->save($path);\n\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::width()\n     */\n    public function width(): int\n    {\n        return $this->analyze(new WidthAnalyzer());\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::height()\n     */\n    public function height(): int\n    {\n        return $this->analyze(new HeightAnalyzer());\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::size()\n     */\n    public function size(): SizeInterface\n    {\n        return new Rectangle($this->width(), $this->height());\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::colorspace()\n     */\n    public function colorspace(): ColorspaceInterface\n    {\n        return $this->analyze(new ColorspaceAnalyzer());\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::setColorspace()\n     */\n    public function setColorspace(string|ColorspaceInterface $colorspace): ImageInterface\n    {\n        return $this->modify(new ColorspaceModifier($colorspace));\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::resolution()\n     */\n    public function resolution(): ResolutionInterface\n    {\n        return $this->analyze(new ResolutionAnalyzer());\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::setResolution()\n     */\n    public function setResolution(float $x, float $y): ImageInterface\n    {\n        return $this->modify(new ResolutionModifier($x, $y));\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::pickColor()\n     */\n    public function pickColor(int $x, int $y, int $frame_key = 0): ColorInterface\n    {\n        return $this->analyze(new PixelColorAnalyzer($x, $y, $frame_key));\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::pickColors()\n     */\n    public function pickColors(int $x, int $y): CollectionInterface\n    {\n        return $this->analyze(new PixelColorsAnalyzer($x, $y));\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::blendingColor()\n     */\n    public function blendingColor(): ColorInterface\n    {\n        return $this->driver()->handleInput(\n            $this->driver()->config()->blendingColor\n        );\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::setBlendingColor()\n     */\n    public function setBlendingColor(mixed $color): ImageInterface\n    {\n        $this->driver()->config()->setOptions(\n            blendingColor: $this->driver()->handleInput($color)\n        );\n\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::blendTransparency()\n     */\n    public function blendTransparency(mixed $color = null): ImageInterface\n    {\n        return $this->modify(new BlendTransparencyModifier($color));\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::profile()\n     */\n    public function profile(): ProfileInterface\n    {\n        return $this->analyze(new ProfileAnalyzer());\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::setProfile()\n     */\n    public function setProfile(ProfileInterface $profile): ImageInterface\n    {\n        return $this->modify(new ProfileModifier($profile));\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::removeProfile()\n     */\n    public function removeProfile(): ImageInterface\n    {\n        return $this->modify(new ProfileRemovalModifier());\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::reduceColors()\n     */\n    public function reduceColors(int $limit, mixed $background = 'transparent'): ImageInterface\n    {\n        return $this->modify(new QuantizeColorsModifier($limit, $background));\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::sharpen()\n     */\n    public function sharpen(int $amount = 10): ImageInterface\n    {\n        return $this->modify(new SharpenModifier($amount));\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::invert()\n     */\n    public function invert(): ImageInterface\n    {\n        return $this->modify(new InvertModifier());\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::pixelate()\n     */\n    public function pixelate(int $size): ImageInterface\n    {\n        return $this->modify(new PixelateModifier($size));\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::greyscale()\n     */\n    public function greyscale(): ImageInterface\n    {\n        return $this->modify(new GreyscaleModifier());\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::brightness()\n     */\n    public function brightness(int $level): ImageInterface\n    {\n        return $this->modify(new BrightnessModifier($level));\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::contrast()\n     */\n    public function contrast(int $level): ImageInterface\n    {\n        return $this->modify(new ContrastModifier($level));\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::gamma()\n     */\n    public function gamma(float $gamma): ImageInterface\n    {\n        return $this->modify(new GammaModifier($gamma));\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::colorize()\n     */\n    public function colorize(int $red = 0, int $green = 0, int $blue = 0): ImageInterface\n    {\n        return $this->modify(new ColorizeModifier($red, $green, $blue));\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::flip()\n     */\n    public function flip(): ImageInterface\n    {\n        return $this->modify(new FlipModifier());\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::flop()\n     */\n    public function flop(): ImageInterface\n    {\n        return $this->modify(new FlopModifier());\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::blur()\n     */\n    public function blur(int $amount = 5): ImageInterface\n    {\n        return $this->modify(new BlurModifier($amount));\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::rotate()\n     */\n    public function rotate(float $angle, mixed $background = 'ffffff'): ImageInterface\n    {\n        return $this->modify(new RotateModifier($angle, $background));\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::orient()\n     */\n    public function orient(): ImageInterface\n    {\n        return $this->modify(new AlignRotationModifier());\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::text()\n     */\n    public function text(string $text, int $x, int $y, callable|Closure|FontInterface $font): ImageInterface\n    {\n        return $this->modify(\n            new TextModifier(\n                $text,\n                new Point($x, $y),\n                call_user_func(new FontFactory($font)),\n            ),\n        );\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::resize()\n     */\n    public function resize(?int $width = null, ?int $height = null): ImageInterface\n    {\n        return $this->modify(new ResizeModifier($width, $height));\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::resizeDown()\n     */\n    public function resizeDown(?int $width = null, ?int $height = null): ImageInterface\n    {\n        return $this->modify(new ResizeDownModifier($width, $height));\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::scale()\n     */\n    public function scale(?int $width = null, ?int $height = null): ImageInterface\n    {\n        return $this->modify(new ScaleModifier($width, $height));\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::scaleDown()\n     */\n    public function scaleDown(?int $width = null, ?int $height = null): ImageInterface\n    {\n        return $this->modify(new ScaleDownModifier($width, $height));\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::cover()\n     */\n    public function cover(int $width, int $height, string $position = 'center'): ImageInterface\n    {\n        return $this->modify(new CoverModifier($width, $height, $position));\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::coverDown()\n     */\n    public function coverDown(int $width, int $height, string $position = 'center'): ImageInterface\n    {\n        return $this->modify(new CoverDownModifier($width, $height, $position));\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::resizeCanvas()\n     */\n    public function resizeCanvas(\n        ?int $width = null,\n        ?int $height = null,\n        mixed $background = 'ffffff',\n        string $position = 'center'\n    ): ImageInterface {\n        return $this->modify(new ResizeCanvasModifier($width, $height, $background, $position));\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::resizeCanvasRelative()\n     */\n    public function resizeCanvasRelative(\n        ?int $width = null,\n        ?int $height = null,\n        mixed $background = 'ffffff',\n        string $position = 'center'\n    ): ImageInterface {\n        return $this->modify(new ResizeCanvasRelativeModifier($width, $height, $background, $position));\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::padDown()\n     */\n    public function pad(\n        int $width,\n        int $height,\n        mixed $background = 'ffffff',\n        string $position = 'center'\n    ): ImageInterface {\n        return $this->modify(new PadModifier($width, $height, $background, $position));\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::pad()\n     */\n    public function contain(\n        int $width,\n        int $height,\n        mixed $background = 'ffffff',\n        string $position = 'center'\n    ): ImageInterface {\n        return $this->modify(new ContainModifier($width, $height, $background, $position));\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::crop()\n     */\n    public function crop(\n        int $width,\n        int $height,\n        int $offset_x = 0,\n        int $offset_y = 0,\n        mixed $background = 'ffffff',\n        string $position = 'top-left'\n    ): ImageInterface {\n        return $this->modify(new CropModifier($width, $height, $offset_x, $offset_y, $background, $position));\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::trim()\n     */\n    public function trim(int $tolerance = 0): ImageInterface\n    {\n        return $this->modify(new TrimModifier($tolerance));\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::place()\n     */\n    public function place(\n        mixed $element,\n        string $position = 'top-left',\n        int $offset_x = 0,\n        int $offset_y = 0,\n        int $opacity = 100\n    ): ImageInterface {\n        return $this->modify(new PlaceModifier($element, $position, $offset_x, $offset_y, $opacity));\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::fill()\n     */\n    public function fill(mixed $color, ?int $x = null, ?int $y = null): ImageInterface\n    {\n        return $this->modify(\n            new FillModifier(\n                $color,\n                is_null($x) || is_null($y) ? null : new Point($x, $y),\n            ),\n        );\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::drawPixel()\n     */\n    public function drawPixel(int $x, int $y, mixed $color): ImageInterface\n    {\n        return $this->modify(new DrawPixelModifier(new Point($x, $y), $color));\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::drawRectangle()\n     */\n    public function drawRectangle(int $x, int $y, callable|Closure|Rectangle $init): ImageInterface\n    {\n        return $this->modify(\n            new DrawRectangleModifier(\n                call_user_func(new RectangleFactory(new Point($x, $y), $init)),\n            ),\n        );\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::drawEllipse()\n     */\n    public function drawEllipse(int $x, int $y, callable|Closure|Ellipse $init): ImageInterface\n    {\n        return $this->modify(\n            new DrawEllipseModifier(\n                call_user_func(new EllipseFactory(new Point($x, $y), $init)),\n            ),\n        );\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::drawCircle()\n     */\n    public function drawCircle(int $x, int $y, callable|Closure|Circle $init): ImageInterface\n    {\n        return $this->modify(\n            new DrawEllipseModifier(\n                call_user_func(new CircleFactory(new Point($x, $y), $init)),\n            ),\n        );\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::drawPolygon()\n     */\n    public function drawPolygon(callable|Closure|Polygon $init): ImageInterface\n    {\n        return $this->modify(\n            new DrawPolygonModifier(\n                call_user_func(new PolygonFactory($init)),\n            ),\n        );\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::drawLine()\n     */\n    public function drawLine(callable|Closure|Line $init): ImageInterface\n    {\n        return $this->modify(\n            new DrawLineModifier(\n                call_user_func(new LineFactory($init)),\n            ),\n        );\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::drawBezier()\n     */\n    public function drawBezier(callable|Closure|Bezier $init): ImageInterface\n    {\n        return $this->modify(\n            new DrawBezierModifier(\n                call_user_func(new BezierFactory($init)),\n            ),\n        );\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::encodeByMediaType()\n     */\n    public function encodeByMediaType(null|string|MediaType $type = null, mixed ...$options): EncodedImageInterface\n    {\n        return $this->encode(new MediaTypeEncoder($type, ...$options));\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::encodeByExtension()\n     */\n    public function encodeByExtension(\n        null|string|FileExtension $extension = null,\n        mixed ...$options\n    ): EncodedImageInterface {\n        return $this->encode(new FileExtensionEncoder($extension, ...$options));\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::encodeByPath()\n     */\n    public function encodeByPath(?string $path = null, mixed ...$options): EncodedImageInterface\n    {\n        return $this->encode(new FilePathEncoder($path, ...$options));\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::toJpeg()\n     */\n    public function toJpeg(mixed ...$options): EncodedImageInterface\n    {\n        return $this->encode(new JpegEncoder(...$options));\n    }\n\n    /**\n     * Alias of self::toJpeg()\n     *\n     * @throws RuntimeException\n     */\n    public function toJpg(mixed ...$options): EncodedImageInterface\n    {\n        return $this->toJpeg(...$options);\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::toJpeg()\n     */\n    public function toJpeg2000(mixed ...$options): EncodedImageInterface\n    {\n        return $this->encode(new Jpeg2000Encoder(...$options));\n    }\n\n    /**\n     * ALias of self::toJpeg2000()\n     *\n     * @throws RuntimeException\n     */\n    public function toJp2(mixed ...$options): EncodedImageInterface\n    {\n        return $this->toJpeg2000(...$options);\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::toPng()\n     */\n    public function toPng(mixed ...$options): EncodedImageInterface\n    {\n        return $this->encode(new PngEncoder(...$options));\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::toGif()\n     */\n    public function toGif(mixed ...$options): EncodedImageInterface\n    {\n        return $this->encode(new GifEncoder(...$options));\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::toWebp()\n     */\n    public function toWebp(mixed ...$options): EncodedImageInterface\n    {\n        return $this->encode(new WebpEncoder(...$options));\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::toBitmap()\n     */\n    public function toBitmap(mixed ...$options): EncodedImageInterface\n    {\n        return $this->encode(new BmpEncoder(...$options));\n    }\n\n    /**\n     * Alias if self::toBitmap()\n     *\n     * @throws RuntimeException\n     */\n    public function toBmp(mixed ...$options): EncodedImageInterface\n    {\n        return $this->toBitmap(...$options);\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::toAvif()\n     */\n    public function toAvif(mixed ...$options): EncodedImageInterface\n    {\n        return $this->encode(new AvifEncoder(...$options));\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::toTiff()\n     */\n    public function toTiff(mixed ...$options): EncodedImageInterface\n    {\n        return $this->encode(new TiffEncoder(...$options));\n    }\n\n    /**\n     * Alias of self::toTiff()\n     *\n     * @throws RuntimeException\n     */\n    public function toTif(mixed ...$options): EncodedImageInterface\n    {\n        return $this->toTiff(...$options);\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageInterface::toHeic()\n     */\n    public function toHeic(mixed ...$options): EncodedImageInterface\n    {\n        return $this->encode(new HeicEncoder(...$options));\n    }\n\n    /**\n     * Show debug info for the current image\n     *\n     * @return array<string, int>\n     */\n    public function __debugInfo(): array\n    {\n        try {\n            return [\n                'width' => $this->width(),\n                'height' => $this->height(),\n            ];\n        } catch (RuntimeException) {\n            return [];\n        }\n    }\n\n    /**\n     * Clone image\n     */\n    public function __clone(): void\n    {\n        $this->driver = clone $this->driver;\n        $this->core = clone $this->core;\n        $this->exif = clone $this->exif;\n    }\n}\n"
  },
  {
    "path": "src/ImageManager.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image;\n\nuse Intervention\\Image\\Interfaces\\DriverInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Drivers\\Gd\\Driver as GdDriver;\nuse Intervention\\Image\\Drivers\\Imagick\\Driver as ImagickDriver;\nuse Intervention\\Image\\Exceptions\\DriverException;\nuse Intervention\\Image\\Exceptions\\InputException;\nuse Intervention\\Image\\Interfaces\\DecoderInterface;\nuse Intervention\\Image\\Interfaces\\ImageManagerInterface;\n\nfinal class ImageManager implements ImageManagerInterface\n{\n    private DriverInterface $driver;\n\n    /**\n     * @link https://image.intervention.io/v3/basics/configuration-drivers#create-a-new-image-manager-instance\n     *\n     * @throws DriverException\n     * @throws InputException\n     */\n    public function __construct(string|DriverInterface $driver, mixed ...$options)\n    {\n        $this->driver = $this->resolveDriver($driver, ...$options);\n    }\n\n    /**\n     * Create image manager with given driver\n     *\n     * @link https://image.intervention.io/v3/basics/configuration-drivers#static-constructor\n     *\n     * @throws DriverException\n     * @throws InputException\n     */\n    public static function withDriver(string|DriverInterface $driver, mixed ...$options): self\n    {\n        return new self(self::resolveDriver($driver, ...$options));\n    }\n\n    /**\n     * Create image manager with GD driver\n     *\n     * @link https://image.intervention.io/v3/basics/configuration-drivers#static-gd-driver-constructor\n     *\n     * @throws DriverException\n     * @throws InputException\n     */\n    public static function gd(mixed ...$options): self\n    {\n        return self::withDriver(new GdDriver(), ...$options);\n    }\n\n    /**\n     * Create image manager with Imagick driver\n     *\n     * @link https://image.intervention.io/v3/basics/configuration-drivers#static-imagick-driver-constructor\n     *\n     * @throws DriverException\n     * @throws InputException\n     */\n    public static function imagick(mixed ...$options): self\n    {\n        return self::withDriver(new ImagickDriver(), ...$options);\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageManagerInterface::create()\n     */\n    public function create(int $width, int $height): ImageInterface\n    {\n        return $this->driver->createImage($width, $height);\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageManagerInterface::read()\n     */\n    public function read(mixed $input, string|array|DecoderInterface $decoders = []): ImageInterface\n    {\n        return $this->driver->handleInput(\n            $input,\n            match (true) {\n                is_string($decoders), is_a($decoders, DecoderInterface::class) => [$decoders],\n                default => $decoders,\n            }\n        );\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageManagerInterface::animate()\n     */\n    public function animate(callable $init): ImageInterface\n    {\n        return $this->driver->createAnimation($init);\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ImageManagerInterface::driver()\n     */\n    public function driver(): DriverInterface\n    {\n        return $this->driver;\n    }\n\n    /**\n     * Return driver object from given input which might be driver classname or instance of DriverInterface\n     *\n     * @throws DriverException\n     * @throws InputException\n     */\n    private static function resolveDriver(string|DriverInterface $driver, mixed ...$options): DriverInterface\n    {\n        $driver = match (true) {\n            $driver instanceof DriverInterface => $driver,\n            class_exists($driver) => new $driver(),\n            default => throw new DriverException(\n                'Unable to resolve driver. Argment must be either an instance of ' .\n                    DriverInterface::class . '::class or a qualified namespaced name of the driver class.',\n            ),\n        };\n\n        if (!$driver instanceof DriverInterface) {\n            throw new DriverException(\n                'Unable to resolve driver. Driver object must implement ' . DriverInterface::class . '.',\n            );\n        }\n\n        $driver->config()->setOptions(...$options);\n\n        return $driver;\n    }\n}\n"
  },
  {
    "path": "src/InputHandler.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image;\n\nuse Intervention\\Image\\Colors\\Cmyk\\Decoders\\StringColorDecoder as CmykStringColorDecoder;\nuse Intervention\\Image\\Colors\\Hsl\\Decoders\\StringColorDecoder as HslStringColorDecoder;\nuse Intervention\\Image\\Colors\\Hsv\\Decoders\\StringColorDecoder as HsvStringColorDecoder;\nuse Intervention\\Image\\Colors\\Rgb\\Decoders\\HexColorDecoder as RgbHexColorDecoder;\nuse Intervention\\Image\\Colors\\Rgb\\Decoders\\HtmlColornameDecoder;\nuse Intervention\\Image\\Colors\\Rgb\\Decoders\\StringColorDecoder as RgbStringColorDecoder;\nuse Intervention\\Image\\Colors\\Rgb\\Decoders\\TransparentColorDecoder;\nuse Intervention\\Image\\Decoders\\Base64ImageDecoder;\nuse Intervention\\Image\\Decoders\\BinaryImageDecoder;\nuse Intervention\\Image\\Decoders\\ColorObjectDecoder;\nuse Intervention\\Image\\Decoders\\DataUriImageDecoder;\nuse Intervention\\Image\\Decoders\\EncodedImageObjectDecoder;\nuse Intervention\\Image\\Decoders\\FilePathImageDecoder;\nuse Intervention\\Image\\Decoders\\FilePointerImageDecoder;\nuse Intervention\\Image\\Decoders\\ImageObjectDecoder;\nuse Intervention\\Image\\Decoders\\NativeObjectDecoder;\nuse Intervention\\Image\\Decoders\\SplFileInfoImageDecoder;\nuse Intervention\\Image\\Exceptions\\DecoderException;\nuse Intervention\\Image\\Exceptions\\DriverException;\nuse Intervention\\Image\\Exceptions\\NotSupportedException;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Interfaces\\DecoderInterface;\nuse Intervention\\Image\\Interfaces\\DriverInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\InputHandlerInterface;\n\nclass InputHandler implements InputHandlerInterface\n{\n    /**\n     * Decoder classnames in hierarchical order\n     *\n     * @var array<string|DecoderInterface>\n     */\n    protected array $decoders = [\n        NativeObjectDecoder::class,\n        ImageObjectDecoder::class,\n        ColorObjectDecoder::class,\n        RgbHexColorDecoder::class,\n        RgbStringColorDecoder::class,\n        CmykStringColorDecoder::class,\n        HsvStringColorDecoder::class,\n        HslStringColorDecoder::class,\n        TransparentColorDecoder::class,\n        HtmlColornameDecoder::class,\n        FilePointerImageDecoder::class,\n        FilePathImageDecoder::class,\n        SplFileInfoImageDecoder::class,\n        BinaryImageDecoder::class,\n        DataUriImageDecoder::class,\n        Base64ImageDecoder::class,\n        EncodedImageObjectDecoder::class,\n    ];\n\n    /**\n     * Driver with which the decoder classes are specialized\n     */\n    protected ?DriverInterface $driver = null;\n\n    /**\n     * Create new input handler instance with given decoder classnames\n     *\n     * @param array<string|DecoderInterface> $decoders\n     * @return void\n     */\n    public function __construct(array $decoders = [], ?DriverInterface $driver = null)\n    {\n        $this->decoders = count($decoders) ? $decoders : $this->decoders;\n        $this->driver = $driver;\n    }\n\n    /**\n     * Static factory method\n     *\n     * @param array<string|DecoderInterface> $decoders\n     */\n    public static function withDecoders(array $decoders, ?DriverInterface $driver = null): self\n    {\n        return new self($decoders, $driver);\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see InputHandlerInterface::handle()\n     */\n    public function handle(mixed $input): ImageInterface|ColorInterface\n    {\n        foreach ($this->decoders as $decoder) {\n            try {\n                // decode with driver specialized decoder\n                return $this->resolve($decoder)->decode($input);\n            } catch (DecoderException | NotSupportedException $e) {\n                // try next decoder\n            }\n        }\n\n        if (isset($e)) {\n            throw new ($e::class)($e->getMessage());\n        }\n\n        throw new DecoderException('Unable to decode input.');\n    }\n\n    /**\n     * Resolve the given classname to an decoder object\n     *\n     * @throws DriverException\n     * @throws NotSupportedException\n     */\n    private function resolve(string|DecoderInterface $decoder): DecoderInterface\n    {\n        if (($decoder instanceof DecoderInterface) && empty($this->driver)) {\n            return $decoder;\n        }\n\n        if (($decoder instanceof DecoderInterface) && !empty($this->driver)) {\n            return $this->driver->specialize($decoder);\n        }\n\n        if (empty($this->driver)) {\n            return new $decoder();\n        }\n\n        return $this->driver->specialize(new $decoder());\n    }\n}\n"
  },
  {
    "path": "src/Interfaces/AnalyzerInterface.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Interfaces;\n\nuse Intervention\\Image\\Exceptions\\RuntimeException;\n\ninterface AnalyzerInterface\n{\n    /**\n     * Analyze given image and return the retrieved data\n     *\n     * @throws RuntimeException\n     */\n    public function analyze(ImageInterface $image): mixed;\n}\n"
  },
  {
    "path": "src/Interfaces/CollectionInterface.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Interfaces;\n\nuse Traversable;\n\n/**\n * @extends Traversable<int|string, mixed>\n */\ninterface CollectionInterface extends Traversable\n{\n    /**\n     * Determine if the collection has item at given key\n     */\n    public function has(int|string $key): bool;\n\n    /**\n     * Add item to collection\n     *\n     * @return CollectionInterface<int|string, mixed>\n     */\n    public function push(mixed $item): self;\n\n    /**\n     * Return item for given key or return default is key does not exist\n     */\n    public function get(int|string $key, mixed $default = null): mixed;\n\n    /**\n     * Return item at given numeric position starting at 0\n     */\n    public function getAtPosition(int $key = 0, mixed $default = null): mixed;\n\n    /**\n     * Return first item in collection\n     */\n    public function first(): mixed;\n\n    /**\n     * Return last item in collection\n     */\n    public function last(): mixed;\n\n    /**\n     * Return item count of collection\n     */\n    public function count(): int;\n\n    /**\n     * Empty collection\n     *\n     * @return CollectionInterface<int|string, mixed>\n     */\n    public function empty(): self;\n\n    /**\n     * Transform collection as array\n     *\n     * @return array<int|string, mixed>\n     */\n    public function toArray(): array;\n\n    /**\n     * Extract items based on given values and discard the rest.\n     *\n     * @return CollectionInterface<int|string, mixed>\n     */\n    public function slice(int $offset, ?int $length = 0): self;\n}\n"
  },
  {
    "path": "src/Interfaces/ColorChannelInterface.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Interfaces;\n\nuse Intervention\\Image\\Exceptions\\ColorException;\n\ninterface ColorChannelInterface\n{\n    /**\n     * Create new instance by either value or normalized value\n     *\n     * @throws ColorException\n     */\n    public function __construct(?int $value = null, ?float $normalized = null);\n\n    /**\n     * Return color channels integer value\n     */\n    public function value(): int;\n\n    /**\n     * Return the channels value normalized to a float value form 0 to 1 by its range\n     */\n    public function normalize(int $precision = 32): float;\n\n    /**\n     * Throw exception if the given value is not applicable for channel\n     * otherwise the value is returned unchanged.\n     *\n     * @throws ColorException\n     */\n    public function validate(mixed $value): mixed;\n\n    /**\n     * Return the the minimal possible value of the color channel\n     */\n    public function min(): int;\n\n    /*\n     * Return the the maximal possible value of the color channel\n     *\n     * @return int\n     */\n    public function max(): int;\n\n    /**\n     * Cast color channel's value to string\n     */\n    public function toString(): string;\n\n    /**\n     * Cast color channel's value to string\n     */\n    public function __toString(): string;\n}\n"
  },
  {
    "path": "src/Interfaces/ColorInterface.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Interfaces;\n\nuse Intervention\\Image\\Exceptions\\ColorException;\nuse Intervention\\Image\\Exceptions\\RuntimeException;\n\ninterface ColorInterface\n{\n    /**\n     * Static color factory method that takes any supported color format\n     * and returns a corresponding color object\n     *\n     * @throws RuntimeException\n     */\n    public static function create(mixed $input): self;\n\n    /**\n     * Return colorspace of current color\n     */\n    public function colorspace(): ColorspaceInterface;\n\n    /**\n     * Cast color object to string\n     */\n    public function toString(): string;\n\n    /**\n     * Cast color object to array\n     *\n     * @return array<int>\n     */\n    public function toArray(): array;\n\n    /**\n     * Cast color object to hex encoded web color\n     */\n    public function toHex(string $prefix = ''): string;\n\n    /**\n     * Return array of all color channels\n     *\n     * @return array<ColorChannelInterface>\n     */\n    public function channels(): array;\n\n    /**\n     * Return array of normalized color channel values\n     *\n     * @return array<float>\n     */\n    public function normalize(): array;\n\n    /**\n     * Retrieve the color channel by its classname\n     *\n     * @throws ColorException\n     */\n    public function channel(string $classname): ColorChannelInterface;\n\n    /**\n     * Convert color to given colorspace\n     */\n    public function convertTo(string|ColorspaceInterface $colorspace): self;\n\n    /**\n     * Determine if the current color is gray\n     */\n    public function isGreyscale(): bool;\n\n    /**\n     * Determine if the current color is (semi) transparent\n     */\n    public function isTransparent(): bool;\n\n    /**\n     * Determine whether the current color is completely transparent\n     */\n    public function isClear(): bool;\n\n    /**\n     * Cast color object to string\n     */\n    public function __toString(): string;\n}\n"
  },
  {
    "path": "src/Interfaces/ColorProcessorInterface.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Interfaces;\n\nuse Intervention\\Image\\Exceptions\\ColorException;\n\ninterface ColorProcessorInterface\n{\n    /**\n     * Turn given color in the driver's color implementation\n     *\n     * @throws ColorException\n     */\n    public function colorToNative(ColorInterface $color): mixed;\n\n    /**\n     * Turn the given driver's definition of a color into a color object\n     *\n     * @throws ColorException\n     */\n    public function nativeToColor(mixed $native): ColorInterface;\n}\n"
  },
  {
    "path": "src/Interfaces/ColorspaceInterface.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Interfaces;\n\ninterface ColorspaceInterface\n{\n    /**\n     * Convert given color to the format of the current colorspace\n     */\n    public function importColor(ColorInterface $color): ColorInterface;\n\n    /**\n     * Create new color in colorspace from given normalized channel values\n     *\n     * @param array<float> $normalized\n     */\n    public function colorFromNormalized(array $normalized): ColorInterface;\n}\n"
  },
  {
    "path": "src/Interfaces/CoreInterface.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Interfaces;\n\nuse Intervention\\Image\\Exceptions\\AnimationException;\n\ninterface CoreInterface extends CollectionInterface\n{\n    /**\n     * return driver's representation of the image core.\n     *\n     * @throws AnimationException\n     */\n    public function native(): mixed;\n\n    /**\n     * Set driver's representation of the image core.\n     *\n     * @return CoreInterface<FrameInterface>\n     */\n    public function setNative(mixed $native): self;\n\n    /**\n     * Count number of frames of animated image core\n     */\n    public function count(): int;\n\n    /**\n     * Return frame of given position in an animated image\n     *\n     * @throws AnimationException\n     */\n    public function frame(int $position): FrameInterface;\n\n    /**\n     * Add new frame to core\n     *\n     * @return CoreInterface<FrameInterface>\n     */\n    public function add(FrameInterface $frame): self;\n\n    /**\n     * Return number of repetitions of an animated image\n     */\n    public function loops(): int;\n\n    /**\n     * Set the number of repetitions for an animation. Where a\n     * value of 0 means infinite repetition.\n     *\n     * @return CoreInterface<FrameInterface>\n     */\n    public function setLoops(int $loops): self;\n\n    /**\n     * Get first frame in core\n     *\n     * @throws AnimationException\n     */\n    public function first(): FrameInterface;\n\n    /**\n     * Get last frame in core\n     *\n     * @throws AnimationException\n     */\n    public function last(): FrameInterface;\n}\n"
  },
  {
    "path": "src/Interfaces/DecoderInterface.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Interfaces;\n\nuse Intervention\\Image\\Exceptions\\RuntimeException;\n\ninterface DecoderInterface\n{\n    /**\n     * Decode given input either to color or image\n     *\n     * @throws RuntimeException\n     */\n    public function decode(mixed $input): ImageInterface|ColorInterface;\n}\n"
  },
  {
    "path": "src/Interfaces/DrawableFactoryInterface.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Interfaces;\n\nuse Closure;\n\ninterface DrawableFactoryInterface\n{\n    /**\n     * Create a new factory instance statically\n     */\n    public static function init(null|Closure|DrawableInterface $init = null): self;\n\n    /**\n     * Create the end product of the factory\n     */\n    public function create(): DrawableInterface;\n\n    /**\n     * Define the background color of the drawable object\n     */\n    public function background(mixed $color): self;\n\n    /**\n     * Set the border size & color of the drawable object to be produced\n     */\n    public function border(mixed $color, int $size = 1): self;\n\n    /**\n     * Create the end product by invoking the factory\n     */\n    public function __invoke(): DrawableInterface;\n}\n"
  },
  {
    "path": "src/Interfaces/DrawableInterface.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Interfaces;\n\ninterface DrawableInterface\n{\n    /**\n     * Position of the drawable object\n     */\n    public function position(): PointInterface;\n\n    /**\n     * Set position of the drawable object\n     */\n    public function setPosition(PointInterface $position): self;\n\n    /**\n     * Set the background color of the drawable object\n     */\n    public function setBackgroundColor(mixed $color): self;\n\n    /**\n     * Return background color of drawable object\n     */\n    public function backgroundColor(): mixed;\n\n    /**\n     * Determine if a background color was set\n     */\n    public function hasBackgroundColor(): bool;\n\n    /**\n     * Set border color & size of the drawable object\n     */\n    public function setBorder(mixed $color, int $size = 1): self;\n\n    /**\n     * Set border size of the drawable object\n     */\n    public function setBorderSize(int $size): self;\n\n    /**\n     * Set border color of the drawable object\n     */\n    public function setBorderColor(mixed $color): self;\n\n    /**\n     * Get border size\n     */\n    public function borderSize(): int;\n\n    /**\n     * Get border color of drawable object\n     */\n    public function borderColor(): mixed;\n\n    /**\n     * Determine if the drawable object has a border\n     */\n    public function hasBorder(): bool;\n}\n"
  },
  {
    "path": "src/Interfaces/DriverInterface.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Interfaces;\n\nuse Intervention\\Image\\Config;\nuse Intervention\\Image\\Exceptions\\DriverException;\nuse Intervention\\Image\\Exceptions\\NotSupportedException;\nuse Intervention\\Image\\Exceptions\\RuntimeException;\nuse Intervention\\Image\\FileExtension;\nuse Intervention\\Image\\Format;\nuse Intervention\\Image\\MediaType;\n\ninterface DriverInterface\n{\n    /**\n     * Return drivers unique id\n     */\n    public function id(): string;\n\n    /**\n     * Get driver configuration\n     */\n    public function config(): Config;\n\n    /**\n     * Resolve given (generic) object into a specialized version for the current driver\n     *\n     * @throws NotSupportedException\n     * @throws DriverException\n     */\n    public function specialize(\n        ModifierInterface|AnalyzerInterface|EncoderInterface|DecoderInterface $object\n    ): ModifierInterface|AnalyzerInterface|EncoderInterface|DecoderInterface;\n\n    /**\n     * Resolve array of classnames or objects into their specialized version for the current driver\n     *\n     * @param array<string|object> $objects\n     * @throws NotSupportedException\n     * @throws DriverException\n     * @return array<object>\n     */\n    public function specializeMultiple(array $objects): array;\n\n    /**\n     * Create new image instance with the current driver in given dimensions\n     *\n     * @throws RuntimeException\n     */\n    public function createImage(int $width, int $height): ImageInterface;\n\n    /**\n     * Create new animated image\n     *\n     * @throws RuntimeException\n     */\n    public function createAnimation(callable $init): ImageInterface;\n\n    /**\n     * Handle given input by decoding it to ImageInterface or ColorInterface\n     *\n     * @param array<string|DecoderInterface> $decoders\n     * @throws RuntimeException\n     */\n    public function handleInput(mixed $input, array $decoders = []): ImageInterface|ColorInterface;\n\n    /**\n     * Return color processor for the given colorspace\n     */\n    public function colorProcessor(ColorspaceInterface $colorspace): ColorProcessorInterface;\n\n    /**\n     * Return font processor of the current driver\n     */\n    public function fontProcessor(): FontProcessorInterface;\n\n    /**\n     * Check whether all requirements for operating the driver are met and\n     * throw exception if the check fails.\n     *\n     * @throws DriverException\n     */\n    public function checkHealth(): void;\n\n    /**\n     * Check if the current driver supports the given format and if the\n     * underlying PHP extension was built with support for the format.\n     */\n    public function supports(string|Format|FileExtension|MediaType $identifier): bool;\n}\n"
  },
  {
    "path": "src/Interfaces/EncodedImageInterface.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Interfaces;\n\ninterface EncodedImageInterface extends FileInterface\n{\n    /**\n     * Return Media (MIME) Type of encoded image\n     */\n    public function mediaType(): string;\n\n    /**\n     * Alias of self::mediaType()\n     */\n    public function mimetype(): string;\n\n    /**\n     * Transform encoded image data into an data uri string\n     */\n    public function toDataUri(): string;\n}\n"
  },
  {
    "path": "src/Interfaces/EncoderInterface.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Interfaces;\n\nuse Intervention\\Image\\Exceptions\\RuntimeException;\n\ninterface EncoderInterface\n{\n    /**\n     * Encode given image\n     *\n     * @throws RuntimeException\n     */\n    public function encode(ImageInterface $image): EncodedImageInterface;\n}\n"
  },
  {
    "path": "src/Interfaces/FileInterface.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Interfaces;\n\nuse Intervention\\Image\\Exceptions\\RuntimeException;\n\ninterface FileInterface\n{\n    /**\n     * Save data in given path in file system\n     *\n     * @throws RuntimeException\n     */\n    public function save(string $filepath): void;\n\n    /**\n     * Create file pointer from encoded data\n     *\n     * @return resource\n     */\n    public function toFilePointer();\n\n    /**\n     * Return size in bytes\n     */\n    public function size(): int;\n\n    /**\n     * Turn encoded data into string\n     */\n    public function toString(): string;\n\n    /**\n     * Cast encoded data into string\n     */\n    public function __toString(): string;\n}\n"
  },
  {
    "path": "src/Interfaces/FontInterface.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Interfaces;\n\nuse Intervention\\Image\\Exceptions\\FontException;\n\ninterface FontInterface\n{\n    /**\n     * Set color of font\n     */\n    public function setColor(mixed $color): self;\n\n    /**\n     * Get color of font\n     */\n    public function color(): mixed;\n\n    /**\n     * Set stroke color of font\n     */\n    public function setStrokeColor(mixed $color): self;\n\n    /**\n     * Get stroke color of font\n     */\n    public function strokeColor(): mixed;\n\n    /**\n        /**\n    * Set stroke width of font\n    *\n    * @throws FontException\n    */\n    public function setStrokeWidth(int $width): self;\n\n    /**\n     * Get stroke width of font\n     */\n    public function strokeWidth(): int;\n\n    /**\n     * Determine if the font is drawn with outline stroke effect\n     */\n    public function hasStrokeEffect(): bool;\n\n    /**\n     * Set font size\n     */\n    public function setSize(float $size): self;\n\n    /**\n     * Get font size\n     */\n    public function size(): float;\n\n    /**\n     * Set rotation angle of font\n     */\n    public function setAngle(float $angle): self;\n\n    /**\n     * Get rotation angle of font\n     */\n    public function angle(): float;\n\n    /**\n     * Set font filename\n     */\n    public function setFilename(string $filename): self;\n\n    /**\n     * Get font filename\n     */\n    public function filename(): ?string;\n\n    /**\n     * Determine if font has a corresponding filename\n     */\n    public function hasFilename(): bool;\n\n    /**\n     * Set horizontal alignment of font\n     */\n    public function setAlignment(string $align): self;\n\n    /**\n     * Get horizontal alignment of font\n     */\n    public function alignment(): string;\n\n    /**\n     * Set vertical alignment of font\n     */\n    public function setValignment(string $align): self;\n\n    /**\n     * Get vertical alignment of font\n     */\n    public function valignment(): string;\n\n    /**\n     * Set typographical line height\n     */\n    public function setLineHeight(float $value): self;\n\n    /**\n     * Get line height of font\n     */\n    public function lineHeight(): float;\n\n    /**\n     *  Set the wrap width with which the text is rendered\n     */\n    public function setWrapWidth(?int $width): self;\n\n    /**\n     * Get wrap width with which the text is rendered\n     */\n    public function wrapWidth(): ?int;\n}\n"
  },
  {
    "path": "src/Interfaces/FontProcessorInterface.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Interfaces;\n\nuse Intervention\\Image\\Exceptions\\FontException;\nuse Intervention\\Image\\Typography\\TextBlock;\n\ninterface FontProcessorInterface\n{\n    /**\n     * Calculate size of bounding box of given text in conjunction with the given font\n     *\n     * @throws FontException\n     */\n    public function boxSize(string $text, FontInterface $font): SizeInterface;\n\n    /**\n     * Build TextBlock object from text string and align every line according\n     * to text modifier's font object and position.\n     *\n     * @throws FontException\n     */\n    public function textBlock(string $text, FontInterface $font, PointInterface $position): TextBlock;\n\n    /**\n     * Calculate the actual font size to pass at the driver level\n     */\n    public function nativeFontSize(FontInterface $font): float;\n\n    /**\n     * Calculate the typographical font size in pixels\n     *\n     * @throws FontException\n     */\n    public function typographicalSize(FontInterface $font): int;\n\n    /**\n     * Calculates typographical cap height\n     *\n     * @throws FontException\n     */\n    public function capHeight(FontInterface $font): int;\n\n    /**\n     * Calculates typographical leading size\n     *\n     * @throws FontException\n     */\n    public function leading(FontInterface $font): int;\n}\n"
  },
  {
    "path": "src/Interfaces/FrameInterface.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Interfaces;\n\nuse Intervention\\Image\\Exceptions\\RuntimeException;\n\ninterface FrameInterface\n{\n    /**\n     * Return image data of frame in driver specific format\n     */\n    public function native(): mixed;\n\n    /**\n     * Set image data of drame in driver specific format\n     */\n    public function setNative(mixed $native): self;\n\n    /**\n     * Transform frame into an image\n     *\n     * @throws RuntimeException\n     */\n    public function toImage(DriverInterface $driver): ImageInterface;\n\n    /**\n     * Get image size of current frame\n     */\n    public function size(): SizeInterface;\n\n    /**\n     * Return animation delay of current frame in seconds\n     */\n    public function delay(): float;\n\n    /**\n     * Set animation frame delay in seoncds\n     */\n    public function setDelay(float $delay): self;\n\n    /**\n     * Get disposal method of current frame\n     */\n    public function dispose(): int;\n\n    /**\n     * Set disposal method of current frame\n     */\n    public function setDispose(int $dispose): self;\n\n    /**\n     * Set pixel offset of current frame\n     */\n    public function setOffset(int $left, int $top): self;\n\n    /**\n     * Get left offset in pixels\n     */\n    public function offsetLeft(): int;\n\n    /**\n     * Set left pixel offset for current frame\n     */\n    public function setOffsetLeft(int $offset): self;\n\n    /**\n     * Get top pixel offset of current frame\n     */\n    public function offsetTop(): int;\n\n    /**\n     * Set top pixel offset of current frame\n     */\n    public function setOffsetTop(int $offset): self;\n}\n"
  },
  {
    "path": "src/Interfaces/ImageInterface.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Interfaces;\n\nuse Closure;\nuse Countable;\nuse Intervention\\Image\\Encoders\\AutoEncoder;\nuse Intervention\\Image\\Exceptions\\AnimationException;\nuse Intervention\\Image\\Exceptions\\RuntimeException;\nuse Intervention\\Image\\FileExtension;\nuse Intervention\\Image\\Geometry\\Bezier;\nuse Intervention\\Image\\Geometry\\Circle;\nuse Intervention\\Image\\Geometry\\Ellipse;\nuse Intervention\\Image\\Geometry\\Line;\nuse Intervention\\Image\\Geometry\\Polygon;\nuse Intervention\\Image\\Geometry\\Rectangle;\nuse Intervention\\Image\\MediaType;\nuse Intervention\\Image\\Origin;\nuse IteratorAggregate;\n\n/**\n * @extends IteratorAggregate<FrameInterface>\n */\ninterface ImageInterface extends IteratorAggregate, Countable\n{\n    /**\n     * Return driver of current image\n     */\n    public function driver(): DriverInterface;\n\n    /**\n     * Return core of current image\n     */\n    public function core(): CoreInterface;\n\n    /**\n     * Return the origin of the image\n     */\n    public function origin(): Origin;\n\n    /**\n     * Set the origin of the image\n     */\n    public function setOrigin(Origin $origin): self;\n\n    /**\n     * Return width of current image\n     *\n     * @link https://image.intervention.io/v3/basics/meta-information#read-the-pixel-width\n     *\n     * @throws RuntimeException\n     */\n    public function width(): int;\n\n    /**\n     * Return height of current image\n     *\n     * @link https://image.intervention.io/v3/basics/meta-information#read-the-pixel-height\n     *\n     * @throws RuntimeException\n     */\n    public function height(): int;\n\n    /**\n     * Return size of current image\n     *\n     * @link https://image.intervention.io/v3/basics/meta-information#read-the-image-size-as-an-object\n     *\n     * @throws RuntimeException\n     */\n    public function size(): SizeInterface;\n\n    /**\n     * Encode image with given encoder\n     *\n     * @link https://image.intervention.io/v3/basics/image-output#encode-images\n     *\n     * @throws RuntimeException\n     */\n    public function encode(EncoderInterface $encoder = new AutoEncoder()): EncodedImageInterface;\n\n    /**\n     * Save the image to the specified path in the file system. If no path is\n     * given, the image will be saved at its original location.\n     *\n     * @link https://image.intervention.io/v3/basics/image-output#encode--save-combined\n     *\n     * @throws RuntimeException\n     */\n    public function save(?string $path = null, mixed ...$options): self;\n\n    /**\n     * Apply given modifier to current image\n     *\n     * @link https://image.intervention.io/v3/modifying-images/custom-modifiers\n     *\n     * @throws RuntimeException\n     */\n    public function modify(ModifierInterface $modifier): self;\n\n    /**\n     * Analyzer current image with given analyzer\n     *\n     * @throws RuntimeException\n     */\n    public function analyze(AnalyzerInterface $analyzer): mixed;\n\n    /**\n     * Determine if current image is animated\n     *\n     * @link https://image.intervention.io/v3/modifying-images/animations#check-the-current-image-instance-for-animation\n     */\n    public function isAnimated(): bool;\n\n    /**\n     * Remove all frames but keep the one at the specified position\n     *\n     * It is possible to specify the position as integer or string values.\n     * With the former, the exact position passed is searched for, while\n     * string values must represent a percentage value between '0%' and '100%'\n     * and the respective frame position is only determined approximately.\n     *\n     * @link https://image.intervention.io/v3/modifying-images/animations#remove-animation\n     *\n     * @throws RuntimeException\n     */\n    public function removeAnimation(int|string $position = 0): self;\n\n    /**\n     * Extract animation frames based on given values and discard the rest\n     *\n     * @link https://image.intervention.io/v3/modifying-images/animations#change-the-animation-iteration-count\n     *\n     * @throws RuntimeException\n     */\n    public function sliceAnimation(int $offset = 0, ?int $length = null): self;\n\n    /**\n     * Return loop count of animated image\n     *\n     * @link https://image.intervention.io/v3/modifying-images/animations#read-the-animation-iteration-count\n     */\n    public function loops(): int;\n\n    /**\n     * Set loop count of animated image\n     *\n     * @link https://image.intervention.io/v3/modifying-images/animations#change-the-animation-iteration-count\n     */\n    public function setLoops(int $loops): self;\n\n    /**\n     * Return exif data of current image\n     *\n     * @link https://image.intervention.io/v3/basics/meta-information#exif-information\n     */\n    public function exif(?string $query = null): mixed;\n\n    /**\n     * Set exif data for the image object\n     */\n    public function setExif(CollectionInterface $exif): self;\n\n    /**\n     * Return image resolution/density\n     *\n     * @link https://image.intervention.io/v3/basics/meta-information#image-resolution\n     *\n     * @throws RuntimeException\n     */\n    public function resolution(): ResolutionInterface;\n\n    /**\n     * Set image resolution\n     *\n     * @link https://image.intervention.io/v3/basics/meta-information#image-resolution\n     *\n     * @throws RuntimeException\n     */\n    public function setResolution(float $x, float $y): self;\n\n    /**\n     * Get the colorspace of the image\n     *\n     * @link https://image.intervention.io/v3/basics/colors#read-the-image-colorspace\n     *\n     * @throws RuntimeException\n     */\n    public function colorspace(): ColorspaceInterface;\n\n    /**\n     * Transform image to given colorspace\n     *\n     * @link https://image.intervention.io/v3/basics/colors#change-the-image-colorspace\n     *\n     * @throws RuntimeException\n     */\n    public function setColorspace(string|ColorspaceInterface $colorspace): self;\n\n    /**\n     * Return color of pixel at given position on given frame position\n     *\n     * @link https://image.intervention.io/v3/basics/colors#color-information\n     *\n     * @throws RuntimeException\n     */\n    public function pickColor(int $x, int $y, int $frame_key = 0): ColorInterface;\n\n    /**\n     * Return all colors of pixel at given position for all frames of image\n     *\n     * @link https://image.intervention.io/v3/basics/colors#color-information\n     *\n     * @throws RuntimeException\n     */\n    public function pickColors(int $x, int $y): CollectionInterface;\n\n    /**\n     * Return color that is mixed with transparent areas when converting to a format which\n     * does not support transparency.\n     *\n     * @throws RuntimeException\n     */\n    public function blendingColor(): ColorInterface;\n\n    /**\n     * Set blending color will have no effect unless image is converted into a format\n     * which does not support transparency.\n     *\n     * @throws RuntimeException\n     */\n    public function setBlendingColor(mixed $color): self;\n\n    /**\n     * Replace transparent areas of the image with given color\n     *\n     * @throws RuntimeException\n     */\n    public function blendTransparency(mixed $color = null): self;\n\n    /**\n     * Retrieve ICC color profile of image\n     *\n     * @link https://image.intervention.io/v3/basics/colors#color-profiles\n     *\n     * @throws RuntimeException\n     */\n    public function profile(): ProfileInterface;\n\n    /**\n     * Set given icc color profile to image\n     *\n     * @link https://image.intervention.io/v3/basics/colors#color-profiles\n     *\n     * @throws RuntimeException\n     */\n    public function setProfile(ProfileInterface $profile): self;\n\n    /**\n     * Remove ICC color profile from the current image\n     *\n     * @link https://image.intervention.io/v3/basics/colors#color-profiles\n     *\n     * @throws RuntimeException\n     */\n    public function removeProfile(): self;\n\n    /**\n     * Apply color quantization to the current image\n     *\n     * @link https://image.intervention.io/v3/modifying-images/effects#reduce-colors\n     *\n     * @throws RuntimeException\n     */\n    public function reduceColors(int $limit, mixed $background = 'transparent'): self;\n\n    /**\n     * Sharpen the current image with given strength\n     *\n     * @link https://image.intervention.io/v3/modifying-images/effects#sharpening-effect\n     *\n     * @throws RuntimeException\n     */\n    public function sharpen(int $amount = 10): self;\n\n    /**\n     * Turn image into a greyscale version\n     *\n     * @link https://image.intervention.io/v3/modifying-images/effects#convert-image-to-a-greyscale-version\n     *\n     * @throws RuntimeException\n     */\n    public function greyscale(): self;\n\n    /**\n     * Adjust brightness of the current image\n     *\n     * @link https://image.intervention.io/v3/modifying-images/effects#change-the-image-brightness\n     *\n     * @throws RuntimeException\n     */\n    public function brightness(int $level): self;\n\n    /**\n     * Adjust color contrast of the current image\n     *\n     * @link https://image.intervention.io/v3/modifying-images/effects#change-the-image-contrast\n     *\n     * @throws RuntimeException\n     */\n    public function contrast(int $level): self;\n\n    /**\n     * Apply gamma correction on the current image\n     *\n     * @link https://image.intervention.io/v3/modifying-images/effects#gamma-correction\n     *\n     * @throws RuntimeException\n     */\n    public function gamma(float $gamma): self;\n\n    /**\n     * Adjust the intensity of the RGB color channels\n     *\n     * @link https://image.intervention.io/v3/modifying-images/effects#color-correction\n     *\n     * @throws RuntimeException\n     */\n    public function colorize(int $red = 0, int $green = 0, int $blue = 0): self;\n\n    /**\n     * Mirror the current image vertically by swapping top and bottom\n     *\n     * @link https://image.intervention.io/v3/modifying-images/effects#mirror-image-vertically\n     *\n     * @throws RuntimeException\n     */\n    public function flip(): self;\n\n    /**\n     * Mirror the current image horizontally by swapping left and right\n     *\n     * @link https://image.intervention.io/v3/modifying-images/effects#mirror-image-horizontally\n     *\n     * @throws RuntimeException\n     */\n    public function flop(): self;\n\n    /**\n     * Blur current image by given strength\n     *\n     * @link https://image.intervention.io/v3/modifying-images/effects#blur-effect\n     *\n     * @throws RuntimeException\n     */\n    public function blur(int $amount = 5): self;\n\n    /**\n     * Invert the colors of the current image\n     *\n     * @link https://image.intervention.io/v3/modifying-images/effects#invert-colors\n     *\n     * @throws RuntimeException\n     */\n    public function invert(): self;\n\n    /**\n     * Apply pixelation filter effect on current image\n     *\n     * @link https://image.intervention.io/v3/modifying-images/effects#pixelation-effect\n     *\n     * @throws RuntimeException\n     */\n    public function pixelate(int $size): self;\n\n    /**\n     * Rotate current image by given angle\n     *\n     * @link https://image.intervention.io/v3/modifying-images/effects#image-rotation\n     *\n     * @param string $background\n     * @throws RuntimeException\n     */\n    public function rotate(float $angle, mixed $background = 'ffffff'): self;\n\n    /**\n     * Rotate the image to be upright according to exif information\n     *\n     * @link https://image.intervention.io/v3/modifying-images/effects#image-orientation-according-to-exif-data\n     *\n     * @throws RuntimeException\n     */\n    public function orient(): self;\n\n    /**\n     * Draw text on image\n     *\n     * @link https://image.intervention.io/v3/modifying-images/text-fonts\n     *\n     * @throws RuntimeException\n     */\n    public function text(string $text, int $x, int $y, callable|Closure|FontInterface $font): self;\n\n    /**\n     * Resize image to the given width and/or height\n     *\n     * @link https://image.intervention.io/v3/modifying-images/resizing#simple-image-resizing\n     *\n     * @throws RuntimeException\n     */\n    public function resize(?int $width = null, ?int $height = null): self;\n\n    /**\n     * Resize image to the given width and/or height without exceeding the original dimensions\n     *\n     * @link https://image.intervention.io/v3/modifying-images/resizing#resize-without-exceeding-the-original-size\n     *\n     * @throws RuntimeException\n     */\n    public function resizeDown(?int $width = null, ?int $height = null): self;\n\n    /**\n     * Resize image to the given width and/or height and keep the original aspect ratio\n     *\n     * @link https://image.intervention.io/v3/modifying-images/resizing#resize-images-proportionally\n     *\n     * @throws RuntimeException\n     */\n    public function scale(?int $width = null, ?int $height = null): self;\n\n    /**\n     * Resize image to the given width and/or height, keep the original aspect ratio\n     * and do not exceed the original image width or height\n     *\n     * @link https://image.intervention.io/v3/modifying-images/resizing#scale-images-but-do-not-exceed-the-original-size\n     *\n     * @throws RuntimeException\n     */\n    public function scaleDown(?int $width = null, ?int $height = null): self;\n\n    /**\n     * Takes the specified width and height and scales them to the largest\n     * possible size that fits within the original size. This scaled size is\n     * then positioned on the original and cropped, before this result is resized\n     * to the desired size using the arguments\n     *\n     * @link https://image.intervention.io/v3/modifying-images/resizing#cropping--resizing-combined\n     *\n     * @throws RuntimeException\n     */\n    public function cover(int $width, int $height, string $position = 'center'): self;\n\n    /**\n     * Same as cover() but do not exceed the original image size\n     *\n     * @link https://image.intervention.io/v3/modifying-images/resizing#fitted-resizing-without-exceeding-the-original-size\n     *\n     * @throws RuntimeException\n     */\n    public function coverDown(int $width, int $height, string $position = 'center'): self;\n\n    /**\n     * Resize the boundaries of the current image to given width and height.\n     * An anchor position can be defined to determine where the original image\n     * is fixed. A background color can be passed to define the color of the\n     * new emerging areas.\n     *\n     * @link https://image.intervention.io/v3/modifying-images/resizing#resize-image-boundaries-without-resampling-the-original-image\n     *\n     * @throws RuntimeException\n     */\n    public function resizeCanvas(\n        ?int $width = null,\n        ?int $height = null,\n        mixed $background = 'ffffff',\n        string $position = 'center'\n    ): self;\n\n    /**\n     * Resize canvas in the same way as resizeCanvas() but takes relative values\n     * for the width and height, which will be added or subtracted to the\n     * original image size.\n     *\n     * @link https://image.intervention.io/v3/modifying-images/resizing#resize-image-boundaries-relative-to-the-original\n     *\n     * @throws RuntimeException\n     */\n    public function resizeCanvasRelative(\n        ?int $width = null,\n        ?int $height = null,\n        mixed $background = 'ffffff',\n        string $position = 'center'\n    ): self;\n\n    /**\n     * Padded resizing means that the original image is scaled until it fits the\n     * defined target size with unchanged aspect ratio. The original image is\n     * not scaled up but only down.\n     *\n     * Compared to the cover() method, this method does not create cropped areas,\n     * but possibly new empty areas on the sides of the result image. These are\n     * filled with the specified background color.\n     *\n     * @link https://image.intervention.io/v3/modifying-images/resizing#resizing--padding-combined\n     *\n     * @param string $background\n     * @throws RuntimeException\n     */\n    public function pad(\n        int $width,\n        int $height,\n        mixed $background = 'ffffff',\n        string $position = 'center'\n    ): self;\n\n    /**\n     * This method does the same as pad(), but the original image is also scaled\n     * up if the target size exceeds the original size.\n     *\n     * @link https://image.intervention.io/v3/modifying-images/resizing#padded-resizing-with-upscaling\n     *\n     * @param string $background\n     * @throws RuntimeException\n     */\n    public function contain(\n        int $width,\n        int $height,\n        mixed $background = 'ffffff',\n        string $position = 'center'\n    ): self;\n\n    /**\n     * Cut out a rectangular part of the current image with given width and\n     * height at a given position. Define optional x,y offset coordinates\n     * to move the cutout by the given amount of pixels.\n     *\n     * @link https://image.intervention.io/v3/modifying-images/resizing#cut-out-a-rectangular-part\n     *\n     * @throws RuntimeException\n     */\n    public function crop(\n        int $width,\n        int $height,\n        int $offset_x = 0,\n        int $offset_y = 0,\n        mixed $background = 'ffffff',\n        string $position = 'top-left'\n    ): self;\n\n    /**\n     * Trim the image by removing border areas of similar color within a the given tolerance\n     *\n     * @link https://image.intervention.io/v3/modifying-images/resizing#remove-border-areas-in-similar-color\n     *\n     * @throws RuntimeException\n     * @throws AnimationException\n     */\n    public function trim(int $tolerance = 0): self;\n\n    /**\n     * Place another image into the current image instance\n     *\n     * @link https://image.intervention.io/v3/modifying-images/inserting#insert-images\n     *\n     * @throws RuntimeException\n     */\n    public function place(\n        mixed $element,\n        string $position = 'top-left',\n        int $offset_x = 0,\n        int $offset_y = 0,\n        int $opacity = 100\n    ): self;\n\n    /**\n     * Fill image with given color\n     *\n     * If an optional position is specified for the filling process ln the form\n     * of x and y coordinates, the process is executed as flood fill. This means\n     * that the color at the specified position is taken as a reference and all\n     * adjacent pixels are also filled with the filling color.\n     *\n     * If no coordinates are specified, the entire image area is filled.\n     *\n     * @link https://image.intervention.io/v3/modifying-images/drawing#fill-images-with-color\n     *\n     * @throws RuntimeException\n     */\n    public function fill(mixed $color, ?int $x = null, ?int $y = null): self;\n\n    /**\n     * Draw a single pixel at given position defined by the coordinates x and y in a given color.\n     *\n     * @link https://image.intervention.io/v3/modifying-images/drawing#draw-pixels\n     *\n     * @throws RuntimeException\n     */\n    public function drawPixel(int $x, int $y, mixed $color): self;\n\n    /**\n     * Draw a rectangle on the current image\n     *\n     * @link https://image.intervention.io/v3/modifying-images/drawing#draw-a-rectangle\n     *\n     * @throws RuntimeException\n     */\n    public function drawRectangle(int $x, int $y, callable|Closure|Rectangle $init): self;\n\n    /**\n     * Draw ellipse on the current image\n     *\n     * @link https://image.intervention.io/v3/modifying-images/drawing#draw-ellipses\n     *\n     * @throws RuntimeException\n     */\n    public function drawEllipse(int $x, int $y, callable|Closure|Ellipse $init): self;\n\n    /**\n     * Draw circle on the current image\n     *\n     * @link https://image.intervention.io/v3/modifying-images/drawing#draw-a-circle\n     *\n     * @throws RuntimeException\n     */\n    public function drawCircle(int $x, int $y, callable|Closure|Circle $init): self;\n\n    /**\n     * Draw a polygon on the current image\n     *\n     * @link https://image.intervention.io/v3/modifying-images/drawing#draw-a-polygon\n     *\n     * @throws RuntimeException\n     */\n    public function drawPolygon(callable|Closure|Polygon $init): self;\n\n    /**\n     * Draw a line on the current image\n     *\n     * @link https://image.intervention.io/v3/modifying-images/drawing#draw-a-line\n     *\n     * @throws RuntimeException\n     */\n    public function drawLine(callable|Closure|Line $init): self;\n\n    /**\n     * Draw a bezier curve on the current image\n     *\n     * @link https://image.intervention.io/v3/modifying-images/drawing#draw-bezier-curves\n     *\n     * @throws RuntimeException\n     */\n    public function drawBezier(callable|Closure|Bezier $init): self;\n\n    /**\n     * Encode image to given media (mime) type. If no type is given the image\n     * will be encoded to the format of the originally read image.\n     *\n     * @link https://image.intervention.io/v3/basics/image-output#encode-images-by-media-mime-type\n     *\n     * @throws RuntimeException\n     */\n    public function encodeByMediaType(null|string|MediaType $type = null, mixed ...$options): EncodedImageInterface;\n\n    /**\n     * Encode the image into the format represented by the given extension. If no\n     * extension is given the image will be encoded to the format of the\n     * originally read image.\n     *\n     * @link https://image.intervention.io/v3/basics/image-output#encode-images-by-file-extension\n     *\n     * @throws RuntimeException\n     */\n    public function encodeByExtension(\n        null|string|FileExtension $extension = null,\n        mixed ...$options\n    ): EncodedImageInterface;\n\n    /**\n     * Encode the image into the format represented by the given extension of\n     * the given file path extension is given the image will be encoded to\n     * the format of the originally read image.\n     *\n     * @link https://image.intervention.io/v3/basics/image-output#encode-images-by-file-path\n     *\n     * @throws RuntimeException\n     */\n    public function encodeByPath(?string $path = null, mixed ...$options): EncodedImageInterface;\n\n    /**\n     * Encode image to JPEG format\n     *\n     * @link https://image.intervention.io/v3/basics/image-output#encode-jpeg-format\n     *\n     * @throws RuntimeException\n     */\n    public function toJpeg(mixed ...$options): EncodedImageInterface;\n\n    /**\n     * Encode image to Jpeg2000 format\n     *\n     * @link https://image.intervention.io/v3/basics/image-output#encode-jpeg-2000-format\n     *\n     * @throws RuntimeException\n     */\n    public function toJpeg2000(mixed ...$options): EncodedImageInterface;\n\n    /**\n     * Encode image to Webp format\n     *\n     * @link https://image.intervention.io/v3/basics/image-output#encode-webp-format\n     *\n     * @throws RuntimeException\n     */\n    public function toWebp(mixed ...$options): EncodedImageInterface;\n\n    /**\n     * Encode image to PNG format\n     *\n     * @link https://image.intervention.io/v3/basics/image-output#encode-png-format\n     *\n     * @throws RuntimeException\n     */\n    public function toPng(mixed ...$options): EncodedImageInterface;\n\n    /**\n     * Encode image to GIF format\n     *\n     * @link https://image.intervention.io/v3/basics/image-output#encode-gif-format\n     *\n     * @throws RuntimeException\n     */\n    public function toGif(mixed ...$options): EncodedImageInterface;\n\n    /**\n     * Encode image to Bitmap format\n     *\n     * @link https://image.intervention.io/v3/basics/image-output#encode-windows-bitmap-format\n     *\n     * @throws RuntimeException\n     */\n    public function toBitmap(mixed ...$options): EncodedImageInterface;\n\n    /**\n     * Encode image to AVIF format\n     *\n     * @link https://image.intervention.io/v3/basics/image-output#encode-av1-image-file-format-avif\n     *\n     * @throws RuntimeException\n     */\n    public function toAvif(mixed ...$options): EncodedImageInterface;\n\n    /**\n     * Encode image to TIFF format\n     *\n     * @link https://image.intervention.io/v3/basics/image-output#encode-tiff-format\n     *\n     * @throws RuntimeException\n     */\n    public function toTiff(mixed ...$options): EncodedImageInterface;\n\n    /**\n     * Encode image to HEIC format\n     *\n     * @link https://image.intervention.io/v3/basics/image-output#encode-heic-format\n     *\n     * @throws RuntimeException\n     */\n    public function toHeic(mixed ...$options): EncodedImageInterface;\n}\n"
  },
  {
    "path": "src/Interfaces/ImageManagerInterface.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Interfaces;\n\nuse Intervention\\Image\\Exceptions\\RuntimeException;\n\ninterface ImageManagerInterface\n{\n    /**\n     * Create new image instance with given width & height\n     *\n     * @link https://image.intervention.io/v3/basics/instantiation#create-new-images\n     *\n     * @throws RuntimeException\n     */\n    public function create(int $width, int $height): ImageInterface;\n\n    /**\n     * Create new image instance from given input which can be one of the following\n     *\n     * - Path in filesystem\n     * - File Pointer resource\n     * - SplFileInfo object\n     * - Raw binary image data\n     * - Base64 encoded image data\n     * - Data Uri\n     * - Intervention\\Image\\Image Instance\n     *\n     * To decode the raw input data, you can optionally specify a decoding strategy\n     * with the second parameter. This can be an array of class names or objects\n     * of decoders to be processed in sequence. In this case, the input must be\n     * decodedable with one of the decoders passed. It is also possible to pass\n     * a single object or class name of a decoder.\n     *\n     * All decoders that implement the `DecoderInterface::class` can be passed. Usually\n     * a selection of classes of the namespace `Intervention\\Image\\Decoders`\n     *\n     * If the second parameter is not set, an attempt to decode the input is made\n     * with all available decoders of the driver.\n     *\n     * @link https://image.intervention.io/v3/basics/instantiation#read-image-sources\n     *\n     * @param string|array<string|DecoderInterface>|DecoderInterface $decoders\n     * @throws RuntimeException\n     */\n    public function read(mixed $input, string|array|DecoderInterface $decoders = []): ImageInterface;\n\n    /**\n     * Create new animated image by given callback\n     *\n     * @link https://image.intervention.io/v3/basics/instantiation#create-animations\n     *\n     * @throws RuntimeException\n     */\n    public function animate(callable $init): ImageInterface;\n\n    /**\n     * Return currently used driver\n     */\n    public function driver(): DriverInterface;\n}\n"
  },
  {
    "path": "src/Interfaces/InputHandlerInterface.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Interfaces;\n\nuse Intervention\\Image\\Exceptions\\RuntimeException;\n\ninterface InputHandlerInterface\n{\n    /**\n     * Try to decode the given input with each decoder of the the handler chain\n     *\n     * @throws RuntimeException\n     */\n    public function handle(mixed $input): ImageInterface|ColorInterface;\n}\n"
  },
  {
    "path": "src/Interfaces/ModifierInterface.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Interfaces;\n\nuse Intervention\\Image\\Exceptions\\RuntimeException;\n\ninterface ModifierInterface\n{\n    /**\n     * Apply modifications of the current modifier to the given image\n     *\n     * @throws RuntimeException\n     */\n    public function apply(ImageInterface $image): ImageInterface;\n}\n"
  },
  {
    "path": "src/Interfaces/PointInterface.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Interfaces;\n\ninterface PointInterface\n{\n    /**\n     * Return x position\n     */\n    public function x(): int;\n\n    /**\n     * Return y position\n     */\n    public function y(): int;\n\n    /**\n     * Set x position\n     */\n    public function setX(int $x): self;\n\n    /**\n     * Set y position\n     */\n    public function setY(int $y): self;\n\n    /**\n     * Move X coordinate\n     */\n    public function moveX(int $value): self;\n\n    /**\n     * Move Y coordinate\n     */\n    public function moveY(int $value): self;\n\n    /**\n     * Move position of current point by given coordinates\n     */\n    public function move(int $x, int $y): self;\n\n    /**\n     * Set position of point\n     */\n    public function setPosition(int $x, int $y): self;\n\n    /**\n     * Rotate point counter clock wise around given pivot point\n     */\n    public function rotate(float $angle, self $pivot): self;\n}\n"
  },
  {
    "path": "src/Interfaces/ProfileInterface.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Interfaces;\n\ninterface ProfileInterface\n{\n    /**\n     * Cast color profile object to string\n     */\n    public function __toString(): string;\n}\n"
  },
  {
    "path": "src/Interfaces/ResolutionInterface.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Interfaces;\n\ninterface ResolutionInterface\n{\n    /**\n     * Return resolution of x-axis\n     */\n    public function x(): float;\n\n    /**\n     * Set resolution on x-axis\n     */\n    public function setX(float $x): self;\n\n    /**\n     * Return resolution on y-axis\n     */\n    public function y(): float;\n\n    /**\n     * Set resolution on y-axis\n     */\n    public function setY(float $y): self;\n\n    /**\n     * Convert the resolution to DPI\n     */\n    public function perInch(): self;\n\n    /**\n     * Convert the resolution to DPCM\n     */\n    public function perCm(): self;\n\n    /**\n     * Return string representation of unit\n     */\n    public function unit(): string;\n\n    /**\n     * Transform object to string\n     */\n    public function toString(): string;\n\n    /**\n     * Cast object to string\n     */\n    public function __toString(): string;\n}\n"
  },
  {
    "path": "src/Interfaces/SizeInterface.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Interfaces;\n\nuse Intervention\\Image\\Exceptions\\GeometryException;\n\ninterface SizeInterface\n{\n    /**\n     * Get width\n     */\n    public function width(): int;\n\n    /**\n     * Get height\n     */\n    public function height(): int;\n\n    /**\n     * Get pivot point\n     */\n    public function pivot(): PointInterface;\n\n    /**\n     * Set width\n     */\n    public function setWidth(int $width): self;\n\n    /**\n     * Set height\n     */\n    public function setHeight(int $height): self;\n\n    /**\n     * Set pivot point\n     */\n    public function setPivot(PointInterface $pivot): self;\n\n    /**\n     * Calculate aspect ratio of the current size\n     */\n    public function aspectRatio(): float;\n\n    /**\n     * Determine if current size fits into given size\n     */\n    public function fitsInto(self $size): bool;\n\n    /**\n     * Determine if size is in landscape format\n     */\n    public function isLandscape(): bool;\n\n    /**\n     * Determine if size is in portrait format\n     */\n    public function isPortrait(): bool;\n\n    /**\n     * Move pivot to given position in size\n     */\n    public function movePivot(string $position, int $offset_x = 0, int $offset_y = 0): self;\n\n    /**\n     * Align pivot of current object to given position\n     */\n    public function alignPivotTo(self $size, string $position): self;\n\n    /**\n     * Calculate the relative position to another Size\n     * based on the pivot point settings of both sizes.\n     */\n    public function relativePositionTo(self $size): PointInterface;\n\n    /**\n     * @see ImageInterface::resize()\n     *\n     * @throws GeometryException\n     */\n    public function resize(?int $width = null, ?int $height = null): self;\n\n    /**\n     * @see ImageInterface::resizeDown()\n     *\n     * @throws GeometryException\n     */\n    public function resizeDown(?int $width = null, ?int $height = null): self;\n\n    /**\n     * @see ImageInterface::scale()\n     *\n     * @throws GeometryException\n     */\n    public function scale(?int $width = null, ?int $height = null): self;\n\n    /**\n     * @see ImageInterface::scaleDown()\n     *\n     * @throws GeometryException\n     */\n    public function scaleDown(?int $width = null, ?int $height = null): self;\n\n    /**\n     * @see ImageInterface::cover()\n     *\n     * @throws GeometryException\n     */\n    public function cover(int $width, int $height): self;\n\n    /**\n     * @see ImageInterface::contain()\n     *\n     * @throws GeometryException\n     */\n    public function contain(int $width, int $height): self;\n\n    /**\n     * @throws GeometryException\n     */\n    public function containMax(int $width, int $height): self;\n}\n"
  },
  {
    "path": "src/Interfaces/SpecializableInterface.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Interfaces;\n\nuse Intervention\\Image\\Exceptions\\DriverException;\n\ninterface SpecializableInterface\n{\n    /**\n     * Return an array of constructor parameters, which is usually passed from\n     * the generic object to the specialized object\n     *\n     * @return array<string, mixed>\n     */\n    public function specializable(): array;\n\n    /**\n     * Set the driver for which the object is specialized\n     *\n     * @throws DriverException\n     */\n    public function setDriver(DriverInterface $driver): self;\n\n    /**\n     * Return the driver for which the object was specialized\n     */\n    public function driver(): DriverInterface;\n}\n"
  },
  {
    "path": "src/Interfaces/SpecializedInterface.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Interfaces;\n\ninterface SpecializedInterface\n{\n    //\n}\n"
  },
  {
    "path": "src/MediaType.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image;\n\nuse Error;\nuse Intervention\\Image\\Exceptions\\NotSupportedException;\n\nenum MediaType: string\n{\n    case IMAGE_JPEG = 'image/jpeg';\n    case IMAGE_JPG = 'image/jpg';\n    case IMAGE_PJPEG = 'image/pjpeg';\n    case IMAGE_X_JPEG = 'image/x-jpeg';\n    case IMAGE_WEBP = 'image/webp';\n    case IMAGE_X_WEBP = 'image/x-webp';\n    case IMAGE_GIF = 'image/gif';\n    case IMAGE_PNG = 'image/png';\n    case IMAGE_X_PNG = 'image/x-png';\n    case IMAGE_AVIF = 'image/avif';\n    case IMAGE_X_AVIF = 'image/x-avif';\n    case IMAGE_BMP = 'image/bmp';\n    case IMAGE_MS_BMP = 'image/ms-bmp';\n    case IMAGE_X_BITMAP = 'image/x-bitmap';\n    case IMAGE_X_BMP = 'image/x-bmp';\n    case IMAGE_X_MS_BMP = 'image/x-ms-bmp';\n    case IMAGE_X_WINDOWS_BMP = 'image/x-windows-bmp';\n    case IMAGE_X_WIN_BITMAP = 'image/x-win-bitmap';\n    case IMAGE_X_XBITMAP = 'image/x-xbitmap';\n    case IMAGE_X_BMP3 = 'image/x-bmp3';\n    case IMAGE_TIFF = 'image/tiff';\n    case IMAGE_JP2 = 'image/jp2';\n    case IMAGE_X_JP2_CODESTREAM = 'image/x-jp2-codestream';\n    case IMAGE_JPX = 'image/jpx';\n    case IMAGE_JPM = 'image/jpm';\n    case IMAGE_HEIC = 'image/heic';\n    case IMAGE_X_HEIC = 'image/x-heic';\n    case IMAGE_HEIF = 'image/heif';\n\n    /**\n     * Create media type from given identifier\n     *\n     * @param string|Format|MediaType|FileExtension $identifier\n     * @throws NotSupportedException\n     */\n    public static function create(string|self|Format|FileExtension $identifier): self\n    {\n        if ($identifier instanceof self) {\n            return $identifier;\n        }\n\n        if ($identifier instanceof Format) {\n            return $identifier->mediaType();\n        }\n\n        if ($identifier instanceof FileExtension) {\n            return $identifier->mediaType();\n        }\n\n        try {\n            $type = self::from(strtolower($identifier));\n        } catch (Error) {\n            try {\n                $type = FileExtension::from(strtolower($identifier))->mediaType();\n            } catch (Error) {\n                throw new NotSupportedException('Unable to create media type from \"' . $identifier . '\".');\n            }\n        }\n\n        return $type;\n    }\n\n    /**\n     * Try to create media type from given identifier and return null on failure\n     *\n     * @param string|Format|MediaType|FileExtension $identifier\n     * @return MediaType|null\n     */\n    public static function tryCreate(string|self|Format|FileExtension $identifier): ?self\n    {\n        try {\n            return self::create($identifier);\n        } catch (NotSupportedException) {\n            return null;\n        }\n    }\n\n    /**\n     * Return the matching format for the current media (MIME) type\n     */\n    public function format(): Format\n    {\n        return match ($this) {\n            self::IMAGE_JPEG,\n            self::IMAGE_JPG,\n            self::IMAGE_PJPEG,\n            self::IMAGE_X_JPEG => Format::JPEG,\n            self::IMAGE_WEBP,\n            self::IMAGE_X_WEBP => Format::WEBP,\n            self::IMAGE_GIF => Format::GIF,\n            self::IMAGE_PNG,\n            self::IMAGE_X_PNG => Format::PNG,\n            self::IMAGE_AVIF,\n            self::IMAGE_X_AVIF => Format::AVIF,\n            self::IMAGE_BMP,\n            self::IMAGE_MS_BMP,\n            self::IMAGE_X_BITMAP,\n            self::IMAGE_X_BMP,\n            self::IMAGE_X_MS_BMP,\n            self::IMAGE_X_XBITMAP,\n            self::IMAGE_X_WINDOWS_BMP,\n            self::IMAGE_X_BMP3,\n            self::IMAGE_X_WIN_BITMAP => Format::BMP,\n            self::IMAGE_TIFF => Format::TIFF,\n            self::IMAGE_JP2,\n            self::IMAGE_JPX,\n            self::IMAGE_X_JP2_CODESTREAM,\n            self::IMAGE_JPM => Format::JP2,\n            self::IMAGE_HEIF,\n            self::IMAGE_HEIC,\n            self::IMAGE_X_HEIC => Format::HEIC,\n        };\n    }\n\n    /**\n     * Return the possible file extension for the current media type\n     *\n     * @return array<FileExtension>\n     */\n    public function fileExtensions(): array\n    {\n        return $this->format()->fileExtensions();\n    }\n\n    /**\n     * Return the first file extension for the current media type\n     */\n    public function fileExtension(): FileExtension\n    {\n        return $this->format()->fileExtension();\n    }\n}\n"
  },
  {
    "path": "src/ModifierStack.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image;\n\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\ModifierInterface;\n\nclass ModifierStack implements ModifierInterface\n{\n    /**\n     * Create new modifier stack object with an array of modifier objects\n     *\n     * @param array<ModifierInterface> $modifiers\n     * @return void\n     */\n    public function __construct(protected array $modifiers)\n    {\n        //\n    }\n\n    /**\n     * Apply all modifiers in stack to the given image\n     */\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        foreach ($this->modifiers as $modifier) {\n            $modifier->apply($image);\n        }\n\n        return $image;\n    }\n\n    /**\n     * Append new modifier to the stack\n     */\n    public function push(ModifierInterface $modifier): self\n    {\n        $this->modifiers[] = $modifier;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/Modifiers/AbstractDrawModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Modifiers;\n\nuse Intervention\\Image\\Drivers\\SpecializableModifier;\nuse Intervention\\Image\\Exceptions\\DecoderException;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Interfaces\\DrawableInterface;\nuse RuntimeException;\n\nabstract class AbstractDrawModifier extends SpecializableModifier\n{\n    /**\n     * Return the drawable object which will be rendered by the modifier\n     */\n    abstract public function drawable(): DrawableInterface;\n\n    /**\n     * @throws RuntimeException\n     */\n    public function backgroundColor(): ColorInterface\n    {\n        try {\n            $color = $this->driver()->handleInput($this->drawable()->backgroundColor());\n        } catch (DecoderException) {\n            return $this->driver()->handleInput('transparent');\n        }\n\n        return $color;\n    }\n\n    /**\n     * @throws RuntimeException\n     */\n    public function borderColor(): ColorInterface\n    {\n        try {\n            $color = $this->driver()->handleInput($this->drawable()->borderColor());\n        } catch (DecoderException) {\n            return $this->driver()->handleInput('transparent');\n        }\n\n        return $color;\n    }\n}\n"
  },
  {
    "path": "src/Modifiers/AlignRotationModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Modifiers;\n\nuse Intervention\\Image\\Drivers\\SpecializableModifier;\n\nclass AlignRotationModifier extends SpecializableModifier\n{\n    //\n}\n"
  },
  {
    "path": "src/Modifiers/BlendTransparencyModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Modifiers;\n\nuse Intervention\\Image\\Colors\\Rgb\\Channels\\Blue;\nuse Intervention\\Image\\Colors\\Rgb\\Channels\\Green;\nuse Intervention\\Image\\Colors\\Rgb\\Channels\\Red;\nuse Intervention\\Image\\Colors\\Rgb\\Color;\nuse Intervention\\Image\\Drivers\\SpecializableModifier;\nuse Intervention\\Image\\Exceptions\\ColorException;\nuse Intervention\\Image\\Exceptions\\RuntimeException;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Interfaces\\DriverInterface;\n\nclass BlendTransparencyModifier extends SpecializableModifier\n{\n    /**\n     * Create new modifier object\n     *\n     * @return void\n     */\n    public function __construct(public mixed $color = null)\n    {\n        //\n    }\n\n    /**\n     * Decode blending color of current modifier with given driver. Possible\n     * (semi-)transparent alpha channel values are made opaque.\n     *\n     * @throws RuntimeException\n     * @throws ColorException\n     */\n    protected function blendingColor(DriverInterface $driver): ColorInterface\n    {\n        // decode blending color\n        $color = $driver->handleInput(\n            $this->color ?: $driver->config()->blendingColor\n        );\n\n        // replace alpha channel value with opaque value\n        if ($color->isTransparent()) {\n            return new Color(\n                $color->channel(Red::class)->value(),\n                $color->channel(Green::class)->value(),\n                $color->channel(Blue::class)->value(),\n            );\n        }\n\n        return $color;\n    }\n}\n"
  },
  {
    "path": "src/Modifiers/BlurModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Modifiers;\n\nuse Intervention\\Image\\Drivers\\SpecializableModifier;\n\nclass BlurModifier extends SpecializableModifier\n{\n    public function __construct(public int $amount)\n    {\n        //\n    }\n}\n"
  },
  {
    "path": "src/Modifiers/BrightnessModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Modifiers;\n\nuse Intervention\\Image\\Drivers\\SpecializableModifier;\n\nclass BrightnessModifier extends SpecializableModifier\n{\n    public function __construct(public int $level)\n    {\n        //\n    }\n}\n"
  },
  {
    "path": "src/Modifiers/ColorizeModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Modifiers;\n\nuse Intervention\\Image\\Drivers\\SpecializableModifier;\n\nclass ColorizeModifier extends SpecializableModifier\n{\n    /**\n     * Create new modifier object\n     *\n     * @return void\n     */\n    public function __construct(\n        public int $red = 0,\n        public int $green = 0,\n        public int $blue = 0\n    ) {\n        //\n    }\n}\n"
  },
  {
    "path": "src/Modifiers/ColorspaceModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Modifiers;\n\nuse Intervention\\Image\\Interfaces\\ColorspaceInterface;\nuse Intervention\\Image\\Colors\\Cmyk\\Colorspace as CmykColorspace;\nuse Intervention\\Image\\Colors\\Rgb\\Colorspace as RgbColorspace;\nuse Intervention\\Image\\Drivers\\SpecializableModifier;\nuse Intervention\\Image\\Exceptions\\NotSupportedException;\n\nclass ColorspaceModifier extends SpecializableModifier\n{\n    public function __construct(public string|ColorspaceInterface $target)\n    {\n        //\n    }\n\n    /**\n     * @throws NotSupportedException\n     */\n    public function targetColorspace(): ColorspaceInterface\n    {\n        if (is_object($this->target)) {\n            return $this->target;\n        }\n\n        if (in_array($this->target, ['rgb', 'RGB', RgbColorspace::class])) {\n            return new RgbColorspace();\n        }\n\n        if (in_array($this->target, ['cmyk', 'CMYK', CmykColorspace::class])) {\n            return new CmykColorspace();\n        }\n\n        throw new NotSupportedException('Given colorspace is not supported.');\n    }\n}\n"
  },
  {
    "path": "src/Modifiers/ContainModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Modifiers;\n\nuse Intervention\\Image\\Drivers\\SpecializableModifier;\nuse Intervention\\Image\\Exceptions\\RuntimeException;\nuse Intervention\\Image\\Geometry\\Rectangle;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SizeInterface;\n\nclass ContainModifier extends SpecializableModifier\n{\n    public function __construct(\n        public int $width,\n        public int $height,\n        public mixed $background = 'ffffff',\n        public string $position = 'center'\n    ) {\n        //\n    }\n\n    /**\n     * @throws RuntimeException\n     */\n    public function getCropSize(ImageInterface $image): SizeInterface\n    {\n        return $image->size()\n            ->contain(\n                $this->width,\n                $this->height\n            )\n            ->alignPivotTo(\n                $this->getResizeSize($image),\n                $this->position\n            );\n    }\n\n    public function getResizeSize(ImageInterface $image): SizeInterface\n    {\n        return new Rectangle($this->width, $this->height);\n    }\n}\n"
  },
  {
    "path": "src/Modifiers/ContrastModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Modifiers;\n\nuse Intervention\\Image\\Drivers\\SpecializableModifier;\n\nclass ContrastModifier extends SpecializableModifier\n{\n    /**\n     * Create new modifier object\n     *\n     * @return void\n     */\n    public function __construct(public int $level)\n    {\n        //\n    }\n}\n"
  },
  {
    "path": "src/Modifiers/CoverDownModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Modifiers;\n\nclass CoverDownModifier extends CoverModifier\n{\n    //\n}\n"
  },
  {
    "path": "src/Modifiers/CoverModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Modifiers;\n\nuse Intervention\\Image\\Drivers\\SpecializableModifier;\nuse Intervention\\Image\\Exceptions\\RuntimeException;\nuse Intervention\\Image\\Geometry\\Rectangle;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SizeInterface;\n\nclass CoverModifier extends SpecializableModifier\n{\n    /**\n     * Create new modifier object\n     *\n     * @return void\n     */\n    public function __construct(\n        public int $width,\n        public int $height,\n        public string $position = 'center'\n    ) {\n        //\n    }\n\n    /**\n     * @throws RuntimeException\n     */\n    public function getCropSize(ImageInterface $image): SizeInterface\n    {\n        $imagesize = $image->size();\n        $crop = new Rectangle($this->width, $this->height);\n\n        return $crop->contain(\n            $imagesize->width(),\n            $imagesize->height()\n        )->alignPivotTo($imagesize, $this->position);\n    }\n\n    /**\n     * @throws RuntimeException\n     */\n    public function getResizeSize(SizeInterface $size): SizeInterface\n    {\n        return $size->resize($this->width, $this->height);\n    }\n}\n"
  },
  {
    "path": "src/Modifiers/CropModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Modifiers;\n\nuse Intervention\\Image\\Drivers\\SpecializableModifier;\nuse Intervention\\Image\\Exceptions\\RuntimeException;\nuse Intervention\\Image\\Geometry\\Rectangle;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SizeInterface;\n\nclass CropModifier extends SpecializableModifier\n{\n    /**\n     * Create new modifier object\n     *\n     * @return void\n     */\n    public function __construct(\n        public int $width,\n        public int $height,\n        public int $offset_x = 0,\n        public int $offset_y = 0,\n        public mixed $background = 'ffffff',\n        public string $position = 'top-left'\n    ) {\n        //\n    }\n\n    /**\n     * @throws RuntimeException\n     */\n    public function crop(ImageInterface $image): SizeInterface\n    {\n        $crop = new Rectangle($this->width, $this->height);\n        $crop->align($this->position);\n\n        return $crop->alignPivotTo(\n            $image->size(),\n            $this->position\n        );\n    }\n}\n"
  },
  {
    "path": "src/Modifiers/DrawBezierModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Modifiers;\n\nuse Intervention\\Image\\Geometry\\Bezier;\nuse Intervention\\Image\\Interfaces\\DrawableInterface;\n\nclass DrawBezierModifier extends AbstractDrawModifier\n{\n    /**\n     * Create new modifier object\n     *\n     * @return void\n     */\n    public function __construct(public Bezier $drawable)\n    {\n        //\n    }\n\n    /**\n     * Return object to be drawn\n     */\n    public function drawable(): DrawableInterface\n    {\n        return $this->drawable;\n    }\n}\n"
  },
  {
    "path": "src/Modifiers/DrawEllipseModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Modifiers;\n\nuse Intervention\\Image\\Geometry\\Ellipse;\nuse Intervention\\Image\\Interfaces\\DrawableInterface;\n\nclass DrawEllipseModifier extends AbstractDrawModifier\n{\n    public function __construct(public Ellipse $drawable)\n    {\n        //\n    }\n\n    public function drawable(): DrawableInterface\n    {\n        return $this->drawable;\n    }\n}\n"
  },
  {
    "path": "src/Modifiers/DrawLineModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Modifiers;\n\nuse Intervention\\Image\\Geometry\\Line;\nuse Intervention\\Image\\Interfaces\\DrawableInterface;\n\nclass DrawLineModifier extends AbstractDrawModifier\n{\n    /**\n     * Create new modifier object\n     *\n     * @return void\n     */\n    public function __construct(public Line $drawable)\n    {\n        //\n    }\n\n    /**\n     * Return object to be drawn\n     */\n    public function drawable(): DrawableInterface\n    {\n        return $this->drawable;\n    }\n}\n"
  },
  {
    "path": "src/Modifiers/DrawPixelModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Modifiers;\n\nuse Intervention\\Image\\Drivers\\SpecializableModifier;\nuse Intervention\\Image\\Interfaces\\PointInterface;\n\nclass DrawPixelModifier extends SpecializableModifier\n{\n    /**\n     * Create new modifier object\n     *\n     * @return void\n     */\n    public function __construct(\n        public PointInterface $position,\n        public mixed $color\n    ) {\n        //\n    }\n}\n"
  },
  {
    "path": "src/Modifiers/DrawPolygonModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Modifiers;\n\nuse Intervention\\Image\\Geometry\\Polygon;\nuse Intervention\\Image\\Interfaces\\DrawableInterface;\n\nclass DrawPolygonModifier extends AbstractDrawModifier\n{\n    public function __construct(public Polygon $drawable)\n    {\n        //\n    }\n\n    public function drawable(): DrawableInterface\n    {\n        return $this->drawable;\n    }\n}\n"
  },
  {
    "path": "src/Modifiers/DrawRectangleModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Modifiers;\n\nuse Intervention\\Image\\Geometry\\Rectangle;\nuse Intervention\\Image\\Interfaces\\DrawableInterface;\n\nclass DrawRectangleModifier extends AbstractDrawModifier\n{\n    /**\n     * Create new modifier object\n     *\n     * @return void\n     */\n    public function __construct(public Rectangle $drawable)\n    {\n        //\n    }\n\n    /**\n     * Return object to be drawn\n     */\n    public function drawable(): DrawableInterface\n    {\n        return $this->drawable;\n    }\n}\n"
  },
  {
    "path": "src/Modifiers/FillModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Modifiers;\n\nuse Intervention\\Image\\Drivers\\SpecializableModifier;\nuse Intervention\\Image\\Interfaces\\PointInterface;\n\nclass FillModifier extends SpecializableModifier\n{\n    public function __construct(\n        public mixed $color,\n        public ?PointInterface $position = null\n    ) {\n        //\n    }\n\n    public function hasPosition(): bool\n    {\n        return $this->position instanceof PointInterface;\n    }\n}\n"
  },
  {
    "path": "src/Modifiers/FlipModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Modifiers;\n\nuse Intervention\\Image\\Drivers\\SpecializableModifier;\n\nclass FlipModifier extends SpecializableModifier\n{\n    //\n}\n"
  },
  {
    "path": "src/Modifiers/FlopModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Modifiers;\n\nuse Intervention\\Image\\Drivers\\SpecializableModifier;\n\nclass FlopModifier extends SpecializableModifier\n{\n    //\n}\n"
  },
  {
    "path": "src/Modifiers/GammaModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Modifiers;\n\nuse Intervention\\Image\\Drivers\\SpecializableModifier;\n\nclass GammaModifier extends SpecializableModifier\n{\n    public function __construct(public float $gamma)\n    {\n        //\n    }\n}\n"
  },
  {
    "path": "src/Modifiers/GreyscaleModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Modifiers;\n\nuse Intervention\\Image\\Drivers\\SpecializableModifier;\n\nclass GreyscaleModifier extends SpecializableModifier\n{\n    //\n}\n"
  },
  {
    "path": "src/Modifiers/InvertModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Modifiers;\n\nuse Intervention\\Image\\Drivers\\SpecializableModifier;\n\nclass InvertModifier extends SpecializableModifier\n{\n    //\n}\n"
  },
  {
    "path": "src/Modifiers/PadModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Modifiers;\n\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SizeInterface;\n\nclass PadModifier extends ContainModifier\n{\n    public function getCropSize(ImageInterface $image): SizeInterface\n    {\n        return $image->size()\n            ->containMax(\n                $this->width,\n                $this->height\n            )\n            ->alignPivotTo(\n                $this->getResizeSize($image),\n                $this->position\n            );\n    }\n}\n"
  },
  {
    "path": "src/Modifiers/PixelateModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Modifiers;\n\nuse Intervention\\Image\\Drivers\\SpecializableModifier;\n\nclass PixelateModifier extends SpecializableModifier\n{\n    public function __construct(public int $size)\n    {\n        //\n    }\n}\n"
  },
  {
    "path": "src/Modifiers/PlaceModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Modifiers;\n\nuse Intervention\\Image\\Drivers\\SpecializableModifier;\nuse Intervention\\Image\\Exceptions\\RuntimeException;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\PointInterface;\n\nclass PlaceModifier extends SpecializableModifier\n{\n    /**\n     * Create new modifier object\n     *\n     * @return void\n     */\n    public function __construct(\n        public mixed $element,\n        public string $position = 'top-left',\n        public int $offset_x = 0,\n        public int $offset_y = 0,\n        public int $opacity = 100\n    ) {\n        //\n    }\n\n    /**\n     * @throws RuntimeException\n     */\n    public function getPosition(ImageInterface $image, ImageInterface $watermark): PointInterface\n    {\n        $image_size = $image->size()->movePivot(\n            $this->position,\n            $this->offset_x,\n            $this->offset_y\n        );\n\n        $watermark_size = $watermark->size()->movePivot(\n            $this->position\n        );\n\n        return $image_size->relativePositionTo($watermark_size);\n    }\n}\n"
  },
  {
    "path": "src/Modifiers/ProfileModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Modifiers;\n\nuse Intervention\\Image\\Drivers\\SpecializableModifier;\nuse Intervention\\Image\\Interfaces\\ProfileInterface;\n\nclass ProfileModifier extends SpecializableModifier\n{\n    public function __construct(public ProfileInterface $profile)\n    {\n        //\n    }\n}\n"
  },
  {
    "path": "src/Modifiers/ProfileRemovalModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Modifiers;\n\nuse Intervention\\Image\\Drivers\\SpecializableModifier;\n\nclass ProfileRemovalModifier extends SpecializableModifier\n{\n    //\n}\n"
  },
  {
    "path": "src/Modifiers/QuantizeColorsModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Modifiers;\n\nuse Intervention\\Image\\Drivers\\SpecializableModifier;\n\nclass QuantizeColorsModifier extends SpecializableModifier\n{\n    /**\n     * Create new modifier object\n     *\n     * @return void\n     */\n    public function __construct(\n        public int $limit,\n        public mixed $background = 'ffffff'\n    ) {\n        //\n    }\n}\n"
  },
  {
    "path": "src/Modifiers/RemoveAnimationModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Modifiers;\n\nuse Intervention\\Image\\Drivers\\SpecializableModifier;\nuse Intervention\\Image\\Exceptions\\InputException;\nuse Intervention\\Image\\Exceptions\\RuntimeException;\nuse Intervention\\Image\\Interfaces\\FrameInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\n\nclass RemoveAnimationModifier extends SpecializableModifier\n{\n    public function __construct(public int|string $position = 0)\n    {\n        //\n    }\n\n    /**\n     * @throws RuntimeException\n     */\n    protected function selectedFrame(ImageInterface $image): FrameInterface\n    {\n        return $image->core()->frame($this->normalizePosition($image));\n    }\n\n    /**\n     * Return the position of the selected frame as integer\n     *\n     * @throws InputException\n     */\n    protected function normalizePosition(ImageInterface $image): int\n    {\n        if (is_int($this->position)) {\n            return $this->position;\n        }\n\n        if (is_numeric($this->position)) {\n            return (int) $this->position;\n        }\n\n        // calculate position from percentage value\n        if (preg_match(\"/^(?P<percent>[0-9]{1,3})%$/\", $this->position, $matches) != 1) {\n            throw new InputException(\n                'Position must be either integer or a percent value as string.'\n            );\n        }\n\n        $total = count($image);\n        $position = intval(round($total / 100 * intval($matches['percent'])));\n\n        return $position == $total ? $position - 1 : $position;\n    }\n}\n"
  },
  {
    "path": "src/Modifiers/ResizeCanvasModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Modifiers;\n\nuse Intervention\\Image\\Drivers\\SpecializableModifier;\nuse Intervention\\Image\\Exceptions\\RuntimeException;\nuse Intervention\\Image\\Geometry\\Rectangle;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SizeInterface;\n\nclass ResizeCanvasModifier extends SpecializableModifier\n{\n    /**\n     * Create new modifier object\n     *\n     * @return void\n     */\n    public function __construct(\n        public ?int $width = null,\n        public ?int $height = null,\n        public mixed $background = 'ffffff',\n        public string $position = 'center'\n    ) {\n        //\n    }\n\n    /**\n     * Build the crop size to be used for the ResizeCanvas process\n     *\n     * @throws RuntimeException\n     */\n    protected function cropSize(ImageInterface $image, bool $relative = false): SizeInterface\n    {\n        $size = match ($relative) {\n            true => new Rectangle(\n                is_null($this->width) ? $image->width() : $image->width() + $this->width,\n                is_null($this->height) ? $image->height() : $image->height() + $this->height,\n            ),\n            default => new Rectangle(\n                is_null($this->width) ? $image->width() : $this->width,\n                is_null($this->height) ? $image->height() : $this->height,\n            ),\n        };\n\n        return $size->alignPivotTo($image->size(), $this->position);\n    }\n}\n"
  },
  {
    "path": "src/Modifiers/ResizeCanvasRelativeModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Modifiers;\n\nclass ResizeCanvasRelativeModifier extends ResizeCanvasModifier\n{\n    //\n}\n"
  },
  {
    "path": "src/Modifiers/ResizeDownModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Modifiers;\n\nclass ResizeDownModifier extends ResizeModifier\n{\n    //\n}\n"
  },
  {
    "path": "src/Modifiers/ResizeModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Modifiers;\n\nuse Intervention\\Image\\Drivers\\SpecializableModifier;\n\nclass ResizeModifier extends SpecializableModifier\n{\n    /**\n     * Create new modifier object\n     *\n     * @return void\n     */\n    public function __construct(public ?int $width = null, public ?int $height = null)\n    {\n        //\n    }\n}\n"
  },
  {
    "path": "src/Modifiers/ResolutionModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Modifiers;\n\nuse Intervention\\Image\\Drivers\\SpecializableModifier;\n\nclass ResolutionModifier extends SpecializableModifier\n{\n    /**\n     * Create new modifier object\n     *\n     * @return void\n     */\n    public function __construct(public float $x, public float $y)\n    {\n        //\n    }\n}\n"
  },
  {
    "path": "src/Modifiers/RotateModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Modifiers;\n\nuse Intervention\\Image\\Drivers\\SpecializableModifier;\n\nclass RotateModifier extends SpecializableModifier\n{\n    public function __construct(public float $angle, public mixed $background)\n    {\n        //\n    }\n\n    /**\n     * Restrict rotations beyond 360 degrees\n     * because the end result is the same\n     */\n    public function rotationAngle(): float\n    {\n        return fmod($this->angle, 360);\n    }\n}\n"
  },
  {
    "path": "src/Modifiers/ScaleDownModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Modifiers;\n\nclass ScaleDownModifier extends ScaleModifier\n{\n    //\n}\n"
  },
  {
    "path": "src/Modifiers/ScaleModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Modifiers;\n\nclass ScaleModifier extends ResizeModifier\n{\n    //\n}\n"
  },
  {
    "path": "src/Modifiers/SharpenModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Modifiers;\n\nuse Intervention\\Image\\Drivers\\SpecializableModifier;\n\nclass SharpenModifier extends SpecializableModifier\n{\n    public function __construct(public int $amount)\n    {\n        //\n    }\n}\n"
  },
  {
    "path": "src/Modifiers/SliceAnimationModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Modifiers;\n\nuse Intervention\\Image\\Drivers\\SpecializableModifier;\n\nclass SliceAnimationModifier extends SpecializableModifier\n{\n    public function __construct(public int $offset = 0, public ?int $length = null)\n    {\n        //\n    }\n}\n"
  },
  {
    "path": "src/Modifiers/TextModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Modifiers;\n\nuse Intervention\\Image\\Drivers\\SpecializableModifier;\nuse Intervention\\Image\\Exceptions\\ColorException;\nuse Intervention\\Image\\Exceptions\\RuntimeException;\nuse Intervention\\Image\\Geometry\\Point;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Interfaces\\FontInterface;\nuse Intervention\\Image\\Interfaces\\PointInterface;\n\nclass TextModifier extends SpecializableModifier\n{\n    /**\n     * Create new modifier object\n     *\n     * @return void\n     */\n    public function __construct(\n        public string $text,\n        public PointInterface $position,\n        public FontInterface $font\n    ) {\n        //\n    }\n\n    /**\n     * Decode text color\n     *\n     * The text outline effect is drawn with a trick by plotting additional text\n     * under the actual text with an offset in the color of the outline effect.\n     * For this reason, no colors with transparency can be used for the text\n     * color or the color of the stroke effect, as this would be superimposed.\n     *\n     * @throws RuntimeException\n     * @throws ColorException\n     */\n    protected function textColor(): ColorInterface\n    {\n        $color = $this->driver()->handleInput($this->font->color());\n\n        if ($this->font->hasStrokeEffect() && $color->isTransparent()) {\n            throw new ColorException(\n                'The text color must be fully opaque when using the stroke effect.'\n            );\n        }\n\n        return $color;\n    }\n\n    /**\n     * Decode outline stroke color\n     *\n     * @throws RuntimeException\n     * @throws ColorException\n     */\n    protected function strokeColor(): ColorInterface\n    {\n        $color = $this->driver()->handleInput($this->font->strokeColor());\n\n        if ($color->isTransparent()) {\n            throw new ColorException(\n                'The stroke color must be fully opaque.'\n            );\n        }\n\n        return $color;\n    }\n\n    /**\n     * Return array of offset points to draw text stroke effect below the actual text\n     *\n     * @return array<PointInterface>\n     */\n    protected function strokeOffsets(FontInterface $font): array\n    {\n        $offsets = [];\n\n        if ($font->strokeWidth() <= 0) {\n            return $offsets;\n        }\n\n        for ($x = $font->strokeWidth() * -1; $x <= $font->strokeWidth(); $x++) {\n            for ($y = $font->strokeWidth() * -1; $y <= $font->strokeWidth(); $y++) {\n                $offsets[] = new Point($x, $y);\n            }\n        }\n\n        return $offsets;\n    }\n}\n"
  },
  {
    "path": "src/Modifiers/TrimModifier.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Modifiers;\n\nuse Intervention\\Image\\Drivers\\SpecializableModifier;\n\nclass TrimModifier extends SpecializableModifier\n{\n    /**\n     * Create new modifier object\n     *\n     * @return void\n     */\n    public function __construct(public int $tolerance = 0)\n    {\n        //\n    }\n}\n"
  },
  {
    "path": "src/Origin.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image;\n\nclass Origin\n{\n    /**\n     * Create new origin instance\n     *\n     * @return void\n     */\n    public function __construct(\n        protected string $mediaType = 'application/octet-stream',\n        protected ?string $filePath = null\n    ) {\n        //\n    }\n\n    /**\n     * Return media type of origin\n     */\n    public function mediaType(): string\n    {\n        return $this->mediaType;\n    }\n\n    /**\n     * Alias of self::mediaType()\n     */\n    public function mimetype(): string\n    {\n        return $this->mediaType();\n    }\n\n    /**\n     * Set media type of current instance\n     */\n    public function setMediaType(string|MediaType $type): self\n    {\n        $this->mediaType = match (true) {\n            is_string($type) => $type,\n            default => $type->value,\n        };\n\n        return $this;\n    }\n\n    /**\n     * Return file path of origin\n     */\n    public function filePath(): ?string\n    {\n        return $this->filePath;\n    }\n\n    /**\n     * Set file path for origin\n     */\n    public function setFilePath(string $path): self\n    {\n        $this->filePath = $path;\n\n        return $this;\n    }\n\n    /**\n     * Return file extension if origin was created from file path\n     */\n    public function fileExtension(): ?string\n    {\n        return pathinfo($this->filePath ?: '', PATHINFO_EXTENSION) ?: null;\n    }\n\n    /**\n     * Show debug info for the current image\n     *\n     * @return array<string, null|string>\n     */\n    public function __debugInfo(): array\n    {\n        return [\n            'mediaType' => $this->mediaType(),\n            'filePath' => $this->filePath(),\n        ];\n    }\n}\n"
  },
  {
    "path": "src/Resolution.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image;\n\nuse ArrayIterator;\nuse Intervention\\Image\\Interfaces\\ResolutionInterface;\nuse IteratorAggregate;\nuse Stringable;\nuse Traversable;\n\n/**\n * @implements IteratorAggregate<float>\n */\nclass Resolution implements ResolutionInterface, Stringable, IteratorAggregate\n{\n    public const PER_INCH = 1;\n    public const PER_CM = 2;\n\n    /**\n     * Create new instance\n     */\n    public function __construct(\n        protected float $x,\n        protected float $y,\n        protected int $per_unit = self::PER_INCH\n    ) {\n        //\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see IteratorAggregate::getIterator()\n     */\n    public function getIterator(): Traversable\n    {\n        return new ArrayIterator([$this->x, $this->y]);\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ResolutionInterface::x()\n     */\n    public function x(): float\n    {\n        return $this->x;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ResolutionInterface::setX()\n     */\n    public function setX(float $x): self\n    {\n        $this->x = $x;\n\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ResolutionInterface::y()\n     */\n    public function y(): float\n    {\n        return $this->y;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ResolutionInterface::setY()\n     */\n    public function setY(float $y): self\n    {\n        $this->y = $y;\n\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ResolutionInterface::setPerUnit()\n     */\n    protected function setPerUnit(int $per_unit): self\n    {\n        $this->per_unit = $per_unit;\n\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ResolutionInterface::unit()\n     */\n    public function unit(): string\n    {\n        return match ($this->per_unit) {\n            self::PER_CM => 'dpcm',\n            default => 'dpi',\n        };\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ResolutionInterface::perInch()\n     */\n    public function perInch(): self\n    {\n        return match ($this->per_unit) {\n            self::PER_CM => $this\n                ->setPerUnit(self::PER_INCH)\n                ->setX($this->x * 2.54)\n                ->setY($this->y * 2.54),\n            default => $this\n        };\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ResolutionInterface::perCm()\n     */\n    public function perCm(): self\n    {\n        return match ($this->per_unit) {\n            self::PER_INCH => $this\n                ->setPerUnit(self::PER_CM)\n                ->setX($this->x / 2.54)\n                ->setY($this->y / 2.54),\n            default => $this,\n        };\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ResolutionInterface::toString()\n     */\n    public function toString(): string\n    {\n        return sprintf(\"%1\\$.2f x %2\\$.2f %3\\$s\", $this->x, $this->y, $this->unit());\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ResolutionInterface::__toString()\n     */\n    public function __toString(): string\n    {\n        return $this->toString();\n    }\n}\n"
  },
  {
    "path": "src/Traits/CanBeDriverSpecialized.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Traits;\n\nuse Intervention\\Image\\Exceptions\\DriverException;\nuse Intervention\\Image\\Interfaces\\DriverInterface;\nuse Intervention\\Image\\Interfaces\\SpecializableInterface;\nuse ReflectionClass;\n\ntrait CanBeDriverSpecialized\n{\n    /**\n     * The driver with which the instance may be specialized\n     */\n    protected DriverInterface $driver;\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see SpecializableInterface::specializable()\n     */\n    public function specializable(): array\n    {\n        $specializable = [];\n\n        $reflectionClass = new ReflectionClass($this::class);\n        if ($constructor = $reflectionClass->getConstructor()) {\n            foreach ($constructor->getParameters() as $parameter) {\n                $specializable[$parameter->getName()] = $this->{$parameter->getName()};\n            }\n        }\n\n        return $specializable;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see SpecializableInterface::driver()\n     */\n    public function driver(): DriverInterface\n    {\n        return $this->driver;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see SpecializableInterface::setDriver()\n     */\n    public function setDriver(DriverInterface $driver): SpecializableInterface\n    {\n        if (!$this->belongsToDriver($driver)) {\n            throw new DriverException(\n                \"Class '\" . $this::class . \"' can not be used with \" . $driver->id() . \" driver.\"\n            );\n        }\n\n        $this->driver = $driver;\n\n        return $this;\n    }\n\n    /**\n     * Determine if the current object belongs to the given driver's namespace\n     */\n    protected function belongsToDriver(object $driver): bool\n    {\n        $namespace = function (object $object): string {\n            return (new ReflectionClass($object))->getNamespaceName();\n        };\n\n        return str_starts_with($namespace($this), $namespace($driver));\n    }\n}\n"
  },
  {
    "path": "src/Traits/CanBuildFilePointer.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Traits;\n\nuse Intervention\\Image\\Exceptions\\RuntimeException;\n\ntrait CanBuildFilePointer\n{\n    /**\n     * Transform the provided data into a pointer with the data as its content\n     *\n     * @param resource|string|null $data\n     * @throws RuntimeException\n     * @return resource|false\n     */\n    public function buildFilePointer(mixed $data = null)\n    {\n        switch (true) {\n            case is_string($data):\n                $pointer = fopen('php://temp', 'r+');\n                fwrite($pointer, $data);\n                break;\n\n            case is_resource($data) && get_resource_type($data) === 'stream':\n                $pointer = $data;\n                break;\n\n            case is_null($data):\n                $pointer = fopen('php://temp', 'r+');\n                break;\n\n            default:\n                throw new RuntimeException('Unable to build file pointer.');\n        }\n\n        rewind($pointer);\n\n        return $pointer;\n    }\n}\n"
  },
  {
    "path": "src/Typography/Font.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Typography;\n\nuse Intervention\\Image\\Exceptions\\FontException;\nuse Intervention\\Image\\Interfaces\\FontInterface;\n\nclass Font implements FontInterface\n{\n    protected float $size = 12;\n    protected float $angle = 0;\n    protected mixed $color = '000000';\n    protected mixed $strokeColor = 'ffffff';\n    protected int $strokeWidth = 0;\n    protected ?string $filename = null;\n    protected string $alignment = 'left';\n    protected string $valignment = 'bottom';\n    protected float $lineHeight = 1.25;\n    protected ?int $wrapWidth = null;\n\n    public function __construct(?string $filename = null)\n    {\n        $this->filename = $filename;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see FontInterface::setSize()\n     */\n    public function setSize(float $size): FontInterface\n    {\n        $this->size = $size;\n\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see FontInterface::size()\n     */\n    public function size(): float\n    {\n        return $this->size;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see FontInterface::setAngle()\n     */\n    public function setAngle(float $angle): FontInterface\n    {\n        $this->angle = $angle;\n\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see FontInterface::angle()\n     */\n    public function angle(): float\n    {\n        return $this->angle;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see FontInterface::setFilename()\n     *\n     * @throws FontException\n     */\n    public function setFilename(string $filename): FontInterface\n    {\n        if (!file_exists($filename)) {\n            throw new FontException('Font file ' . $filename . ' does not exist.');\n        }\n\n        $this->filename = $filename;\n\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see FontInterface::filename()\n     */\n    public function filename(): ?string\n    {\n        return $this->filename;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see FontInterface::hasFilename()\n     */\n    public function hasFilename(): bool\n    {\n        return !is_null($this->filename) && is_file($this->filename);\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see FontInterface::setColor()\n     */\n    public function setColor(mixed $color): FontInterface\n    {\n        $this->color = $color;\n\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see FontInterface::color()\n     */\n    public function color(): mixed\n    {\n        return $this->color;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see FontInterface::setStrokeColor()\n     */\n    public function setStrokeColor(mixed $color): FontInterface\n    {\n        $this->strokeColor = $color;\n\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see FontInterface::strokeColor()\n     */\n    public function strokeColor(): mixed\n    {\n        return $this->strokeColor;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see FontInterface::setStrokeWidth()\n     */\n    public function setStrokeWidth(int $width): FontInterface\n    {\n        if (!in_array($width, range(0, 10))) {\n            throw new FontException(\n                'The stroke width must be in the range from 0 to 10.'\n            );\n        }\n\n        $this->strokeWidth = $width;\n\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see FontInterface::strokeWidth()\n     */\n    public function strokeWidth(): int\n    {\n        return $this->strokeWidth;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see FontInterface::hasStrokeEffect()\n     */\n    public function hasStrokeEffect(): bool\n    {\n        return $this->strokeWidth > 0;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see FontInterface::alignment()\n     */\n    public function alignment(): string\n    {\n        return $this->alignment;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see FontInterface::setAlignment()\n     */\n    public function setAlignment(string $value): FontInterface\n    {\n        $this->alignment = $value;\n\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see FontInterface::valignment()\n     */\n    public function valignment(): string\n    {\n        return $this->valignment;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see FontInterface::setValignment()\n     */\n    public function setValignment(string $value): FontInterface\n    {\n        $this->valignment = $value;\n\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see FontInterface::setLineHeight()\n     */\n    public function setLineHeight(float $height): FontInterface\n    {\n        $this->lineHeight = $height;\n\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see FontInterface::lineHeight()\n     */\n    public function lineHeight(): float\n    {\n        return $this->lineHeight;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see FontInterface::setWrapWidth()\n     */\n    public function setWrapWidth(?int $width): FontInterface\n    {\n        $this->wrapWidth = $width;\n\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see FontInterface::wrapWidth()\n     */\n    public function wrapWidth(): ?int\n    {\n        return $this->wrapWidth;\n    }\n}\n"
  },
  {
    "path": "src/Typography/FontFactory.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Typography;\n\nuse Closure;\nuse Intervention\\Image\\Exceptions\\FontException;\nuse Intervention\\Image\\Interfaces\\FontInterface;\n\nclass FontFactory\n{\n    protected FontInterface $font;\n\n    /**\n     * Create new instance\n     *\n     * @param Closure|FontInterface $init\n     * @throws FontException\n     * @return void\n     */\n    public function __construct(callable|Closure|FontInterface $init)\n    {\n        $this->font = is_a($init, FontInterface::class) ? $init : new Font();\n\n        if (is_callable($init)) {\n            $init($this);\n        }\n    }\n\n    /**\n     * Set the filename of the font to be built\n     */\n    public function filename(string $value): self\n    {\n        $this->font->setFilename($value);\n\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see self::filename()\n     */\n    public function file(string $value): self\n    {\n        return $this->filename($value);\n    }\n\n    /**\n     * Set outline stroke effect for the font to be built\n     *\n     * @throws FontException\n     */\n    public function stroke(mixed $color, int $width = 1): self\n    {\n        $this->font->setStrokeWidth($width);\n        $this->font->setStrokeColor($color);\n\n        return $this;\n    }\n\n    /**\n     * Set color for the font to be built\n     */\n    public function color(mixed $value): self\n    {\n        $this->font->setColor($value);\n\n        return $this;\n    }\n\n    /**\n     * Set the size for the font to be built\n     */\n    public function size(float $value): self\n    {\n        $this->font->setSize($value);\n\n        return $this;\n    }\n\n    /**\n     * Set the horizontal alignment of the font to be built\n     */\n    public function align(string $value): self\n    {\n        $this->font->setAlignment($value);\n\n        return $this;\n    }\n\n    /**\n     * Set the vertical alignment of the font to be built\n     */\n    public function valign(string $value): self\n    {\n        $this->font->setValignment($value);\n\n        return $this;\n    }\n\n    /**\n     * Set the line height of the font to be built\n     */\n    public function lineHeight(float $value): self\n    {\n        $this->font->setLineHeight($value);\n\n        return $this;\n    }\n\n    /**\n     * Set the rotation angle of the font to be built\n     */\n    public function angle(float $value): self\n    {\n        $this->font->setAngle($value);\n\n        return $this;\n    }\n\n    /**\n     * Set the maximum width of the text block to be built\n     */\n    public function wrap(int $width): self\n    {\n        $this->font->setWrapWidth($width);\n\n        return $this;\n    }\n\n    /**\n     * Build font\n     */\n    public function __invoke(): FontInterface\n    {\n        return $this->font;\n    }\n}\n"
  },
  {
    "path": "src/Typography/Line.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Typography;\n\nuse ArrayIterator;\nuse Countable;\nuse Intervention\\Image\\Geometry\\Point;\nuse Intervention\\Image\\Interfaces\\PointInterface;\nuse IteratorAggregate;\nuse Stringable;\nuse Traversable;\n\n/**\n * @implements IteratorAggregate<string>\n */\nclass Line implements IteratorAggregate, Countable, Stringable\n{\n    /**\n     * Segments (usually individual words including punctuation marks) of the line\n     *\n     * @var array<string>\n     */\n    protected array $segments = [];\n\n    /**\n     * Create new text line object with given text & position\n     *\n     * @return void\n     */\n    public function __construct(\n        ?string $text = null,\n        protected PointInterface $position = new Point()\n    ) {\n        if (is_string($text)) {\n            $this->segments = $this->wordsSeperatedBySpaces($text) ? explode(\" \", $text) : mb_str_split($text);\n        }\n    }\n\n    /**\n     * Add word to current line\n     */\n    public function add(string $word): self\n    {\n        $this->segments[] = $word;\n\n        return $this;\n    }\n\n    /**\n     * Returns Iterator\n     *\n     * @return Traversable<string>\n     */\n    public function getIterator(): Traversable\n    {\n        return new ArrayIterator($this->segments);\n    }\n\n    /**\n     * Get Position of line\n     */\n    public function position(): PointInterface\n    {\n        return $this->position;\n    }\n\n    /**\n     * Set position of current line\n     */\n    public function setPosition(PointInterface $point): self\n    {\n        $this->position = $point;\n\n        return $this;\n    }\n\n    /**\n     * Count segments (individual words including punctuation marks) of line\n     */\n    public function count(): int\n    {\n        return count($this->segments);\n    }\n\n    /**\n     * Count characters of line\n     */\n    public function length(): int\n    {\n        return mb_strlen((string) $this);\n    }\n\n    /**\n     * Dermine if words are sperarated by spaces in the written language of the given text\n     */\n    private function wordsSeperatedBySpaces(string $text): bool\n    {\n        return 1 !== preg_match(\n            '/[' .\n            '\\x{4E00}-\\x{9FFF}' . // CJK Unified Ideographs (chinese)\n            '\\x{3400}-\\x{4DBF}' . // CJK Unified Ideographs Extension A (chinese)\n            '\\x{3040}-\\x{309F}' . // hiragana (japanese)\n            '\\x{30A0}-\\x{30FF}' . // katakana (japanese)\n            '\\x{0E00}-\\x{0E7F}' . // thai\n            ']/u',\n            $text\n        );\n    }\n\n    /**\n     * Cast line to string\n     */\n    public function __toString(): string\n    {\n        $string = implode(\"\", $this->segments);\n\n        if ($this->wordsSeperatedBySpaces($string)) {\n            return implode(\" \", $this->segments);\n        }\n\n        return $string;\n    }\n}\n"
  },
  {
    "path": "src/Typography/TextBlock.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Typography;\n\nuse Intervention\\Image\\Collection;\n\nclass TextBlock extends Collection\n{\n    /**\n     * Create new text block object\n     *\n     * @return void\n     */\n    public function __construct(string $text)\n    {\n        foreach (explode(\"\\n\", $text) as $line) {\n            $this->push(new Line($line));\n        }\n    }\n\n    /**\n     * Return array of lines in text block\n     *\n     * @return array<Line>\n     */\n    public function lines(): array\n    {\n        return $this->items;\n    }\n\n    /**\n     * Set lines of the text block\n     *\n     * @param array<Line> $lines\n     */\n    public function setLines(array $lines): self\n    {\n        $this->items = $lines;\n\n        return $this;\n    }\n\n    /**\n     * Get line by given key\n     */\n    public function line(mixed $key): ?Line\n    {\n        if (!array_key_exists($key, $this->lines())) {\n            return null;\n        }\n\n        return $this->lines()[$key];\n    }\n\n    /**\n     * Return line with most characters of text block\n     */\n    public function longestLine(): Line\n    {\n        $lines = $this->lines();\n        usort($lines, function (Line $a, Line $b): int {\n            if ($a->length() === $b->length()) {\n                return 0;\n            }\n            return $a->length() > $b->length() ? -1 : 1;\n        });\n\n        return $lines[0];\n    }\n}\n"
  },
  {
    "path": "tests/BaseTestCase.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests;\n\nuse Intervention\\Image\\Colors\\Rgb\\Channels\\Alpha;\nuse Intervention\\Image\\Colors\\Rgb\\Channels\\Blue;\nuse Intervention\\Image\\Colors\\Rgb\\Channels\\Green;\nuse Intervention\\Image\\Colors\\Rgb\\Channels\\Red;\nuse Intervention\\Image\\Colors\\Rgb\\Color as RgbColor;\nuse Intervention\\Image\\EncodedImage;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Mockery\\Adapter\\Phpunit\\MockeryTestCase;\nuse PHPUnit\\Framework\\ExpectationFailedException;\n\nabstract class BaseTestCase extends MockeryTestCase\n{\n    public static function getTestResourcePath(string $filename = 'test.jpg'): string\n    {\n        return sprintf('%s/resources/%s', __DIR__, $filename);\n    }\n\n    public static function getTestResourceData(string $filename = 'test.jpg'): string\n    {\n        return file_get_contents(self::getTestResourcePath($filename));\n    }\n\n    public static function getTestResourcePointer(string $filename = 'test.jpg'): mixed\n    {\n        $pointer = fopen('php://temp', 'rw');\n        fwrite($pointer, self::getTestResourceData($filename));\n        rewind($pointer);\n\n        return $pointer;\n    }\n\n    /**\n     * Assert that given color equals the given color channel values in the given optional tolerance\n     *\n     * @throws ExpectationFailedException\n     */\n    protected function assertColor(int $r, int $g, int $b, int $a, ColorInterface $color, int $tolerance = 0): void\n    {\n        // build errorMessage\n        $errorMessage = function (int $r, int $g, $b, int $a, ColorInterface $color): string {\n            $color = 'rgba(' . implode(', ', [\n                $color->channel(Red::class)->value(),\n                $color->channel(Green::class)->value(),\n                $color->channel(Blue::class)->value(),\n                $color->channel(Alpha::class)->value(),\n            ]) . ')';\n\n            return implode(' ', [\n                'Failed asserting that color',\n                $color,\n                'equals',\n                'rgba(' . $r . ', ' . $g . ', ' . $b . ', ' . $a . ')'\n            ]);\n        };\n\n        // build color channel value range\n        $range = function (int $base, int $tolerance): array {\n            return range(max($base - $tolerance, 0), min($base + $tolerance, 255));\n        };\n\n        $this->assertContains(\n            $color->channel(Red::class)->value(),\n            $range($r, $tolerance),\n            $errorMessage($r, $g, $b, $a, $color)\n        );\n\n        $this->assertContains(\n            $color->channel(Green::class)->value(),\n            $range($g, $tolerance),\n            $errorMessage($r, $g, $b, $a, $color)\n        );\n\n        $this->assertContains(\n            $color->channel(Blue::class)->value(),\n            $range($b, $tolerance),\n            $errorMessage($r, $g, $b, $a, $color)\n        );\n\n        $this->assertContains(\n            $color->channel(Alpha::class)->value(),\n            $range($a, $tolerance),\n            $errorMessage($r, $g, $b, $a, $color)\n        );\n    }\n\n    protected function assertTransparency(ColorInterface $color): void\n    {\n        $this->assertInstanceOf(RgbColor::class, $color);\n        $channel = $color->channel(Alpha::class);\n        $this->assertEquals(0, $channel->value(), 'Detected color ' . $color . ' is not completely transparent.');\n    }\n\n    protected function assertMediaType(string|array $allowed, string|EncodedImage $input): void\n    {\n        $pointer = fopen('php://temp', 'rw');\n        fwrite($pointer, (string) $input);\n        rewind($pointer);\n        $detected = mime_content_type($pointer);\n        fclose($pointer);\n\n        $allowed = is_string($allowed) ? [$allowed] : $allowed;\n        $this->assertTrue(\n            in_array($detected, $allowed),\n            'Detected media type \"' . $detected . '\" is not: ' . implode(', ', $allowed),\n        );\n    }\n\n    protected function assertMediaTypeBitmap(string|EncodedImage $input): void\n    {\n        $this->assertMediaType([\n            'image/x-ms-bmp',\n            'image/bmp',\n            'bmp',\n            'ms-bmp',\n            'x-bitmap',\n            'x-bmp',\n            'x-ms-bmp',\n            'x-win-bitmap',\n            'x-windows-bmp',\n            'x-xbitmap',\n            'image/ms-bmp',\n            'image/x-bitmap',\n            'image/x-bmp',\n            'image/x-ms-bmp',\n            'image/x-win-bitmap',\n            'image/x-windows-bmp',\n            'image/x-xbitmap',\n        ], $input);\n    }\n}\n"
  },
  {
    "path": "tests/Feature/Gd/ConvertPngGif.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Feature\\Gd;\n\nuse Intervention\\Image\\ImageManager;\nuse Intervention\\Image\\Tests\\GdTestCase;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\n\n#[RequiresPhpExtension('gd')]\nclass ConvertPngGif extends GdTestCase\n{\n    public function testConversionKeepsTransparency(): void\n    {\n        $converted = ImageManager::gd()\n            ->read(\n                $this->readTestImage('circle.png')->toGif()\n            );\n\n        $this->assertTransparency($converted->pickColor(0, 0));\n        $this->assertColor(4, 2, 4, 255, $converted->pickColor(25, 25), 4);\n    }\n}\n"
  },
  {
    "path": "tests/Feature/Imagick/ConvertPngGif.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Feature\\Imagick;\n\nuse Intervention\\Image\\ImageManager;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\n\n#[RequiresPhpExtension('imagick')]\nclass ConvertPngGif extends ImagickTestCase\n{\n    public function testConversionKeepsTransparency(): void\n    {\n        $converted = ImageManager::imagick()\n            ->read(\n                $this->readTestImage('circle.png')->toGif()\n            );\n\n        $this->assertTransparency($converted->pickColor(0, 0));\n        $this->assertColor(4, 2, 4, 255, $converted->pickColor(25, 25), 4);\n    }\n}\n"
  },
  {
    "path": "tests/Feature/Imagick/CropResizePngTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Feature\\Imagick;\n\nuse Intervention\\Image\\Tests\\ImagickTestCase;\n\nclass CropResizePngTest extends ImagickTestCase\n{\n    public function testCropResizePng(): void\n    {\n        $image = $this->readTestImage('tile.png');\n        $image->crop(100, 100);\n        $image->resize(200, 200);\n        $this->assertTransparency($image->pickColor(7, 22));\n        $this->assertTransparency($image->pickColor(22, 7));\n    }\n}\n"
  },
  {
    "path": "tests/GdTestCase.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests;\n\nuse Intervention\\Image\\Decoders\\FilePathImageDecoder;\nuse Intervention\\Image\\Drivers\\Gd\\Core;\nuse Intervention\\Image\\Drivers\\Gd\\Driver;\nuse Intervention\\Image\\Drivers\\Gd\\Frame;\nuse Intervention\\Image\\Image;\n\nabstract class GdTestCase extends BaseTestCase\n{\n    public static function readTestImage(string $filename = 'test.jpg'): Image\n    {\n        return (new Driver())->specialize(new FilePathImageDecoder())->decode(\n            static::getTestResourcePath($filename)\n        );\n    }\n\n    public static function createTestImage(int $width, int $height): Image\n    {\n        $gd = imagecreatetruecolor($width, $height);\n        imagefill($gd, 0, 0, imagecolorallocate($gd, 255, 0, 0));\n\n        return new Image(\n            new Driver(),\n            new Core([\n                new Frame($gd)\n            ])\n        );\n    }\n\n    public static function createTestAnimation(): Image\n    {\n        $gd1 = imagecreatetruecolor(3, 2);\n        imagefill($gd1, 0, 0, imagecolorallocate($gd1, 255, 0, 0));\n        $gd2 = imagecreatetruecolor(3, 2);\n        imagefill($gd2, 0, 0, imagecolorallocate($gd1, 0, 255, 0));\n        $gd3 = imagecreatetruecolor(3, 2);\n        imagefill($gd3, 0, 0, imagecolorallocate($gd1, 0, 0, 255));\n\n        return new Image(\n            new Driver(),\n            new Core([\n                new Frame($gd1),\n                new Frame($gd2),\n                new Frame($gd3),\n            ])\n        );\n    }\n}\n"
  },
  {
    "path": "tests/ImagickTestCase.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests;\n\nuse Imagick;\nuse ImagickException;\nuse ImagickPixel;\nuse Intervention\\Image\\Decoders\\FilePathImageDecoder;\nuse Intervention\\Image\\Drivers\\Imagick\\Core;\nuse Intervention\\Image\\Drivers\\Imagick\\Driver;\nuse Intervention\\Image\\Image;\n\nabstract class ImagickTestCase extends BaseTestCase\n{\n    public static function readTestImage(string $filename = 'test.jpg'): Image\n    {\n        return (new Driver())->specialize(new FilePathImageDecoder())->decode(\n            static::getTestResourcePath($filename)\n        );\n    }\n\n    /**\n     * Create test image with red (#ff0000) background\n     *\n     * @throws ImagickException\n     */\n    public static function createTestImage(int $width, int $height): Image\n    {\n        $background = new ImagickPixel('rgb(255, 0, 0)');\n        $imagick = new Imagick();\n        $imagick->newImage($width, $height, $background, 'png');\n        $imagick->setType(Imagick::IMGTYPE_UNDEFINED);\n        $imagick->setImageType(Imagick::IMGTYPE_UNDEFINED);\n        $imagick->setColorspace(Imagick::COLORSPACE_SRGB);\n        $imagick->setImageResolution(96, 96);\n        $imagick->setImageBackgroundColor($background);\n\n        return new Image(\n            new Driver(),\n            new Core($imagick)\n        );\n    }\n\n    public static function createTestAnimation(): Image\n    {\n        $imagick = new Imagick();\n        $imagick->setFormat('gif');\n\n        for ($i = 0; $i < 3; $i++) {\n            $frame = new Imagick();\n            $frame->newImage(3, 2, new ImagickPixel('rgb(255, 0, 0)'), 'gif');\n            $frame->setImageDelay(10);\n            $imagick->addImage($frame);\n        }\n\n        return new Image(\n            new Driver(),\n            new Core($imagick)\n        );\n    }\n}\n"
  },
  {
    "path": "tests/Traits/CanDetectProgressiveJpeg.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Traits;\n\nuse Intervention\\Image\\EncodedImage;\nuse Intervention\\Image\\Traits\\CanBuildFilePointer;\n\ntrait CanDetectProgressiveJpeg\n{\n    use CanBuildFilePointer;\n\n    /**\n     * Checks if the given image data is progressive encoded Jpeg format\n     *\n     * @param EncodedImage $imagedata\n     */\n    private function isProgressiveJpeg(EncodedImage $image): bool\n    {\n        $f = $image->toFilePointer();\n\n        while (!feof($f)) {\n            if (unpack('C', fread($f, 1))[1] !== 0xff) {\n                return false;\n            }\n\n            $blockType = unpack('C', fread($f, 1))[1];\n\n            switch (true) {\n                case $blockType == 0xd8:\n                case $blockType >= 0xd0 && $blockType <= 0xd7:\n                    break;\n\n                case $blockType == 0xc0:\n                    fclose($f);\n                    return false;\n\n                case $blockType == 0xc2:\n                    fclose($f);\n                    return true;\n\n                case $blockType == 0xd9:\n                    break 2;\n\n                default:\n                    $blockSize = unpack('n', fread($f, 2))[1];\n                    fseek($f, $blockSize - 2, SEEK_CUR);\n                    break;\n            }\n        }\n\n        fclose($f);\n\n        return false;\n    }\n}\n"
  },
  {
    "path": "tests/Traits/CanInspectPngFormat.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Traits;\n\nuse Intervention\\Image\\EncodedImage;\nuse Intervention\\Image\\Traits\\CanBuildFilePointer;\n\ntrait CanInspectPngFormat\n{\n    use CanBuildFilePointer;\n\n    /**\n     * Checks if the given image data is interlaced encoded PNG format\n     */\n    private function isInterlacedPng(EncodedImage $image): bool\n    {\n        $f = $image->toFilePointer();\n        $contents = fread($f, 32);\n        fclose($f);\n\n        return ord($contents[28]) != 0;\n    }\n\n    /**\n     * Try to detect PNG color type from given binary data\n     */\n    private function pngColorType(EncodedImage $image): string\n    {\n        $data = $image->toString();\n\n        if (substr($data, 1, 3) !== 'PNG') {\n            return 'unkown';\n        }\n\n        $pos = strpos($data, 'IHDR');\n        $type = substr($data, $pos + 13, 1);\n\n        return match (unpack('C', $type)[1]) {\n            0 => 'grayscale',\n            2 => 'truecolor',\n            3 => 'indexed',\n            4 => 'grayscale-alpha',\n            6 => 'truecolor-alpha',\n            default => 'unknown',\n        };\n    }\n}\n"
  },
  {
    "path": "tests/Unit/CollectionTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse Intervention\\Image\\Collection;\nuse Intervention\\Image\\Tests\\BaseTestCase;\n\n#[CoversClass(Collection::class)]\nfinal class CollectionTest extends BaseTestCase\n{\n    public function testConstructor(): void\n    {\n        $collection = new Collection(['foo', 'bar', 'baz']);\n        $this->assertInstanceOf(Collection::class, $collection);\n\n        $collection = Collection::create(['foo', 'bar', 'baz']);\n        $this->assertInstanceOf(Collection::class, $collection);\n    }\n\n    public function testIterator(): void\n    {\n        $collection = new Collection(['foo', 'bar', 'baz']);\n        foreach ($collection as $key => $item) {\n            switch ($key) {\n                case 0:\n                    $this->assertEquals('foo', $item);\n                    break;\n\n                case 1:\n                    $this->assertEquals('bar', $item);\n                    break;\n\n                case 2:\n                    $this->assertEquals('baz', $item);\n                    break;\n            }\n        }\n    }\n\n    public function testCount(): void\n    {\n        $collection = new Collection(['foo', 'bar', 'baz']);\n        $this->assertEquals(3, $collection->count());\n        $this->assertEquals(3, count($collection));\n    }\n\n    public function testFilter(): void\n    {\n        $collection = new Collection(['foo', 'bar', 'baz']);\n        $this->assertEquals(3, $collection->count());\n        $collection = $collection->filter(function ($text): bool {\n            return substr($text, 0, 1) == 'b';\n        });\n        $this->assertEquals(2, $collection->count());\n    }\n\n    public function testFirstLast(): void\n    {\n        $collection = new Collection(['foo', 'bar', 'baz']);\n        $this->assertEquals('foo', $collection->first());\n        $this->assertEquals('baz', $collection->last());\n\n        $collection = new Collection();\n        $this->assertNull($collection->first());\n        $this->assertNull($collection->last());\n    }\n\n    public function testPush(): void\n    {\n        $collection = new Collection(['foo', 'bar', 'baz']);\n        $this->assertEquals(3, $collection->count());\n        $result = $collection->push('test');\n        $this->assertEquals(4, $collection->count());\n        $this->assertInstanceOf(Collection::class, $result);\n    }\n\n    public function testToArray(): void\n    {\n        $collection = new Collection(['foo', 'bar', 'baz']);\n        $this->assertEquals(['foo', 'bar', 'baz'], $collection->toArray());\n    }\n\n    public function testMap(): void\n    {\n        $collection = new Collection(['FOO', 'BAR', 'BAZ']);\n        $mapped = $collection->map(function ($item) {\n            return strtolower($item);\n        });\n        $this->assertInstanceOf(Collection::class, $collection);\n        $this->assertInstanceOf(Collection::class, $mapped);\n        $this->assertEquals(['FOO', 'BAR', 'BAZ'], $collection->toArray());\n        $this->assertEquals(['foo', 'bar', 'baz'], $mapped->toArray());\n    }\n\n    public function testGet(): void\n    {\n        // phpcs:ignore SlevomatCodingStandard.Arrays.DisallowPartiallyKeyed\n        $collection = new Collection([\n            'first',\n            'second',\n            ['testx' => 'x'],\n            'foo' => 'foo_value',\n            'bar' => 'bar_value',\n            'baz' => [\n                'test1' => '1',\n                'test2' => '2',\n                'test3' => [\n                    'example' => 'value'\n                ]\n            ]\n        ]);\n\n        $this->assertEquals('first', $collection->get(0));\n        $this->assertEquals('second', $collection->get(1));\n        $this->assertEquals('first', $collection->get('0'));\n        $this->assertEquals('second', $collection->get('1'));\n        $this->assertEquals('x', $collection->get('2.testx'));\n        $this->assertEquals('foo_value', $collection->get('foo'));\n        $this->assertEquals('bar_value', $collection->get('bar'));\n        $this->assertEquals('1', $collection->get('baz.test1'));\n        $this->assertEquals('2', $collection->get('baz.test2'));\n        $this->assertEquals('value', $collection->get('baz.test3.example'));\n        $this->assertEquals('value', $collection->get('baz.test3.example', 'default'));\n        $this->assertEquals('default', $collection->get('baz.test3.no', 'default'));\n        $this->assertEquals(['example' => 'value'], $collection->get('baz.test3'));\n    }\n\n    public function testGetAtPosition(): void\n    {\n        // phpcs:ignore SlevomatCodingStandard.Arrays.DisallowPartiallyKeyed\n        $collection = new Collection([1, 2, 'foo' => 'bar']);\n        $this->assertEquals(1, $collection->getAtPosition(0));\n        $this->assertEquals(2, $collection->getAtPosition(1));\n        $this->assertEquals('bar', $collection->getAtPosition(2));\n        $this->assertNull($collection->getAtPosition(3));\n        $this->assertEquals('default', $collection->getAtPosition(3, 'default'));\n    }\n\n    public function testGetAtPositionEmpty(): void\n    {\n        $collection = new Collection();\n        $this->assertNull($collection->getAtPosition());\n        $this->assertEquals('default', $collection->getAtPosition(3, 'default'));\n    }\n\n    public function testEmpty(): void\n    {\n        $collection = new Collection([1, 2, 3]);\n        $this->assertEquals(3, $collection->count());\n        $result = $collection->empty();\n        $this->assertEquals(0, $collection->count());\n        $this->assertEquals(0, $result->count());\n    }\n\n    public function testSlice(): void\n    {\n        $collection = new Collection(['a', 'b', 'c', 'd', 'e', 'f']);\n        $this->assertEquals(6, $collection->count());\n        $result = $collection->slice(0, 3);\n        $this->assertEquals(['a', 'b', 'c'], $collection->toArray());\n        $this->assertEquals(['a', 'b', 'c'], $result->toArray());\n        $this->assertEquals('a', $result->get(0));\n        $this->assertEquals('b', $result->get(1));\n        $this->assertEquals('c', $result->get(2));\n\n        $result = $collection->slice(2, 1);\n        $this->assertEquals(['c'], $collection->toArray());\n        $this->assertEquals(['c'], $result->toArray());\n        $this->assertEquals('c', $result->get(0));\n    }\n\n    public function testSliceOutOfBounds(): void\n    {\n        $collection = new Collection(['a', 'b', 'c']);\n        $result = $collection->slice(6);\n        $this->assertEquals(0, $result->count());\n        $this->assertEquals([], $result->toArray());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Colors/Cmyk/ChannelTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Colors\\Cmyk;\n\nuse Intervention\\Image\\Colors\\Cmyk\\Channels\\Cyan;\nuse Intervention\\Image\\Colors\\Cmyk\\Channels\\Key;\nuse Intervention\\Image\\Colors\\Cmyk\\Channels\\Magenta;\nuse Intervention\\Image\\Colors\\Cmyk\\Channels\\Yellow;\nuse Intervention\\Image\\Exceptions\\ColorException;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\n\n#[CoversClass(Cyan::class)]\n#[CoversClass(Magenta::class)]\n#[CoversClass(Yellow::class)]\n#[CoversClass(Key::class)]\nfinal class ChannelTest extends BaseTestCase\n{\n    public function testConstructor(): void\n    {\n        $channel = new Cyan(0);\n        $this->assertInstanceOf(Cyan::class, $channel);\n\n        $channel = new Cyan(value: 0);\n        $this->assertInstanceOf(Cyan::class, $channel);\n\n        $channel = new Cyan(normalized: 0);\n        $this->assertInstanceOf(Cyan::class, $channel);\n\n        $this->expectException(ColorException::class);\n         new Cyan();\n\n        $this->expectException(ColorException::class);\n         new Cyan(normalized: 2);\n    }\n\n    public function testConstructorFail(): void\n    {\n        $this->expectException(ColorException::class);\n         new Cyan(200);\n    }\n\n    public function testToInt(): void\n    {\n        $channel = new Cyan(10);\n        $this->assertEquals(10, $channel->toInt());\n    }\n\n    public function testToString(): void\n    {\n        $channel = new Cyan(10);\n        $this->assertEquals(\"10\", $channel->toString());\n        $this->assertEquals(\"10\", (string) $channel);\n    }\n\n    public function testValue(): void\n    {\n        $channel = new Cyan(10);\n        $this->assertEquals(10, $channel->value());\n    }\n\n    public function testNormalize(): void\n    {\n        $channel = new Cyan(100);\n        $this->assertEquals(1, $channel->normalize());\n        $channel = new Cyan(0);\n        $this->assertEquals(0, $channel->normalize());\n        $channel = new Cyan(20);\n        $this->assertEquals(.2, $channel->normalize());\n    }\n\n    public function testValidate(): void\n    {\n        $this->expectException(ColorException::class);\n         new Cyan(101);\n\n        $this->expectException(ColorException::class);\n         new Cyan(-1);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Colors/Cmyk/ColorTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Colors\\Cmyk;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse Intervention\\Image\\Colors\\Cmyk\\Channels\\Cyan;\nuse Intervention\\Image\\Colors\\Cmyk\\Channels\\Key;\nuse Intervention\\Image\\Colors\\Cmyk\\Channels\\Magenta;\nuse Intervention\\Image\\Colors\\Cmyk\\Channels\\Yellow;\nuse Intervention\\Image\\Colors\\Cmyk\\Color;\nuse Intervention\\Image\\Colors\\Cmyk\\Colorspace;\nuse Intervention\\Image\\Exceptions\\ColorException;\nuse Intervention\\Image\\Tests\\BaseTestCase;\n\n#[CoversClass(Color::class)]\nfinal class ColorTest extends BaseTestCase\n{\n    public function testConstructor(): void\n    {\n        $color = new Color(0, 0, 0, 0);\n        $this->assertInstanceOf(Color::class, $color);\n    }\n\n    public function testCreate(): void\n    {\n        $color = Color::create('cmyk(10, 20, 30, 40)');\n        $this->assertInstanceOf(Color::class, $color);\n    }\n\n    public function testColorspace(): void\n    {\n        $color = new Color(0, 0, 0, 0);\n        $this->assertInstanceOf(Colorspace::class, $color->colorspace());\n    }\n\n    public function testChannels(): void\n    {\n        $color = new Color(10, 20, 30, 40);\n        $this->assertIsArray($color->channels());\n        $this->assertCount(4, $color->channels());\n    }\n\n    public function testChannel(): void\n    {\n        $color = new Color(10, 20, 30, 40);\n        $channel = $color->channel(Cyan::class);\n        $this->assertInstanceOf(Cyan::class, $channel);\n        $this->assertEquals(10, $channel->value());\n    }\n\n    public function testChannelNotFound(): void\n    {\n        $color = new Color(10, 20, 30, 30);\n        $this->expectException(ColorException::class);\n        $color->channel('none');\n    }\n\n    public function testCyanMagentaYellowKey(): void\n    {\n        $color = new Color(10, 20, 30, 40);\n        $this->assertInstanceOf(Cyan::class, $color->cyan());\n        $this->assertInstanceOf(Magenta::class, $color->magenta());\n        $this->assertInstanceOf(Yellow::class, $color->yellow());\n        $this->assertInstanceOf(Key::class, $color->key());\n        $this->assertEquals(10, $color->cyan()->value());\n        $this->assertEquals(20, $color->magenta()->value());\n        $this->assertEquals(30, $color->yellow()->value());\n        $this->assertEquals(40, $color->key()->value());\n    }\n\n    public function testToArray(): void\n    {\n        $color = new Color(10, 20, 30, 40);\n        $this->assertEquals([10, 20, 30, 40], $color->toArray());\n    }\n\n    public function testToHex(): void\n    {\n        $color = new Color(0, 73, 100, 0);\n        $this->assertEquals('ff4400', $color->toHex());\n        $this->assertEquals('#ff4400', $color->toHex('#'));\n    }\n\n    public function testIsGreyscale(): void\n    {\n        $color = new Color(0, 73, 100, 0);\n        $this->assertFalse($color->isGreyscale());\n\n        $color = new Color(0, 0, 0, 50);\n        $this->assertTrue($color->isGreyscale());\n    }\n\n    public function testNormalize(): void\n    {\n        $color = new Color(100, 50, 20, 0);\n        $this->assertEquals([1.0, 0.5, 0.2, 0.0], $color->normalize());\n    }\n\n    public function testToString(): void\n    {\n        $color = new Color(100, 50, 20, 0);\n        $this->assertEquals('cmyk(100%, 50%, 20%, 0%)', (string) $color);\n    }\n\n    public function testIsTransparent(): void\n    {\n        $color = new Color(100, 50, 50, 0);\n        $this->assertFalse($color->isTransparent());\n    }\n\n    public function testIsClear(): void\n    {\n        $color = new Color(0, 0, 0, 0);\n        $this->assertFalse($color->isClear());\n    }\n\n    public function testDebugInfo(): void\n    {\n        $info = (new Color(10, 20, 30, 40))->__debugInfo();\n        $this->assertEquals(10, $info['cyan']);\n        $this->assertEquals(20, $info['magenta']);\n        $this->assertEquals(30, $info['yellow']);\n        $this->assertEquals(40, $info['key']);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Colors/Cmyk/ColorspaceTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Colors\\Cmyk;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse Intervention\\Image\\Colors\\Cmyk\\Channels\\Cyan;\nuse Intervention\\Image\\Colors\\Cmyk\\Channels\\Key;\nuse Intervention\\Image\\Colors\\Cmyk\\Channels\\Magenta;\nuse Intervention\\Image\\Colors\\Cmyk\\Channels\\Yellow;\nuse Intervention\\Image\\Colors\\Cmyk\\Color as CmykColor;\nuse Intervention\\Image\\Colors\\Rgb\\Color as RgbColor;\nuse Intervention\\Image\\Colors\\Hsv\\Color as HsvColor;\nuse Intervention\\Image\\Colors\\Hsl\\Color as HslColor;\nuse Intervention\\Image\\Colors\\Cmyk\\Colorspace;\nuse Intervention\\Image\\Tests\\BaseTestCase;\n\n#[CoversClass(Colorspace::class)]\nfinal class ColorspaceTest extends BaseTestCase\n{\n    public function testColorFromNormalized(): void\n    {\n        $colorspace = new Colorspace();\n        $result = $colorspace->colorFromNormalized([0, 1, 0, 1]);\n        $this->assertInstanceOf(CmykColor::class, $result);\n        $this->assertEquals(0, $result->channel(Cyan::class)->value());\n        $this->assertEquals(100, $result->channel(Magenta::class)->value());\n        $this->assertEquals(0, $result->channel(Yellow::class)->value());\n        $this->assertEquals(100, $result->channel(Key::class)->value());\n    }\n\n    public function testImportRgbColor(): void\n    {\n        $colorspace = new Colorspace();\n\n        $result = $colorspace->importColor(new RgbColor(255, 0, 255));\n        $this->assertInstanceOf(CmykColor::class, $result);\n        $this->assertEquals(0, $result->channel(Cyan::class)->value());\n        $this->assertEquals(100, $result->channel(Magenta::class)->value());\n        $this->assertEquals(0, $result->channel(Yellow::class)->value());\n        $this->assertEquals(0, $result->channel(Key::class)->value());\n\n        $result = $colorspace->importColor(new RgbColor(127, 127, 127));\n        $this->assertInstanceOf(CmykColor::class, $result);\n        $this->assertEquals(0, $result->channel(Cyan::class)->value());\n        $this->assertEquals(0, $result->channel(Magenta::class)->value());\n        $this->assertEquals(0, $result->channel(Yellow::class)->value());\n        $this->assertEquals(50, $result->channel(Key::class)->value());\n\n        $result = $colorspace->importColor(new RgbColor(127, 127, 127, 85));\n        $this->assertInstanceOf(CmykColor::class, $result);\n        $this->assertEquals(0, $result->channel(Cyan::class)->value());\n        $this->assertEquals(0, $result->channel(Magenta::class)->value());\n        $this->assertEquals(0, $result->channel(Yellow::class)->value());\n        $this->assertEquals(50, $result->channel(Key::class)->value());\n    }\n\n    public function testImportHsvColor(): void\n    {\n        $colorspace = new Colorspace();\n        $result = $colorspace->importColor(new HsvColor(0, 0, 50));\n        $this->assertInstanceOf(CmykColor::class, $result);\n        $this->assertEquals(0, $result->channel(Cyan::class)->value());\n        $this->assertEquals(0, $result->channel(Magenta::class)->value());\n        $this->assertEquals(0, $result->channel(Yellow::class)->value());\n        $this->assertEquals(50, $result->channel(Key::class)->value());\n    }\n\n    public function testImportHslColor(): void\n    {\n        $colorspace = new Colorspace();\n\n        $result = $colorspace->importColor(new HslColor(300, 100, 50));\n        $this->assertInstanceOf(CmykColor::class, $result);\n        $this->assertEquals(0, $result->channel(Cyan::class)->value());\n        $this->assertEquals(100, $result->channel(Magenta::class)->value());\n        $this->assertEquals(0, $result->channel(Yellow::class)->value());\n        $this->assertEquals(0, $result->channel(Key::class)->value());\n\n        $result = $colorspace->importColor(new HslColor(0, 0, 50));\n        $this->assertInstanceOf(CmykColor::class, $result);\n        $this->assertEquals(0, $result->channel(Cyan::class)->value());\n        $this->assertEquals(0, $result->channel(Magenta::class)->value());\n        $this->assertEquals(0, $result->channel(Yellow::class)->value());\n        $this->assertEquals(50, $result->channel(Key::class)->value());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Colors/Cmyk/Decoders/StringColorDecoderTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Colors\\Cmyk\\Decoders;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse Intervention\\Image\\Colors\\Cmyk\\Color;\nuse Intervention\\Image\\Colors\\Cmyk\\Decoders\\StringColorDecoder;\nuse Intervention\\Image\\Exceptions\\DecoderException;\nuse Intervention\\Image\\Tests\\BaseTestCase;\n\n#[CoversClass(StringColorDecoder::class)]\nfinal class StringColorDecoderTest extends BaseTestCase\n{\n    public function testDecode(): void\n    {\n        $decoder = new StringColorDecoder();\n        $result = $decoder->decode('cmyk(0,0,0,0)');\n        $this->assertInstanceOf(Color::class, $result);\n        $this->assertEquals([0, 0, 0, 0], $result->toArray());\n\n        $result = $decoder->decode('cmyk(0, 100, 100, 0)');\n        $this->assertInstanceOf(Color::class, $result);\n        $this->assertEquals([0, 100, 100, 0], $result->toArray());\n\n        $result = $decoder->decode('cmyk(0, 100, 100, 0)');\n        $this->assertInstanceOf(Color::class, $result);\n        $this->assertEquals([0, 100, 100, 0], $result->toArray());\n\n        $result = $decoder->decode('cmyk(0%, 100%, 100%, 0%)');\n        $this->assertInstanceOf(Color::class, $result);\n        $this->assertEquals([0, 100, 100, 0], $result->toArray());\n    }\n\n    public function testDecodeInvalid(): void\n    {\n        $decoder = new StringColorDecoder();\n        $this->expectException(DecoderException::class);\n        $decoder->decode(null);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Colors/Hsl/ChannelTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Colors\\Hsl;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse Intervention\\Image\\Colors\\Hsl\\Channels\\Hue;\nuse Intervention\\Image\\Colors\\Hsl\\Channels\\Saturation;\nuse Intervention\\Image\\Colors\\Hsl\\Channels\\Luminance;\nuse Intervention\\Image\\Exceptions\\ColorException;\nuse Intervention\\Image\\Tests\\BaseTestCase;\n\n#[CoversClass(Hue::class)]\n#[CoversClass(Saturation::class)]\n#[CoversClass(Luminance::class)]\nfinal class ChannelTest extends BaseTestCase\n{\n    public function testConstructor(): void\n    {\n        $channel = new Hue(0);\n        $this->assertInstanceOf(Hue::class, $channel);\n\n        $channel = new Hue(value: 0);\n        $this->assertInstanceOf(Hue::class, $channel);\n\n        $channel = new Hue(normalized: 0);\n        $this->assertInstanceOf(Hue::class, $channel);\n\n        $this->expectException(ColorException::class);\n        new Hue();\n\n        $this->expectException(ColorException::class);\n        new Hue(normalized: 2);\n    }\n\n    public function testConstructorFail(): void\n    {\n        $this->expectException(ColorException::class);\n        new Hue(400);\n    }\n\n    public function testToInt(): void\n    {\n        $channel = new Hue(10);\n        $this->assertEquals(10, $channel->toInt());\n    }\n\n    public function testToString(): void\n    {\n        $channel = new Hue(10);\n        $this->assertEquals(\"10\", $channel->toString());\n        $this->assertEquals(\"10\", (string) $channel);\n    }\n\n    public function testValue(): void\n    {\n        $channel = new Hue(10);\n        $this->assertEquals(10, $channel->value());\n    }\n\n    public function testNormalize(): void\n    {\n        $channel = new Hue(360);\n        $this->assertEquals(1, $channel->normalize());\n        $channel = new Hue(180);\n        $this->assertEquals(0.5, $channel->normalize());\n        $channel = new Hue(0);\n        $this->assertEquals(0, $channel->normalize());\n        $channel = new Luminance(90);\n        $this->assertEquals(.9, $channel->normalize());\n    }\n\n    public function testValidate(): void\n    {\n        $this->expectException(ColorException::class);\n        new Hue(361);\n\n        $this->expectException(ColorException::class);\n        new Hue(-1);\n\n        $this->expectException(ColorException::class);\n        new Saturation(101);\n\n        $this->expectException(ColorException::class);\n        new Saturation(-1);\n\n        $this->expectException(ColorException::class);\n        new Luminance(101);\n\n        $this->expectException(ColorException::class);\n        new Luminance(-1);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Colors/Hsl/Channels/SaturationTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Colors\\Hsl\\Channels;\n\nuse Intervention\\Image\\Colors\\Hsl\\Channels\\Saturation;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\n\n#[CoversClass(Saturation::class)]\nfinal class SaturationTest extends BaseTestCase\n{\n    public function testMinMax(): void\n    {\n        $saturation = new Saturation(0);\n        $this->assertEquals(0, $saturation->min());\n        $this->assertEquals(100, $saturation->max());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Colors/Hsl/ColorTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Colors\\Hsl;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse Intervention\\Image\\Colors\\Hsl\\Channels\\Hue;\nuse Intervention\\Image\\Colors\\Hsl\\Channels\\Luminance;\nuse Intervention\\Image\\Colors\\Hsl\\Channels\\Saturation;\nuse Intervention\\Image\\Colors\\Hsl\\Color;\nuse Intervention\\Image\\Colors\\Hsl\\Colorspace;\nuse Intervention\\Image\\Exceptions\\ColorException;\nuse Intervention\\Image\\Tests\\BaseTestCase;\n\n#[CoversClass(Color::class)]\nfinal class ColorTest extends BaseTestCase\n{\n    public function testConstructor(): void\n    {\n        $color = new Color(0, 0, 0);\n        $this->assertInstanceOf(Color::class, $color);\n    }\n\n    public function testCreate(): void\n    {\n        $color = Color::create('hsl(10, 20, 30)');\n        $this->assertInstanceOf(Color::class, $color);\n    }\n\n    public function testColorspace(): void\n    {\n        $color = new Color(0, 0, 0);\n        $this->assertInstanceOf(Colorspace::class, $color->colorspace());\n    }\n\n    public function testChannels(): void\n    {\n        $color = new Color(10, 20, 30);\n        $this->assertIsArray($color->channels());\n        $this->assertCount(3, $color->channels());\n    }\n\n    public function testChannel(): void\n    {\n        $color = new Color(10, 20, 30);\n        $channel = $color->channel(Hue::class);\n        $this->assertInstanceOf(Hue::class, $channel);\n        $this->assertEquals(10, $channel->value());\n    }\n\n    public function testChannelNotFound(): void\n    {\n        $color = new Color(10, 20, 30);\n        $this->expectException(ColorException::class);\n        $color->channel('none');\n    }\n\n    public function testHueSaturationLuminanceKey(): void\n    {\n        $color = new Color(10, 20, 30);\n        $this->assertInstanceOf(Hue::class, $color->hue());\n        $this->assertInstanceOf(Saturation::class, $color->saturation());\n        $this->assertInstanceOf(Luminance::class, $color->luminance());\n        $this->assertEquals(10, $color->hue()->value());\n        $this->assertEquals(20, $color->saturation()->value());\n        $this->assertEquals(30, $color->luminance()->value());\n    }\n\n    public function testToArray(): void\n    {\n        $color = new Color(10, 20, 30);\n        $this->assertEquals([10, 20, 30], $color->toArray());\n    }\n\n    public function testToHex(): void\n    {\n        $color = new Color(16, 100, 50);\n        $this->assertEquals('ff4400', $color->toHex());\n    }\n\n    public function testNormalize(): void\n    {\n        $color = new Color(180, 50, 25);\n        $this->assertEquals([.5, 0.5, 0.25], $color->normalize());\n    }\n\n    public function testToString(): void\n    {\n        $color = new Color(100, 50, 20, 0);\n        $this->assertEquals('hsl(100, 50%, 20%)', (string) $color);\n    }\n\n    public function testIsGreyscale(): void\n    {\n        $color = new Color(0, 1, 0);\n        $this->assertFalse($color->isGreyscale());\n\n        $color = new Color(1, 0, 0);\n        $this->assertTrue($color->isGreyscale());\n\n        $color = new Color(0, 0, 1);\n        $this->assertTrue($color->isGreyscale());\n    }\n\n    public function testIsTransparent(): void\n    {\n        $color = new Color(0, 1, 0);\n        $this->assertFalse($color->isTransparent());\n    }\n\n    public function testIsClear(): void\n    {\n        $color = new Color(0, 1, 0);\n        $this->assertFalse($color->isClear());\n    }\n\n    public function testDebugInfo(): void\n    {\n        $info = (new Color(10, 20, 30))->__debugInfo();\n        $this->assertEquals(10, $info['hue']);\n        $this->assertEquals(20, $info['saturation']);\n        $this->assertEquals(30, $info['luminance']);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Colors/Hsl/ColorspaceTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Colors\\Hsl;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse Intervention\\Image\\Colors\\Cmyk\\Color as CmykColor;\nuse Intervention\\Image\\Colors\\Hsl\\Channels\\Hue;\nuse Intervention\\Image\\Colors\\Hsl\\Channels\\Luminance;\nuse Intervention\\Image\\Colors\\Hsl\\Channels\\Saturation;\nuse Intervention\\Image\\Colors\\Hsl\\Color as HslColor;\nuse Intervention\\Image\\Colors\\Rgb\\Color as RgbColor;\nuse Intervention\\Image\\Colors\\Hsv\\Color as HsvColor;\nuse Intervention\\Image\\Colors\\Hsl\\Colorspace;\nuse Intervention\\Image\\Tests\\BaseTestCase;\n\n#[CoversClass(Colorspace::class)]\nfinal class ColorspaceTest extends BaseTestCase\n{\n    public function testColorFromNormalized(): void\n    {\n        $colorspace = new Colorspace();\n        $result = $colorspace->colorFromNormalized([1, 0, 1]);\n        $this->assertInstanceOf(HslColor::class, $result);\n        $this->assertEquals(360, $result->channel(Hue::class)->value());\n        $this->assertEquals(0, $result->channel(Saturation::class)->value());\n        $this->assertEquals(100, $result->channel(Luminance::class)->value());\n    }\n\n    public function testImportRgbColor(): void\n    {\n        $colorspace = new Colorspace();\n\n        $result = $colorspace->importColor(new RgbColor(255, 0, 255));\n        $this->assertInstanceOf(HslColor::class, $result);\n        $this->assertEquals(300, $result->channel(Hue::class)->value());\n        $this->assertEquals(100, $result->channel(Saturation::class)->value());\n        $this->assertEquals(50, $result->channel(Luminance::class)->value());\n\n        $result = $colorspace->importColor(new RgbColor(127, 127, 127));\n        $this->assertInstanceOf(HslColor::class, $result);\n        $this->assertEquals(0, $result->channel(Hue::class)->value());\n        $this->assertEquals(0, $result->channel(Saturation::class)->value());\n        $this->assertEquals(50, $result->channel(Luminance::class)->value());\n\n        $result = $colorspace->importColor(new RgbColor(255, 0, 0, 85));\n        $this->assertInstanceOf(HslColor::class, $result);\n        $this->assertEquals(0, $result->channel(Hue::class)->value());\n        $this->assertEquals(100, $result->channel(Saturation::class)->value());\n        $this->assertEquals(50, $result->channel(Luminance::class)->value());\n    }\n\n    public function testImportCmykColor(): void\n    {\n        $colorspace = new Colorspace();\n\n        $result = $colorspace->importColor(new CmykColor(0, 100, 0, 0));\n        $this->assertInstanceOf(HslColor::class, $result);\n        $this->assertEquals(300, $result->channel(Hue::class)->value());\n        $this->assertEquals(100, $result->channel(Saturation::class)->value());\n        $this->assertEquals(50, $result->channel(Luminance::class)->value());\n\n        $result = $colorspace->importColor(new CmykColor(0, 0, 0, 50));\n        $this->assertInstanceOf(HslColor::class, $result);\n        $this->assertEquals(0, $result->channel(Hue::class)->value());\n        $this->assertEquals(0, $result->channel(Saturation::class)->value());\n        $this->assertEquals(50, $result->channel(Luminance::class)->value());\n    }\n\n    public function testImportHsvColor(): void\n    {\n        $colorspace = new Colorspace();\n\n        $result = $colorspace->importColor(new HsvColor(300, 100, 100));\n        $this->assertInstanceOf(HslColor::class, $result);\n        $this->assertEquals(300, $result->channel(Hue::class)->value());\n        $this->assertEquals(100, $result->channel(Saturation::class)->value());\n        $this->assertEquals(50, $result->channel(Luminance::class)->value());\n\n        $result = $colorspace->importColor(new HsvColor(0, 0, 50));\n        $this->assertInstanceOf(HslColor::class, $result);\n        $this->assertEquals(0, $result->channel(Hue::class)->value());\n        $this->assertEquals(0, $result->channel(Saturation::class)->value());\n        $this->assertEquals(50, $result->channel(Luminance::class)->value());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Colors/Hsl/Decoders/StringColorDecoderTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Colors\\Hsl\\Decoders;\n\nuse Generator;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse Intervention\\Image\\Colors\\Hsl\\Color;\nuse Intervention\\Image\\Colors\\Hsl\\Decoders\\StringColorDecoder;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\n\n#[CoversClass(StringColorDecoder::class)]\nfinal class StringColorDecoderTest extends BaseTestCase\n{\n    /**\n     * @param $channelValues array<int>\n     */\n    #[DataProvider('decodeDataProvier')]\n    public function testDecode(string $input, string $classname, array $channelValues): void\n    {\n        $decoder = new StringColorDecoder();\n        $result = $decoder->decode($input);\n        $this->assertInstanceOf($classname, $result);\n        $this->assertEquals($channelValues, $result->toArray());\n    }\n\n    public static function decodeDataProvier(): Generator\n    {\n        yield [\n            'hsl(0,0,0)',\n            Color::class,\n            [0, 0, 0],\n        ];\n        yield [\n            'hsl(0, 100, 50)',\n            Color::class,\n            [0, 100, 50],\n        ];\n        yield [\n            'hsl(360, 100, 50)',\n            Color::class,\n            [360, 100, 50],\n        ];\n        yield [\n            'hsl(180, 100%, 50%)',\n            Color::class,\n            [180, 100, 50],\n        ];\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Colors/Hsv/ChannelTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Colors\\Hsv;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse Intervention\\Image\\Colors\\Hsv\\Channels\\Hue;\nuse Intervention\\Image\\Colors\\Hsv\\Channels\\Saturation;\nuse Intervention\\Image\\Colors\\Hsv\\Channels\\Value;\nuse Intervention\\Image\\Exceptions\\ColorException;\nuse Intervention\\Image\\Tests\\BaseTestCase;\n\n#[CoversClass(Hue::class)]\n#[CoversClass(Saturation::class)]\n#[CoversClass(Value::class)]\nfinal class ChannelTest extends BaseTestCase\n{\n    public function testConstructor(): void\n    {\n        $channel = new Hue(0);\n        $this->assertInstanceOf(Hue::class, $channel);\n\n        $channel = new Hue(value: 0);\n        $this->assertInstanceOf(Hue::class, $channel);\n\n        $channel = new Hue(normalized: 0);\n        $this->assertInstanceOf(Hue::class, $channel);\n\n        $this->expectException(ColorException::class);\n        new Hue();\n\n        $this->expectException(ColorException::class);\n        new Hue(normalized: 2);\n    }\n\n    public function testConstructorFail(): void\n    {\n        $this->expectException(ColorException::class);\n        new Hue(400);\n    }\n\n    public function testToInt(): void\n    {\n        $channel = new Hue(10);\n        $this->assertEquals(10, $channel->toInt());\n    }\n\n    public function testToString(): void\n    {\n        $channel = new Hue(10);\n        $this->assertEquals(\"10\", $channel->toString());\n        $this->assertEquals(\"10\", (string) $channel);\n    }\n\n    public function testValue(): void\n    {\n        $channel = new Hue(10);\n        $this->assertEquals(10, $channel->value());\n    }\n\n    public function testNormalize(): void\n    {\n        $channel = new Hue(360);\n        $this->assertEquals(1, $channel->normalize());\n        $channel = new Hue(180);\n        $this->assertEquals(0.5, $channel->normalize());\n        $channel = new Hue(0);\n        $this->assertEquals(0, $channel->normalize());\n        $channel = new Hue(90);\n        $this->assertEquals(.25, $channel->normalize());\n    }\n\n    public function testValidate(): void\n    {\n        $this->expectException(ColorException::class);\n        new Hue(361);\n\n        $this->expectException(ColorException::class);\n        new Hue(-1);\n\n        $this->expectException(ColorException::class);\n        new Saturation(101);\n\n        $this->expectException(ColorException::class);\n        new Saturation(-1);\n\n        $this->expectException(ColorException::class);\n        new Value(101);\n\n        $this->expectException(ColorException::class);\n        new Value(-1);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Colors/Hsv/Channels/SaturationTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Colors\\Hsv\\Channels;\n\nuse Intervention\\Image\\Colors\\Hsv\\Channels\\Saturation;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\n\n#[CoversClass(Saturation::class)]\nfinal class SaturationTest extends BaseTestCase\n{\n    public function testMinMax(): void\n    {\n        $saturation = new Saturation(0);\n        $this->assertEquals(0, $saturation->min());\n        $this->assertEquals(100, $saturation->max());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Colors/Hsv/Channels/ValueTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Colors\\Hsv\\Channels;\n\nuse Intervention\\Image\\Colors\\Hsv\\Channels\\Value;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\n\n#[CoversClass(Value::class)]\nfinal class ValueTest extends BaseTestCase\n{\n    public function testMinMax(): void\n    {\n        $saturation = new Value(0);\n        $this->assertEquals(0, $saturation->min());\n        $this->assertEquals(100, $saturation->max());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Colors/Hsv/ColorTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Colors\\Hsv;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse Intervention\\Image\\Colors\\Hsv\\Channels\\Hue;\nuse Intervention\\Image\\Colors\\Hsv\\Channels\\Saturation;\nuse Intervention\\Image\\Colors\\Hsv\\Channels\\Value;\nuse Intervention\\Image\\Colors\\Hsv\\Color;\nuse Intervention\\Image\\Colors\\Hsv\\Colorspace;\nuse Intervention\\Image\\Exceptions\\ColorException;\nuse Intervention\\Image\\Tests\\BaseTestCase;\n\n#[CoversClass(Color::class)]\nfinal class ColorTest extends BaseTestCase\n{\n    public function testConstructor(): void\n    {\n        $color = new Color(0, 0, 0);\n        $this->assertInstanceOf(Color::class, $color);\n    }\n\n    public function testCreate(): void\n    {\n        $color = Color::create('hsv(10, 20, 30)');\n        $this->assertInstanceOf(Color::class, $color);\n    }\n\n    public function testColorspace(): void\n    {\n        $color = new Color(0, 0, 0);\n        $this->assertInstanceOf(Colorspace::class, $color->colorspace());\n    }\n\n    public function testChannels(): void\n    {\n        $color = new Color(10, 20, 30);\n        $this->assertIsArray($color->channels());\n        $this->assertCount(3, $color->channels());\n    }\n\n    public function testChannel(): void\n    {\n        $color = new Color(10, 20, 30);\n        $channel = $color->channel(Hue::class);\n        $this->assertInstanceOf(Hue::class, $channel);\n        $this->assertEquals(10, $channel->value());\n    }\n\n    public function testChannelNotFound(): void\n    {\n        $color = new Color(10, 20, 30);\n        $this->expectException(ColorException::class);\n        $color->channel('none');\n    }\n\n    public function testHueSaturationValueKey(): void\n    {\n        $color = new Color(10, 20, 30);\n        $this->assertInstanceOf(Hue::class, $color->hue());\n        $this->assertInstanceOf(Saturation::class, $color->saturation());\n        $this->assertInstanceOf(Value::class, $color->value());\n        $this->assertEquals(10, $color->hue()->value());\n        $this->assertEquals(20, $color->saturation()->value());\n        $this->assertEquals(30, $color->value()->value());\n    }\n\n    public function testToArray(): void\n    {\n        $color = new Color(10, 20, 30);\n        $this->assertEquals([10, 20, 30], $color->toArray());\n    }\n\n    public function testToHex(): void\n    {\n        $color = new Color(16, 100, 100);\n        $this->assertEquals('ff4400', $color->toHex());\n    }\n\n    public function testNormalize(): void\n    {\n        $color = new Color(180, 50, 25);\n        $this->assertEquals([.5, 0.5, 0.25], $color->normalize());\n    }\n\n    public function testToString(): void\n    {\n        $color = new Color(100, 50, 20, 0);\n        $this->assertEquals('hsv(100, 50%, 20%)', (string) $color);\n    }\n\n    public function testIsGreyscale(): void\n    {\n        $color = new Color(0, 1, 0);\n        $this->assertFalse($color->isGreyscale());\n\n        $color = new Color(1, 0, 0);\n        $this->assertTrue($color->isGreyscale());\n\n        $color = new Color(0, 0, 1);\n        $this->assertTrue($color->isGreyscale());\n    }\n\n    public function testIsTransparent(): void\n    {\n        $color = new Color(1, 0, 0);\n        $this->assertFalse($color->isTransparent());\n    }\n\n    public function testIsClear(): void\n    {\n        $color = new Color(0, 1, 0);\n        $this->assertFalse($color->isClear());\n    }\n\n    public function testDebugInfo(): void\n    {\n        $info = (new Color(10, 20, 30))->__debugInfo();\n        $this->assertEquals(10, $info['hue']);\n        $this->assertEquals(20, $info['saturation']);\n        $this->assertEquals(30, $info['value']);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Colors/Hsv/ColorspaceTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Colors\\Hsv;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse Intervention\\Image\\Colors\\Cmyk\\Color as CmykColor;\nuse Intervention\\Image\\Colors\\Hsv\\Channels\\Hue;\nuse Intervention\\Image\\Colors\\Hsv\\Channels\\Saturation;\nuse Intervention\\Image\\Colors\\Hsv\\Channels\\Value;\nuse Intervention\\Image\\Colors\\Hsv\\Color as HsvColor;\nuse Intervention\\Image\\Colors\\Rgb\\Color as RgbColor;\nuse Intervention\\Image\\Colors\\Hsl\\Color as HslColor;\nuse Intervention\\Image\\Colors\\Hsv\\Colorspace;\nuse Intervention\\Image\\Tests\\BaseTestCase;\n\n#[CoversClass(Colorspace::class)]\nfinal class ColorspaceTest extends BaseTestCase\n{\n    public function testColorFromNormalized(): void\n    {\n        $colorspace = new Colorspace();\n        $result = $colorspace->colorFromNormalized([1, 0, 1]);\n        $this->assertInstanceOf(HsvColor::class, $result);\n        $this->assertEquals(360, $result->channel(Hue::class)->value());\n        $this->assertEquals(0, $result->channel(Saturation::class)->value());\n        $this->assertEquals(100, $result->channel(Value::class)->value());\n    }\n\n    public function testImportRgbColor(): void\n    {\n        $colorspace = new Colorspace();\n\n        $result = $colorspace->importColor(new RgbColor(255, 0, 255));\n        $this->assertInstanceOf(HsvColor::class, $result);\n        $this->assertEquals(300, $result->channel(Hue::class)->value());\n        $this->assertEquals(100, $result->channel(Saturation::class)->value());\n        $this->assertEquals(100, $result->channel(Value::class)->value());\n\n        $result = $colorspace->importColor(new RgbColor(127, 127, 127));\n        $this->assertInstanceOf(HsvColor::class, $result);\n        $this->assertEquals(0, $result->channel(Hue::class)->value());\n        $this->assertEquals(0, $result->channel(Saturation::class)->value());\n        $this->assertEquals(50, $result->channel(Value::class)->value());\n\n        $result = $colorspace->importColor(new RgbColor(127, 127, 127, 85));\n        $this->assertInstanceOf(HsvColor::class, $result);\n        $this->assertEquals(0, $result->channel(Hue::class)->value());\n        $this->assertEquals(0, $result->channel(Saturation::class)->value());\n        $this->assertEquals(50, $result->channel(Value::class)->value());\n    }\n\n    public function testImportCmykColor(): void\n    {\n        $colorspace = new Colorspace();\n\n        $result = $colorspace->importColor(new CmykColor(0, 100, 0, 0));\n        $this->assertInstanceOf(HsvColor::class, $result);\n        $this->assertEquals(300, $result->channel(Hue::class)->value());\n        $this->assertEquals(100, $result->channel(Saturation::class)->value());\n        $this->assertEquals(100, $result->channel(Value::class)->value());\n\n        $result = $colorspace->importColor(new CmykColor(0, 0, 0, 50));\n        $this->assertInstanceOf(HsvColor::class, $result);\n        $this->assertEquals(0, $result->channel(Hue::class)->value());\n        $this->assertEquals(0, $result->channel(Saturation::class)->value());\n        $this->assertEquals(50, $result->channel(Value::class)->value());\n    }\n\n    public function testImportHslColor(): void\n    {\n        $colorspace = new Colorspace();\n\n        $result = $colorspace->importColor(new HslColor(300, 100, 50));\n        $this->assertInstanceOf(HsvColor::class, $result);\n        $this->assertEquals(300, $result->channel(Hue::class)->value());\n        $this->assertEquals(100, $result->channel(Saturation::class)->value());\n        $this->assertEquals(100, $result->channel(Value::class)->value());\n\n        $result = $colorspace->importColor(new HslColor(0, 0, 50));\n        $this->assertInstanceOf(HsvColor::class, $result);\n        $this->assertEquals(0, $result->channel(Hue::class)->value());\n        $this->assertEquals(0, $result->channel(Saturation::class)->value());\n        $this->assertEquals(50, $result->channel(Value::class)->value());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Colors/Hsv/Decoders/StringColorDecoderTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Colors\\Hsv\\Decoders;\n\nuse Generator;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse Intervention\\Image\\Colors\\Hsv\\Color;\nuse Intervention\\Image\\Colors\\Hsv\\Decoders\\StringColorDecoder;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\n\n#[CoversClass(StringColorDecoder::class)]\nfinal class StringColorDecoderTest extends BaseTestCase\n{\n    /**\n     * @param $channelValues array<int>\n     */\n    #[DataProvider('decodeDataProvier')]\n    public function testDecodeHsv(string $input, string $classname, array $channelValues): void\n    {\n        $decoder = new StringColorDecoder();\n        $result = $decoder->decode($input);\n        $this->assertInstanceOf($classname, $result);\n        $this->assertEquals($channelValues, $result->toArray());\n    }\n\n    public static function decodeDataProvier(): Generator\n    {\n        yield [\n            'hsv(0,0,0)',\n            Color::class,\n            [0, 0, 0],\n        ];\n        yield [\n            'hsv(0, 100, 100)',\n            Color::class,\n            [0, 100, 100],\n        ];\n        yield [\n            'hsv(360, 100, 100)',\n            Color::class,\n            [360, 100, 100],\n        ];\n        yield [\n            'hsv(180, 100%, 100%)',\n            Color::class,\n            [180, 100, 100],\n        ];\n        yield [\n            'hsb(0,0,0)',\n            Color::class,\n            [0, 0, 0],\n        ];\n        yield [\n            'hsb(0, 100, 100)',\n            Color::class,\n            [0, 100, 100],\n        ];\n        yield [\n            'hsb(360, 100, 100)',\n            Color::class,\n            [360, 100, 100],\n        ];\n        yield [\n            'hsb(180, 100%, 100%)',\n            Color::class,\n            [180, 100, 100],\n        ];\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Colors/ProfileTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Colors;\n\nuse Intervention\\Image\\Colors\\Profile;\nuse Intervention\\Image\\Tests\\BaseTestCase;\n\nclass ProfileTest extends BaseTestCase\n{\n    public function testFromPath(): void\n    {\n        $profile = Profile::fromPath($this->getTestResourcePath());\n        $this->assertInstanceOf(Profile::class, $profile);\n        $this->assertTrue($profile->size() > 0);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Colors/Rgb/ChannelTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Colors\\Rgb;\n\nuse Intervention\\Image\\Colors\\Rgb\\Channels\\Blue;\nuse Intervention\\Image\\Colors\\Rgb\\Channels\\Green;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse Intervention\\Image\\Colors\\Rgb\\Channels\\Red as Channel;\nuse Intervention\\Image\\Colors\\Rgb\\Channels\\Red;\nuse Intervention\\Image\\Exceptions\\ColorException;\nuse Intervention\\Image\\Tests\\BaseTestCase;\n\n#[CoversClass(Red::class)]\n#[CoversClass(Green::class)]\n#[CoversClass(Blue::class)]\nfinal class ChannelTest extends BaseTestCase\n{\n    public function testConstructor(): void\n    {\n        $channel = new Channel(0);\n        $this->assertInstanceOf(Channel::class, $channel);\n\n        $channel = new Channel(value: 0);\n        $this->assertInstanceOf(Channel::class, $channel);\n\n        $channel = new Channel(normalized: 0);\n        $this->assertInstanceOf(Channel::class, $channel);\n\n        $this->expectException(ColorException::class);\n        new Channel();\n\n        $this->expectException(ColorException::class);\n        new Channel(normalized: 2);\n    }\n\n    public function testConstructorFail(): void\n    {\n        $this->expectException(ColorException::class);\n        new Channel(300);\n    }\n\n    public function testToInt(): void\n    {\n        $channel = new Channel(255);\n        $this->assertEquals(255, $channel->toInt());\n    }\n\n    public function testToString(): void\n    {\n        $channel = new Channel(10);\n        $this->assertEquals(\"10\", $channel->toString());\n        $this->assertEquals(\"10\", (string) $channel);\n    }\n\n    public function testValue(): void\n    {\n        $channel = new Channel(10);\n        $this->assertEquals(10, $channel->value());\n    }\n\n    public function testNormalize(): void\n    {\n        $channel = new Channel(255);\n        $this->assertEquals(1, $channel->normalize());\n        $channel = new Channel(0);\n        $this->assertEquals(0, $channel->normalize());\n        $channel = new Channel(51);\n        $this->assertEquals(.2, $channel->normalize());\n    }\n\n    public function testValidate(): void\n    {\n        $this->expectException(ColorException::class);\n        new Channel(256);\n\n        $this->expectException(ColorException::class);\n        new Channel(-1);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Colors/Rgb/Channels/AlphaTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Colors\\Rgb\\Channels;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse Intervention\\Image\\Colors\\Rgb\\Channels\\Alpha;\nuse Intervention\\Image\\Tests\\BaseTestCase;\n\n#[CoversClass(Alpha::class)]\nfinal class AlphaTest extends BaseTestCase\n{\n    public function testToString(): void\n    {\n        $alpha = new Alpha(255 / 3);\n        $this->assertEquals('0.333333', $alpha->toString());\n        $this->assertEquals('0.333333', (string) $alpha);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Colors/Rgb/ColorTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Colors\\Rgb;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse Intervention\\Image\\Colors\\Cmyk\\Color as CmykColor;\nuse Intervention\\Image\\Colors\\Cmyk\\Colorspace as CmykColorspace;\nuse Intervention\\Image\\Colors\\Rgb\\Channels\\Red;\nuse Intervention\\Image\\Colors\\Rgb\\Channels\\Green;\nuse Intervention\\Image\\Colors\\Rgb\\Channels\\Blue;\nuse Intervention\\Image\\Colors\\Rgb\\Color;\nuse Intervention\\Image\\Colors\\Rgb\\Colorspace as RgbColorspace;\nuse Intervention\\Image\\Exceptions\\ColorException;\nuse Intervention\\Image\\Tests\\BaseTestCase;\n\n#[CoversClass(Color::class)]\nfinal class ColorTest extends BaseTestCase\n{\n    public function testConstructor(): void\n    {\n        $color = new Color(0, 0, 0);\n        $this->assertInstanceOf(Color::class, $color);\n\n        $color = new Color(0, 0, 0, 0);\n        $this->assertInstanceOf(Color::class, $color);\n    }\n\n    public function testCreate(): void\n    {\n        $color = Color::create('ccc');\n        $this->assertInstanceOf(Color::class, $color);\n        $this->assertEquals([204, 204, 204, 255], $color->toArray());\n\n        $color = Color::create('rgba(10, 20, 30, .2)');\n        $this->assertInstanceOf(Color::class, $color);\n        $this->assertEquals([10, 20, 30, 51], $color->toArray());\n    }\n\n    public function testColorspace(): void\n    {\n        $color = new Color(0, 0, 0);\n        $this->assertInstanceOf(RgbColorspace::class, $color->colorspace());\n    }\n\n    public function testChannels(): void\n    {\n        $color = new Color(10, 20, 30);\n        $this->assertIsArray($color->channels());\n        $this->assertCount(4, $color->channels());\n    }\n\n    public function testChannel(): void\n    {\n        $color = new Color(10, 20, 30);\n        $channel = $color->channel(Red::class);\n        $this->assertInstanceOf(Red::class, $channel);\n        $this->assertEquals(10, $channel->value());\n    }\n\n    public function testChannelNotFound(): void\n    {\n        $color = new Color(10, 20, 30);\n        $this->expectException(ColorException::class);\n        $color->channel('none');\n    }\n\n    public function testRedGreenBlue(): void\n    {\n        $color = new Color(10, 20, 30);\n        $this->assertInstanceOf(Red::class, $color->red());\n        $this->assertInstanceOf(Green::class, $color->green());\n        $this->assertInstanceOf(Blue::class, $color->blue());\n        $this->assertEquals(10, $color->red()->value());\n        $this->assertEquals(20, $color->green()->value());\n        $this->assertEquals(30, $color->blue()->value());\n    }\n\n    public function testToArray(): void\n    {\n        $color = new Color(10, 20, 30);\n        $this->assertEquals([10, 20, 30, 255], $color->toArray());\n    }\n\n    public function testToHex(): void\n    {\n        $color = new Color(181, 55, 23);\n        $this->assertEquals('b53717', $color->toHex());\n        $this->assertEquals('#b53717', $color->toHex('#'));\n\n        $color = new Color(181, 55, 23, 51);\n        $this->assertEquals('b5371733', $color->toHex());\n    }\n\n    public function testNormalize(): void\n    {\n        $color = new Color(255, 0, 51);\n        $this->assertEquals([1.0, 0.0, 0.2, 1.0], $color->normalize());\n    }\n\n    public function testToString(): void\n    {\n        $color = new Color(181, 55, 23);\n        $this->assertEquals('rgb(181, 55, 23)', (string) $color);\n    }\n\n    public function testConvertTo(): void\n    {\n        $color = new Color(0, 0, 0);\n        $converted = $color->convertTo(CmykColorspace::class);\n        $this->assertInstanceOf(CmykColor::class, $converted);\n        $this->assertEquals([0, 0, 0, 100], $converted->toArray());\n\n        $color = new Color(255, 255, 255);\n        $converted = $color->convertTo(CmykColorspace::class);\n        $this->assertInstanceOf(CmykColor::class, $converted);\n        $this->assertEquals([0, 0, 0, 0], $converted->toArray());\n\n        $color = new Color(255, 0, 0);\n        $converted = $color->convertTo(CmykColorspace::class);\n        $this->assertInstanceOf(CmykColor::class, $converted);\n        $this->assertEquals([0, 100, 100, 0], $converted->toArray());\n\n        $color = new Color(255, 0, 255);\n        $converted = $color->convertTo(CmykColorspace::class);\n        $this->assertInstanceOf(CmykColor::class, $converted);\n        $this->assertEquals([0, 100, 0, 0], $converted->toArray());\n\n        $color = new Color(255, 255, 0);\n        $converted = $color->convertTo(CmykColorspace::class);\n        $this->assertInstanceOf(CmykColor::class, $converted);\n        $this->assertEquals([0, 0, 100, 0], $converted->toArray());\n\n        $color = new Color(255, 204, 204);\n        $converted = $color->convertTo(CmykColorspace::class);\n        $this->assertInstanceOf(CmykColor::class, $converted);\n        $this->assertEquals([0, 20, 20, 0], $converted->toArray());\n    }\n\n    public function testIsGreyscale(): void\n    {\n        $color = new Color(255, 0, 100);\n        $this->assertFalse($color->isGreyscale());\n\n        $color = new Color(50, 50, 50);\n        $this->assertTrue($color->isGreyscale());\n    }\n\n    public function testIsTransparent(): void\n    {\n        $color = new Color(255, 255, 255);\n        $this->assertFalse($color->isTransparent());\n\n        $color = new Color(255, 255, 255, 255);\n        $this->assertFalse($color->isTransparent());\n\n        $color = new Color(255, 255, 255, 85);\n        $this->assertTrue($color->isTransparent());\n\n        $color = new Color(255, 255, 255, 0);\n        $this->assertTrue($color->isTransparent());\n    }\n\n    public function testIsClear(): void\n    {\n        $color = new Color(255, 255, 255);\n        $this->assertFalse($color->isClear());\n\n        $color = new Color(255, 255, 255, 255);\n        $this->assertFalse($color->isClear());\n\n        $color = new Color(255, 255, 255, 85);\n        $this->assertFalse($color->isClear());\n\n        $color = new Color(255, 255, 255, 0);\n        $this->assertTrue($color->isClear());\n    }\n\n    public function testDebugInfo(): void\n    {\n        $info = (new Color(10, 20, 30, 40))->__debugInfo();\n        $this->assertEquals(10, $info['red']);\n        $this->assertEquals(20, $info['green']);\n        $this->assertEquals(30, $info['blue']);\n        $this->assertEquals(40, $info['alpha']);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Colors/Rgb/ColorspaceTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Colors\\Rgb;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse Intervention\\Image\\Colors\\Cmyk\\Color as CmykColor;\nuse Intervention\\Image\\Colors\\Hsv\\Color as HsvColor;\nuse Intervention\\Image\\Colors\\Rgb\\Channels\\Blue;\nuse Intervention\\Image\\Colors\\Rgb\\Channels\\Green;\nuse Intervention\\Image\\Colors\\Rgb\\Channels\\Red;\nuse Intervention\\Image\\Colors\\Rgb\\Color as RgbColor;\nuse Intervention\\Image\\Colors\\Hsl\\Color as HslColor;\nuse Intervention\\Image\\Colors\\Rgb\\Channels\\Alpha;\nuse Intervention\\Image\\Colors\\Rgb\\Colorspace;\nuse Intervention\\Image\\Tests\\BaseTestCase;\n\n#[CoversClass(Colorspace::class)]\nfinal class ColorspaceTest extends BaseTestCase\n{\n    public function testColorFromNormalized(): void\n    {\n        $colorspace = new Colorspace();\n\n        $result = $colorspace->colorFromNormalized([1, 0, 1, 1]);\n        $this->assertInstanceOf(RgbColor::class, $result);\n        $this->assertEquals(255, $result->channel(Red::class)->value());\n        $this->assertEquals(0, $result->channel(Green::class)->value());\n        $this->assertEquals(255, $result->channel(Blue::class)->value());\n        $this->assertEquals(255, $result->channel(Alpha::class)->value());\n    }\n\n    public function testImportCmykColor(): void\n    {\n        $colorspace = new Colorspace();\n        $result = $colorspace->importColor(new CmykColor(0, 100, 0, 0));\n        $this->assertInstanceOf(RgbColor::class, $result);\n        $this->assertEquals(255, $result->channel(Red::class)->value());\n        $this->assertEquals(0, $result->channel(Green::class)->value());\n        $this->assertEquals(255, $result->channel(Blue::class)->value());\n\n        $result = $colorspace->importColor(new CmykColor(0, 0, 0, 50));\n        $this->assertInstanceOf(RgbColor::class, $result);\n        $this->assertEquals(127, $result->channel(Red::class)->value());\n        $this->assertEquals(127, $result->channel(Green::class)->value());\n        $this->assertEquals(127, $result->channel(Blue::class)->value());\n    }\n\n    public function testImportHsvColor(): void\n    {\n        $colorspace = new Colorspace();\n\n        $result = $colorspace->importColor(new HsvColor(300, 100, 100));\n        $this->assertInstanceOf(RgbColor::class, $result);\n        $this->assertEquals(255, $result->channel(Red::class)->value());\n        $this->assertEquals(0, $result->channel(Green::class)->value());\n        $this->assertEquals(255, $result->channel(Blue::class)->value());\n\n        $result = $colorspace->importColor(new HsvColor(0, 0, 50));\n        $this->assertInstanceOf(RgbColor::class, $result);\n        $this->assertEquals(128, $result->channel(Red::class)->value());\n        $this->assertEquals(128, $result->channel(Green::class)->value());\n        $this->assertEquals(128, $result->channel(Blue::class)->value());\n    }\n\n    public function testImportHslColor(): void\n    {\n        $colorspace = new Colorspace();\n\n        $result = $colorspace->importColor(new HslColor(300, 100, 50));\n        $this->assertInstanceOf(RgbColor::class, $result);\n        $this->assertEquals(255, $result->channel(Red::class)->value());\n        $this->assertEquals(0, $result->channel(Green::class)->value());\n        $this->assertEquals(255, $result->channel(Blue::class)->value());\n\n        $result = $colorspace->importColor(new HslColor(0, 0, 50));\n        $this->assertInstanceOf(RgbColor::class, $result);\n        $this->assertEquals(128, $result->channel(Red::class)->value());\n        $this->assertEquals(128, $result->channel(Green::class)->value());\n        $this->assertEquals(128, $result->channel(Blue::class)->value());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Colors/Rgb/Decoders/HexColorDecoderTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Colors\\Rgb\\Decoders;\n\nuse Generator;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse Intervention\\Image\\Colors\\Rgb\\Color;\nuse Intervention\\Image\\Colors\\Rgb\\Decoders\\HexColorDecoder;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\n\n#[CoversClass(HexColorDecoder::class)]\nfinal class HexColorDecoderTest extends BaseTestCase\n{\n    /**\n     * @param $channelValues array<int>\n     */\n    #[DataProvider('decodeDataProvier')]\n    public function testDecode(string $input, string $classname, array $channelValues): void\n    {\n        $decoder = new HexColorDecoder();\n        $result = $decoder->decode($input);\n        $this->assertInstanceOf($classname, $result);\n        $this->assertEquals($channelValues, $result->toArray());\n    }\n\n    public static function decodeDataProvier(): Generator\n    {\n        yield [\n            'ccc',\n            Color::class,\n            [204, 204, 204, 255]\n        ];\n        yield [\n            'ccff33',\n            Color::class,\n            [204, 255, 51, 255],\n        ];\n        yield [\n            '#ccc',\n            Color::class,\n            [204, 204, 204, 255],\n        ];\n        yield [\n            'cccccc',\n            Color::class,\n            [204, 204, 204, 255],\n        ];\n        yield [\n            '#cccccc',\n            Color::class,\n            [204, 204, 204, 255],\n        ];\n        yield [\n            '#ccccccff',\n            Color::class,\n            [204, 204, 204, 255],\n        ];\n        yield [\n            '#cccf',\n            Color::class,\n            [204, 204, 204, 255],\n        ];\n        yield [\n            'ccccccff',\n            Color::class,\n            [204, 204, 204, 255],\n        ];\n        yield [\n            'cccf',\n            Color::class,\n            [204, 204, 204, 255],\n        ];\n        yield [\n            '#b53717aa',\n            Color::class,\n            [181, 55, 23, 170],\n        ];\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Colors/Rgb/Decoders/HtmlColornameDecoderTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Colors\\Rgb\\Decoders;\n\nuse Generator;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse Intervention\\Image\\Colors\\Rgb\\Color;\nuse Intervention\\Image\\Colors\\Rgb\\Decoders\\HtmlColornameDecoder;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\n\n#[CoversClass(HtmlColorNameDecoder::class)]\nfinal class HtmlColornameDecoderTest extends BaseTestCase\n{\n    /**\n     * @param $channelValues array<int>\n     */\n    #[DataProvider('decodeDataProvier')]\n    public function testDecode(string $input, string $classname, array $channelValues): void\n    {\n        $decoder = new HtmlColornameDecoder();\n        $result = $decoder->decode($input);\n        $this->assertInstanceOf($classname, $result);\n        $this->assertEquals($channelValues, $result->toArray());\n    }\n\n    public static function decodeDataProvier(): Generator\n    {\n        yield [\n            'salmon',\n            Color::class,\n            [250, 128, 114, 255],\n        ];\n        yield [\n            'khaki',\n            Color::class,\n            [240, 230, 140, 255],\n        ];\n        yield [\n            'peachpuff',\n            Color::class,\n            [255, 218, 185, 255],\n        ];\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Colors/Rgb/Decoders/StringColorDecoderTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Colors\\Rgb\\Decoders;\n\nuse Generator;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse Intervention\\Image\\Colors\\Rgb\\Color;\nuse Intervention\\Image\\Colors\\Rgb\\Decoders\\StringColorDecoder;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\n\n#[CoversClass(StringColorDecoder::class)]\nfinal class StringColorDecoderTest extends BaseTestCase\n{\n    /**\n     * @param $channelValues array<int>\n     */\n    #[DataProvider('decodeDataProvier')]\n    public function testDecode(string $input, string $classname, array $channelValues): void\n    {\n        $decoder = new StringColorDecoder();\n        $result = $decoder->decode($input);\n        $this->assertInstanceOf($classname, $result);\n        $this->assertEquals($channelValues, $result->toArray());\n    }\n\n    public static function decodeDataProvier(): Generator\n    {\n        yield [\n            'rgb(204, 204, 204)',\n            Color::class,\n            [204, 204, 204, 255],\n        ];\n        yield [\n            'rgb(204,204,204)',\n            Color::class,\n            [204, 204, 204, 255],\n        ];\n        yield [\n            'rgb(100%,20%,0%)',\n            Color::class,\n            [255, 51, 0, 255],\n        ];\n        yield [\n            'rgb(100%,19.8064%,0.1239483%)',\n            Color::class,\n            [255, 51, 0, 255],\n        ];\n        yield [\n            'rgba(204, 204, 204, 1)',\n            Color::class,\n            [204, 204, 204, 255],\n        ];\n        yield [\n            'rgba(204,204,204,.2)',\n            Color::class,\n            [204, 204, 204, 51],\n        ];\n        yield [\n            'rgba(204,204,204,0.2)',\n            Color::class,\n            [204, 204, 204, 51],\n        ];\n        yield [\n            'srgb(255, 0, 0)',\n            Color::class,\n            [255, 0, 0, 255],\n        ];\n    }\n}\n"
  },
  {
    "path": "tests/Unit/ConfigTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit;\n\nuse Intervention\\Image\\Config;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\n\n#[CoversClass(Config::class)]\nfinal class ConfigTest extends BaseTestCase\n{\n    public function testConstructor(): void\n    {\n        $config = new Config();\n        $this->assertInstanceOf(Config::class, $config);\n\n        $this->assertTrue($config->autoOrientation);\n        $this->assertTrue($config->decodeAnimation);\n        $this->assertEquals('ffffff', $config->blendingColor);\n\n        $config = new Config(\n            autoOrientation: false,\n            decodeAnimation: false,\n            blendingColor: 'f00',\n            strip: true,\n        );\n        $this->assertInstanceOf(Config::class, $config);\n\n        $this->assertFalse($config->autoOrientation);\n        $this->assertFalse($config->decodeAnimation);\n        $this->assertTrue($config->strip);\n        $this->assertEquals('f00', $config->blendingColor);\n    }\n\n    public function testGetSetOptions(): void\n    {\n        $config = new Config();\n        $this->assertTrue($config->autoOrientation);\n        $this->assertTrue($config->decodeAnimation);\n        $this->assertFalse($config->strip);\n        $this->assertEquals('ffffff', $config->blendingColor);\n\n        $result = $config->setOptions(\n            autoOrientation: false,\n            decodeAnimation: false,\n            blendingColor: 'f00',\n            strip: true,\n        );\n\n        $this->assertFalse($config->autoOrientation);\n        $this->assertFalse($config->decodeAnimation);\n        $this->assertEquals('f00', $config->blendingColor);\n\n        $this->assertFalse($result->autoOrientation);\n        $this->assertFalse($result->decodeAnimation);\n        $this->assertTrue($result->strip);\n        $this->assertEquals('f00', $result->blendingColor);\n\n        $result = $config->setOptions(blendingColor: '000');\n\n        $this->assertFalse($config->autoOrientation);\n        $this->assertFalse($config->decodeAnimation);\n        $this->assertTrue($config->strip);\n        $this->assertEquals('000', $config->blendingColor);\n\n        $this->assertFalse($result->autoOrientation);\n        $this->assertFalse($result->decodeAnimation);\n        $this->assertTrue($result->strip);\n        $this->assertEquals('000', $result->blendingColor);\n    }\n\n    public function testSetOptionsWithArray(): void\n    {\n        $config = new Config();\n        $result = $config->setOptions([\n            'autoOrientation' => false,\n            'decodeAnimation' => false,\n            'blendingColor' => 'f00',\n            'strip' => true,\n        ]);\n\n        $this->assertFalse($config->autoOrientation);\n        $this->assertFalse($config->decodeAnimation);\n        $this->assertTrue($config->strip);\n        $this->assertEquals('f00', $config->blendingColor);\n        $this->assertFalse($result->autoOrientation);\n        $this->assertFalse($result->decodeAnimation);\n        $this->assertTrue($result->strip);\n        $this->assertEquals('f00', $result->blendingColor);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/AbstractDecoderTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse Exception;\nuse Intervention\\Image\\Drivers\\AbstractDecoder;\nuse Intervention\\Image\\Interfaces\\CollectionInterface;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse Mockery;\nuse stdClass;\n\n#[CoversClass(AbstractDecoder::class)]\nfinal class AbstractDecoderTest extends BaseTestCase\n{\n    public function testIsGifFormat(): void\n    {\n        $decoder = Mockery::mock(AbstractDecoder::class);\n        $this->assertFalse($decoder->isGifFormat($this->getTestResourceData('exif.jpg')));\n        $this->assertTrue($decoder->isGifFormat($this->getTestResourceData('red.gif')));\n    }\n\n    public function testIsFile(): void\n    {\n        $decoder = Mockery::mock(AbstractDecoder::class);\n        $this->assertTrue($decoder->isFile($this->getTestResourcePath()));\n        $this->assertFalse($decoder->isFile('non-existent-file'));\n        $this->assertFalse($decoder->isFile(new stdClass()));\n        $this->assertFalse($decoder->isFile(str_repeat('o', PHP_MAXPATHLEN + 1)));\n        $this->assertFalse($decoder->isFile(__DIR__));\n    }\n\n    public function testExtractExifDataFromBinary(): void\n    {\n        $source = $this->getTestResourceData('exif.jpg');\n        $pointer = $this->getTestResourcePointer('exif.jpg');\n        $decoder = Mockery::mock(AbstractDecoder::class);\n        $decoder->shouldReceive('buildFilePointer')->with($source)->andReturn($pointer);\n        $result = $decoder->extractExifData($source);\n        $this->assertInstanceOf(CollectionInterface::class, $result);\n        $this->assertEquals('Oliver Vogel', $result->get('IFD0.Artist'));\n    }\n\n    public function testExtractExifDataFromPath(): void\n    {\n        $decoder = Mockery::mock(AbstractDecoder::class);\n        $result = $decoder->extractExifData($this->getTestResourcePath('exif.jpg'));\n        $this->assertInstanceOf(CollectionInterface::class, $result);\n        $this->assertEquals('Oliver Vogel', $result->get('IFD0.Artist'));\n    }\n\n    public function testParseDataUri(): void\n    {\n        $decoder = new class () extends AbstractDecoder\n        {\n            public function parse(mixed $input): object\n            {\n                return parent::parseDataUri($input);\n            }\n\n            public function decode(mixed $input): ImageInterface|ColorInterface\n            {\n                throw new Exception('');\n            }\n        };\n\n        $result = $decoder->parse(\n            'data:image/gif;foo=bar;base64,R0lGODdhAwADAKIAAAQyrKTy/ByS7AQytLT2/AAAAAAAAAAAACwAAAAAAwADAAADBhgU0gMgAQA7'\n        );\n\n        $this->assertTrue($result->isValid());\n        $this->assertEquals('image/gif', $result->mediaType());\n        $this->assertTrue($result->hasMediaType());\n        $this->assertTrue($result->isBase64Encoded());\n        $this->assertEquals(\n            'R0lGODdhAwADAKIAAAQyrKTy/ByS7AQytLT2/AAAAAAAAAAAACwAAAAAAwADAAADBhgU0gMgAQA7',\n            $result->data()\n        );\n\n        $result = $decoder->parse('data:text/plain;charset=utf-8,test');\n        $this->assertTrue($result->isValid());\n        $this->assertEquals('text/plain', $result->mediaType());\n        $this->assertTrue($result->hasMediaType());\n        $this->assertFalse($result->isBase64Encoded());\n        $this->assertEquals('test', $result->data());\n\n        $result = $decoder->parse('data:;charset=utf-8,');\n        $this->assertTrue($result->isValid());\n        $this->assertNull($result->mediaType());\n        $this->assertFalse($result->hasMediaType());\n        $this->assertFalse($result->isBase64Encoded());\n        $this->assertNull($result->data());\n    }\n\n    public function testIsValidBase64(): void\n    {\n        $decoder = new class () extends AbstractDecoder\n        {\n            public function isValid(mixed $input): bool\n            {\n                return parent::isValidBase64($input);\n            }\n\n            public function decode(mixed $input): ImageInterface|ColorInterface\n            {\n                throw new Exception('');\n            }\n        };\n\n        $this->assertTrue(\n            $decoder->isValid('R0lGODdhAwADAKIAAAQyrKTy/ByS7AQytLT2/AAAAAAAAAAAACwAAAAAAwADAAADBhgU0gMgAQA7')\n        );\n        $this->assertFalse(\n            $decoder->isValid('foo')\n        );\n\n        $this->assertFalse(\n            $decoder->isValid(new stdClass())\n        );\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/AbstractEncoderTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers;\n\nuse Intervention\\Image\\EncodedImage;\nuse Intervention\\Image\\Drivers\\AbstractEncoder;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse Mockery;\nuse PHPUnit\\Metadata\\CoversClass;\n\n#[CoversClass(AbstractEncoder::class)]\nfinal class AbstractEncoderTest extends BaseTestCase\n{\n    public function testEncode(): void\n    {\n        $encoder = Mockery::mock(AbstractEncoder::class)->makePartial();\n        $image = Mockery::mock(ImageInterface::class);\n        $encoded = Mockery::mock(EncodedImage::class);\n        $image->shouldReceive('encode')->andReturn($encoded);\n        $result = $encoder->encode($image);\n        $this->assertInstanceOf(EncodedImage::class, $result);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/AbstractFontProcessorTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers;\n\nuse Intervention\\Image\\Drivers\\AbstractFontProcessor;\nuse Intervention\\Image\\Geometry\\Point;\nuse Intervention\\Image\\Geometry\\Rectangle;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse Intervention\\Image\\Typography\\Font;\nuse Intervention\\Image\\Typography\\TextBlock;\nuse Mockery;\nuse PHPUnit\\Metadata\\CoversClass;\n\n#[CoversClass(AbstractFontProcessor::class)]\nclass AbstractFontProcessorTest extends BaseTestCase\n{\n    public function testTextBlock(): void\n    {\n        $text = 'AAAA BBBB CCCC';\n        $font = (new Font($this->getTestResourcePath('test.ttf')))\n            ->setWrapWidth(20)\n            ->setSize(50)\n            ->setLineHeight(1.25)\n            ->setAlignment('center');\n\n        $processor = Mockery::mock(AbstractFontProcessor::class)->makePartial();\n\n        $processor\n            ->shouldReceive('boxSize')\n            ->with('T', $font)\n            ->andReturn(new Rectangle(12, 6));\n        $processor\n            ->shouldReceive('boxSize')\n            ->with('Hy', $font)\n            ->andReturn(new Rectangle(24, 6));\n\n        $processor\n            ->shouldReceive('boxSize')\n            ->with('AAAA', $font)\n            ->andReturn(new Rectangle(24, 6, new Point(1000, 0)));\n\n        $processor\n            ->shouldReceive('boxSize')\n            ->with('AAAA BBBB', $font)\n            ->andReturn(new Rectangle(24, 6));\n\n        $processor\n            ->shouldReceive('boxSize')\n            ->with('BBBB', $font)\n            ->andReturn(new Rectangle(24, 6, new Point(2000, 0)));\n\n        $processor\n            ->shouldReceive('boxSize')\n            ->with('BBBB CCCC', $font)\n            ->andReturn(new Rectangle(24, 6));\n\n        $processor\n            ->shouldReceive('boxSize')\n            ->with('CCCC', $font)\n            ->andReturn(new Rectangle(24, 6, new Point(3000, 0)));\n\n        $processor\n            ->shouldReceive('boxSize')\n            ->with($text, $font)\n            ->andReturn(new Rectangle(100, 25, new Point(10, 0)));\n\n        $block = $processor->textBlock($text, $font, new Point(0, 0));\n\n        $this->assertInstanceOf(TextBlock::class, $block);\n        $this->assertEquals(3, $block->count());\n        $this->assertEquals(-512, $block->getAtPosition(0)->position()->x());\n        $this->assertEquals(-16, $block->getAtPosition(0)->position()->y());\n        $this->assertEquals(-1012, $block->getAtPosition(1)->position()->x());\n        $this->assertEquals(-8, $block->getAtPosition(1)->position()->y());\n        $this->assertEquals(-1512, $block->getAtPosition(2)->position()->x());\n        $this->assertEquals(0, $block->getAtPosition(2)->position()->y());\n    }\n\n    public function testNativeFontSize(): void\n    {\n        $font = (new Font($this->getTestResourcePath('test.ttf')))->setSize(32);\n        $processor = Mockery::mock(AbstractFontProcessor::class)->makePartial();\n        $this->assertEquals(32, $processor->nativeFontSize($font));\n    }\n\n    public function testTypographicalSize(): void\n    {\n        $font = new Font($this->getTestResourcePath('test.ttf'));\n        $processor = Mockery::mock(AbstractFontProcessor::class)->makePartial();\n        $processor->shouldReceive('boxSize')->with('Hy', $font)->andReturn(new Rectangle(24, 6));\n        $this->assertEquals(6, $processor->typographicalSize($font));\n    }\n\n    public function testCapHeight(): void\n    {\n        $font = new Font($this->getTestResourcePath('test.ttf'));\n        $processor = Mockery::mock(AbstractFontProcessor::class)->makePartial();\n        $processor->shouldReceive('boxSize')->with('T', $font)->andReturn(new Rectangle(24, 6));\n        $this->assertEquals(6, $processor->capHeight($font));\n    }\n\n    public function testLeading(): void\n    {\n        $font = (new Font($this->getTestResourcePath('test.ttf')))->setLineHeight(3);\n        $processor = Mockery::mock(AbstractFontProcessor::class)->makePartial();\n        $processor->shouldReceive('boxSize')->with('Hy', $font)->andReturn(new Rectangle(24, 6));\n        $this->assertEquals(18, $processor->leading($font));\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/Analyzers/ColorspaceAnalyzerTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd\\Analyzers;\n\nuse Intervention\\Image\\Drivers\\Gd\\Analyzers\\ColorspaceAnalyzer;\nuse Intervention\\Image\\Drivers\\Gd\\Driver;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Interfaces\\ColorspaceInterface;\nuse Intervention\\Image\\Tests\\GdTestCase;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(ColorspaceAnalyzer::class)]\nfinal class ColorspaceAnalyzerTest extends GdTestCase\n{\n    public function testAnalyze(): void\n    {\n        $image = $this->readTestImage('tile.png');\n        $analyzer = new ColorspaceAnalyzer();\n        $analyzer->setDriver(new Driver());\n        $result = $analyzer->analyze($image);\n        $this->assertInstanceOf(ColorspaceInterface::class, $result);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/Analyzers/HeightAnalyzerTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd\\Analyzers;\n\nuse Intervention\\Image\\Drivers\\Gd\\Analyzers\\HeightAnalyzer;\nuse Intervention\\Image\\Drivers\\Gd\\Driver;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Tests\\GdTestCase;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(HeightAnalyzer::class)]\nfinal class HeightAnalyzerTest extends GdTestCase\n{\n    public function testAnalyze(): void\n    {\n        $image = $this->readTestImage('tile.png');\n        $analyzer = new HeightAnalyzer();\n        $analyzer->setDriver(new Driver());\n        $result = $analyzer->analyze($image);\n        $this->assertEquals(16, $result);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/Analyzers/PixelColorAnalyzerTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd\\Analyzers;\n\nuse Intervention\\Image\\Drivers\\Gd\\Analyzers\\PixelColorAnalyzer;\nuse Intervention\\Image\\Drivers\\Gd\\Driver;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Tests\\GdTestCase;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(PixelColorAnalyzer::class)]\nfinal class PixelColorAnalyzerTest extends GdTestCase\n{\n    public function testAnalyze(): void\n    {\n        $image = $this->readTestImage('tile.png');\n        $analyzer = new PixelColorAnalyzer(0, 0);\n        $analyzer->setDriver(new Driver());\n        $result = $analyzer->analyze($image);\n        $this->assertInstanceOf(ColorInterface::class, $result);\n        $this->assertEquals('b4e000', $result->toHex());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/Analyzers/PixelColorsAnalyzerTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd\\Analyzers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Collection;\nuse Intervention\\Image\\Drivers\\Gd\\Analyzers\\PixelColorsAnalyzer;\nuse Intervention\\Image\\Drivers\\Gd\\Driver;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Tests\\GdTestCase;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(PixelColorsAnalyzer::class)]\nfinal class PixelColorsAnalyzerTest extends GdTestCase\n{\n    public function testAnalyzeAnimated(): void\n    {\n        $image = $this->readTestImage('animation.gif');\n        $analyzer = new PixelColorsAnalyzer(0, 0);\n        $analyzer->setDriver(new Driver());\n        $result = $analyzer->analyze($image);\n        $this->assertInstanceOf(Collection::class, $result);\n        $colors = array_map(fn(ColorInterface $color) => $color->toHex(), $result->toArray());\n        $this->assertEquals($colors, [\"394b63\", \"394b63\", \"394b63\", \"ffa601\", \"ffa601\", \"ffa601\", \"ffa601\", \"394b63\"]);\n    }\n\n    public function testAnalyzeNonAnimated(): void\n    {\n        $image = $this->readTestImage('tile.png');\n        $analyzer = new PixelColorsAnalyzer(0, 0);\n        $analyzer->setDriver(new Driver());\n        $result = $analyzer->analyze($image);\n        $this->assertInstanceOf(Collection::class, $result);\n        $this->assertInstanceOf(ColorInterface::class, $result->first());\n        $this->assertEquals('b4e000', $result->first()->toHex());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/Analyzers/ResolutionAnalyzerTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd\\Analyzers;\n\nuse Intervention\\Image\\Drivers\\Gd\\Analyzers\\ResolutionAnalyzer;\nuse Intervention\\Image\\Drivers\\Gd\\Driver;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Resolution;\nuse Intervention\\Image\\Tests\\GdTestCase;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(ResolutionAnalyzer::class)]\nfinal class ResolutionAnalyzerTest extends GdTestCase\n{\n    public function testAnalyze(): void\n    {\n        $image = $this->readTestImage('300dpi.png');\n        $analyzer = new ResolutionAnalyzer();\n        $analyzer->setDriver(new Driver());\n        $result = $analyzer->analyze($image);\n        $this->assertInstanceOf(Resolution::class, $result);\n        $this->assertEquals(300, $result->perInch()->x());\n        $this->assertEquals(300, $result->perInch()->y());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/Analyzers/WidthAnalyzerTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd\\Analyzers;\n\nuse Intervention\\Image\\Drivers\\Gd\\Analyzers\\WidthAnalyzer;\nuse Intervention\\Image\\Drivers\\Gd\\Driver;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Tests\\GdTestCase;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(WidthAnalyzer::class)]\nfinal class WidthAnalyzerTest extends GdTestCase\n{\n    public function testAnalyze(): void\n    {\n        $image = $this->readTestImage('tile.png');\n        $analyzer = new WidthAnalyzer();\n        $analyzer->setDriver(new Driver());\n        $result = $analyzer->analyze($image);\n        $this->assertEquals(16, $result);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/ClonerTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd;\n\nuse Intervention\\Image\\Colors\\Rgb\\Color;\nuse Intervention\\Image\\Drivers\\Gd\\Cloner;\nuse Intervention\\Image\\Geometry\\Rectangle;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(Cloner::class)]\nfinal class ClonerTest extends BaseTestCase\n{\n    public function testClone(): void\n    {\n        $gd = imagecreatefromgif($this->getTestResourcePath('gradient.gif'));\n        $clone = Cloner::clone($gd);\n\n        $this->assertEquals(16, imagesx($gd));\n        $this->assertEquals(16, imagesy($gd));\n        $this->assertEquals(16, imagesx($clone));\n        $this->assertEquals(16, imagesy($clone));\n\n        $this->assertEquals(\n            imagecolorsforindex($gd, imagecolorat($gd, 10, 10)),\n            imagecolorsforindex($clone, imagecolorat($clone, 10, 10))\n        );\n    }\n\n    public function testCloneEmpty(): void\n    {\n        $gd = imagecreatefromgif($this->getTestResourcePath('gradient.gif'));\n        $clone = Cloner::cloneEmpty($gd, new Rectangle(12, 12), new Color(255, 0, 0, 0));\n\n        $this->assertEquals(16, imagesx($gd));\n        $this->assertEquals(16, imagesy($gd));\n        $this->assertEquals(12, imagesx($clone));\n        $this->assertEquals(12, imagesy($clone));\n\n        $this->assertEquals(\n            ['red' => 0, 'green' => 255, 'blue' => 2, 'alpha' => 0],\n            imagecolorsforindex($gd, imagecolorat($gd, 10, 10)),\n        );\n\n        $this->assertEquals(\n            ['red' => 255, 'green' => 0, 'blue' => 0, 'alpha' => 127],\n            imagecolorsforindex($clone, imagecolorat($clone, 10, 10))\n        );\n    }\n\n    public function testCloneBlended(): void\n    {\n        $gd = imagecreatefromgif($this->getTestResourcePath('gradient.gif'));\n        $clone = Cloner::cloneBlended($gd, new Color(255, 0, 255, 255));\n\n        $this->assertEquals(16, imagesx($gd));\n        $this->assertEquals(16, imagesy($gd));\n        $this->assertEquals(16, imagesx($clone));\n        $this->assertEquals(16, imagesy($clone));\n\n        $this->assertEquals(\n            ['red' => 0, 'green' => 0, 'blue' => 0, 'alpha' => 127],\n            imagecolorsforindex($gd, imagecolorat($gd, 1, 0)),\n        );\n\n        $this->assertEquals(\n            ['red' => 255, 'green' => 0, 'blue' => 255, 'alpha' => 0],\n            imagecolorsforindex($clone, imagecolorat($clone, 1, 0))\n        );\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/ColorProcessorTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd;\n\nuse Intervention\\Image\\Colors\\Rgb\\Channels\\Alpha;\nuse Intervention\\Image\\Colors\\Rgb\\Channels\\Blue;\nuse Intervention\\Image\\Colors\\Rgb\\Channels\\Green;\nuse Intervention\\Image\\Colors\\Rgb\\Channels\\Red;\nuse Intervention\\Image\\Colors\\Rgb\\Color;\nuse Intervention\\Image\\Drivers\\Gd\\ColorProcessor;\nuse Intervention\\Image\\Exceptions\\ColorException;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(ColorProcessor::class)]\nfinal class ColorProcessorTest extends BaseTestCase\n{\n    public function testColorToNative(): void\n    {\n        $processor = new ColorProcessor();\n        $result = $processor->colorToNative(new Color(255, 55, 0, 255));\n        $this->assertEquals(16725760, $result);\n    }\n\n    public function testNativeToColorInteger(): void\n    {\n        $processor = new ColorProcessor();\n        $result = $processor->nativeToColor(16725760);\n        $this->assertInstanceOf(Color::class, $result);\n        $this->assertEquals(255, $result->channel(Red::class)->value());\n        $this->assertEquals(55, $result->channel(Green::class)->value());\n        $this->assertEquals(0, $result->channel(Blue::class)->value());\n        $this->assertEquals(255, $result->channel(Alpha::class)->value());\n    }\n\n    public function testNativeToColorArray(): void\n    {\n        $processor = new ColorProcessor();\n        $result = $processor->nativeToColor(['red' => 255, 'green' => 55, 'blue' => 0, 'alpha' => 0]);\n        $this->assertInstanceOf(Color::class, $result);\n        $this->assertEquals(255, $result->channel(Red::class)->value());\n        $this->assertEquals(55, $result->channel(Green::class)->value());\n        $this->assertEquals(0, $result->channel(Blue::class)->value());\n        $this->assertEquals(255, $result->channel(Alpha::class)->value());\n    }\n\n    public function testNativeToColorInvalid(): void\n    {\n        $processor = new ColorProcessor();\n        $this->expectException(ColorException::class);\n        $processor->nativeToColor('test');\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/CoreTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd;\n\nuse GdImage;\nuse Intervention\\Image\\Drivers\\Gd\\Core;\nuse Intervention\\Image\\Drivers\\Gd\\Frame;\nuse Intervention\\Image\\Exceptions\\AnimationException;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(Core::class)]\nfinal class CoreTest extends BaseTestCase\n{\n    protected Core $core;\n\n    protected function setUp(): void\n    {\n        $this->core = new Core([\n            new Frame(imagecreatetruecolor(3, 2)),\n            new Frame(imagecreatetruecolor(3, 2)),\n            new Frame(imagecreatetruecolor(3, 2)),\n        ]);\n    }\n\n    public function getTestFrame(): Frame\n    {\n        return new Frame(imagecreatetruecolor(3, 2));\n    }\n\n    public function testAdd(): void\n    {\n        $this->assertEquals(3, $this->core->count());\n        $result = $this->core->add($this->getTestFrame());\n        $this->assertEquals(4, $this->core->count());\n        $this->assertInstanceOf(Core::class, $result);\n    }\n\n    public function testSetNative(): void\n    {\n        $gd1 = imagecreatetruecolor(3, 2);\n        $gd2 = imagecreatetruecolor(3, 2);\n        $core = new Core([new Frame($gd1)]);\n        $this->assertEquals($gd1, $core->native());\n        $core->setNative($gd2);\n        $this->assertEquals($gd2, $core->native());\n    }\n\n    public function testCount(): void\n    {\n        $this->assertEquals(3, $this->core->count());\n    }\n\n    public function testIterator(): void\n    {\n        foreach ($this->core as $frame) {\n            $this->assertInstanceOf(Frame::class, $frame);\n        }\n    }\n\n    public function testNative(): void\n    {\n        $this->assertInstanceOf(GdImage::class, $this->core->native());\n    }\n\n    public function testFrame(): void\n    {\n        $this->assertInstanceOf(Frame::class, $this->core->frame(0));\n        $this->assertInstanceOf(Frame::class, $this->core->frame(1));\n        $this->assertInstanceOf(Frame::class, $this->core->frame(2));\n        $this->expectException(AnimationException::class);\n        $this->core->frame(3);\n    }\n\n    public function testSetGetLoops(): void\n    {\n        $this->assertEquals(0, $this->core->loops());\n        $result = $this->core->setLoops(12);\n        $this->assertInstanceOf(Core::class, $result);\n        $this->assertEquals(12, $this->core->loops());\n    }\n\n    public function testHas(): void\n    {\n        $this->assertTrue($this->core->has(0));\n        $this->assertTrue($this->core->has(1));\n        $this->assertTrue($this->core->has(2));\n        $this->assertFalse($this->core->has(3));\n    }\n\n    public function testPush(): void\n    {\n        $this->assertEquals(3, $this->core->count());\n        $result = $this->core->push($this->getTestFrame());\n        $this->assertEquals(4, $this->core->count());\n        $this->assertEquals(4, $result->count());\n    }\n\n    public function testGet(): void\n    {\n        $this->assertInstanceOf(Frame::class, $this->core->get(0));\n        $this->assertInstanceOf(Frame::class, $this->core->get(1));\n        $this->assertInstanceOf(Frame::class, $this->core->get(2));\n        $this->assertNull($this->core->get(3));\n        $this->assertEquals('foo', $this->core->get(3, 'foo'));\n    }\n\n    public function testEmpty(): void\n    {\n        $result = $this->core->empty();\n        $this->assertEquals(0, $this->core->count());\n        $this->assertEquals(0, $result->count());\n    }\n\n    public function testSlice(): void\n    {\n        $this->assertEquals(3, $this->core->count());\n        $result = $this->core->slice(1, 2);\n        $this->assertEquals(2, $this->core->count());\n        $this->assertEquals(2, $result->count());\n    }\n\n    public function testFirst(): void\n    {\n        $this->assertInstanceOf(Frame::class, $this->core->first());\n    }\n\n    public function testLast(): void\n    {\n        $this->assertInstanceOf(Frame::class, $this->core->last());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/Decoders/AbstractDecoderTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd\\Decoders;\n\nuse Intervention\\Image\\Drivers\\Gd\\Decoders\\AbstractDecoder;\nuse Intervention\\Image\\MediaType;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse Mockery;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(AbstractDecoder::class)]\nfinal class AbstractDecoderTest extends BaseTestCase\n{\n    public function testGetMediaTypeFromFilePath(): void\n    {\n        $decoder = Mockery::mock(AbstractDecoder::class)->makePartial();\n        $this->assertEquals(\n            MediaType::IMAGE_JPEG,\n            $decoder->getMediaTypeByFilePath($this->getTestResourcePath('test.jpg'))\n        );\n    }\n\n    public function testGetMediaTypeFromFileBinary(): void\n    {\n        $decoder = Mockery::mock(AbstractDecoder::class)->makePartial();\n        $this->assertEquals(\n            MediaType::IMAGE_JPEG,\n            $decoder->getMediaTypeByBinary($this->getTestResourceData('test.jpg')),\n        );\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/Decoders/Base64ImageDecoderTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd\\Decoders;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Drivers\\Gd\\Decoders\\Base64ImageDecoder;\nuse Intervention\\Image\\Drivers\\Gd\\Driver;\nuse Intervention\\Image\\Exceptions\\DecoderException;\nuse Intervention\\Image\\Image;\nuse Intervention\\Image\\Tests\\BaseTestCase;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(Base64ImageDecoder::class)]\nfinal class Base64ImageDecoderTest extends BaseTestCase\n{\n    protected Base64ImageDecoder $decoder;\n\n    protected function setUp(): void\n    {\n        $this->decoder = new Base64ImageDecoder();\n        $this->decoder->setDriver(new Driver());\n    }\n\n    public function testDecode(): void\n    {\n        $result = $this->decoder->decode(\n            base64_encode($this->getTestResourceData('blue.gif'))\n        );\n\n        $this->assertInstanceOf(Image::class, $result);\n    }\n\n    public function testDecoderInvalid(): void\n    {\n        $this->expectException(DecoderException::class);\n        $this->decoder->decode('test');\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/Decoders/BinaryImageDecoderTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd\\Decoders;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Drivers\\Gd\\Decoders\\BinaryImageDecoder;\nuse Intervention\\Image\\Drivers\\Gd\\Driver;\nuse Intervention\\Image\\Image;\nuse Intervention\\Image\\Tests\\BaseTestCase;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(BinaryImageDecoder::class)]\nfinal class BinaryImageDecoderTest extends BaseTestCase\n{\n    protected BinaryImageDecoder $decoder;\n\n    protected function setUp(): void\n    {\n        $this->decoder = new BinaryImageDecoder();\n        $this->decoder->setDriver(new Driver());\n    }\n\n    public function testDecodePng(): void\n    {\n        $image = $this->decoder->decode(file_get_contents($this->getTestResourcePath('tile.png')));\n        $this->assertInstanceOf(Image::class, $image);\n        $this->assertEquals(16, $image->width());\n        $this->assertEquals(16, $image->height());\n        $this->assertCount(1, $image);\n    }\n\n    public function testDecodeGif(): void\n    {\n        $image = $this->decoder->decode(file_get_contents($this->getTestResourcePath('red.gif')));\n        $this->assertInstanceOf(Image::class, $image);\n        $this->assertEquals(16, $image->width());\n        $this->assertEquals(16, $image->height());\n        $this->assertCount(1, $image);\n    }\n\n    public function testDecodeAnimatedGif(): void\n    {\n        $image = $this->decoder->decode(file_get_contents($this->getTestResourcePath('cats.gif')));\n        $this->assertInstanceOf(Image::class, $image);\n        $this->assertEquals(75, $image->width());\n        $this->assertEquals(50, $image->height());\n        $this->assertCount(4, $image);\n    }\n\n    public function testDecodeJpegWithExif(): void\n    {\n        $image = $this->decoder->decode(file_get_contents($this->getTestResourcePath('exif.jpg')));\n        $this->assertInstanceOf(Image::class, $image);\n        $this->assertEquals(16, $image->width());\n        $this->assertEquals(16, $image->height());\n        $this->assertCount(1, $image);\n        $this->assertEquals('Oliver Vogel', $image->exif('IFD0.Artist'));\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/Decoders/DataUriImageDecoderTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd\\Decoders;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Drivers\\Gd\\Decoders\\DataUriImageDecoder;\nuse Intervention\\Image\\Drivers\\Gd\\Driver;\nuse Intervention\\Image\\Exceptions\\DecoderException;\nuse Intervention\\Image\\Image;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse stdClass;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(DataUriImageDecoder::class)]\nfinal class DataUriImageDecoderTest extends BaseTestCase\n{\n    protected DataUriImageDecoder $decoder;\n\n    protected function setUp(): void\n    {\n        $this->decoder = new DataUriImageDecoder();\n        $this->decoder->setDriver(new Driver());\n    }\n\n    public function testDecode(): void\n    {\n        $result = $this->decoder->decode(\n            sprintf('data:image/jpeg;base64,%s', base64_encode($this->getTestResourceData('blue.gif')))\n        );\n\n        $this->assertInstanceOf(Image::class, $result);\n    }\n\n    public function testDecoderNonString(): void\n    {\n        $this->expectException(DecoderException::class);\n        $this->decoder->decode(new stdClass());\n    }\n\n    public function testDecoderInvalid(): void\n    {\n        $this->expectException(DecoderException::class);\n        $this->decoder->decode('invalid');\n    }\n\n    public function testDecoderNonImage(): void\n    {\n        $this->expectException(DecoderException::class);\n        $this->decoder->decode('data:text/plain;charset=utf-8,test');\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/Decoders/EncodedImageObjectDecoderTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd\\Decoders;\n\nuse Intervention\\Image\\Drivers\\Gd\\Decoders\\EncodedImageObjectDecoder;\nuse Intervention\\Image\\Drivers\\Gd\\Driver;\nuse Intervention\\Image\\EncodedImage;\nuse Intervention\\Image\\Image;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(EncodedImageObjectDecoder::class)]\nclass EncodedImageObjectDecoderTest extends ImagickTestCase\n{\n    protected EncodedImageObjectDecoder $decoder;\n\n    protected function setUp(): void\n    {\n        $this->decoder = new EncodedImageObjectDecoder();\n        $this->decoder->setDriver(new Driver());\n    }\n\n    public function testDecode(): void\n    {\n        $result = $this->decoder->decode(new EncodedImage($this->getTestResourceData()));\n        $this->assertInstanceOf(Image::class, $result);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/Decoders/FilePathImageDecoderTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd\\Decoders;\n\nuse Generator;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Drivers\\Gd\\Decoders\\FilePathImageDecoder;\nuse Intervention\\Image\\Drivers\\Gd\\Driver;\nuse Intervention\\Image\\Exceptions\\DecoderException;\nuse Intervention\\Image\\Image;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(FilePathImageDecoder::class)]\nfinal class FilePathImageDecoderTest extends BaseTestCase\n{\n    protected FilePathImageDecoder $decoder;\n\n    protected function setUp(): void\n    {\n        $this->decoder = new FilePathImageDecoder();\n        $this->decoder->setDriver(new Driver());\n    }\n\n    #[DataProvider('validFormatPathsProvider')]\n    public function testDecode(string $path, bool $result): void\n    {\n        if ($result === false) {\n            $this->expectException(DecoderException::class);\n        }\n\n        $result = $this->decoder->decode($path);\n\n        if ($result === true) {\n            $this->assertInstanceOf(Image::class, $result);\n        }\n    }\n\n    public static function validFormatPathsProvider(): Generator\n    {\n        yield [self::getTestResourcePath('cats.gif'), true];\n        yield [self::getTestResourcePath('animation.gif'), true];\n        yield [self::getTestResourcePath('red.gif'), true];\n        yield [self::getTestResourcePath('green.gif'), true];\n        yield [self::getTestResourcePath('blue.gif'), true];\n        yield [self::getTestResourcePath('gradient.bmp'), true];\n        yield [self::getTestResourcePath('circle.png'), true];\n        yield ['no-path', false];\n        yield [str_repeat('x', PHP_MAXPATHLEN + 1), false];\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/Decoders/FilePointerImageDecoderTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd\\Decoders;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Drivers\\Gd\\Decoders\\FilePointerImageDecoder;\nuse Intervention\\Image\\Drivers\\Gd\\Driver;\nuse Intervention\\Image\\Image;\nuse Intervention\\Image\\Tests\\GdTestCase;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(FilePointerImageDecoder::class)]\nfinal class FilePointerImageDecoderTest extends GdTestCase\n{\n    public function testDecode(): void\n    {\n        $decoder = new FilePointerImageDecoder();\n        $decoder->setDriver(new Driver());\n\n        $fp = fopen($this->getTestResourcePath('test.jpg'), 'r');\n        $result = $decoder->decode($fp);\n        $this->assertInstanceOf(Image::class, $result);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/Decoders/ImageObjectDecoderTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd\\Decoders;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Decoders\\ImageObjectDecoder;\nuse Intervention\\Image\\Image;\nuse Intervention\\Image\\Tests\\GdTestCase;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(ImageObjectDecoder::class)]\nfinal class ImageObjectDecoderTest extends GdTestCase\n{\n    public function testDecode(): void\n    {\n        $decoder = new ImageObjectDecoder();\n        $result = $decoder->decode($this->readTestImage('blue.gif'));\n        $this->assertInstanceOf(Image::class, $result);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/Decoders/NativeObjectDecoderTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd\\Decoders;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Drivers\\Gd\\Decoders\\NativeObjectDecoder;\nuse Intervention\\Image\\Drivers\\Gd\\Driver;\nuse Intervention\\Image\\Image;\nuse Intervention\\Image\\Tests\\BaseTestCase;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(NativeObjectDecoder::class)]\nfinal class NativeObjectDecoderTest extends BaseTestCase\n{\n    protected NativeObjectDecoder $decoder;\n\n    protected function setUp(): void\n    {\n        $this->decoder = new NativeObjectDecoder();\n        $this->decoder->setDriver(new Driver());\n    }\n\n    public function testDecode(): void\n    {\n        $result = $this->decoder->decode(\n            imagecreatetruecolor(3, 2)\n        );\n\n        $this->assertInstanceOf(Image::class, $result);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/Decoders/SplFileInfoImageDecoderTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd\\Decoders;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Drivers\\Gd\\Decoders\\SplFileInfoImageDecoder;\nuse Intervention\\Image\\Drivers\\Gd\\Driver;\nuse Intervention\\Image\\Image;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse SplFileInfo;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(SplFileInfoImageDecoder::class)]\nfinal class SplFileInfoImageDecoderTest extends BaseTestCase\n{\n    public function testDecode(): void\n    {\n        $decoder = new SplFileInfoImageDecoder();\n        $decoder->setDriver(new Driver());\n\n        $result = $decoder->decode(\n            new SplFileInfo($this->getTestResourcePath('blue.gif'))\n        );\n        $this->assertInstanceOf(Image::class, $result);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/DriverTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd;\n\nuse Generator;\nuse Intervention\\Image\\Analyzers\\WidthAnalyzer as GenericWidthAnalyzer;\nuse Intervention\\Image\\Colors\\Rgb\\Colorspace;\nuse Intervention\\Image\\Colors\\Rgb\\Decoders\\HexColorDecoder;\nuse Intervention\\Image\\Decoders\\FilePathImageDecoder as GenericFilePathImageDecoder;\nuse Intervention\\Image\\Drivers\\Gd\\Analyzers\\WidthAnalyzer;\nuse Intervention\\Image\\Drivers\\Gd\\Decoders\\FilePathImageDecoder;\nuse Intervention\\Image\\Drivers\\Gd\\Driver;\nuse Intervention\\Image\\Drivers\\Gd\\Encoders\\PngEncoder;\nuse Intervention\\Image\\Drivers\\Gd\\Modifiers\\ResizeModifier;\nuse Intervention\\Image\\Encoders\\PngEncoder as GenericPngEncoder;\nuse Intervention\\Image\\Exceptions\\NotSupportedException;\nuse Intervention\\Image\\FileExtension;\nuse Intervention\\Image\\Format;\nuse Intervention\\Image\\Interfaces\\AnalyzerInterface;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Interfaces\\ColorProcessorInterface;\nuse Intervention\\Image\\Interfaces\\DriverInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializableInterface;\nuse Intervention\\Image\\MediaType;\nuse Intervention\\Image\\Modifiers\\ResizeModifier as GenericResizeModifier;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(Driver::class)]\nfinal class DriverTest extends BaseTestCase\n{\n    protected Driver $driver;\n\n    protected function setUp(): void\n    {\n        $this->driver = new Driver();\n    }\n\n    public function testId(): void\n    {\n        $this->assertEquals('GD', $this->driver->id());\n    }\n\n    public function testCreateImage(): void\n    {\n        $image = $this->driver->createImage(3, 2);\n        $this->assertInstanceOf(ImageInterface::class, $image);\n        $this->assertEquals(3, $image->width());\n        $this->assertEquals(2, $image->height());\n    }\n\n    public function testCreateAnimation(): void\n    {\n        $image = $this->driver->createAnimation(function ($animation): void {\n            $animation->add($this->getTestResourcePath('red.gif'), .25);\n            $animation->add($this->getTestResourcePath('green.gif'), .25);\n        })->setLoops(5);\n        $this->assertInstanceOf(ImageInterface::class, $image);\n\n        $this->assertEquals(16, $image->width());\n        $this->assertEquals(16, $image->height());\n        $this->assertEquals(5, $image->loops());\n        $this->assertEquals(2, $image->count());\n    }\n\n    public function testHandleInputImage(): void\n    {\n        $result = $this->driver->handleInput($this->getTestResourcePath('test.jpg'));\n        $this->assertInstanceOf(ImageInterface::class, $result);\n    }\n\n    public function testHandleInputColor(): void\n    {\n        $result = $this->driver->handleInput('ffffff');\n        $this->assertInstanceOf(ColorInterface::class, $result);\n    }\n\n    public function testHandleInputObjects(): void\n    {\n        $result = $this->driver->handleInput('ffffff', [\n            new HexColorDecoder()\n        ]);\n        $this->assertInstanceOf(ColorInterface::class, $result);\n    }\n\n    public function testHandleInputClassnames(): void\n    {\n        $result = $this->driver->handleInput('ffffff', [\n            HexColorDecoder::class\n        ]);\n        $this->assertInstanceOf(ColorInterface::class, $result);\n    }\n\n    public function testColorProcessor(): void\n    {\n        $result = $this->driver->colorProcessor(new Colorspace());\n        $this->assertInstanceOf(ColorProcessorInterface::class, $result);\n    }\n\n    #[DataProvider('supportsDataProvider')]\n    public function testSupports(bool $result, mixed $identifier): void\n    {\n        $this->assertEquals($result, $this->driver->supports($identifier));\n    }\n\n    public static function supportsDataProvider(): Generator\n    {\n        yield [true, Format::JPEG];\n        yield [true, MediaType::IMAGE_JPEG];\n        yield [true, MediaType::IMAGE_JPG];\n        yield [true, FileExtension::JPG];\n        yield [true, FileExtension::JPEG];\n        yield [true, 'jpg'];\n        yield [true, 'jpeg'];\n        yield [true, 'image/jpg'];\n        yield [true, 'image/jpeg'];\n\n        yield [true, Format::WEBP];\n        yield [true, MediaType::IMAGE_WEBP];\n        yield [true, MediaType::IMAGE_X_WEBP];\n        yield [true, FileExtension::WEBP];\n        yield [true, 'webp'];\n        yield [true, 'image/webp'];\n        yield [true, 'image/x-webp'];\n\n        yield [true, Format::GIF];\n        yield [true, MediaType::IMAGE_GIF];\n        yield [true, FileExtension::GIF];\n        yield [true, 'gif'];\n        yield [true, 'image/gif'];\n\n        yield [true, Format::PNG];\n        yield [true, MediaType::IMAGE_PNG];\n        yield [true, MediaType::IMAGE_X_PNG];\n        yield [true, FileExtension::PNG];\n        yield [true, 'png'];\n        yield [true, 'image/png'];\n        yield [true, 'image/x-png'];\n\n        yield [true, Format::AVIF];\n        yield [true, MediaType::IMAGE_AVIF];\n        yield [true, MediaType::IMAGE_X_AVIF];\n        yield [true, FileExtension::AVIF];\n        yield [true, 'avif'];\n        yield [true, 'image/avif'];\n        yield [true, 'image/x-avif'];\n\n        yield [true, Format::BMP];\n        yield [true, FileExtension::BMP];\n        yield [true, MediaType::IMAGE_BMP];\n        yield [true, MediaType::IMAGE_MS_BMP];\n        yield [true, MediaType::IMAGE_X_BITMAP];\n        yield [true, MediaType::IMAGE_X_BMP];\n        yield [true, MediaType::IMAGE_X_MS_BMP];\n        yield [true, MediaType::IMAGE_X_WINDOWS_BMP];\n        yield [true, MediaType::IMAGE_X_WIN_BITMAP];\n        yield [true, MediaType::IMAGE_X_XBITMAP];\n        yield [true, 'bmp'];\n        yield [true, 'image/bmp'];\n        yield [true, 'image/ms-bmp'];\n        yield [true, 'image/x-bitmap'];\n        yield [true, 'image/x-bmp'];\n        yield [true, 'image/x-ms-bmp'];\n        yield [true, 'image/x-windows-bmp'];\n        yield [true, 'image/x-win-bitmap'];\n        yield [true, 'image/x-xbitmap'];\n\n        yield [false, Format::TIFF];\n        yield [false, MediaType::IMAGE_TIFF];\n        yield [false, FileExtension::TIFF];\n        yield [false, FileExtension::TIF];\n        yield [false, 'tif'];\n        yield [false, 'tiff'];\n        yield [false, 'image/tiff'];\n\n        yield [false, Format::JP2];\n        yield [false, MediaType::IMAGE_JP2];\n        yield [false, MediaType::IMAGE_JPX];\n        yield [false, MediaType::IMAGE_JPM];\n        yield [false, FileExtension::TIFF];\n        yield [false, FileExtension::TIF];\n        yield [false, FileExtension::JP2];\n        yield [false, FileExtension::J2K];\n        yield [false, FileExtension::JPF];\n        yield [false, FileExtension::JPM];\n        yield [false, FileExtension::JPG2];\n        yield [false, FileExtension::J2C];\n        yield [false, FileExtension::JPC];\n        yield [false, FileExtension::JPX];\n        yield [false, 'jp2'];\n        yield [false, 'j2k'];\n        yield [false, 'jpf'];\n        yield [false, 'jpm'];\n        yield [false, 'jpg2'];\n        yield [false, 'j2c'];\n        yield [false, 'jpc'];\n        yield [false, 'jpx'];\n\n        yield [false, Format::HEIC];\n        yield [false, MediaType::IMAGE_HEIC];\n        yield [false, MediaType::IMAGE_HEIF];\n        yield [false, FileExtension::HEIC];\n        yield [false, FileExtension::HEIF];\n        yield [false, 'heic'];\n        yield [false, 'heif'];\n        yield [false, 'image/heic'];\n        yield [false, 'image/heif'];\n\n        yield [false, 'tga'];\n        yield [false, 'image/tga'];\n        yield [false, 'image/x-targa'];\n        yield [false, 'foo'];\n        yield [false, ''];\n    }\n\n    public function testVersion(): void\n    {\n        $this->assertTrue(is_string($this->driver->version()));\n    }\n\n    #[DataProvider('spezializeDataProvider')]\n    public function testSpecialize(string $inputClassname, string $outputClassname): void\n    {\n        $this->assertInstanceOf($outputClassname, $this->driver->specialize(new $inputClassname()));\n    }\n\n    public static function spezializeDataProvider(): Generator\n    {\n        // specializing possible\n        yield [GenericResizeModifier::class, ResizeModifier::class];\n        yield [GenericWidthAnalyzer::class, WidthAnalyzer::class];\n        yield [GenericPngEncoder::class, PngEncoder::class];\n        yield [GenericFilePathImageDecoder::class, FilePathImageDecoder::class];\n\n        // already specialized\n        yield [ResizeModifier::class, ResizeModifier::class];\n        yield [WidthAnalyzer::class, WidthAnalyzer::class];\n        yield [PngEncoder::class, PngEncoder::class];\n        yield [FilePathImageDecoder::class, FilePathImageDecoder::class];\n    }\n\n    public function testSpecializeFailure(): void\n    {\n        $this->expectException(NotSupportedException::class);\n        $this->driver->specialize(new class () implements AnalyzerInterface, SpecializableInterface\n        {\n            protected DriverInterface $driver;\n\n            public function analyze(ImageInterface $image): mixed\n            {\n                return true;\n            }\n\n            /** @return array<string, mixed> **/\n            public function specializable(): array\n            {\n                return [];\n            }\n\n            public function setDriver(DriverInterface $driver): SpecializableInterface\n            {\n                return $this;\n            }\n\n            public function driver(): DriverInterface\n            {\n                return $this->driver;\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/Encoders/AvifEncoderTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd\\Encoders;\n\nuse Intervention\\Image\\Drivers\\Gd\\Encoders\\AvifEncoder;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Tests\\GdTestCase;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(AvifEncoder::class)]\nfinal class AvifEncoderTest extends GdTestCase\n{\n    public function testEncode(): void\n    {\n        $image = $this->createTestImage(3, 2);\n        $encoder = new AvifEncoder(10);\n        $result = $encoder->encode($image);\n        $this->assertMediaType('image/avif', $result);\n        $this->assertEquals('image/avif', $result->mimetype());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/Encoders/BmpEncoderTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd\\Encoders;\n\nuse Intervention\\Image\\Drivers\\Gd\\Encoders\\BmpEncoder;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Tests\\GdTestCase;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(BmpEncoder::class)]\nfinal class BmpEncoderTest extends GdTestCase\n{\n    public function testEncode(): void\n    {\n        $image = $this->createTestImage(3, 2);\n        $encoder = new BmpEncoder();\n        $result = $encoder->encode($image);\n        $this->assertMediaType(['image/bmp', 'image/x-ms-bmp'], $result);\n        $this->assertEquals('image/bmp', $result->mimetype());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/Encoders/GifEncoderTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd\\Encoders;\n\nuse Intervention\\Gif\\Decoder;\nuse Intervention\\Image\\Drivers\\Gd\\Encoders\\GifEncoder;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Tests\\GdTestCase;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(GifEncoder::class)]\nfinal class GifEncoderTest extends GdTestCase\n{\n    public function testEncode(): void\n    {\n        $image = $this->createTestAnimation();\n        $encoder = new GifEncoder();\n        $result = $encoder->encode($image);\n        $this->assertMediaType('image/gif', $result);\n        $this->assertEquals('image/gif', $result->mimetype());\n        $this->assertFalse(\n            Decoder::decode((string) $result)->getFirstFrame()->getImageDescriptor()->isInterlaced()\n        );\n    }\n\n    public function testEncodeInterlaced(): void\n    {\n        $image = $this->createTestImage(3, 2);\n        $encoder = new GifEncoder(interlaced: true);\n        $result = $encoder->encode($image);\n        $this->assertMediaType('image/gif', $result);\n        $this->assertEquals('image/gif', $result->mimetype());\n        $this->assertTrue(\n            Decoder::decode((string) $result)->getFirstFrame()->getImageDescriptor()->isInterlaced()\n        );\n    }\n\n    public function testEncodeInterlacedAnimation(): void\n    {\n        $image = $this->createTestAnimation();\n        $encoder = new GifEncoder(interlaced: true);\n        $result = $encoder->encode($image);\n        $this->assertMediaType('image/gif', $result);\n        $this->assertEquals('image/gif', $result->mimetype());\n        $this->assertTrue(\n            Decoder::decode((string) $result)->getFirstFrame()->getImageDescriptor()->isInterlaced()\n        );\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/Encoders/JpegEncoderTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd\\Encoders;\n\nuse Intervention\\Image\\Drivers\\Gd\\Driver;\nuse Intervention\\Image\\Drivers\\Gd\\Encoders\\JpegEncoder;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Tests\\GdTestCase;\nuse Intervention\\Image\\Tests\\Traits\\CanDetectProgressiveJpeg;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(JpegEncoder::class)]\nfinal class JpegEncoderTest extends GdTestCase\n{\n    use CanDetectProgressiveJpeg;\n\n    public function testEncode(): void\n    {\n        $image = $this->createTestImage(3, 2);\n        $encoder = new JpegEncoder(75);\n        $encoder->setDriver(new Driver());\n        $result = $encoder->encode($image);\n        $this->assertMediaType('image/jpeg', $result);\n        $this->assertEquals('image/jpeg', $result->mimetype());\n    }\n\n    public function testEncodeProgressive(): void\n    {\n        $image = $this->createTestImage(3, 2);\n        $encoder = new JpegEncoder(progressive: true);\n        $encoder->setDriver(new Driver());\n        $result = $encoder->encode($image);\n        $this->assertMediaType('image/jpeg', $result);\n        $this->assertEquals('image/jpeg', $result->mimetype());\n        $this->assertTrue($this->isProgressiveJpeg($result));\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/Encoders/PngEncoderTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd\\Encoders;\n\nuse Generator;\nuse Intervention\\Image\\Drivers\\Gd\\Encoders\\PngEncoder;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Tests\\GdTestCase;\nuse Intervention\\Image\\Tests\\Traits\\CanInspectPngFormat;\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(PngEncoder::class)]\nfinal class PngEncoderTest extends GdTestCase\n{\n    use CanInspectPngFormat;\n\n    public function testEncode(): void\n    {\n        $image = $this->createTestImage(3, 2);\n        $encoder = new PngEncoder();\n        $result = $encoder->encode($image);\n        $this->assertMediaType('image/png', $result);\n        $this->assertEquals('image/png', $result->mimetype());\n        $this->assertFalse($this->isInterlacedPng($result));\n    }\n\n    public function testEncodeInterlaced(): void\n    {\n        $image = $this->createTestImage(3, 2);\n        $encoder = new PngEncoder(interlaced: true);\n        $result = $encoder->encode($image);\n        $this->assertMediaType('image/png', $result);\n        $this->assertEquals('image/png', $result->mimetype());\n        $this->assertTrue($this->isInterlacedPng($result));\n    }\n\n    #[DataProvider('indexedDataProvider')]\n    public function testEncoderIndexed(ImageInterface $image, PngEncoder $encoder, string $result): void\n    {\n        $this->assertEquals(\n            $result,\n            $this->pngColorType($encoder->encode($image)),\n        );\n    }\n\n    public static function indexedDataProvider(): Generator\n    {\n        yield [\n            static::createTestImage(3, 2), // new\n            new PngEncoder(indexed: false),\n            'truecolor-alpha',\n        ];\n        yield [\n            static::createTestImage(3, 2), // new\n            new PngEncoder(indexed: true),\n            'indexed',\n        ];\n        yield [\n            static::readTestImage('circle.png'), // truecolor-alpha\n            new PngEncoder(indexed: false),\n            'truecolor-alpha',\n        ];\n        yield [\n            static::readTestImage('circle.png'), // indexedcolor-alpha\n            new PngEncoder(indexed: true),\n            'indexed',\n        ];\n        yield [\n            static::readTestImage('tile.png'), // indexed\n            new PngEncoder(indexed: false),\n            'truecolor-alpha',\n        ];\n        yield [\n            static::readTestImage('tile.png'), // indexed\n            new PngEncoder(indexed: true),\n            'indexed',\n        ];\n        yield [\n            static::readTestImage('test.jpg'), // jpeg\n            new PngEncoder(indexed: false),\n            'truecolor-alpha',\n        ];\n        yield [\n            static::readTestImage('test.jpg'), // jpeg\n            new PngEncoder(indexed: true),\n            'indexed',\n        ];\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/Encoders/WebpEncoderTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd\\Encoders;\n\nuse Intervention\\Image\\Drivers\\Gd\\Encoders\\WebpEncoder;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Tests\\GdTestCase;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(WebpEncoder::class)]\nfinal class WebpEncoderTest extends GdTestCase\n{\n    public function testEncode(): void\n    {\n        $image = $this->createTestImage(3, 2);\n        $encoder = new WebpEncoder(75);\n        $result = $encoder->encode($image);\n        $this->assertMediaType('image/webp', $result);\n        $this->assertEquals('image/webp', $result->mimetype());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/FontProcessorTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd;\n\nuse Intervention\\Image\\Drivers\\Gd\\FontProcessor;\nuse Intervention\\Image\\Geometry\\Point;\nuse Intervention\\Image\\Interfaces\\SizeInterface;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse Intervention\\Image\\Typography\\Font;\nuse Intervention\\Image\\Typography\\TextBlock;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(FontProcessor::class)]\nfinal class FontProcessorTest extends BaseTestCase\n{\n    public function testBoxSizeGdOne(): void\n    {\n        $processor = new FontProcessor();\n        $size = $processor->boxSize('test', new Font());\n        $this->assertInstanceOf(SizeInterface::class, $size);\n        $this->assertEquals(16, $size->width());\n        $this->assertEquals(8, $size->height());\n    }\n\n    public function testBoxSizeGdTwo(): void\n    {\n        $processor = new FontProcessor();\n        $size = $processor->boxSize('test', new Font('2'));\n        $this->assertInstanceOf(SizeInterface::class, $size);\n        $this->assertEquals(24, $size->width());\n        $this->assertEquals(14, $size->height());\n    }\n\n    public function testBoxSizeGdThree(): void\n    {\n        $processor = new FontProcessor();\n        $size = $processor->boxSize('test', new Font('3'));\n        $this->assertInstanceOf(SizeInterface::class, $size);\n        $this->assertEquals(28, $size->width());\n        $this->assertEquals(14, $size->height());\n    }\n\n    public function testBoxSizeGdFour(): void\n    {\n        $processor = new FontProcessor();\n        $size = $processor->boxSize('test', new Font('4'));\n        $this->assertInstanceOf(SizeInterface::class, $size);\n        $this->assertEquals(32, $size->width());\n        $this->assertEquals(16, $size->height());\n    }\n\n    public function testBoxSizeGdFive(): void\n    {\n        $processor = new FontProcessor();\n        $size = $processor->boxSize('test', new Font('5'));\n        $this->assertInstanceOf(SizeInterface::class, $size);\n        $this->assertEquals(36, $size->width());\n        $this->assertEquals(16, $size->height());\n    }\n\n    public function testBoxSizeTtf(): void\n    {\n        $processor = new FontProcessor();\n        $size = $processor->boxSize('ABC', $this->testFont());\n        $this->assertInstanceOf(SizeInterface::class, $size);\n        $this->assertContains($size->width(), [74, 75, 76]);\n        $this->assertContains($size->height(), [19, 20, 21]);\n    }\n\n    public function testNativeFontSize(): void\n    {\n        $processor = new FontProcessor();\n        $size = $processor->nativeFontSize(new Font('5'));\n        $this->assertEquals(9.12, $size);\n    }\n\n    public function testTextBlock(): void\n    {\n        $processor = new FontProcessor();\n        $result = $processor->textBlock('test', new Font(), new Point(0, 0));\n        $this->assertInstanceOf(TextBlock::class, $result);\n    }\n\n    public function testTypographicalSize(): void\n    {\n        $processor = new FontProcessor();\n        $result = $processor->typographicalSize(new Font());\n        $this->assertEquals(8, $result);\n    }\n\n    public function testCapHeight(): void\n    {\n        $processor = new FontProcessor();\n        $result = $processor->capHeight(new Font());\n        $this->assertEquals(8, $result);\n    }\n\n    public function testLeading(): void\n    {\n        $processor = new FontProcessor();\n        $result = $processor->leading(new Font());\n        $this->assertEquals(8, $result);\n    }\n\n    public function testNativeFontSizeTtf(): void\n    {\n        $processor = new FontProcessor();\n        $size = $processor->nativeFontSize($this->testFont());\n        $this->assertEquals(42.56, $size);\n    }\n\n    public function testTextBlockTtf(): void\n    {\n        $processor = new FontProcessor();\n        $result = $processor->textBlock('test', $this->testFont(), new Point(0, 0));\n        $this->assertInstanceOf(TextBlock::class, $result);\n    }\n\n    public function testTypographicalSizeTtf(): void\n    {\n        $processor = new FontProcessor();\n        $result = $processor->typographicalSize($this->testFont());\n        $this->assertContains($result, [44, 45]);\n    }\n\n    public function testCapHeightTtf(): void\n    {\n        $processor = new FontProcessor();\n        $result = $processor->capHeight($this->testFont());\n        $this->assertContains($result, [44, 45]);\n    }\n\n    public function testLeadingTtf(): void\n    {\n        $processor = new FontProcessor();\n        $result = $processor->leading($this->testFont());\n        $this->assertContains($result, [44, 45]);\n    }\n\n    private function testFont(): Font\n    {\n        return (new Font($this->getTestResourcePath('test.ttf')))->setSize(56);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/FrameTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse GdImage;\nuse Intervention\\Image\\Drivers\\Gd\\Driver;\nuse Intervention\\Image\\Drivers\\Gd\\Frame;\nuse Intervention\\Image\\Image;\nuse Intervention\\Image\\Geometry\\Rectangle;\nuse Intervention\\Image\\Tests\\BaseTestCase;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(Frame::class)]\nfinal class FrameTest extends BaseTestCase\n{\n    protected function getTestFrame(): Frame\n    {\n        return new Frame(imagecreatetruecolor(3, 2));\n    }\n\n    public function testConstructor(): void\n    {\n        $frame = $this->getTestFrame();\n        $this->assertInstanceOf(Frame::class, $frame);\n    }\n\n    public function testGetNative(): void\n    {\n        $frame = $this->getTestFrame();\n        $this->assertInstanceOf(GdImage::class, $frame->native());\n    }\n\n    public function testSetCore(): void\n    {\n        $core1 = imagecreatetruecolor(3, 2);\n        $core2 = imagecreatetruecolor(3, 3);\n        $frame = new Frame($core1);\n        $this->assertEquals(2, $frame->size()->height());\n        $result = $frame->setNative($core2);\n        $this->assertInstanceOf(Frame::class, $result);\n        $this->assertEquals(3, $frame->size()->height());\n    }\n\n    public function testGetSize(): void\n    {\n        $frame = $this->getTestFrame();\n        $this->assertInstanceOf(Rectangle::class, $frame->size());\n    }\n\n    public function testSetGetDelay(): void\n    {\n        $frame = $this->getTestFrame();\n        $this->assertEquals(0, $frame->delay());\n\n        $result = $frame->setDelay(1.5);\n        $this->assertInstanceOf(Frame::class, $result);\n        $this->assertEquals(1.5, $frame->delay());\n    }\n\n    public function testSetGetDispose(): void\n    {\n        $frame = $this->getTestFrame();\n        $this->assertEquals(1, $frame->dispose());\n\n        $result = $frame->setDispose(3);\n        $this->assertInstanceOf(Frame::class, $result);\n        $this->assertEquals(3, $frame->dispose());\n    }\n\n    public function testSetGetOffsetLeft(): void\n    {\n        $frame = $this->getTestFrame();\n        $this->assertEquals(0, $frame->offsetLeft());\n\n        $result = $frame->setOffsetLeft(100);\n        $this->assertInstanceOf(Frame::class, $result);\n        $this->assertEquals(100, $frame->offsetLeft());\n    }\n\n    public function testSetGetOffsetTop(): void\n    {\n        $frame = $this->getTestFrame();\n        $this->assertEquals(0, $frame->offsetTop());\n\n        $result = $frame->setOffsetTop(100);\n        $this->assertInstanceOf(Frame::class, $result);\n        $this->assertEquals(100, $frame->offsetTop());\n    }\n\n    public function testSetGetOffset(): void\n    {\n        $frame = $this->getTestFrame();\n        $this->assertEquals(0, $frame->offsetTop());\n        $this->assertEquals(0, $frame->offsetLeft());\n\n        $result = $frame->setOffset(100, 200);\n        $this->assertInstanceOf(Frame::class, $result);\n        $this->assertEquals(100, $frame->offsetLeft());\n        $this->assertEquals(200, $frame->offsetTop());\n    }\n\n    public function testToImage(): void\n    {\n        $frame = $this->getTestFrame();\n        $this->assertInstanceOf(Image::class, $frame->toImage(new Driver()));\n    }\n\n    public function testDebugInfo(): void\n    {\n        $info = $this->getTestFrame()->__debugInfo();\n        $this->assertEquals(0, $info['delay']);\n        $this->assertEquals(0, $info['left']);\n        $this->assertEquals(0, $info['top']);\n        $this->assertEquals(1, $info['dispose']);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/ImageTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd;\n\nuse Intervention\\Image\\Analyzers\\WidthAnalyzer;\nuse Intervention\\Image\\Collection;\nuse Intervention\\Image\\Colors\\Hsl\\Colorspace;\nuse Intervention\\Image\\Drivers\\Gd\\Core;\nuse Intervention\\Image\\Drivers\\Gd\\Driver;\nuse Intervention\\Image\\Drivers\\Gd\\Frame;\nuse Intervention\\Image\\EncodedImage;\nuse Intervention\\Image\\Encoders\\PngEncoder;\nuse Intervention\\Image\\Exceptions\\EncoderException;\nuse Intervention\\Image\\Exceptions\\NotSupportedException;\nuse Intervention\\Image\\FileExtension;\nuse Intervention\\Image\\Image;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Interfaces\\ColorspaceInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\ResolutionInterface;\nuse Intervention\\Image\\Interfaces\\SizeInterface;\nuse Intervention\\Image\\MediaType;\nuse Intervention\\Image\\Modifiers\\GreyscaleModifier;\nuse Intervention\\Image\\Tests\\GdTestCase;\nuse Intervention\\Image\\Typography\\Font;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(Image::class)]\nfinal class ImageTest extends GdTestCase\n{\n    protected Image $image;\n\n    protected function setUp(): void\n    {\n        $this->image = new Image(\n            new Driver(),\n            new Core([\n                new Frame(imagecreatetruecolor(3, 2)),\n                new Frame(imagecreatetruecolor(3, 2)),\n            ]),\n            new Collection([\n                'test' => 'foo'\n            ]),\n        );\n    }\n\n    public function testClone(): void\n    {\n        $image = $this->readTestImage('gradient.gif');\n        $clone = clone $image;\n\n        $this->assertEquals(16, $image->width());\n        $this->assertEquals(16, $clone->width());\n        $result = $clone->crop(4, 4);\n        $this->assertEquals(16, $image->width());\n        $this->assertEquals(4, $clone->width());\n        $this->assertEquals(4, $result->width());\n\n        $this->assertEquals('ff0000', $image->pickColor(0, 0)->toHex());\n        $this->assertTransparency($image->pickColor(1, 0));\n\n        $this->assertEquals('ff0000', $clone->pickColor(0, 0)->toHex());\n        $this->assertTransparency($image->pickColor(1, 0));\n    }\n\n    public function testDriver(): void\n    {\n        $this->assertInstanceOf(Driver::class, $this->image->driver());\n    }\n\n    public function testCore(): void\n    {\n        $this->assertInstanceOf(Core::class, $this->image->core());\n    }\n\n    public function testCount(): void\n    {\n        $this->assertEquals(2, $this->image->count());\n    }\n\n    public function testIteration(): void\n    {\n        foreach ($this->image as $frame) {\n            $this->assertInstanceOf(Frame::class, $frame);\n        }\n    }\n\n    public function testIsAnimated(): void\n    {\n        $this->assertTrue($this->image->isAnimated());\n    }\n\n    public function testSetGetLoops(): void\n    {\n        $this->assertEquals(0, $this->image->loops());\n        $result = $this->image->setLoops(10);\n        $this->assertInstanceOf(ImageInterface::class, $result);\n        $this->assertEquals(10, $this->image->loops());\n    }\n\n    public function testRemoveAnimation(): void\n    {\n        $this->assertTrue($this->image->isAnimated());\n        $result = $this->image->removeAnimation();\n        $this->assertInstanceOf(ImageInterface::class, $result);\n        $this->assertFalse($this->image->isAnimated());\n    }\n\n    public function testSliceAnimation(): void\n    {\n        $this->assertEquals(2, $this->image->count());\n        $result = $this->image->sliceAnimation(0, 1);\n        $this->assertInstanceOf(ImageInterface::class, $result);\n        $this->assertEquals(1, $this->image->count());\n    }\n\n    public function testExif(): void\n    {\n        $this->assertInstanceOf(Collection::class, $this->image->exif());\n        $this->assertEquals('foo', $this->image->exif('test'));\n    }\n\n    public function testModify(): void\n    {\n        $result = $this->image->modify(new GreyscaleModifier());\n        $this->assertInstanceOf(Image::class, $result);\n    }\n\n    public function testAnalyze(): void\n    {\n        $result = $this->image->analyze(new WidthAnalyzer());\n        $this->assertEquals(3, $result);\n    }\n\n    public function testEncode(): void\n    {\n        $result = $this->image->encode(new PngEncoder());\n        $this->assertInstanceOf(EncodedImage::class, $result);\n    }\n\n    public function testAutoEncode(): void\n    {\n        $result = $this->readTestImage('blue.gif')->encode();\n        $this->assertInstanceOf(EncodedImage::class, $result);\n        $this->assertMediaType('image/gif', $result);\n    }\n\n    public function testEncodeByMediaType(): void\n    {\n        $result = $this->readTestImage('blue.gif')->encodeByMediaType();\n        $this->assertInstanceOf(EncodedImage::class, $result);\n        $this->assertMediaType('image/gif', $result);\n\n        $result = $this->readTestImage('blue.gif')->encodeByMediaType('image/png');\n        $this->assertInstanceOf(EncodedImage::class, $result);\n        $this->assertMediaType('image/png', $result);\n\n        $result = $this->readTestImage('blue.gif')->encodeByMediaType(MediaType::IMAGE_PNG);\n        $this->assertInstanceOf(EncodedImage::class, $result);\n        $this->assertMediaType('image/png', $result);\n    }\n\n    public function testEncodeByExtension(): void\n    {\n        $result = $this->readTestImage('blue.gif')->encodeByExtension();\n        $this->assertInstanceOf(EncodedImage::class, $result);\n        $this->assertMediaType('image/gif', $result);\n\n        $result = $this->readTestImage('blue.gif')->encodeByExtension('png');\n        $this->assertInstanceOf(EncodedImage::class, $result);\n        $this->assertMediaType('image/png', $result);\n\n        $result = $this->readTestImage('blue.gif')->encodeByExtension(FileExtension::PNG);\n        $this->assertInstanceOf(EncodedImage::class, $result);\n        $this->assertMediaType('image/png', $result);\n    }\n\n    public function testEncodeByPath(): void\n    {\n        $result = $this->readTestImage('blue.gif')->encodeByPath();\n        $this->assertInstanceOf(EncodedImage::class, $result);\n        $this->assertMediaType('image/gif', $result);\n\n        $result = $this->readTestImage('blue.gif')->encodeByPath('foo/bar.png');\n        $this->assertInstanceOf(EncodedImage::class, $result);\n        $this->assertMediaType('image/png', $result);\n    }\n\n    public function testSaveAsFormat(): void\n    {\n        $path = __DIR__ . '/tmp.png';\n        $result = $this->readTestImage('blue.gif')->save($path);\n        $this->assertInstanceOf(Image::class, $result);\n        $this->assertFileExists($path);\n        $this->assertMediaType('image/png', file_get_contents($path));\n        unlink($path);\n    }\n\n    public function testSaveFallback(): void\n    {\n        $path = __DIR__ . '/tmp.unknown';\n        $result = $this->readTestImage('blue.gif')->save($path);\n        $this->assertInstanceOf(Image::class, $result);\n        $this->assertFileExists($path);\n        $this->assertMediaType('image/gif', file_get_contents($path));\n        unlink($path);\n    }\n\n    public function testSaveUndeterminedPath(): void\n    {\n        $this->expectException(EncoderException::class);\n        $this->createTestImage(2, 3)->save();\n    }\n\n    public function testWidthHeightSize(): void\n    {\n        $this->assertEquals(3, $this->image->width());\n        $this->assertEquals(2, $this->image->height());\n        $this->assertInstanceOf(SizeInterface::class, $this->image->size());\n    }\n\n    public function testColorspace(): void\n    {\n        $this->assertInstanceOf(ColorspaceInterface::class, $this->image->colorspace());\n    }\n\n    public function testSetColorspace(): void\n    {\n        $this->expectException(NotSupportedException::class);\n        $this->image->setColorspace(Colorspace::class);\n    }\n\n    public function testSetGetResolution(): void\n    {\n        $resolution = $this->image->resolution();\n        $this->assertInstanceOf(ResolutionInterface::class, $resolution);\n        $this->assertEquals(96, $resolution->x());\n        $this->assertEquals(96, $resolution->y());\n        $result = $this->image->setResolution(300, 300);\n        $resolution = $this->image->resolution();\n        $this->assertInstanceOf(ImageInterface::class, $result);\n        $this->assertEquals(300, $resolution->x());\n        $this->assertEquals(300, $resolution->y());\n    }\n\n    public function testPickColor(): void\n    {\n        $this->assertInstanceOf(ColorInterface::class, $this->image->pickColor(0, 0));\n        $this->assertInstanceOf(ColorInterface::class, $this->image->pickColor(0, 0, 1));\n    }\n\n    public function testPickColors(): void\n    {\n        $result = $this->image->pickColors(0, 0);\n        $this->assertInstanceOf(Collection::class, $result);\n        $this->assertEquals(2, $result->count());\n    }\n\n    public function testProfile(): void\n    {\n        $this->expectException(NotSupportedException::class);\n        $this->image->profile();\n    }\n\n    public function testReduceColors(): void\n    {\n        $image = $this->readTestImage();\n        $result = $image->reduceColors(8);\n        $this->assertInstanceOf(ImageInterface::class, $result);\n    }\n\n    public function testSharpen(): void\n    {\n        $this->assertInstanceOf(Image::class, $this->image->sharpen(12));\n    }\n\n    public function testText(): void\n    {\n        $this->assertInstanceOf(Image::class, $this->image->text('test', 0, 0, new Font()));\n    }\n\n    public function testBlendTransparencyDefault(): void\n    {\n        $image = $this->readTestImage('gradient.gif');\n        $this->assertColor(0, 0, 0, 0, $image->pickColor(1, 0));\n        $result = $image->blendTransparency();\n        $this->assertColor(255, 255, 255, 255, $image->pickColor(1, 0));\n        $this->assertColor(255, 255, 255, 255, $result->pickColor(1, 0));\n    }\n\n    public function testBlendTransparencyArgument(): void\n    {\n        $image = $this->readTestImage('gradient.gif');\n        $this->assertColor(0, 0, 0, 0, $image->pickColor(1, 0));\n        $result = $image->blendTransparency('ff5500');\n        $this->assertColor(255, 85, 0, 255, $image->pickColor(1, 0));\n        $this->assertColor(255, 85, 0, 255, $result->pickColor(1, 0));\n    }\n\n    public function testBlendTransparencyIgnoreTransparencyInBlendingColor(): void\n    {\n        $image = $this->readTestImage('gradient.gif');\n        $this->assertColor(0, 0, 0, 0, $image->pickColor(1, 0));\n        $result = $image->blendTransparency('ff550055');\n        $this->assertColor(255, 85, 0, 255, $image->pickColor(1, 0));\n        $this->assertColor(255, 85, 0, 255, $result->pickColor(1, 0));\n    }\n\n    public function testToJpeg(): void\n    {\n        $this->assertMediaType('image/jpeg', $this->image->toJpeg());\n        $this->assertMediaType('image/jpeg', $this->image->toJpg());\n    }\n\n    public function testToJpeg2000(): void\n    {\n        $this->expectException(NotSupportedException::class);\n        $this->image->toJpeg2000();\n    }\n\n    public function testToPng(): void\n    {\n        $this->assertMediaType('image/png', $this->image->toPng());\n    }\n\n    public function testToGif(): void\n    {\n        $this->assertMediaType('image/gif', $this->image->toGif());\n    }\n\n    public function testToWebp(): void\n    {\n        $this->assertMediaType('image/webp', $this->image->toWebp());\n    }\n\n    public function testToBitmap(): void\n    {\n        $this->assertMediaTypeBitmap($this->image->toBitmap());\n        $this->assertMediaTypeBitmap($this->image->toBmp());\n    }\n\n    public function testToAvif(): void\n    {\n        $this->assertMediaType('image/avif', $this->image->toAvif());\n    }\n\n    public function testToTiff(): void\n    {\n        $this->expectException(NotSupportedException::class);\n        $this->image->toTiff();\n    }\n\n    public function testToHeic(): void\n    {\n        $this->expectException(NotSupportedException::class);\n        $this->image->toHeic();\n    }\n\n    public function testInvert(): void\n    {\n        $image = $this->readTestImage('trim.png');\n        $this->assertEquals('00aef0', $image->pickColor(0, 0)->toHex());\n        $this->assertEquals('ffa601', $image->pickColor(25, 25)->toHex());\n        $result = $image->invert();\n        $this->assertInstanceOf(ImageInterface::class, $result);\n        $this->assertEquals('ff510f', $image->pickColor(0, 0)->toHex());\n        $this->assertEquals('0059fe', $image->pickColor(25, 25)->toHex());\n    }\n\n    public function testPixelate(): void\n    {\n        $image = $this->readTestImage('trim.png');\n        $this->assertEquals('00aef0', $image->pickColor(0, 0)->toHex());\n        $this->assertEquals('00aef0', $image->pickColor(14, 14)->toHex());\n        $result = $image->pixelate(10);\n        $this->assertInstanceOf(ImageInterface::class, $result);\n        $this->assertEquals('00aef0', $image->pickColor(0, 0)->toHex());\n        $this->assertEquals('6aaa8b', $image->pickColor(14, 14)->toHex());\n    }\n\n    public function testGreyscale(): void\n    {\n        $image = $this->readTestImage('trim.png');\n        $this->assertFalse($image->pickColor(0, 0)->isGreyscale());\n        $result = $image->greyscale();\n        $this->assertInstanceOf(ImageInterface::class, $result);\n        $this->assertTrue($image->pickColor(0, 0)->isGreyscale());\n    }\n\n    public function testBrightness(): void\n    {\n        $image = $this->readTestImage('trim.png');\n        $this->assertEquals('00aef0', $image->pickColor(14, 14)->toHex());\n        $result = $image->brightness(30);\n        $this->assertInstanceOf(ImageInterface::class, $result);\n        $this->assertEquals('4cfaff', $image->pickColor(14, 14)->toHex());\n    }\n\n    public function testDebugInfo(): void\n    {\n        $info = $this->readTestImage('trim.png')->__debugInfo();\n        $this->assertArrayHasKey('width', $info);\n        $this->assertArrayHasKey('height', $info);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/Modifiers/BlurModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\BlurModifier;\nuse Intervention\\Image\\Tests\\GdTestCase;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\BlurModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Gd\\Modifiers\\BlurModifier::class)]\nfinal class BlurModifierTest extends GdTestCase\n{\n    public function testColorChange(): void\n    {\n        $image = $this->readTestImage('trim.png');\n        $this->assertEquals('00aef0', $image->pickColor(14, 14)->toHex());\n        $image->modify(new BlurModifier(30));\n        $this->assertEquals('4fa68d', $image->pickColor(14, 14)->toHex());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/Modifiers/BrightnessModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\BrightnessModifier;\nuse Intervention\\Image\\Tests\\GdTestCase;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\BrightnessModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Gd\\Modifiers\\BrightnessModifier::class)]\nfinal class BrightnessModifierTest extends GdTestCase\n{\n    public function testApply(): void\n    {\n        $image = $this->readTestImage('trim.png');\n        $this->assertEquals('00aef0', $image->pickColor(14, 14)->toHex());\n        $image->modify(new BrightnessModifier(30));\n        $this->assertEquals('4cfaff', $image->pickColor(14, 14)->toHex());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/Modifiers/ColorizeModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\ColorizeModifier;\nuse Intervention\\Image\\Tests\\GdTestCase;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\ColorizeModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Gd\\Modifiers\\ColorizeModifier::class)]\nfinal class ColorizeModifierTest extends GdTestCase\n{\n    public function testModify(): void\n    {\n        $image = $this->readTestImage('tile.png');\n        $image = $image->modify(new ColorizeModifier(100, -100, -100));\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(5, 5));\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(15, 15));\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/Modifiers/ContainModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\ContainModifier;\nuse Intervention\\Image\\Tests\\GdTestCase;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\ContainModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Gd\\Modifiers\\ContainModifier::class)]\nfinal class ContainModifierTest extends GdTestCase\n{\n    public function testModify(): void\n    {\n        $image = $this->readTestImage('blocks.png');\n        $this->assertEquals(640, $image->width());\n        $this->assertEquals(480, $image->height());\n        $image->modify(new ContainModifier(200, 100, 'ff0'));\n        $this->assertEquals(200, $image->width());\n        $this->assertEquals(100, $image->height());\n        $this->assertColor(255, 255, 0, 255, $image->pickColor(0, 0));\n        $this->assertTransparency($image->pickColor(140, 10));\n        $this->assertColor(255, 255, 0, 255, $image->pickColor(175, 10));\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/Modifiers/ContrastModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\ContrastModifier;\nuse Intervention\\Image\\Tests\\GdTestCase;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\ContrastModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Gd\\Modifiers\\ContrastModifier::class)]\nfinal class ContrastModifierTest extends GdTestCase\n{\n    public function testApply(): void\n    {\n        $image = $this->readTestImage('trim.png');\n        $this->assertEquals('00aef0', $image->pickColor(14, 14)->toHex());\n        $image->modify(new ContrastModifier(30));\n        $this->assertEquals('00ceff', $image->pickColor(14, 14)->toHex());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/Modifiers/CoverDownModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd\\Modifiers;\n\nuse Intervention\\Image\\Drivers\\Gd\\Modifiers\\CoverDownModifier;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Tests\\GdTestCase;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\CoverModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Gd\\Modifiers\\CoverModifier::class)]\nfinal class CoverDownModifierTest extends GdTestCase\n{\n    public function testModify(): void\n    {\n        $image = $this->readTestImage('blocks.png');\n        $this->assertEquals(640, $image->width());\n        $this->assertEquals(480, $image->height());\n        $image->modify(new CoverDownModifier(100, 100, 'center'));\n        $this->assertEquals(100, $image->width());\n        $this->assertEquals(100, $image->height());\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(90, 90));\n        $this->assertColor(0, 255, 0, 255, $image->pickColor(65, 70));\n        $this->assertColor(0, 0, 255, 255, $image->pickColor(70, 52));\n        $this->assertTransparency($image->pickColor(90, 30));\n    }\n\n    public function testModifyOddSize(): void\n    {\n        $image = $this->createTestImage(375, 250);\n        $image->modify(new CoverDownModifier(240, 90, 'center'));\n        $this->assertEquals(240, $image->width());\n        $this->assertEquals(90, $image->height());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/Modifiers/CoverModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\CoverModifier;\nuse Intervention\\Image\\Tests\\GdTestCase;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\CoverModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Gd\\Modifiers\\CoverModifier::class)]\nfinal class CoverModifierTest extends GdTestCase\n{\n    public function testModify(): void\n    {\n        $image = $this->readTestImage('blocks.png');\n        $this->assertEquals(640, $image->width());\n        $this->assertEquals(480, $image->height());\n        $image->modify(new CoverModifier(100, 100, 'center'));\n        $this->assertEquals(100, $image->width());\n        $this->assertEquals(100, $image->height());\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(90, 90));\n        $this->assertColor(0, 255, 0, 255, $image->pickColor(65, 70));\n        $this->assertColor(0, 0, 255, 255, $image->pickColor(70, 52));\n        $this->assertTransparency($image->pickColor(90, 30));\n    }\n\n    public function testModifyOddSize(): void\n    {\n        $image = $this->createTestImage(375, 250);\n        $image->modify(new CoverModifier(240, 90, 'center'));\n        $this->assertEquals(240, $image->width());\n        $this->assertEquals(90, $image->height());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/Modifiers/CropModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\CropModifier;\nuse Intervention\\Image\\Tests\\GdTestCase;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\CropModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Gd\\Modifiers\\CropModifier::class)]\nfinal class CropModifierTest extends GdTestCase\n{\n    public function testModify(): void\n    {\n        $image = $this->readTestImage('blocks.png');\n        $image = $image->modify(new CropModifier(200, 200, 0, 0, 'ffffff', 'bottom-right'));\n        $this->assertEquals(200, $image->width());\n        $this->assertEquals(200, $image->height());\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(5, 5));\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(100, 100));\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(190, 190));\n    }\n\n    public function testModifyExtend(): void\n    {\n        $image = $this->readTestImage('blocks.png');\n        $image = $image->modify(new CropModifier(800, 100, -10, -10, 'ff0000', 'top-left'));\n        $this->assertEquals(800, $image->width());\n        $this->assertEquals(100, $image->height());\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(9, 9));\n        $this->assertColor(0, 0, 255, 255, $image->pickColor(16, 16));\n        $this->assertColor(0, 0, 255, 255, $image->pickColor(445, 16));\n        $this->assertTransparency($image->pickColor(460, 16));\n    }\n\n    public function testModifySinglePixel(): void\n    {\n        $image = $this->createTestImage(1, 1);\n        $this->assertEquals(1, $image->width());\n        $this->assertEquals(1, $image->height());\n        $image->modify(new CropModifier(3, 3, 0, 0, 'ff0', 'center'));\n        $this->assertEquals(3, $image->width());\n        $this->assertEquals(3, $image->height());\n        $this->assertColor(255, 255, 0, 255, $image->pickColor(0, 0));\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(1, 1));\n        $this->assertColor(255, 255, 0, 255, $image->pickColor(2, 2));\n    }\n\n    public function testModifyKeepsResolution(): void\n    {\n        $image = $this->readTestImage('300dpi.png');\n        $this->assertEquals(300, round($image->resolution()->perInch()->x()));\n        $image = $image->modify(new CropModifier(800, 100, -10, -10, 'ff0000'));\n        $this->assertEquals(300, round($image->resolution()->perInch()->x()));\n    }\n\n    public function testHalfTransparent(): void\n    {\n        $image = $this->createTestImage(16, 16);\n        $image->modify(new CropModifier(32, 32, 0, 0, '00f5', 'center'));\n        $this->assertEquals(32, $image->width());\n        $this->assertEquals(32, $image->height());\n        $this->assertColor(0, 0, 255, 85, $image->pickColor(5, 5));\n        $this->assertColor(0, 0, 255, 85, $image->pickColor(16, 5));\n        $this->assertColor(0, 0, 255, 85, $image->pickColor(30, 5));\n        $this->assertColor(0, 0, 255, 85, $image->pickColor(5, 16));\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(16, 16));\n        $this->assertColor(0, 0, 255, 85, $image->pickColor(30, 16));\n        $this->assertColor(0, 0, 255, 85, $image->pickColor(5, 30));\n        $this->assertColor(0, 0, 255, 85, $image->pickColor(16, 30));\n        $this->assertColor(0, 0, 255, 85, $image->pickColor(30, 30));\n    }\n\n    public function testMergeTransparentBackgrounds(): void\n    {\n        $image = $this->createTestImage(1, 1)->fill('f00');\n        $this->assertEquals(1, $image->width());\n        $this->assertEquals(1, $image->height());\n        $image->modify(new CropModifier(3, 3, 0, 0, '00f7', 'center'));\n        $this->assertEquals(3, $image->width());\n        $this->assertEquals(3, $image->height());\n        $this->assertColor(0, 0, 255, 119, $image->pickColor(0, 0));\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(1, 1));\n        $this->assertColor(0, 0, 255, 119, $image->pickColor(2, 2));\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/Modifiers/DrawBezierModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\DrawBezierModifier;\nuse Intervention\\Image\\Geometry\\Point;\nuse Intervention\\Image\\Geometry\\Bezier;\nuse Intervention\\Image\\Tests\\GdTestCase;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\DrawPixelModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Gd\\Modifiers\\DrawPixelModifier::class)]\nfinal class DrawBezierModifierTest extends GdTestCase\n{\n    public function testApply(): void\n    {\n        $image = $this->readTestImage('trim.png');\n        $this->assertEquals('00aef0', $image->pickColor(14, 14)->toHex());\n        $drawable = new Bezier([\n            new Point(0, 0),\n            new Point(15, 0),\n            new Point(15, 15),\n            new Point(0, 15)\n        ]);\n        $drawable->setBackgroundColor('b53717');\n        $image->modify(new DrawBezierModifier($drawable));\n        $this->assertEquals('b53717', $image->pickColor(5, 5)->toHex());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/Modifiers/DrawEllipseModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\DrawEllipseModifier;\nuse Intervention\\Image\\Geometry\\Ellipse;\nuse Intervention\\Image\\Geometry\\Point;\nuse Intervention\\Image\\Tests\\GdTestCase;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\DrawEllipseModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Gd\\Modifiers\\DrawEllipseModifier::class)]\nfinal class DrawEllipseModifierTest extends GdTestCase\n{\n    public function testApply(): void\n    {\n        $image = $this->readTestImage('trim.png');\n        $this->assertEquals('00aef0', $image->pickColor(14, 14)->toHex());\n        $drawable = new Ellipse(10, 10, new Point(14, 14));\n        $drawable->setBackgroundColor('b53717');\n        $image->modify(new DrawEllipseModifier($drawable));\n        $this->assertEquals('b53717', $image->pickColor(14, 14)->toHex());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/Modifiers/DrawLineModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\DrawLineModifier;\nuse Intervention\\Image\\Geometry\\Line;\nuse Intervention\\Image\\Geometry\\Point;\nuse Intervention\\Image\\Tests\\GdTestCase;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\DrawLineModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Gd\\Modifiers\\DrawLineModifier::class)]\nfinal class DrawLineModifierTest extends GdTestCase\n{\n    public function testApply(): void\n    {\n        $image = $this->readTestImage('trim.png');\n        $this->assertEquals('00aef0', $image->pickColor(14, 14)->toHex());\n        $line = new Line(new Point(0, 0), new Point(10, 0), 4);\n        $line->setBackgroundColor('b53517');\n        $image->modify(new DrawLineModifier($line));\n        $this->assertEquals('b53517', $image->pickColor(0, 0)->toHex());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/Modifiers/DrawPixelModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\DrawPixelModifier;\nuse Intervention\\Image\\Geometry\\Point;\nuse Intervention\\Image\\Tests\\GdTestCase;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\DrawPixelModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Gd\\Modifiers\\DrawPixelModifier::class)]\nfinal class DrawPixelModifierTest extends GdTestCase\n{\n    public function testApply(): void\n    {\n        $image = $this->readTestImage('trim.png');\n        $this->assertEquals('00aef0', $image->pickColor(14, 14)->toHex());\n        $image->modify(new DrawPixelModifier(new Point(14, 14), 'ffffff'));\n        $this->assertEquals('ffffff', $image->pickColor(14, 14)->toHex());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/Modifiers/DrawPolygonModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\DrawPolygonModifier;\nuse Intervention\\Image\\Geometry\\Point;\nuse Intervention\\Image\\Geometry\\Polygon;\nuse Intervention\\Image\\Tests\\GdTestCase;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\DrawPixelModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Gd\\Modifiers\\DrawPixelModifier::class)]\nfinal class DrawPolygonModifierTest extends GdTestCase\n{\n    public function testApply(): void\n    {\n        $image = $this->readTestImage('trim.png');\n        $this->assertEquals('00aef0', $image->pickColor(14, 14)->toHex());\n        $drawable = new Polygon([new Point(0, 0), new Point(15, 15), new Point(20, 20)]);\n        $drawable->setBackgroundColor('b53717');\n        $image->modify(new DrawPolygonModifier($drawable));\n        $this->assertEquals('b53717', $image->pickColor(14, 14)->toHex());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/Modifiers/DrawRectangleModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\DrawRectangleModifier;\nuse Intervention\\Image\\Geometry\\Point;\nuse Intervention\\Image\\Geometry\\Rectangle;\nuse Intervention\\Image\\Tests\\GdTestCase;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\DrawRectangleModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Gd\\Modifiers\\DrawRectangleModifier::class)]\nfinal class DrawRectangleModifierTest extends GdTestCase\n{\n    public function testApply(): void\n    {\n        $image = $this->readTestImage('trim.png');\n        $this->assertEquals('00aef0', $image->pickColor(14, 14)->toHex());\n        $rectangle = new Rectangle(300, 200, new Point(14, 14));\n        $rectangle->setBackgroundColor('ffffff');\n        $image->modify(new DrawRectangleModifier($rectangle));\n        $this->assertEquals('ffffff', $image->pickColor(14, 14)->toHex());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/Modifiers/FillModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Colors\\Rgb\\Color;\nuse Intervention\\Image\\Modifiers\\FillModifier;\nuse Intervention\\Image\\Geometry\\Point;\nuse Intervention\\Image\\Tests\\GdTestCase;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\FillModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Gd\\Modifiers\\FillModifier::class)]\nfinal class FillModifierTest extends GdTestCase\n{\n    public function testFloodFillColor(): void\n    {\n        $image = $this->readTestImage('blocks.png');\n        $this->assertEquals('0000ff', $image->pickColor(420, 270)->toHex());\n        $this->assertEquals('ff0000', $image->pickColor(540, 400)->toHex());\n        $image->modify(new FillModifier(new Color(204, 204, 204), new Point(540, 400)));\n        $this->assertEquals('0000ff', $image->pickColor(420, 270)->toHex());\n        $this->assertEquals('cccccc', $image->pickColor(540, 400)->toHex());\n    }\n\n    public function testFillAllColor(): void\n    {\n        $image = $this->readTestImage('blocks.png');\n        $this->assertEquals('0000ff', $image->pickColor(420, 270)->toHex());\n        $this->assertEquals('ff0000', $image->pickColor(540, 400)->toHex());\n        $image->modify(new FillModifier(new Color(204, 204, 204)));\n        $this->assertEquals('cccccc', $image->pickColor(420, 270)->toHex());\n        $this->assertEquals('cccccc', $image->pickColor(540, 400)->toHex());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/Modifiers/FlipFlopModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\FlipModifier;\nuse Intervention\\Image\\Modifiers\\FlopModifier;\nuse Intervention\\Image\\Tests\\GdTestCase;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\FlipModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Gd\\Modifiers\\FlipModifier::class)]\nfinal class FlipFlopModifierTest extends GdTestCase\n{\n    public function testFlipImage(): void\n    {\n        $image = $this->readTestImage('tile.png');\n        $this->assertEquals('b4e000', $image->pickColor(0, 0)->toHex());\n        $image->modify(new FlipModifier());\n        $this->assertTransparency($image->pickColor(0, 0));\n    }\n\n    public function testFlopImage(): void\n    {\n        $image = $this->readTestImage('tile.png');\n        $this->assertEquals('b4e000', $image->pickColor(0, 0)->toHex());\n        $image->modify(new FlopModifier());\n        $this->assertTransparency($image->pickColor(0, 0));\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/Modifiers/GammaModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\GammaModifier;\nuse Intervention\\Image\\Tests\\GdTestCase;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\GammaModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Gd\\Modifiers\\GammaModifier::class)]\nfinal class GammaModifierTest extends GdTestCase\n{\n    public function testModifier(): void\n    {\n        $image = $this->readTestImage('trim.png');\n        $this->assertEquals('00aef0', $image->pickColor(0, 0)->toHex());\n        $image->modify(new GammaModifier(2.1));\n        $this->assertEquals('00d5f8', $image->pickColor(0, 0)->toHex());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/Modifiers/GreyscaleModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\GreyscaleModifier;\nuse Intervention\\Image\\Tests\\GdTestCase;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\GreyscaleModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Gd\\Modifiers\\GreyscaleModifier::class)]\nfinal class GreyscaleModifierTest extends GdTestCase\n{\n    public function testColorChange(): void\n    {\n        $image = $this->readTestImage('trim.png');\n        $this->assertFalse($image->pickColor(0, 0)->isGreyscale());\n        $image->modify(new GreyscaleModifier());\n        $this->assertTrue($image->pickColor(0, 0)->isGreyscale());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/Modifiers/InvertModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\InvertModifier;\nuse Intervention\\Image\\Tests\\GdTestCase;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\InvertModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Gd\\Modifiers\\InvertModifier::class)]\nfinal class InvertModifierTest extends GdTestCase\n{\n    public function testApply(): void\n    {\n        $image = $this->readTestImage('trim.png');\n        $this->assertEquals('00aef0', $image->pickColor(0, 0)->toHex());\n        $this->assertEquals('ffa601', $image->pickColor(25, 25)->toHex());\n        $image->modify(new InvertModifier());\n        $this->assertEquals('ff510f', $image->pickColor(0, 0)->toHex());\n        $this->assertEquals('0059fe', $image->pickColor(25, 25)->toHex());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/Modifiers/PadModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\PadModifier;\nuse Intervention\\Image\\Tests\\GdTestCase;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\PadModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Gd\\Modifiers\\PadModifier::class)]\nfinal class PadModifierTest extends GdTestCase\n{\n    public function testModify(): void\n    {\n        $image = $this->readTestImage('blue.gif');\n        $this->assertEquals(16, $image->width());\n        $this->assertEquals(16, $image->height());\n        $image->modify(new PadModifier(30, 20, 'f00'));\n        $this->assertEquals(30, $image->width());\n        $this->assertEquals(20, $image->height());\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(0, 0));\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(0, 19));\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(29, 0));\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(29, 19));\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(6, 2));\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(7, 1));\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(6, 17));\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(7, 18));\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(23, 1));\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(23, 2));\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(23, 17));\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(23, 18));\n        $this->assertColor(100, 100, 255, 255, $image->pickColor(7, 2));\n        $this->assertColor(100, 100, 255, 255, $image->pickColor(22, 2));\n        $this->assertColor(100, 100, 255, 255, $image->pickColor(7, 17));\n        $this->assertColor(100, 100, 255, 255, $image->pickColor(22, 17));\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/Modifiers/PixelateModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\PixelateModifier;\nuse Intervention\\Image\\Tests\\GdTestCase;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\PixelateModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Gd\\Modifiers\\PixelateModifier::class)]\nfinal class PixelateModifierTest extends GdTestCase\n{\n    public function testModify(): void\n    {\n        $image = $this->readTestImage('trim.png');\n        $this->assertEquals('00aef0', $image->pickColor(0, 0)->toHex());\n        $this->assertEquals('00aef0', $image->pickColor(14, 14)->toHex());\n        $image->modify(new PixelateModifier(10));\n        $this->assertEquals('00aef0', $image->pickColor(0, 0)->toHex());\n        $this->assertEquals('6aaa8b', $image->pickColor(14, 14)->toHex());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/Modifiers/PlaceModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\PlaceModifier;\nuse Intervention\\Image\\Tests\\GdTestCase;\nuse Intervention\\Image\\Drivers\\Gd\\Modifiers\\PlaceModifier as PlaceModifierGd;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(PlaceModifier::class)]\n#[CoversClass(PlaceModifierGd::class)]\nfinal class PlaceModifierTest extends GdTestCase\n{\n    public function testColorChange(): void\n    {\n        $image = $this->readTestImage('test.jpg');\n        $this->assertEquals('febc44', $image->pickColor(300, 25)->toHex());\n        $image->modify(new PlaceModifier($this->getTestResourcePath('circle.png'), 'top-right', 0, 0));\n        $this->assertEquals('32250d', $image->pickColor(300, 25)->toHex());\n    }\n\n    public function testColorChangeOpacityPng(): void\n    {\n        $image = $this->readTestImage('test.jpg');\n        $this->assertEquals('febc44', $image->pickColor(300, 25)->toHex());\n        $image->modify(new PlaceModifier($this->getTestResourcePath('circle.png'), 'top-right', 0, 0, 50));\n        $this->assertColor(152, 112, 40, 255, $image->pickColor(300, 25), tolerance: 1);\n        $this->assertColor(255, 202, 107, 255, $image->pickColor(274, 5), tolerance: 1);\n    }\n\n    public function testColorChangeOpacityJpeg(): void\n    {\n        $image = $this->createTestImage(16, 16)->fill('0000ff');\n        $this->assertEquals('0000ff', $image->pickColor(10, 10)->toHex());\n        $image->modify(new PlaceModifier($this->getTestResourcePath('exif.jpg'), opacity: 50));\n        $this->assertColor(127, 83, 127, 255, $image->pickColor(10, 10), tolerance: 1);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/Modifiers/QuantizeColorsModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Exceptions\\InputException;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Modifiers\\QuantizeColorsModifier;\nuse Intervention\\Image\\Tests\\GdTestCase;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\QuantizeColorsModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Gd\\Modifiers\\QuantizeColorsModifier::class)]\nfinal class QuantizeColorsModifierTest extends GdTestCase\n{\n    public function testColorChange(): void\n    {\n        $image = $this->readTestImage('gradient.bmp');\n        $this->assertColorCount(15, $image);\n        $image->modify(new QuantizeColorsModifier(4));\n        $this->assertColorCount(4, $image);\n    }\n\n    public function testNoColorReduction(): void\n    {\n        $image = $this->readTestImage('gradient.bmp');\n        $this->assertColorCount(15, $image);\n        $image->modify(new QuantizeColorsModifier(150));\n        $this->assertColorCount(15, $image);\n    }\n\n    public function testInvalidColorInput(): void\n    {\n        $image = $this->readTestImage('gradient.bmp');\n        $this->expectException(InputException::class);\n        $image->modify(new QuantizeColorsModifier(0));\n    }\n\n    private function assertColorCount(int $count, ImageInterface $image): void\n    {\n        $colors = [];\n        $width = $image->width();\n        $height = $image->height();\n        for ($x = 0; $x < $width; $x++) {\n            for ($y = 0; $y < $height; $y++) {\n                $rgb = imagecolorat($image->core()->native(), $x, $y);\n                $color = imagecolorsforindex($image->core()->native(), $rgb);\n                $color = implode('-', $color);\n                $colors[$color] = $color;\n            }\n        }\n\n        $this->assertEquals(count($colors), $count);\n    }\n\n    public function testVerifyColorValueAfterQuantization(): void\n    {\n        $image = $this->createTestImage(3, 2)->fill('f00');\n        $image->modify(new QuantizeColorsModifier(1));\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(1, 1), 4);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/Modifiers/RemoveAnimationModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Exceptions\\InputException;\nuse Intervention\\Image\\Modifiers\\RemoveAnimationModifier;\nuse Intervention\\Image\\Tests\\GdTestCase;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\RemoveAnimationModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Gd\\Modifiers\\RemoveAnimationModifier::class)]\nfinal class RemoveAnimationModifierTest extends GdTestCase\n{\n    public function testApply(): void\n    {\n        $image = $this->readTestImage('animation.gif');\n        $this->assertEquals(8, count($image));\n        $result = $image->modify(new RemoveAnimationModifier(2));\n        $this->assertEquals(1, count($image));\n        $this->assertEquals(1, count($result));\n    }\n\n    public function testApplyPercent(): void\n    {\n        $image = $this->readTestImage('animation.gif');\n        $this->assertEquals(8, count($image));\n        $result = $image->modify(new RemoveAnimationModifier('20%'));\n        $this->assertEquals(1, count($image));\n        $this->assertEquals(1, count($result));\n    }\n\n    public function testApplyNonAnimated(): void\n    {\n        $image = $this->readTestImage('test.jpg');\n        $this->assertEquals(1, count($image));\n        $result = $image->modify(new RemoveAnimationModifier());\n        $this->assertEquals(1, count($image));\n        $this->assertEquals(1, count($result));\n    }\n\n    public function testApplyInvalid(): void\n    {\n        $image = $this->readTestImage('animation.gif');\n        $this->expectException(InputException::class);\n        $image->modify(new RemoveAnimationModifier('test'));\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/Modifiers/ResizeCanvasModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\ResizeCanvasModifier;\nuse Intervention\\Image\\Tests\\GdTestCase;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\ResizeCanvasModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Gd\\Modifiers\\ResizeCanvasModifier::class)]\nfinal class ResizeCanvasModifierTest extends GdTestCase\n{\n    public function testModify(): void\n    {\n        $image = $this->createTestImage(1, 1);\n        $this->assertEquals(1, $image->width());\n        $this->assertEquals(1, $image->height());\n        $image->modify(new ResizeCanvasModifier(3, 3, 'ff0', 'center'));\n        $this->assertEquals(3, $image->width());\n        $this->assertEquals(3, $image->height());\n        $this->assertColor(255, 255, 0, 255, $image->pickColor(0, 0));\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(1, 1));\n        $this->assertColor(255, 255, 0, 255, $image->pickColor(2, 2));\n    }\n\n    public function testModifyWithTransparency(): void\n    {\n        $image = $this->readTestImage('tile.png');\n        $this->assertEquals(16, $image->width());\n        $this->assertEquals(16, $image->height());\n        $image->modify(new ResizeCanvasModifier(18, 18, 'ff0', 'center'));\n        $this->assertEquals(18, $image->width());\n        $this->assertEquals(18, $image->height());\n        $this->assertColor(255, 255, 0, 255, $image->pickColor(0, 0));\n        $this->assertColor(180, 224, 0, 255, $image->pickColor(1, 1));\n        $this->assertColor(180, 224, 0, 255, $image->pickColor(2, 2));\n        $this->assertColor(255, 255, 0, 255, $image->pickColor(17, 17));\n        $this->assertTransparency($image->pickColor(12, 1));\n\n        $image = $this->createTestImage(16, 16);\n        $image->modify(new ResizeCanvasModifier(32, 32, '00f5', 'center'));\n        $this->assertEquals(32, $image->width());\n        $this->assertEquals(32, $image->height());\n        $this->assertColor(0, 0, 255, 85, $image->pickColor(5, 5));\n        $this->assertColor(0, 0, 255, 85, $image->pickColor(16, 5));\n        $this->assertColor(0, 0, 255, 85, $image->pickColor(30, 5));\n        $this->assertColor(0, 0, 255, 85, $image->pickColor(5, 16));\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(16, 16));\n        $this->assertColor(0, 0, 255, 85, $image->pickColor(30, 16));\n        $this->assertColor(0, 0, 255, 85, $image->pickColor(5, 30));\n        $this->assertColor(0, 0, 255, 85, $image->pickColor(16, 30));\n        $this->assertColor(0, 0, 255, 85, $image->pickColor(30, 30));\n    }\n\n    public function testModifyEdge(): void\n    {\n        $image = $this->createTestImage(1, 1);\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(0, 0));\n        $image->modify(new ResizeCanvasModifier(null, 2, 'ff0', 'bottom'));\n        $this->assertEquals(1, $image->width());\n        $this->assertEquals(2, $image->height());\n        $this->assertColor(255, 255, 0, 255, $image->pickColor(0, 0));\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(0, 1));\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/Modifiers/ResizeCanvasRelativeModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\ResizeCanvasRelativeModifier;\nuse Intervention\\Image\\Tests\\GdTestCase;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\ResizeCanvasRelativeModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Gd\\Modifiers\\ResizeCanvasRelativeModifier::class)]\nfinal class ResizeCanvasRelativeModifierTest extends GdTestCase\n{\n    public function testModify(): void\n    {\n        $image = $this->createTestImage(1, 1);\n        $this->assertEquals(1, $image->width());\n        $this->assertEquals(1, $image->height());\n        $image->modify(new ResizeCanvasRelativeModifier(2, 2, 'ff0', 'center'));\n        $this->assertEquals(3, $image->width());\n        $this->assertEquals(3, $image->height());\n        $this->assertColor(255, 255, 0, 255, $image->pickColor(0, 0));\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(1, 1));\n        $this->assertColor(255, 255, 0, 255, $image->pickColor(2, 2));\n    }\n\n    public function testModifyWithTransparency(): void\n    {\n        $image = $this->readTestImage('tile.png');\n        $this->assertEquals(16, $image->width());\n        $this->assertEquals(16, $image->height());\n        $image->modify(new ResizeCanvasRelativeModifier(2, 2, 'ff0', 'center'));\n        $this->assertEquals(18, $image->width());\n        $this->assertEquals(18, $image->height());\n        $this->assertColor(255, 255, 0, 255, $image->pickColor(0, 0));\n        $this->assertColor(180, 224, 0, 255, $image->pickColor(1, 1));\n        $this->assertColor(180, 224, 0, 255, $image->pickColor(2, 2));\n        $this->assertColor(255, 255, 0, 255, $image->pickColor(17, 17));\n        $this->assertTransparency($image->pickColor(12, 1));\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/Modifiers/ResizeModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\ResizeModifier;\nuse Intervention\\Image\\Tests\\GdTestCase;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\ResizeModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Gd\\Modifiers\\ResizeModifier::class)]\nfinal class ResizeModifierTest extends GdTestCase\n{\n    public function testModify(): void\n    {\n        $image = $this->readTestImage('blocks.png');\n        $this->assertEquals(640, $image->width());\n        $this->assertEquals(480, $image->height());\n        $image->modify(new ResizeModifier(200, 100));\n        $this->assertEquals(200, $image->width());\n        $this->assertEquals(100, $image->height());\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(150, 70));\n        $this->assertColor(0, 255, 0, 255, $image->pickColor(125, 70));\n        $this->assertColor(0, 0, 255, 255, $image->pickColor(130, 54));\n        $this->assertTransparency($image->pickColor(170, 30));\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/Modifiers/ResolutionModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\ResolutionModifier;\nuse Intervention\\Image\\Tests\\GdTestCase;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\ResolutionModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Gd\\Modifiers\\ResolutionModifier::class)]\nfinal class ResolutionModifierTest extends GdTestCase\n{\n    public function testResolutionChange(): void\n    {\n        $image = $this->readTestImage('test.jpg');\n        $this->assertEquals(72.0, $image->resolution()->x());\n        $this->assertEquals(72.0, $image->resolution()->y());\n        $image->modify(new ResolutionModifier(1, 2));\n        $this->assertEquals(1.0, $image->resolution()->x());\n        $this->assertEquals(2.0, $image->resolution()->y());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/Modifiers/RotateModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\RotateModifier;\nuse Intervention\\Image\\Tests\\GdTestCase;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\RotateModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Gd\\Modifiers\\RotateModifier::class)]\nfinal class RotateModifierTest extends GdTestCase\n{\n    public function testRotate(): void\n    {\n        $image = $this->readTestImage('test.jpg');\n        $this->assertEquals(320, $image->width());\n        $this->assertEquals(240, $image->height());\n        $image->modify(new RotateModifier(90, 'fff'));\n        $this->assertEquals(240, $image->width());\n        $this->assertEquals(320, $image->height());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/Modifiers/SharpenModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\SharpenModifier;\nuse Intervention\\Image\\Tests\\GdTestCase;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\SharpenModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Gd\\Modifiers\\SharpenModifier::class)]\nfinal class SharpenModifierTest extends GdTestCase\n{\n    public function testModify(): void\n    {\n        $image = $this->readTestImage('trim.png');\n        $this->assertEquals('60ab96', $image->pickColor(15, 14)->toHex());\n        $image->modify(new SharpenModifier(10));\n        $this->assertEquals('4daba7', $image->pickColor(15, 14)->toHex());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/Modifiers/TextModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd\\Modifiers;\n\nuse Intervention\\Image\\Drivers\\Gd\\Driver;\nuse Intervention\\Image\\Drivers\\Gd\\Modifiers\\TextModifier;\nuse Intervention\\Image\\Geometry\\Point;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Tests\\GdTestCase;\nuse Intervention\\Image\\Typography\\Font;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\TextModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Gd\\Modifiers\\TextModifier::class)]\nfinal class TextModifierTest extends GdTestCase\n{\n    public function testTextColor(): void\n    {\n        $font = (new Font())->setColor('ff0055');\n\n        $modifier = new class ('test', new Point(), $font) extends TextModifier\n        {\n            public function test(): ColorInterface\n            {\n                return $this->textColor();\n            }\n        };\n\n        $modifier->setDriver(new Driver());\n\n        $this->assertInstanceOf(ColorInterface::class, $modifier->test());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Gd/Modifiers/TrimModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Gd\\Modifiers;\n\nuse Intervention\\Image\\Exceptions\\NotSupportedException;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\TrimModifier;\nuse Intervention\\Image\\Tests\\GdTestCase;\n\n#[RequiresPhpExtension('gd')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\TrimModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Gd\\Modifiers\\TrimModifier::class)]\nfinal class TrimModifierTest extends GdTestCase\n{\n    public function testTrim(): void\n    {\n        $image = $this->readTestImage('trim.png');\n        $this->assertEquals(50, $image->width());\n        $this->assertEquals(50, $image->height());\n        $image->modify(new TrimModifier());\n        $this->assertEquals(28, $image->width());\n        $this->assertEquals(28, $image->height());\n    }\n\n    public function testTrimGradient(): void\n    {\n        $image = $this->readTestImage('radial.png');\n        $this->assertEquals(50, $image->width());\n        $this->assertEquals(50, $image->height());\n        $image->modify(new TrimModifier(50));\n        $this->assertEquals(35, $image->width());\n        $this->assertEquals(35, $image->height());\n    }\n\n    public function testTrimHighTolerance(): void\n    {\n        $image = $this->readTestImage('trim.png');\n        $this->assertEquals(50, $image->width());\n        $this->assertEquals(50, $image->height());\n        $image->modify(new TrimModifier(1000000));\n        $this->assertEquals(1, $image->width());\n        $this->assertEquals(1, $image->height());\n        $this->assertColor(255, 255, 255, 0, $image->pickColor(0, 0));\n    }\n\n    public function testTrimAnimated(): void\n    {\n        $image = $this->readTestImage('animation.gif');\n        $this->expectException(NotSupportedException::class);\n        $image->modify(new TrimModifier());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Analyzers/ColorspaceAnalyzerTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Analyzers;\n\nuse Intervention\\Image\\Drivers\\Imagick\\Analyzers\\ColorspaceAnalyzer;\nuse Intervention\\Image\\Drivers\\Imagick\\Driver;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Interfaces\\ColorspaceInterface;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(ColorspaceAnalyzer::class)]\nfinal class ColorspaceAnalyzerTest extends ImagickTestCase\n{\n    public function testAnalyze(): void\n    {\n        $image = $this->readTestImage('tile.png');\n        $analyzer = new ColorspaceAnalyzer();\n        $analyzer->setDriver(new Driver());\n        $result = $analyzer->analyze($image);\n        $this->assertInstanceOf(ColorspaceInterface::class, $result);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Analyzers/HeightAnalyzerTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Analyzers;\n\nuse Intervention\\Image\\Drivers\\Imagick\\Analyzers\\HeightAnalyzer;\nuse Intervention\\Image\\Drivers\\Imagick\\Driver;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(HeightAnalyzer::class)]\nfinal class HeightAnalyzerTest extends ImagickTestCase\n{\n    public function testAnalyze(): void\n    {\n        $image = $this->readTestImage('tile.png');\n        $analyzer = new HeightAnalyzer();\n        $analyzer->setDriver(new Driver());\n        $result = $analyzer->analyze($image);\n        $this->assertEquals(16, $result);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Analyzers/PixelColorAnalyzerTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Analyzers;\n\nuse Intervention\\Image\\Drivers\\Imagick\\Analyzers\\PixelColorAnalyzer;\nuse Intervention\\Image\\Drivers\\Imagick\\Driver;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(PixelColorAnalyzer::class)]\nfinal class PixelColorAnalyzerTest extends ImagickTestCase\n{\n    public function testAnalyze(): void\n    {\n        $image = $this->readTestImage('tile.png');\n        $analyzer = new PixelColorAnalyzer(0, 0);\n        $analyzer->setDriver(new Driver());\n        $result = $analyzer->analyze($image);\n        $this->assertInstanceOf(ColorInterface::class, $result);\n        $this->assertEquals('b4e000', $result->toHex());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Analyzers/PixelColorsAnalyzerTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Analyzers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Collection;\nuse Intervention\\Image\\Drivers\\Imagick\\Analyzers\\PixelColorsAnalyzer;\nuse Intervention\\Image\\Drivers\\Imagick\\Driver;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(PixelColorsAnalyzer::class)]\nfinal class PixelColorsAnalyzerTest extends ImagickTestCase\n{\n    public function testAnalyzeAnimated(): void\n    {\n        $image = $this->readTestImage('animation.gif');\n        $analyzer = new PixelColorsAnalyzer(0, 0);\n        $analyzer->setDriver(new Driver());\n        $result = $analyzer->analyze($image);\n        $this->assertInstanceOf(Collection::class, $result);\n        $colors = array_map(fn(ColorInterface $color) => $color->toHex(), $result->toArray());\n        $this->assertEquals($colors, [\"394b63\", \"394b63\", \"394b63\", \"ffa601\", \"ffa601\", \"ffa601\", \"ffa601\", \"394b63\"]);\n    }\n\n    public function testAnalyzeNonAnimated(): void\n    {\n        $image = $this->readTestImage('tile.png');\n        $analyzer = new PixelColorsAnalyzer(0, 0);\n        $analyzer->setDriver(new Driver());\n        $result = $analyzer->analyze($image);\n        $this->assertInstanceOf(Collection::class, $result);\n        $this->assertInstanceOf(ColorInterface::class, $result->first());\n        $this->assertEquals('b4e000', $result->first()->toHex());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Analyzers/ProfileAnalyzerTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Analyzers;\n\nuse Intervention\\Image\\Drivers\\Imagick\\Analyzers\\ProfileAnalyzer;\nuse Intervention\\Image\\Drivers\\Imagick\\Driver;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Exceptions\\ColorException;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(ProfileAnalyzer::class)]\nfinal class ProfileAnalyzerTest extends ImagickTestCase\n{\n    public function testAnalyze(): void\n    {\n        $image = $this->readTestImage('tile.png');\n        $analyzer = new ProfileAnalyzer();\n        $analyzer->setDriver(new Driver());\n        $this->expectException(ColorException::class);\n        $analyzer->analyze($image);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Analyzers/ResolutionAnalyzerTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Analyzers;\n\nuse Intervention\\Image\\Drivers\\Imagick\\Analyzers\\ResolutionAnalyzer;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Drivers\\Imagick\\Driver;\nuse Intervention\\Image\\Resolution;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(ResolutionAnalyzer::class)]\nfinal class ResolutionAnalyzerTest extends ImagickTestCase\n{\n    public function testAnalyze(): void\n    {\n        $image = $this->readTestImage('300dpi.png');\n        $analyzer = new ResolutionAnalyzer();\n        $analyzer->setDriver(new Driver());\n        $result = $analyzer->analyze($image);\n        $this->assertInstanceOf(Resolution::class, $result);\n        $this->assertEquals(300, round($result->perInch()->x()));\n        $this->assertEquals(300, round($result->perInch()->y()));\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Analyzers/WidthAnalyzerTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Analyzers;\n\nuse Intervention\\Image\\Drivers\\Imagick\\Analyzers\\WidthAnalyzer;\nuse Intervention\\Image\\Drivers\\Imagick\\Driver;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(WidthAnalyzer::class)]\nfinal class WidthAnalyzerTest extends ImagickTestCase\n{\n    public function testAnalyze(): void\n    {\n        $image = $this->readTestImage('tile.png');\n        $analyzer = new WidthAnalyzer();\n        $analyzer->setDriver(new Driver());\n        $result = $analyzer->analyze($image);\n        $this->assertEquals(16, $result);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/ColorProcessorTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick;\n\nuse ImagickPixel;\nuse Intervention\\Image\\Colors\\Rgb\\Color;\nuse Intervention\\Image\\Colors\\Rgb\\Colorspace;\nuse Intervention\\Image\\Drivers\\Imagick\\ColorProcessor;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(ColorProcessor::class)]\nfinal class ColorProcessorTest extends BaseTestCase\n{\n    public function testColorToNative(): void\n    {\n        $processor = new ColorProcessor(new Colorspace());\n        $result = $processor->colorToNative(new Color(255, 55, 0, 255));\n        $this->assertInstanceOf(ImagickPixel::class, $result);\n    }\n\n    public function testNativeToColor(): void\n    {\n        $processor = new ColorProcessor(new Colorspace());\n        $processor->nativeToColor(new ImagickPixel('rgb(255, 55, 0)'));\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/CoreTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick;\n\nuse Imagick;\nuse ImagickPixel;\nuse Intervention\\Image\\Drivers\\Imagick\\Core;\nuse Intervention\\Image\\Drivers\\Imagick\\Frame;\nuse Intervention\\Image\\Exceptions\\AnimationException;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(Core::class)]\nfinal class CoreTest extends BaseTestCase\n{\n    protected Core $core;\n\n    protected function setUp(): void\n    {\n        $imagick = new Imagick();\n\n        $im = new Imagick();\n        $im->newImage(10, 10, new ImagickPixel('red'));\n        $imagick->addImage($im);\n\n        $im = new Imagick();\n        $im->newImage(10, 10, new ImagickPixel('green'));\n        $imagick->addImage($im);\n\n        $im = new Imagick();\n        $im->newImage(10, 10, new ImagickPixel('blue'));\n        $imagick->addImage($im);\n\n        $this->core = new Core($imagick);\n    }\n\n    public function testAdd(): void\n    {\n        $imagick = new Imagick();\n        $imagick->newImage(100, 100, new ImagickPixel('red'));\n        $this->assertEquals(3, $this->core->count());\n        $result = $this->core->add(new Frame($imagick));\n        $this->assertEquals(4, $this->core->count());\n        $this->assertInstanceOf(Core::class, $result);\n    }\n\n    public function testCount(): void\n    {\n        $this->assertEquals(3, $this->core->count());\n    }\n\n    public function testIterator(): void\n    {\n        foreach ($this->core as $frame) {\n            $this->assertInstanceOf(Frame::class, $frame);\n        }\n    }\n\n    public function testNative(): void\n    {\n        $this->assertInstanceOf(Imagick::class, $this->core->native());\n    }\n\n    public function testSetNative(): void\n    {\n        $imagick1 = new Imagick();\n        $imagick1->newImage(10, 10, new ImagickPixel('red'));\n\n        $imagick2 = new Imagick();\n        $imagick2->newImage(10, 10, new ImagickPixel('red'));\n\n        $core = new Core($imagick1);\n        $this->assertEquals($imagick1, $core->native());\n        $core->setNative($imagick2);\n        $this->assertEquals($imagick2, $core->native());\n    }\n\n    public function testFrame(): void\n    {\n        $this->assertInstanceOf(Frame::class, $this->core->frame(0));\n        $this->assertInstanceOf(Frame::class, $this->core->frame(1));\n        $this->assertInstanceOf(Frame::class, $this->core->frame(2));\n        $this->expectException(AnimationException::class);\n        $this->core->frame(3);\n    }\n\n    public function testSetGetLoops(): void\n    {\n        $this->assertEquals(0, $this->core->loops());\n        $result = $this->core->setLoops(12);\n        $this->assertEquals(12, $this->core->loops());\n        $this->assertInstanceOf(Core::class, $result);\n    }\n\n    public function testHas(): void\n    {\n        $this->assertTrue($this->core->has(0));\n        $this->assertTrue($this->core->has(1));\n        $this->assertTrue($this->core->has(2));\n        $this->assertFalse($this->core->has(3));\n    }\n\n    public function testPush(): void\n    {\n        $im = new Imagick();\n        $im->newImage(100, 100, new ImagickPixel('green'));\n        $this->assertEquals(3, $this->core->count());\n        $result = $this->core->push(new Frame($im));\n        $this->assertEquals(4, $this->core->count());\n        $this->assertEquals(4, $result->count());\n    }\n\n    public function testGet(): void\n    {\n        $this->assertInstanceOf(Frame::class, $this->core->get(0));\n        $this->assertInstanceOf(Frame::class, $this->core->get(1));\n        $this->assertInstanceOf(Frame::class, $this->core->get(2));\n        $this->assertNull($this->core->get(3));\n        $this->assertEquals('foo', $this->core->get(3, 'foo'));\n    }\n\n    public function testEmpty(): void\n    {\n        $result = $this->core->empty();\n        $this->assertEquals(0, $this->core->count());\n        $this->assertEquals(0, $result->count());\n    }\n\n    public function testSlice(): void\n    {\n        $this->assertEquals(3, $this->core->count());\n        $result = $this->core->slice(1, 2);\n        $this->assertEquals(2, $this->core->count());\n        $this->assertEquals(2, $result->count());\n    }\n\n    public function testFirst(): void\n    {\n        $this->assertInstanceOf(Frame::class, $this->core->first());\n    }\n\n    public function testLast(): void\n    {\n        $this->assertInstanceOf(Frame::class, $this->core->last());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Decoders/Base64ImageDecoderTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Decoders;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Drivers\\Imagick\\Decoders\\Base64ImageDecoder;\nuse Intervention\\Image\\Drivers\\Imagick\\Driver;\nuse Intervention\\Image\\Exceptions\\DecoderException;\nuse Intervention\\Image\\Image;\nuse Intervention\\Image\\Tests\\BaseTestCase;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(Base64ImageDecoder::class)]\nfinal class Base64ImageDecoderTest extends BaseTestCase\n{\n    protected Base64ImageDecoder $decoder;\n\n    protected function setUp(): void\n    {\n        $this->decoder = new Base64ImageDecoder();\n        $this->decoder->setDriver(new Driver());\n    }\n\n    public function testDecode(): void\n    {\n        $result = $this->decoder->decode(\n            base64_encode($this->getTestResourceData('blue.gif'))\n        );\n\n        $this->assertInstanceOf(Image::class, $result);\n    }\n\n    public function testDecoderInvalid(): void\n    {\n        $this->expectException(DecoderException::class);\n        $this->decoder->decode('test');\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Decoders/BinaryImageDecoderTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Decoders;\n\nuse Intervention\\Image\\Colors\\Cmyk\\Colorspace as CmykColorspace;\nuse Intervention\\Image\\Colors\\Rgb\\Colorspace as RgbColorspace;\nuse Intervention\\Image\\Drivers\\Imagick\\Decoders\\BinaryImageDecoder;\nuse Intervention\\Image\\Drivers\\Imagick\\Driver;\nuse Intervention\\Image\\Exceptions\\DecoderException;\nuse Intervention\\Image\\Image;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse stdClass;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(BinaryImageDecoder::class)]\nfinal class BinaryImageDecoderTest extends BaseTestCase\n{\n    protected BinaryImageDecoder $decoder;\n\n    protected function setUp(): void\n    {\n        $this->decoder = new BinaryImageDecoder();\n        $this->decoder->setDriver(new Driver());\n    }\n\n    public function testDecodePng(): void\n    {\n        $image = $this->decoder->decode(file_get_contents($this->getTestResourcePath('tile.png')));\n        $this->assertInstanceOf(Image::class, $image);\n        $this->assertInstanceOf(RgbColorspace::class, $image->colorspace());\n        $this->assertEquals(16, $image->width());\n        $this->assertEquals(16, $image->height());\n        $this->assertCount(1, $image);\n    }\n\n    public function testDecodeGif(): void\n    {\n        $image = $this->decoder->decode(file_get_contents($this->getTestResourcePath('red.gif')));\n        $this->assertInstanceOf(Image::class, $image);\n        $this->assertEquals(16, $image->width());\n        $this->assertEquals(16, $image->height());\n        $this->assertCount(1, $image);\n    }\n\n    public function testDecodeAnimatedGif(): void\n    {\n        $image = $this->decoder->decode(file_get_contents($this->getTestResourcePath('cats.gif')));\n        $this->assertInstanceOf(Image::class, $image);\n        $this->assertEquals(75, $image->width());\n        $this->assertEquals(50, $image->height());\n        $this->assertCount(4, $image);\n    }\n\n    public function testDecodeJpegWithExif(): void\n    {\n        $image = $this->decoder->decode(file_get_contents($this->getTestResourcePath('exif.jpg')));\n        $this->assertInstanceOf(Image::class, $image);\n        $this->assertEquals(16, $image->width());\n        $this->assertEquals(16, $image->height());\n        $this->assertCount(1, $image);\n        $this->assertEquals('Oliver Vogel', $image->exif('IFD0.Artist'));\n    }\n\n    public function testDecodeCmykImage(): void\n    {\n        $image = $this->decoder->decode(file_get_contents($this->getTestResourcePath('cmyk.jpg')));\n        $this->assertInstanceOf(Image::class, $image);\n        $this->assertInstanceOf(CmykColorspace::class, $image->colorspace());\n    }\n\n    public function testDecodeNonString(): void\n    {\n        $this->expectException(DecoderException::class);\n        $this->decoder->decode(new stdClass());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Decoders/DataUriImageDecoderTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Decoders;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Drivers\\Imagick\\Decoders\\DataUriImageDecoder;\nuse Intervention\\Image\\Drivers\\Imagick\\Driver;\nuse Intervention\\Image\\Exceptions\\DecoderException;\nuse Intervention\\Image\\Image;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse stdClass;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(DataUriImageDecoder::class)]\nfinal class DataUriImageDecoderTest extends BaseTestCase\n{\n    protected DataUriImageDecoder $decoder;\n\n    protected function setUp(): void\n    {\n        $this->decoder = new DataUriImageDecoder();\n        $this->decoder->setDriver(new Driver());\n    }\n\n    public function testDecode(): void\n    {\n        $result = $this->decoder->decode(\n            sprintf('data:image/jpeg;base64,%s', base64_encode($this->getTestResourceData('blue.gif')))\n        );\n\n        $this->assertInstanceOf(Image::class, $result);\n    }\n\n    public function testDecoderNonString(): void\n    {\n        $this->expectException(DecoderException::class);\n        $this->decoder->decode(new stdClass());\n    }\n\n    public function testDecoderInvalid(): void\n    {\n        $this->expectException(DecoderException::class);\n        $this->decoder->decode('invalid');\n    }\n\n    public function testDecoderNonImage(): void\n    {\n        $this->expectException(DecoderException::class);\n        $this->decoder->decode('data:text/plain;charset=utf-8,test');\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Decoders/EncodedImageObjectDecoderTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Decoders;\n\nuse Intervention\\Image\\Drivers\\Imagick\\Decoders\\EncodedImageObjectDecoder;\nuse Intervention\\Image\\Drivers\\Imagick\\Driver;\nuse Intervention\\Image\\EncodedImage;\nuse Intervention\\Image\\Image;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(EncodedImageObjectDecoder::class)]\nclass EncodedImageObjectDecoderTest extends ImagickTestCase\n{\n    protected EncodedImageObjectDecoder $decoder;\n\n    protected function setUp(): void\n    {\n        $this->decoder = new EncodedImageObjectDecoder();\n        $this->decoder->setDriver(new Driver());\n    }\n\n    public function testDecode(): void\n    {\n        $result = $this->decoder->decode(new EncodedImage($this->getTestResourceData()));\n        $this->assertInstanceOf(Image::class, $result);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Decoders/FilePathImageDecoderTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Decoders;\n\nuse Generator;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Drivers\\Imagick\\Decoders\\FilePathImageDecoder;\nuse Intervention\\Image\\Drivers\\Imagick\\Driver;\nuse Intervention\\Image\\Exceptions\\DecoderException;\nuse Intervention\\Image\\Image;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(FilePathImageDecoder::class)]\nfinal class FilePathImageDecoderTest extends BaseTestCase\n{\n    protected FilePathImageDecoder $decoder;\n\n    protected function setUp(): void\n    {\n        $this->decoder = new FilePathImageDecoder();\n        $this->decoder->setDriver(new Driver());\n    }\n\n    #[DataProvider('validFormatPathsProvider')]\n    public function testDecode(string $path, bool $result): void\n    {\n        if ($result === false) {\n            $this->expectException(DecoderException::class);\n        }\n\n        $result = $this->decoder->decode($path);\n\n        if ($result === true) {\n            $this->assertInstanceOf(Image::class, $result);\n        }\n    }\n\n    public static function validFormatPathsProvider(): Generator\n    {\n        yield [self::getTestResourcePath('cats.gif'), true];\n        yield [self::getTestResourcePath('animation.gif'), true];\n        yield [self::getTestResourcePath('red.gif'), true];\n        yield [self::getTestResourcePath('green.gif'), true];\n        yield [self::getTestResourcePath('blue.gif'), true];\n        yield [self::getTestResourcePath('gradient.bmp'), true];\n        yield [self::getTestResourcePath('circle.png'), true];\n        yield ['no-path', false];\n        yield [str_repeat('x', PHP_MAXPATHLEN + 1), false];\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Decoders/FilePointerImageDecoderTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Decoders;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Drivers\\Imagick\\Decoders\\FilePointerImageDecoder;\nuse Intervention\\Image\\Drivers\\Imagick\\Driver;\nuse Intervention\\Image\\Image;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(FilePointerImageDecoder::class)]\nfinal class FilePointerImageDecoderTest extends ImagickTestCase\n{\n    public function testDecode(): void\n    {\n        $decoder = new FilePointerImageDecoder();\n        $decoder->setDriver(new Driver());\n        $fp = fopen($this->getTestResourcePath('test.jpg'), 'r');\n        $result = $decoder->decode($fp);\n        $this->assertInstanceOf(Image::class, $result);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Decoders/ImageObjectDecoderTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Decoders;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Decoders\\ImageObjectDecoder;\nuse Intervention\\Image\\Image;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(ImageObjectDecoder::class)]\nfinal class ImageObjectDecoderTest extends ImagickTestCase\n{\n    public function testDecode(): void\n    {\n        $decoder = new ImageObjectDecoder();\n        $result = $decoder->decode($this->readTestImage('blue.gif'));\n        $this->assertInstanceOf(Image::class, $result);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Decoders/NativeObjectDecoderTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Decoders;\n\nuse Imagick;\nuse ImagickPixel;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Drivers\\Imagick\\Decoders\\NativeObjectDecoder;\nuse Intervention\\Image\\Drivers\\Imagick\\Driver;\nuse Intervention\\Image\\Image;\nuse Intervention\\Image\\Tests\\BaseTestCase;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(NativeObjectDecoder::class)]\nfinal class NativeObjectDecoderTest extends BaseTestCase\n{\n    protected NativeObjectDecoder $decoder;\n\n    protected function setUp(): void\n    {\n        $this->decoder = new NativeObjectDecoder();\n        $this->decoder->setDriver(new Driver());\n    }\n\n    public function testDecode(): void\n    {\n        $native = new Imagick();\n        $native->newImage(3, 2, new ImagickPixel('red'), 'png');\n        $result = $this->decoder->decode($native);\n\n        $this->assertInstanceOf(Image::class, $result);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Decoders/SplFileInfoImageDecoderTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Decoders;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Drivers\\Imagick\\Decoders\\SplFileInfoImageDecoder;\nuse Intervention\\Image\\Drivers\\Imagick\\Driver;\nuse Intervention\\Image\\Image;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse SplFileInfo;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(SplFileInfoImageDecoder::class)]\nfinal class SplFileInfoImageDecoderTest extends BaseTestCase\n{\n    public function testDecode(): void\n    {\n        $decoder = new SplFileInfoImageDecoder();\n        $decoder->setDriver(new Driver());\n        $result = $decoder->decode(\n            new SplFileInfo($this->getTestResourcePath('blue.gif'))\n        );\n        $this->assertInstanceOf(Image::class, $result);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/DriverTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick;\n\nuse Generator;\nuse Intervention\\Image\\Analyzers\\WidthAnalyzer as GenericWidthAnalyzer;\nuse Intervention\\Image\\Decoders\\FilePathImageDecoder as GenericFilePathImageDecoder;\nuse Intervention\\Image\\Encoders\\PngEncoder as GenericPngEncoder;\nuse Intervention\\Image\\Modifiers\\ResizeModifier as GenericResizeModifier;\nuse Intervention\\Image\\Colors\\Rgb\\Colorspace;\nuse Intervention\\Image\\Colors\\Rgb\\Decoders\\HexColorDecoder;\nuse Intervention\\Image\\Drivers\\Imagick\\Analyzers\\WidthAnalyzer;\nuse Intervention\\Image\\Drivers\\Imagick\\Decoders\\FilePathImageDecoder;\nuse Intervention\\Image\\Drivers\\Imagick\\Driver;\nuse Intervention\\Image\\Drivers\\Imagick\\Encoders\\PngEncoder;\nuse Intervention\\Image\\Drivers\\Imagick\\Modifiers\\ResizeModifier;\nuse Intervention\\Image\\Exceptions\\NotSupportedException;\nuse Intervention\\Image\\FileExtension;\nuse Intervention\\Image\\Format;\nuse Intervention\\Image\\Interfaces\\AnalyzerInterface;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Interfaces\\ColorProcessorInterface;\nuse Intervention\\Image\\Interfaces\\DriverInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializableInterface;\nuse Intervention\\Image\\MediaType;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(Driver::class)]\nfinal class DriverTest extends BaseTestCase\n{\n    protected Driver $driver;\n\n    protected function setUp(): void\n    {\n        $this->driver = new Driver();\n    }\n\n    public function testId(): void\n    {\n        $this->assertEquals('Imagick', $this->driver->id());\n    }\n\n    public function testCreateImage(): void\n    {\n        $image = $this->driver->createImage(3, 2);\n        $this->assertInstanceOf(ImageInterface::class, $image);\n        $this->assertEquals(3, $image->width());\n        $this->assertEquals(2, $image->height());\n    }\n\n    public function testCreateAnimation(): void\n    {\n        $image = $this->driver->createAnimation(function ($animation): void {\n            $animation->add($this->getTestResourcePath('red.gif'), .25);\n            $animation->add($this->getTestResourcePath('green.gif'), .25);\n        })->setLoops(5);\n        $this->assertInstanceOf(ImageInterface::class, $image);\n\n        $this->assertEquals(16, $image->width());\n        $this->assertEquals(16, $image->height());\n        $this->assertEquals(5, $image->loops());\n        $this->assertEquals(2, $image->count());\n    }\n\n    public function testHandleInputImage(): void\n    {\n        $result = $this->driver->handleInput($this->getTestResourcePath('test.jpg'));\n        $this->assertInstanceOf(ImageInterface::class, $result);\n    }\n\n    public function testHandleInputColor(): void\n    {\n        $result = $this->driver->handleInput('ffffff');\n        $this->assertInstanceOf(ColorInterface::class, $result);\n    }\n\n    public function testHandleInputObjects(): void\n    {\n        $result = $this->driver->handleInput('ffffff', [\n            new HexColorDecoder()\n        ]);\n        $this->assertInstanceOf(ColorInterface::class, $result);\n    }\n\n    public function testHandleInputClassnames(): void\n    {\n        $result = $this->driver->handleInput('ffffff', [\n            HexColorDecoder::class\n        ]);\n        $this->assertInstanceOf(ColorInterface::class, $result);\n    }\n\n    public function testColorProcessor(): void\n    {\n        $result = $this->driver->colorProcessor(new Colorspace());\n        $this->assertInstanceOf(ColorProcessorInterface::class, $result);\n    }\n\n    #[DataProvider('supportsDataProvider')]\n    public function testSupports(bool $result, mixed $identifier): void\n    {\n        $this->assertEquals($result, $this->driver->supports($identifier));\n    }\n\n    public static function supportsDataProvider(): Generator\n    {\n        yield [true, Format::JPEG];\n        yield [true, MediaType::IMAGE_JPEG];\n        yield [true, MediaType::IMAGE_JPG];\n        yield [true, FileExtension::JPG];\n        yield [true, FileExtension::JPEG];\n        yield [true, 'jpg'];\n        yield [true, 'jpeg'];\n        yield [true, 'image/jpg'];\n        yield [true, 'image/jpeg'];\n\n        yield [true, Format::WEBP];\n        yield [true, MediaType::IMAGE_WEBP];\n        yield [true, MediaType::IMAGE_X_WEBP];\n        yield [true, FileExtension::WEBP];\n        yield [true, 'webp'];\n        yield [true, 'image/webp'];\n        yield [true, 'image/x-webp'];\n\n        yield [true, Format::GIF];\n        yield [true, MediaType::IMAGE_GIF];\n        yield [true, FileExtension::GIF];\n        yield [true, 'gif'];\n        yield [true, 'image/gif'];\n\n        yield [true, Format::PNG];\n        yield [true, MediaType::IMAGE_PNG];\n        yield [true, MediaType::IMAGE_X_PNG];\n        yield [true, FileExtension::PNG];\n        yield [true, 'png'];\n        yield [true, 'image/png'];\n        yield [true, 'image/x-png'];\n\n        yield [true, Format::AVIF];\n        yield [true, MediaType::IMAGE_AVIF];\n        yield [true, MediaType::IMAGE_X_AVIF];\n        yield [true, FileExtension::AVIF];\n        yield [true, 'avif'];\n        yield [true, 'image/avif'];\n        yield [true, 'image/x-avif'];\n\n        yield [true, Format::BMP];\n        yield [true, FileExtension::BMP];\n        yield [true, MediaType::IMAGE_BMP];\n        yield [true, MediaType::IMAGE_MS_BMP];\n        yield [true, MediaType::IMAGE_X_BITMAP];\n        yield [true, MediaType::IMAGE_X_BMP];\n        yield [true, MediaType::IMAGE_X_MS_BMP];\n        yield [true, MediaType::IMAGE_X_WINDOWS_BMP];\n        yield [true, MediaType::IMAGE_X_WIN_BITMAP];\n        yield [true, MediaType::IMAGE_X_XBITMAP];\n        yield [true, 'bmp'];\n        yield [true, 'image/bmp'];\n        yield [true, 'image/ms-bmp'];\n        yield [true, 'image/x-bitmap'];\n        yield [true, 'image/x-bmp'];\n        yield [true, 'image/x-ms-bmp'];\n        yield [true, 'image/x-windows-bmp'];\n        yield [true, 'image/x-win-bitmap'];\n        yield [true, 'image/x-xbitmap'];\n\n        yield [true, Format::TIFF];\n        yield [true, MediaType::IMAGE_TIFF];\n        yield [true, FileExtension::TIFF];\n        yield [true, FileExtension::TIF];\n        yield [true, 'tif'];\n        yield [true, 'tiff'];\n        yield [true, 'image/tiff'];\n\n        yield [true, Format::JP2];\n        yield [true, MediaType::IMAGE_JP2];\n        yield [true, MediaType::IMAGE_JPX];\n        yield [true, MediaType::IMAGE_JPM];\n        yield [true, FileExtension::TIFF];\n        yield [true, FileExtension::TIF];\n        yield [true, FileExtension::JP2];\n        yield [true, FileExtension::J2K];\n        yield [true, FileExtension::JPF];\n        yield [true, FileExtension::JPM];\n        yield [true, FileExtension::JPG2];\n        yield [true, FileExtension::J2C];\n        yield [true, FileExtension::JPC];\n        yield [true, FileExtension::JPX];\n        yield [true, 'jp2'];\n        yield [true, 'j2k'];\n        yield [true, 'jpf'];\n        yield [true, 'jpm'];\n        yield [true, 'jpg2'];\n        yield [true, 'j2c'];\n        yield [true, 'jpc'];\n        yield [true, 'jpx'];\n\n        yield [true, Format::HEIC];\n        yield [true, MediaType::IMAGE_HEIC];\n        yield [true, MediaType::IMAGE_HEIF];\n        yield [true, FileExtension::HEIC];\n        yield [true, FileExtension::HEIF];\n        yield [true, 'heic'];\n        yield [true, 'heif'];\n        yield [true, 'image/heic'];\n        yield [true, 'image/heif'];\n\n        yield [false, 'tga'];\n        yield [false, 'image/tga'];\n        yield [false, 'image/x-targa'];\n        yield [false, 'foo'];\n        yield [false, ''];\n    }\n\n    public function testVersion(): void\n    {\n        $this->assertTrue(is_string($this->driver->version()));\n    }\n\n    #[DataProvider('spezializeDataProvider')]\n    public function testSpecialize(string $inputClassname, string $outputClassname): void\n    {\n        $this->assertInstanceOf($outputClassname, $this->driver->specialize(new $inputClassname()));\n    }\n\n    public static function spezializeDataProvider(): Generator\n    {\n        // specializing possible\n        yield [GenericResizeModifier::class, ResizeModifier::class];\n        yield [GenericWidthAnalyzer::class, WidthAnalyzer::class];\n        yield [GenericPngEncoder::class, PngEncoder::class];\n        yield [GenericFilePathImageDecoder::class, FilePathImageDecoder::class];\n\n        // already specialized\n        yield [ResizeModifier::class, ResizeModifier::class];\n        yield [WidthAnalyzer::class, WidthAnalyzer::class];\n        yield [PngEncoder::class, PngEncoder::class];\n        yield [FilePathImageDecoder::class, FilePathImageDecoder::class];\n    }\n\n    public function testSpecializeFailure(): void\n    {\n        $this->expectException(NotSupportedException::class);\n        $this->driver->specialize(new class () implements AnalyzerInterface, SpecializableInterface\n        {\n            protected DriverInterface $driver;\n\n            public function analyze(ImageInterface $image): mixed\n            {\n                return true;\n            }\n\n            /** @return array<string, mixed> **/\n            public function specializable(): array\n            {\n                return [];\n            }\n\n            public function setDriver(DriverInterface $driver): SpecializableInterface\n            {\n                return $this;\n            }\n\n            public function driver(): DriverInterface\n            {\n                return $this->driver;\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Encoders/AvifEncoderTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Encoders;\n\nuse Intervention\\Image\\Drivers\\Imagick\\Driver;\nuse Intervention\\Image\\Drivers\\Imagick\\Encoders\\AvifEncoder;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(AvifEncoder::class)]\nfinal class AvifEncoderTest extends ImagickTestCase\n{\n    public function testEncode(): void\n    {\n        $image = $this->createTestImage(3, 2);\n        $encoder = new AvifEncoder(10);\n        $encoder->setDriver(new Driver());\n        $result = $encoder->encode($image);\n        $this->assertMediaType('image/avif', $result);\n        $this->assertEquals('image/avif', $result->mimetype());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Encoders/BmpEncoderTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Encoders;\n\nuse Intervention\\Image\\Drivers\\Imagick\\Encoders\\BmpEncoder;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(BmpEncoder::class)]\nfinal class BmpEncoderTest extends ImagickTestCase\n{\n    public function testEncode(): void\n    {\n        $image = $this->createTestImage(3, 2);\n        $encoder = new BmpEncoder();\n        $result = $encoder->encode($image);\n        $this->assertMediaType(['image/bmp', 'image/x-ms-bmp'], $result);\n        $this->assertEquals('image/bmp', $result->mimetype());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Encoders/GifEncoderTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Encoders;\n\nuse Intervention\\Gif\\Decoder;\nuse Intervention\\Image\\Drivers\\Imagick\\Encoders\\GifEncoder;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(GifEncoder::class)]\nfinal class GifEncoderTest extends ImagickTestCase\n{\n    public function testEncode(): void\n    {\n        $image = $this->createTestImage(3, 2);\n        $encoder = new GifEncoder();\n        $result = $encoder->encode($image);\n        $this->assertMediaType('image/gif', $result);\n        $this->assertEquals('image/gif', $result->mimetype());\n        $this->assertFalse(\n            Decoder::decode((string) $result)->getFirstFrame()->getImageDescriptor()->isInterlaced()\n        );\n    }\n\n    public function testEncodeInterlaced(): void\n    {\n        $image = $this->createTestImage(3, 2);\n        $encoder = new GifEncoder(interlaced: true);\n        $result = $encoder->encode($image);\n        $this->assertMediaType('image/gif', $result);\n        $this->assertEquals('image/gif', $result->mimetype());\n        $this->assertTrue(\n            Decoder::decode((string) $result)->getFirstFrame()->getImageDescriptor()->isInterlaced()\n        );\n    }\n\n    public function testEncodeInterlacedAnimation(): void\n    {\n        $image = $this->createTestAnimation();\n        $encoder = new GifEncoder(interlaced: true);\n        $result = $encoder->encode($image);\n        $this->assertMediaType('image/gif', $result);\n        $this->assertEquals('image/gif', $result->mimetype());\n        $this->assertTrue(\n            Decoder::decode((string) $result)->getFirstFrame()->getImageDescriptor()->isInterlaced()\n        );\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Encoders/HeicEncoderTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Encoders;\n\nuse Intervention\\Image\\Drivers\\Imagick\\Driver;\nuse Intervention\\Image\\Drivers\\Imagick\\Encoders\\HeicEncoder;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(HeicEncoder::class)]\nfinal class HeicEncoderTest extends ImagickTestCase\n{\n    public function testEncode(): void\n    {\n        $image = $this->createTestImage(3, 2);\n        $encoder = new HeicEncoder(75);\n        $encoder->setDriver(new Driver());\n        $result = $encoder->encode($image);\n        $this->assertMediaType('image/heic', $result);\n        $this->assertEquals('image/heic', $result->mimetype());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Encoders/Jpeg2000EncoderTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Encoders;\n\nuse Intervention\\Image\\Drivers\\Imagick\\Driver;\nuse Intervention\\Image\\Drivers\\Imagick\\Encoders\\Jpeg2000Encoder;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(Jpeg2000Encoder::class)]\nfinal class Jpeg2000EncoderTest extends ImagickTestCase\n{\n    public function testEncode(): void\n    {\n        $image = $this->createTestImage(3, 2);\n        $encoder = new Jpeg2000Encoder(75);\n        $encoder->setDriver(new Driver());\n        $result = $encoder->encode($image);\n        $this->assertMediaType('image/jp2', $result);\n        $this->assertEquals('image/jp2', $result->mimetype());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Encoders/JpegEncoderTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Encoders;\n\nuse Intervention\\Image\\Drivers\\Imagick\\Decoders\\FilePointerImageDecoder;\nuse Intervention\\Image\\Drivers\\Imagick\\Driver;\nuse Intervention\\Image\\Drivers\\Imagick\\Encoders\\JpegEncoder;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\nuse Intervention\\Image\\Tests\\Traits\\CanDetectProgressiveJpeg;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(JpegEncoder::class)]\nfinal class JpegEncoderTest extends ImagickTestCase\n{\n    use CanDetectProgressiveJpeg;\n\n    public function testEncode(): void\n    {\n        $image = $this->createTestImage(3, 2);\n        $encoder = new JpegEncoder(75);\n        $encoder->setDriver(new Driver());\n        $result = $encoder->encode($image);\n        $this->assertMediaType('image/jpeg', $result);\n        $this->assertEquals('image/jpeg', $result->mimetype());\n    }\n\n    public function testEncodeProgressive(): void\n    {\n        $image = $this->createTestImage(3, 2);\n        $encoder = new JpegEncoder(progressive: true);\n        $encoder->setDriver(new Driver());\n        $result = $encoder->encode($image);\n        $this->assertMediaType('image/jpeg', $result);\n        $this->assertEquals('image/jpeg', $result->mimetype());\n        $this->assertTrue($this->isProgressiveJpeg($result));\n    }\n\n    public function testEncodeStripExif(): void\n    {\n        $image = $this->readTestImage('exif.jpg');\n        $this->assertEquals('Oliver Vogel', $image->exif('IFD0.Artist'));\n\n        $encoder = new JpegEncoder(strip: true);\n        $encoder->setDriver(new Driver());\n        $result = $encoder->encode($image);\n        $this->assertMediaType('image/jpeg', $result);\n        $this->assertEquals('image/jpeg', $result->mimetype());\n\n        $this->assertEmpty(exif_read_data($result->toFilePointer())['IFD0.Artist'] ?? null);\n    }\n\n    public function testEncodeStripExifKeepICCProfiles(): void\n    {\n        $image = $this->readTestImage('cmyk.jpg');\n        $this->assertNotEmpty($image->core()->native()->getImageProfiles('icc'));\n\n        $encoder = new JpegEncoder(strip: true);\n        $encoder->setDriver(new Driver());\n        $result = $encoder->encode($image);\n\n        $decoder = new FilePointerImageDecoder();\n        $decoder->setDriver(new Driver());\n\n        $image = $decoder->decode($result->toFilePointer());\n        $this->assertNotEmpty($image->core()->native()->getImageProfiles('icc'));\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Encoders/PngEncoderTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Encoders;\n\nuse Generator;\nuse Intervention\\Image\\Drivers\\Imagick\\Encoders\\PngEncoder;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\nuse Intervention\\Image\\Tests\\Traits\\CanInspectPngFormat;\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(PngEncoder::class)]\nfinal class PngEncoderTest extends ImagickTestCase\n{\n    use CanInspectPngFormat;\n\n    public function testEncode(): void\n    {\n        $image = $this->createTestImage(3, 2);\n        $encoder = new PngEncoder();\n        $result = $encoder->encode($image);\n        $this->assertMediaType('image/png', $result);\n        $this->assertEquals('image/png', $result->mimetype());\n        $this->assertFalse($this->isInterlacedPng($result));\n    }\n\n    public function testEncodeInterlaced(): void\n    {\n        $image = $this->createTestImage(3, 2);\n        $encoder = new PngEncoder(interlaced: true);\n        $result = $encoder->encode($image);\n        $this->assertMediaType('image/png', $result);\n        $this->assertEquals('image/png', $result->mimetype());\n        $this->assertTrue($this->isInterlacedPng($result));\n    }\n\n    #[DataProvider('indexedDataProvider')]\n    public function testEncoderIndexed(ImageInterface $image, PngEncoder $encoder, string $result): void\n    {\n        $this->assertEquals(\n            $result,\n            $this->pngColorType($encoder->encode($image)),\n        );\n    }\n\n    public static function indexedDataProvider(): Generator\n    {\n        yield [\n            static::createTestImage(3, 2), // new\n            new PngEncoder(indexed: false),\n            'truecolor-alpha',\n        ];\n        yield [\n            static::createTestImage(3, 2), // new\n            new PngEncoder(indexed: true),\n            'indexed',\n        ];\n\n        yield [\n            static::createTestImage(3, 2)->fill('ccc'), // new grayscale\n            new PngEncoder(indexed: true),\n            'indexed',\n        ];\n        yield [\n            static::readTestImage('circle.png'), // truecolor-alpha\n            new PngEncoder(indexed: false),\n            'truecolor-alpha',\n        ];\n        yield [\n            static::readTestImage('circle.png'), // indexedcolor-alpha\n            new PngEncoder(indexed: true),\n            'grayscale-alpha', // result should be 'indexed' but there seems to be no way to force this with imagick\n        ];\n        yield [\n            static::readTestImage('tile.png'), // indexed\n            new PngEncoder(indexed: false),\n            'truecolor-alpha',\n        ];\n        yield [\n            static::readTestImage('tile.png'), // indexed\n            new PngEncoder(indexed: true),\n            'indexed',\n        ];\n        yield [\n            static::readTestImage('test.jpg'), // jpeg\n            new PngEncoder(indexed: false),\n            'truecolor-alpha',\n        ];\n        yield [\n            static::readTestImage('test.jpg'), // jpeg\n            new PngEncoder(indexed: true),\n            'indexed',\n        ];\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Encoders/TiffEncoderTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Encoders;\n\nuse Intervention\\Image\\Drivers\\Imagick\\Driver;\nuse Intervention\\Image\\Drivers\\Imagick\\Encoders\\TiffEncoder;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(TiffEncoder::class)]\nfinal class TiffEncoderTest extends ImagickTestCase\n{\n    public function testEncode(): void\n    {\n        $image = $this->createTestImage(3, 2);\n        $encoder = new TiffEncoder();\n        $encoder->setDriver(new Driver());\n        $result = $encoder->encode($image);\n        $this->assertMediaType('image/tiff', $result);\n        $this->assertEquals('image/tiff', $result->mimetype());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Encoders/WebpEncoderTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Encoders;\n\nuse Intervention\\Image\\Drivers\\Imagick\\Driver;\nuse Intervention\\Image\\Drivers\\Imagick\\Encoders\\WebpEncoder;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(WebpEncoder::class)]\nfinal class WebpEncoderTest extends ImagickTestCase\n{\n    public function testEncode(): void\n    {\n        $image = $this->createTestImage(3, 2);\n        $encoder = new WebpEncoder(75);\n        $encoder->setDriver(new Driver());\n        $result = $encoder->encode($image);\n        $this->assertMediaType('image/webp', $result);\n        $this->assertEquals('image/webp', $result->mimetype());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/FontProcessorTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick;\n\nuse Intervention\\Image\\Drivers\\Imagick\\FontProcessor;\nuse Intervention\\Image\\Geometry\\Point;\nuse Intervention\\Image\\Interfaces\\SizeInterface;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse Intervention\\Image\\Typography\\Font;\nuse Intervention\\Image\\Typography\\TextBlock;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(FontProcessor::class)]\nfinal class FontProcessorTest extends BaseTestCase\n{\n    public function testBoxSizeTtf(): void\n    {\n        $processor = new FontProcessor();\n        $size = $processor->boxSize(\n            'ABC',\n            $this->testFont()->setSize(120),\n        );\n\n        $this->assertInstanceOf(SizeInterface::class, $size);\n        $this->assertEquals(163, $size->width());\n        $this->assertEquals(72, $size->height());\n    }\n\n    public function testNativeFontSize(): void\n    {\n        $processor = new FontProcessor();\n        $font = new Font();\n        $font->setSize(14.2);\n        $size = $processor->nativeFontSize($font);\n        $this->assertEquals(14.2, $size);\n    }\n\n    public function testTextBlock(): void\n    {\n        $processor = new FontProcessor();\n        $result = $processor->textBlock(\n            'test',\n            $this->testFont(),\n            new Point(0, 0),\n        );\n        $this->assertInstanceOf(TextBlock::class, $result);\n    }\n\n    public function testTypographicalSize(): void\n    {\n        $processor = new FontProcessor();\n        $result = $processor->typographicalSize($this->testFont());\n        $this->assertEquals(7, $result);\n    }\n\n    public function testCapHeight(): void\n    {\n        $processor = new FontProcessor();\n        $result = $processor->capHeight($this->testFont());\n        $this->assertEquals(7, $result);\n    }\n\n    public function testLeading(): void\n    {\n        $processor = new FontProcessor();\n        $result = $processor->leading($this->testFont());\n        $this->assertEquals(9, $result);\n    }\n\n    private function testFont(): Font\n    {\n        return new Font($this->getTestResourcePath('test.ttf'));\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/FrameTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Imagick;\nuse ImagickPixel;\nuse Intervention\\Image\\Drivers\\Imagick\\Driver;\nuse Intervention\\Image\\Drivers\\Imagick\\Frame;\nuse Intervention\\Image\\Image;\nuse Intervention\\Image\\Geometry\\Rectangle;\nuse Intervention\\Image\\Tests\\BaseTestCase;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(Frame::class)]\nfinal class FrameTest extends BaseTestCase\n{\n    protected function getTestFrame(): Frame\n    {\n        $imagick = new Imagick();\n        $imagick->newImage(3, 2, new ImagickPixel('red'), 'png');\n        $imagick->setImageDelay(125); // 1.25 seconds\n        $imagick->setImageDispose(0);\n        $imagick->setImagePage(3, 2, 8, 9);\n\n        return new Frame($imagick);\n    }\n\n    public function testConstructor(): void\n    {\n        $frame = $this->getTestFrame();\n        $this->assertInstanceOf(Frame::class, $frame);\n    }\n\n    public function testGetSize(): void\n    {\n        $frame = $this->getTestFrame();\n        $this->assertInstanceOf(Rectangle::class, $frame->size());\n    }\n\n    public function testSetGetDelay(): void\n    {\n        $frame = $this->getTestFrame();\n        $this->assertEquals(1.25, $frame->delay());\n\n        $result = $frame->setDelay(2.5);\n        $this->assertInstanceOf(Frame::class, $result);\n        $this->assertEquals(2.5, $frame->delay());\n        $this->assertEquals(250, $frame->native()->getImageDelay());\n    }\n\n    public function testSetGetDispose(): void\n    {\n        $frame = $this->getTestFrame();\n        $this->assertEquals(0, $frame->dispose());\n\n        $result = $frame->setDispose(3);\n        $this->assertInstanceOf(Frame::class, $result);\n        $this->assertEquals(3, $frame->dispose());\n    }\n\n    public function testSetGetOffsetLeft(): void\n    {\n        $frame = $this->getTestFrame();\n        $this->assertEquals(8, $frame->offsetLeft());\n\n        $result = $frame->setOffsetLeft(100);\n        $this->assertInstanceOf(Frame::class, $result);\n        $this->assertEquals(100, $frame->offsetLeft());\n    }\n\n    public function testSetGetOffsetTop(): void\n    {\n        $frame = $this->getTestFrame();\n        $this->assertEquals(9, $frame->offsetTop());\n\n        $result = $frame->setOffsetTop(100);\n        $this->assertInstanceOf(Frame::class, $result);\n        $this->assertEquals(100, $frame->offsetTop());\n    }\n\n    public function testSetGetOffset(): void\n    {\n        $frame = $this->getTestFrame();\n        $this->assertEquals(8, $frame->offsetLeft());\n        $this->assertEquals(9, $frame->offsetTop());\n\n        $result = $frame->setOffset(100, 200);\n        $this->assertInstanceOf(Frame::class, $result);\n        $this->assertEquals(100, $frame->offsetLeft());\n        $this->assertEquals(200, $frame->offsetTop());\n    }\n\n    public function testToImage(): void\n    {\n        $frame = $this->getTestFrame();\n        $this->assertInstanceOf(Image::class, $frame->toImage(new Driver()));\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/ImageTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick;\n\nuse Imagick;\nuse Intervention\\Image\\Analyzers\\WidthAnalyzer;\nuse Intervention\\Image\\Collection;\nuse Intervention\\Image\\Colors\\Cmyk\\Colorspace as CmykColorspace;\nuse Intervention\\Image\\Colors\\Rgb\\Colorspace as RgbColorspace;\nuse Intervention\\Image\\Drivers\\Imagick\\Core;\nuse Intervention\\Image\\Drivers\\Imagick\\Driver;\nuse Intervention\\Image\\Drivers\\Imagick\\Frame;\nuse Intervention\\Image\\EncodedImage;\nuse Intervention\\Image\\Encoders\\PngEncoder;\nuse Intervention\\Image\\Exceptions\\ColorException;\nuse Intervention\\Image\\Exceptions\\EncoderException;\nuse Intervention\\Image\\Image;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Interfaces\\ColorspaceInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\ResolutionInterface;\nuse Intervention\\Image\\Interfaces\\SizeInterface;\nuse Intervention\\Image\\Modifiers\\GreyscaleModifier;\nuse Intervention\\Image\\Origin;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(Image::class)]\nfinal class ImageTest extends ImagickTestCase\n{\n    protected Image $image;\n\n    protected function setUp(): void\n    {\n        $imagick = new Imagick();\n        $imagick->readImage($this->getTestResourcePath('animation.gif'));\n        $this->image = new Image(\n            new Driver(),\n            new Core($imagick),\n            new Collection([\n                'test' => 'foo'\n            ]),\n        );\n    }\n\n    public function testClone(): void\n    {\n        $image = $this->readTestImage('gradient.gif');\n        $clone = clone $image;\n\n        $this->assertEquals(16, $image->width());\n        $this->assertEquals(16, $clone->width());\n        $result = $clone->crop(4, 4);\n        $this->assertEquals(16, $image->width());\n        $this->assertEquals(4, $clone->width());\n        $this->assertEquals(4, $result->width());\n\n        $this->assertEquals('ff0000', $image->pickColor(0, 0)->toHex());\n        $this->assertTransparency($image->pickColor(1, 0));\n\n        $this->assertEquals('ff0000', $clone->pickColor(0, 0)->toHex());\n        $this->assertTransparency($clone->pickColor(1, 0));\n    }\n\n    public function testDriver(): void\n    {\n        $this->assertInstanceOf(Driver::class, $this->image->driver());\n    }\n\n    public function testCore(): void\n    {\n        $this->assertInstanceOf(Core::class, $this->image->core());\n    }\n\n    public function testCount(): void\n    {\n        $this->assertEquals(8, $this->image->count());\n    }\n\n    public function testIteration(): void\n    {\n        foreach ($this->image as $frame) {\n            $this->assertInstanceOf(Frame::class, $frame);\n        }\n    }\n\n    public function testIsAnimated(): void\n    {\n        $this->assertTrue($this->image->isAnimated());\n    }\n\n    public function testSetGetLoops(): void\n    {\n        $this->assertEquals(3, $this->image->loops());\n        $result = $this->image->setLoops(10);\n        $this->assertInstanceOf(ImageInterface::class, $result);\n        $this->assertEquals(10, $this->image->loops());\n    }\n\n    public function testSetGetOrigin(): void\n    {\n        $origin = $this->image->origin();\n        $this->assertInstanceOf(Origin::class, $origin);\n        $this->image->setOrigin(new Origin('test1', 'test2'));\n        $this->assertInstanceOf(Origin::class, $this->image->origin());\n        $this->assertEquals('test1', $this->image->origin()->mimetype());\n        $this->assertEquals('test2', $this->image->origin()->filePath());\n    }\n\n    public function testRemoveAnimation(): void\n    {\n        $this->assertTrue($this->image->isAnimated());\n        $result = $this->image->removeAnimation();\n        $this->assertInstanceOf(ImageInterface::class, $result);\n        $this->assertFalse($this->image->isAnimated());\n    }\n\n    public function testSliceAnimation(): void\n    {\n        $this->assertEquals(8, $this->image->count());\n        $result = $this->image->sliceAnimation(0, 2);\n        $this->assertInstanceOf(ImageInterface::class, $result);\n        $this->assertEquals(2, $this->image->count());\n    }\n\n    public function testExif(): void\n    {\n        $this->assertInstanceOf(Collection::class, $this->image->exif());\n        $this->assertEquals('foo', $this->image->exif('test'));\n    }\n\n    public function testModify(): void\n    {\n        $result = $this->image->modify(new GreyscaleModifier());\n        $this->assertInstanceOf(Image::class, $result);\n    }\n\n    public function testAnalyze(): void\n    {\n        $result = $this->image->analyze(new WidthAnalyzer());\n        $this->assertEquals(20, $result);\n    }\n\n    public function testEncode(): void\n    {\n        $result = $this->image->encode(new PngEncoder());\n        $this->assertInstanceOf(EncodedImage::class, $result);\n    }\n\n    public function testAutoEncode(): void\n    {\n        $result = $this->readTestImage('blue.gif')->encode();\n        $this->assertInstanceOf(EncodedImage::class, $result);\n        $this->assertMediaType('image/gif', $result);\n    }\n\n    public function testEncodeByMediaType(): void\n    {\n        $result = $this->readTestImage('blue.gif')->encodeByMediaType();\n        $this->assertInstanceOf(EncodedImage::class, $result);\n        $this->assertMediaType('image/gif', $result);\n\n        $result = $this->readTestImage('blue.gif')->encodeByMediaType('image/png');\n        $this->assertInstanceOf(EncodedImage::class, $result);\n        $this->assertMediaType('image/png', $result);\n    }\n\n    public function testEncodeByExtension(): void\n    {\n        $result = $this->readTestImage('blue.gif')->encodeByExtension();\n        $this->assertInstanceOf(EncodedImage::class, $result);\n        $this->assertMediaType('image/gif', $result);\n\n        $result = $this->readTestImage('blue.gif')->encodeByExtension('png');\n        $this->assertInstanceOf(EncodedImage::class, $result);\n        $this->assertMediaType('image/png', $result);\n    }\n\n    public function testEncodeByPath(): void\n    {\n        $result = $this->readTestImage('blue.gif')->encodeByPath();\n        $this->assertInstanceOf(EncodedImage::class, $result);\n        $this->assertMediaType('image/gif', $result);\n\n        $result = $this->readTestImage('blue.gif')->encodeByPath('foo/bar.png');\n        $this->assertInstanceOf(EncodedImage::class, $result);\n        $this->assertMediaType('image/png', $result);\n    }\n\n    public function testSaveAsFormat(): void\n    {\n        $path = __DIR__ . '/tmp.png';\n        $result = $this->readTestImage('blue.gif')->save($path);\n        $this->assertInstanceOf(Image::class, $result);\n        $this->assertFileExists($path);\n        $this->assertMediaType('image/png', file_get_contents($path));\n        unlink($path);\n    }\n\n    public function testSaveFallback(): void\n    {\n        $path = __DIR__ . '/tmp.unknown';\n        $result = $this->readTestImage('blue.gif')->save($path);\n        $this->assertInstanceOf(Image::class, $result);\n        $this->assertFileExists($path);\n        $this->assertMediaType('image/gif', file_get_contents($path));\n        unlink($path);\n    }\n\n    public function testSaveUndeterminedPath(): void\n    {\n        $this->expectException(EncoderException::class);\n        $this->createTestImage(2, 3)->save();\n    }\n\n    public function testWidthHeightSize(): void\n    {\n        $this->assertEquals(20, $this->image->width());\n        $this->assertEquals(15, $this->image->height());\n        $this->assertInstanceOf(SizeInterface::class, $this->image->size());\n    }\n\n    public function testSetGetColorspace(): void\n    {\n        $this->assertInstanceOf(ColorspaceInterface::class, $this->image->colorspace());\n        $this->assertInstanceOf(RgbColorspace::class, $this->image->colorspace());\n        $result = $this->image->setColorspace(CmykColorspace::class);\n        $this->assertInstanceOf(ImageInterface::class, $result);\n        $this->assertInstanceOf(CmykColorspace::class, $this->image->colorspace());\n    }\n\n    public function testSetGetResolution(): void\n    {\n        $resolution = $this->image->resolution();\n        $this->assertInstanceOf(ResolutionInterface::class, $resolution);\n        $this->assertEquals(0, $resolution->x());\n        $this->assertEquals(0, $resolution->y());\n        $result = $this->image->setResolution(300, 300);\n        $resolution = $this->image->resolution();\n        $this->assertInstanceOf(ImageInterface::class, $result);\n        $this->assertEquals(300, $resolution->x());\n        $this->assertEquals(300, $resolution->y());\n    }\n\n    public function testPickColor(): void\n    {\n        $this->assertInstanceOf(ColorInterface::class, $this->image->pickColor(0, 0));\n        $this->assertInstanceOf(ColorInterface::class, $this->image->pickColor(0, 0, 1));\n    }\n\n    public function testPickColors(): void\n    {\n        $result = $this->image->pickColors(0, 0);\n        $this->assertInstanceOf(Collection::class, $result);\n        $this->assertEquals(8, $result->count());\n    }\n\n    public function testProfile(): void\n    {\n        $this->expectException(ColorException::class);\n        $this->image->profile();\n    }\n\n    public function testReduceColors(): void\n    {\n        $image = $this->readTestImage();\n        $result = $image->reduceColors(8);\n        $this->assertInstanceOf(ImageInterface::class, $result);\n    }\n\n    public function testSharpen(): void\n    {\n        $this->assertInstanceOf(Image::class, $this->image->sharpen(12));\n    }\n\n    public function testBlendTransparencyDefault(): void\n    {\n        $image = $this->readTestImage('gradient.gif');\n        $this->assertColor(0, 0, 0, 0, $image->pickColor(1, 0));\n        $result = $image->blendTransparency();\n        $this->assertColor(255, 255, 255, 255, $image->pickColor(1, 0));\n        $this->assertColor(255, 255, 255, 255, $result->pickColor(1, 0));\n    }\n\n    public function testBlendTransparencyArgument(): void\n    {\n        $image = $this->readTestImage('gradient.gif');\n        $this->assertColor(0, 0, 0, 0, $image->pickColor(1, 0));\n        $result = $image->blendTransparency('ff5500');\n        $this->assertColor(255, 85, 0, 255, $image->pickColor(1, 0));\n        $this->assertColor(255, 85, 0, 255, $result->pickColor(1, 0));\n    }\n\n    public function testBlendTransparencyIgnoreTransparencyInBlendingColor(): void\n    {\n        $image = $this->readTestImage('gradient.gif');\n        $this->assertColor(0, 0, 0, 0, $image->pickColor(1, 0));\n        $result = $image->blendTransparency('ff550055');\n        $this->assertColor(255, 85, 0, 255, $image->pickColor(1, 0));\n        $this->assertColor(255, 85, 0, 255, $result->pickColor(1, 0));\n    }\n\n    public function testToJpeg(): void\n    {\n        $this->assertMediaType('image/jpeg', $this->image->toJpeg());\n        $this->assertMediaType('image/jpeg', $this->image->toJpg());\n    }\n\n    public function testToJpeg2000(): void\n    {\n        $this->assertMediaType('image/jp2', $this->image->toJpeg2000());\n        $this->assertMediaType('image/jp2', $this->image->toJp2());\n    }\n\n    public function testToPng(): void\n    {\n        $this->assertMediaType('image/png', $this->image->toPng());\n    }\n\n    public function testToGif(): void\n    {\n        $this->assertMediaType('image/gif', $this->image->toGif());\n    }\n\n    public function testToWebp(): void\n    {\n        $this->assertMediaType('image/webp', $this->image->toWebp());\n    }\n\n    public function testToBitmap(): void\n    {\n        $this->assertMediaTypeBitmap($this->image->toBitmap());\n        $this->assertMediaTypeBitmap($this->image->toBmp());\n    }\n\n    public function testToAvif(): void\n    {\n        $this->assertMediaType('image/avif', $this->image->toAvif());\n    }\n\n    public function testToTiff(): void\n    {\n        $this->assertMediaType('image/tiff', $this->image->toTiff());\n        $this->assertMediaType('image/tiff', $this->image->toTif());\n    }\n\n    public function testToHeic(): void\n    {\n        $this->assertMediaType('image/heic', $this->image->toHeic());\n    }\n\n    public function testInvert(): void\n    {\n        $image = $this->readTestImage('trim.png');\n        $this->assertEquals('00aef0', $image->pickColor(0, 0)->toHex());\n        $this->assertEquals('ffa601', $image->pickColor(25, 25)->toHex());\n        $result = $image->invert();\n        $this->assertInstanceOf(ImageInterface::class, $result);\n        $this->assertEquals('ff510f', $image->pickColor(0, 0)->toHex());\n        $this->assertEquals('0059fe', $image->pickColor(25, 25)->toHex());\n    }\n\n    public function testPixelate(): void\n    {\n        $image = $this->readTestImage('trim.png');\n        $this->assertEquals('00aef0', $image->pickColor(0, 0)->toHex());\n        $this->assertEquals('00aef0', $image->pickColor(14, 14)->toHex());\n\n        $result = $image->pixelate(10);\n        $this->assertInstanceOf(ImageInterface::class, $result);\n\n        [$r, $g, $b] = $image->pickColor(0, 0)->toArray();\n        $this->assertEquals(0, $r);\n        $this->assertEquals(174, $g);\n        $this->assertEquals(240, $b);\n\n        [$r, $g, $b] = $image->pickColor(14, 14)->toArray();\n        $this->assertEquals(107, $r);\n        $this->assertEquals(171, $g);\n        $this->assertEquals(140, $b);\n    }\n\n    public function testGreyscale(): void\n    {\n        $image = $this->readTestImage('trim.png');\n        $this->assertFalse($image->pickColor(0, 0)->isGreyscale());\n        $result = $image->greyscale();\n        $this->assertInstanceOf(ImageInterface::class, $result);\n        $this->assertTrue($image->pickColor(0, 0)->isGreyscale());\n    }\n\n    public function testBrightness(): void\n    {\n        $image = $this->readTestImage('trim.png');\n        $this->assertEquals('00aef0', $image->pickColor(14, 14)->toHex());\n        $result = $image->brightness(30);\n        $this->assertInstanceOf(ImageInterface::class, $result);\n        $this->assertEquals('39c9ff', $image->pickColor(14, 14)->toHex());\n    }\n\n    public function testDebugInfo(): void\n    {\n        $info = $this->readTestImage('trim.png')->__debugInfo();\n        $this->assertArrayHasKey('width', $info);\n        $this->assertArrayHasKey('height', $info);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Modifiers/BlurModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\BlurModifier;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\BlurModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Imagick\\Modifiers\\BlurModifier::class)]\nfinal class BlurModifierTest extends ImagickTestCase\n{\n    public function testColorChange(): void\n    {\n        $image = $this->readTestImage('trim.png');\n        $this->assertEquals('00aef0', $image->pickColor(14, 14)->toHex());\n        $image->modify(new BlurModifier(30));\n        $this->assertEquals('42acb2', $image->pickColor(14, 14)->toHex());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Modifiers/BrightnessModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\BrightnessModifier;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\BrightnessModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Imagick\\Modifiers\\BrightnessModifier::class)]\nfinal class BrightnessModifierTest extends ImagickTestCase\n{\n    public function testApply(): void\n    {\n        $image = $this->readTestImage('trim.png');\n        $this->assertEquals('00aef0', $image->pickColor(14, 14)->toHex());\n        $image->modify(new BrightnessModifier(30));\n        $this->assertEquals('39c9ff', $image->pickColor(14, 14)->toHex());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Modifiers/ColorizeModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\ColorizeModifier;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\ColorizeModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Imagick\\Modifiers\\ColorizeModifier::class)]\nfinal class ColorizeModifierTest extends ImagickTestCase\n{\n    public function testModify(): void\n    {\n        $image = $this->readTestImage('tile.png');\n        $image = $image->modify(new ColorizeModifier(100, -100, -100));\n        $this->assertColor(251, 0, 0, 255, $image->pickColor(5, 5));\n        $this->assertColor(239, 0, 0, 255, $image->pickColor(15, 15));\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Modifiers/ContainModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\ContainModifier;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\ContainModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Imagick\\Modifiers\\ContainModifier::class)]\nfinal class ContainModifierTest extends ImagickTestCase\n{\n    public function testModify(): void\n    {\n        $image = $this->readTestImage('blocks.png');\n        $this->assertEquals(640, $image->width());\n        $this->assertEquals(480, $image->height());\n        $result = $image->modify(new ContainModifier(200, 100, 'ff0'));\n        $this->assertEquals(200, $image->width());\n        $this->assertEquals(100, $image->height());\n        $this->assertColor(255, 255, 0, 255, $image->pickColor(0, 0));\n        $this->assertColor(0, 0, 0, 0, $image->pickColor(140, 10));\n        $this->assertColor(255, 255, 0, 255, $image->pickColor(175, 10));\n        $this->assertEquals(200, $result->width());\n        $this->assertEquals(100, $result->height());\n        $this->assertColor(255, 255, 0, 255, $result->pickColor(0, 0));\n        $this->assertColor(0, 0, 0, 0, $result->pickColor(140, 10));\n        $this->assertColor(255, 255, 0, 255, $result->pickColor(175, 10));\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Modifiers/ContrastModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\ContrastModifier;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\ContrastModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Imagick\\Modifiers\\ContrastModifier::class)]\nfinal class ContrastModifierTest extends ImagickTestCase\n{\n    public function testApply(): void\n    {\n        $image = $this->readTestImage('trim.png');\n        $this->assertEquals('00aef0', $image->pickColor(14, 14)->toHex());\n        $image->modify(new ContrastModifier(30));\n        $this->assertEquals('00fcff', $image->pickColor(14, 14)->toHex());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Modifiers/CoverDownModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\CoverDownModifier;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\CoverModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Imagick\\Modifiers\\CoverModifier::class)]\nfinal class CoverDownModifierTest extends ImagickTestCase\n{\n    public function testModify(): void\n    {\n        $image = $this->readTestImage('blocks.png');\n        $this->assertEquals(640, $image->width());\n        $this->assertEquals(480, $image->height());\n        $image->modify(new CoverDownModifier(100, 100, 'center'));\n        $this->assertEquals(100, $image->width());\n        $this->assertEquals(100, $image->height());\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(90, 90));\n        $this->assertColor(0, 255, 0, 255, $image->pickColor(65, 70));\n        $this->assertColor(0, 0, 255, 255, $image->pickColor(70, 52));\n        $this->assertTransparency($image->pickColor(90, 30));\n    }\n\n    public function testModifyOddSize(): void\n    {\n        $image = $this->createTestImage(375, 250);\n        $image->modify(new CoverDownModifier(240, 90, 'center'));\n        $this->assertEquals(240, $image->width());\n        $this->assertEquals(90, $image->height());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Modifiers/CoverModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\CoverModifier;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\CoverModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Imagick\\Modifiers\\CoverModifier::class)]\nfinal class CoverModifierTest extends ImagickTestCase\n{\n    public function testModify(): void\n    {\n        $image = $this->readTestImage('blocks.png');\n        $this->assertEquals(640, $image->width());\n        $this->assertEquals(480, $image->height());\n        $image->modify(new CoverModifier(100, 100, 'center'));\n        $this->assertEquals(100, $image->width());\n        $this->assertEquals(100, $image->height());\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(90, 90));\n        $this->assertColor(0, 255, 0, 255, $image->pickColor(65, 70));\n        $this->assertColor(0, 0, 255, 255, $image->pickColor(70, 52));\n        $this->assertTransparency($image->pickColor(90, 30));\n    }\n\n    public function testModifyOddSize(): void\n    {\n        $image = $this->createTestImage(375, 250);\n        $image->modify(new CoverModifier(240, 90, 'center'));\n        $this->assertEquals(240, $image->width());\n        $this->assertEquals(90, $image->height());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Modifiers/CropModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Modifiers;\n\nuse Intervention\\Image\\Colors\\Cmyk\\Colorspace;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\CropModifier;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\CropModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Imagick\\Modifiers\\CropModifier::class)]\nfinal class CropModifierTest extends ImagickTestCase\n{\n    public function testModify(): void\n    {\n        $image = $this->readTestImage('blocks.png');\n        $image = $image->modify(new CropModifier(200, 200, 0, 0, 'ffffff', 'bottom-right'));\n        $this->assertEquals(200, $image->width());\n        $this->assertEquals(200, $image->height());\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(5, 5));\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(100, 100));\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(190, 190));\n    }\n\n    public function testModifyExtend(): void\n    {\n        $image = $this->readTestImage('blocks.png');\n        $image = $image->modify(new CropModifier(800, 100, -10, -10, 'ff0000', 'top-left'));\n        $this->assertEquals(800, $image->width());\n        $this->assertEquals(100, $image->height());\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(9, 9));\n        $this->assertColor(0, 0, 255, 255, $image->pickColor(16, 16));\n        $this->assertColor(0, 0, 255, 255, $image->pickColor(445, 16));\n        $this->assertTransparency($image->pickColor(460, 16));\n    }\n\n    public function testModifySinglePixel(): void\n    {\n        $image = $this->createTestImage(1, 1);\n        $this->assertEquals(1, $image->width());\n        $this->assertEquals(1, $image->height());\n        $image->modify(new CropModifier(3, 3, 0, 0, 'ff0', 'center'));\n        $this->assertEquals(3, $image->width());\n        $this->assertEquals(3, $image->height());\n        $this->assertColor(255, 255, 0, 255, $image->pickColor(0, 0));\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(1, 1));\n        $this->assertColor(255, 255, 0, 255, $image->pickColor(2, 2));\n    }\n\n    public function testModifyKeepsColorspace(): void\n    {\n        $image = $this->readTestImage('cmyk.jpg');\n        $this->assertInstanceOf(Colorspace::class, $image->colorspace());\n        $image = $image->modify(new CropModifier(800, 100, -10, -10, 'ff0000'));\n        $this->assertInstanceOf(Colorspace::class, $image->colorspace());\n    }\n\n    public function testModifyKeepsResolution(): void\n    {\n        $image = $this->readTestImage('300dpi.png');\n        $this->assertEquals(300, round($image->resolution()->perInch()->x()));\n        $image = $image->modify(new CropModifier(800, 100, -10, -10, 'ff0000'));\n        $this->assertEquals(300, round($image->resolution()->perInch()->x()));\n    }\n\n    public function testHalfTransparent(): void\n    {\n        $image = $this->createTestImage(16, 16);\n        $image->modify(new CropModifier(32, 32, 0, 0, '00f5', 'center'));\n        $this->assertEquals(32, $image->width());\n        $this->assertEquals(32, $image->height());\n        $this->assertColor(0, 0, 255, 77, $image->pickColor(5, 5));\n        $this->assertColor(0, 0, 255, 77, $image->pickColor(16, 5));\n        $this->assertColor(0, 0, 255, 77, $image->pickColor(30, 5));\n        $this->assertColor(0, 0, 255, 77, $image->pickColor(5, 16));\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(16, 16));\n        $this->assertColor(0, 0, 255, 77, $image->pickColor(30, 16));\n        $this->assertColor(0, 0, 255, 77, $image->pickColor(5, 30));\n        $this->assertColor(0, 0, 255, 77, $image->pickColor(16, 30));\n        $this->assertColor(0, 0, 255, 77, $image->pickColor(30, 30));\n    }\n\n    public function testMergeTransparentBackgrounds(): void\n    {\n        $image = $this->createTestImage(1, 1)->fill('f00');\n        $this->assertEquals(1, $image->width());\n        $this->assertEquals(1, $image->height());\n        $image->modify(new CropModifier(3, 3, 0, 0, '00f7', 'center'));\n        $this->assertEquals(3, $image->width());\n        $this->assertEquals(3, $image->height());\n        $this->assertColor(0, 0, 255, 127, $image->pickColor(0, 0), 1);\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(1, 1));\n        $this->assertColor(0, 0, 255, 127, $image->pickColor(2, 2), 1);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Modifiers/DrawBezierModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\DrawBezierModifier;\nuse Intervention\\Image\\Geometry\\Point;\nuse Intervention\\Image\\Geometry\\Bezier;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\DrawBezierModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Imagick\\Modifiers\\DrawBezierModifier::class)]\nfinal class DrawBezierModifierTest extends ImagickTestCase\n{\n    public function testApply(): void\n    {\n        $image = $this->readTestImage('trim.png');\n        $this->assertEquals('00aef0', $image->pickColor(14, 14)->toHex());\n        $drawable = new Bezier([\n            new Point(0, 0),\n            new Point(15, 0),\n            new Point(15, 15),\n            new Point(0, 15)\n        ]);\n        $drawable->setBackgroundColor('b53717');\n        $image->modify(new DrawBezierModifier($drawable));\n        $this->assertEquals('b53717', $image->pickColor(5, 5)->toHex());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Modifiers/DrawEllipseModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\DrawEllipseModifier;\nuse Intervention\\Image\\Geometry\\Ellipse;\nuse Intervention\\Image\\Geometry\\Point;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\DrawEllipseModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Imagick\\Modifiers\\DrawEllipseModifier::class)]\nfinal class DrawEllipseModifierTest extends ImagickTestCase\n{\n    public function testApply(): void\n    {\n        $image = $this->readTestImage('trim.png');\n        $this->assertEquals('00aef0', $image->pickColor(14, 14)->toHex());\n        $drawable = new Ellipse(10, 10, new Point(14, 14));\n        $drawable->setBackgroundColor('b53717');\n        $image->modify(new DrawEllipseModifier($drawable));\n        $this->assertEquals('b53717', $image->pickColor(14, 14)->toHex());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Modifiers/DrawLineModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\DrawLineModifier;\nuse Intervention\\Image\\Geometry\\Line;\nuse Intervention\\Image\\Geometry\\Point;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\DrawLineModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Imagick\\Modifiers\\DrawLineModifier::class)]\nfinal class DrawLineModifierTest extends ImagickTestCase\n{\n    public function testApply(): void\n    {\n        $image = $this->readTestImage('trim.png');\n        $this->assertEquals('00aef0', $image->pickColor(14, 14)->toHex());\n        $line = new Line(new Point(0, 0), new Point(10, 0), 4);\n        $line->setBackgroundColor('b53517');\n        $image->modify(new DrawLineModifier($line));\n        $this->assertEquals('b53517', $image->pickColor(0, 0)->toHex());\n    }\n\n    public function testApplyTransparent(): void\n    {\n        $image = $this->createTestImage(10, 10)->fill('ff5500');\n        $this->assertColor(255, 85, 0, 255, $image->pickColor(5, 5));\n        $line = new Line(new Point(0, 5), new Point(10, 5), 4);\n        $line->setBackgroundColor('fff4');\n        $image->modify(new DrawLineModifier($line));\n        $this->assertColor(255, 136, 77, 255, $image->pickColor(5, 5));\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Modifiers/DrawPixelModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\DrawPixelModifier;\nuse Intervention\\Image\\Geometry\\Point;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\DrawPixelModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Imagick\\Modifiers\\DrawPixelModifier::class)]\nfinal class DrawPixelModifierTest extends ImagickTestCase\n{\n    public function testApply(): void\n    {\n        $image = $this->readTestImage('trim.png');\n        $this->assertEquals('00aef0', $image->pickColor(14, 14)->toHex());\n        $image->modify(new DrawPixelModifier(new Point(14, 14), 'ffffff'));\n        $this->assertEquals('ffffff', $image->pickColor(14, 14)->toHex());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Modifiers/DrawPolygonModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\DrawPolygonModifier;\nuse Intervention\\Image\\Geometry\\Point;\nuse Intervention\\Image\\Geometry\\Polygon;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\DrawPolygonModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Imagick\\Modifiers\\DrawPolygonModifier::class)]\nfinal class DrawPolygonModifierTest extends ImagickTestCase\n{\n    public function testApply(): void\n    {\n        $image = $this->readTestImage('trim.png');\n        $this->assertEquals('00aef0', $image->pickColor(14, 14)->toHex());\n        $drawable = new Polygon([new Point(0, 0), new Point(15, 15), new Point(20, 20)]);\n        $drawable->setBackgroundColor('b53717');\n        $image->modify(new DrawPolygonModifier($drawable));\n        $this->assertEquals('b53717', $image->pickColor(14, 14)->toHex());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Modifiers/DrawRectangleModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\DrawRectangleModifier;\nuse Intervention\\Image\\Geometry\\Point;\nuse Intervention\\Image\\Geometry\\Rectangle;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\DrawRectangleModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Imagick\\Modifiers\\DrawRectangleModifier::class)]\nfinal class DrawRectangleModifierTest extends ImagickTestCase\n{\n    public function testApply(): void\n    {\n        $image = $this->readTestImage('trim.png');\n        $this->assertEquals('00aef0', $image->pickColor(14, 14)->toHex());\n        $rectangle = new Rectangle(300, 200, new Point(14, 14));\n        $rectangle->setBackgroundColor('ffffff');\n        $image->modify(new DrawRectangleModifier($rectangle));\n        $this->assertEquals('ffffff', $image->pickColor(14, 14)->toHex());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Modifiers/FillModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Colors\\Rgb\\Color;\nuse Intervention\\Image\\Modifiers\\FillModifier;\nuse Intervention\\Image\\Geometry\\Point;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\FillModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Imagick\\Modifiers\\FillModifier::class)]\nfinal class FillModifierTest extends ImagickTestCase\n{\n    public function testFloodFillColor(): void\n    {\n        $image = $this->readTestImage('blocks.png');\n        $this->assertEquals('0000ff', $image->pickColor(420, 270)->toHex());\n        $this->assertEquals('ff0000', $image->pickColor(540, 400)->toHex());\n        $image->modify(new FillModifier(new Color(204, 204, 204), new Point(540, 400)));\n        $this->assertEquals('0000ff', $image->pickColor(420, 270)->toHex());\n        $this->assertEquals('cccccc', $image->pickColor(540, 400)->toHex());\n    }\n\n    public function testFillAllColor(): void\n    {\n        $image = $this->readTestImage('blocks.png');\n        $this->assertEquals('0000ff', $image->pickColor(420, 270)->toHex());\n        $this->assertEquals('ff0000', $image->pickColor(540, 400)->toHex());\n        $image->modify(new FillModifier(new Color(204, 204, 204)));\n        $this->assertEquals('cccccc', $image->pickColor(420, 270)->toHex());\n        $this->assertEquals('cccccc', $image->pickColor(540, 400)->toHex());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Modifiers/FlipFlopModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\FlipModifier;\nuse Intervention\\Image\\Modifiers\\FlopModifier;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\FlipModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\FlopModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Imagick\\Modifiers\\FlipModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Imagick\\Modifiers\\FlopModifier::class)]\nfinal class FlipFlopModifierTest extends ImagickTestCase\n{\n    public function testFlipImage(): void\n    {\n        $image = $this->readTestImage('tile.png');\n        $this->assertEquals('b4e000', $image->pickColor(0, 0)->toHex());\n        $image->modify(new FlipModifier());\n        $this->assertEquals('00000000', $image->pickColor(0, 0)->toHex());\n    }\n\n    public function testFlopImage(): void\n    {\n        $image = $this->readTestImage('tile.png');\n        $this->assertEquals('b4e000', $image->pickColor(0, 0)->toHex());\n        $image->modify(new FlopModifier());\n        $this->assertEquals('00000000', $image->pickColor(0, 0)->toHex());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Modifiers/GammaModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\GammaModifier;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\GammaModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Imagick\\Modifiers\\GammaModifier::class)]\nfinal class GammaModifierTest extends ImagickTestCase\n{\n    public function testModifier(): void\n    {\n        $image = $this->readTestImage('trim.png');\n        $this->assertEquals('00aef0', $image->pickColor(0, 0)->toHex());\n        $image->modify(new GammaModifier(2.1));\n        $this->assertEquals('00d5f8', $image->pickColor(0, 0)->toHex());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Modifiers/GreyscaleModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\GreyscaleModifier;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\GreyscaleModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Imagick\\Modifiers\\GreyscaleModifier::class)]\nfinal class GreyscaleModifierTest extends ImagickTestCase\n{\n    public function testColorChange(): void\n    {\n        $image = $this->readTestImage('trim.png');\n        $this->assertFalse($image->pickColor(0, 0)->isGreyscale());\n        $image->modify(new GreyscaleModifier());\n        $this->assertTrue($image->pickColor(0, 0)->isGreyscale());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Modifiers/InvertModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\InvertModifier;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\InvertModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Imagick\\Modifiers\\InvertModifier::class)]\nfinal class InvertModifierTest extends ImagickTestCase\n{\n    public function testApply(): void\n    {\n        $image = $this->readTestImage('trim.png');\n        $this->assertEquals('00aef0', $image->pickColor(0, 0)->toHex());\n        $this->assertEquals('ffa601', $image->pickColor(25, 25)->toHex());\n        $image->modify(new InvertModifier());\n        $this->assertEquals('ff510f', $image->pickColor(0, 0)->toHex());\n        $this->assertEquals('0059fe', $image->pickColor(25, 25)->toHex());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Modifiers/PadModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\PadModifier;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\PadModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Imagick\\Modifiers\\PadModifier::class)]\nfinal class PadModifierTest extends ImagickTestCase\n{\n    public function testModify(): void\n    {\n        $image = $this->readTestImage('blue.gif');\n        $this->assertEquals(16, $image->width());\n        $this->assertEquals(16, $image->height());\n        $image->modify(new PadModifier(30, 20, 'f00'));\n        $this->assertEquals(30, $image->width());\n        $this->assertEquals(20, $image->height());\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(0, 0));\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(0, 19));\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(29, 0));\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(29, 19));\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(6, 2));\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(7, 1));\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(6, 17));\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(7, 18));\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(23, 1));\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(23, 2));\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(23, 17));\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(23, 18));\n        $this->assertColor(100, 100, 255, 255, $image->pickColor(7, 2));\n        $this->assertColor(100, 100, 255, 255, $image->pickColor(22, 2));\n        $this->assertColor(100, 100, 255, 255, $image->pickColor(7, 17));\n        $this->assertColor(100, 100, 255, 255, $image->pickColor(22, 17));\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Modifiers/PixelateModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\PixelateModifier;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\PixelateModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Imagick\\Modifiers\\PixelateModifier::class)]\nfinal class PixelateModifierTest extends ImagickTestCase\n{\n    public function testModify(): void\n    {\n        $image = $this->readTestImage('trim.png');\n        $this->assertEquals('00aef0', $image->pickColor(0, 0)->toHex());\n        $this->assertEquals('00aef0', $image->pickColor(14, 14)->toHex());\n        $image->modify(new PixelateModifier(10));\n\n        [$r, $g, $b] = $image->pickColor(0, 0)->toArray();\n        $this->assertEquals(0, $r);\n        $this->assertEquals(174, $g);\n        $this->assertEquals(240, $b);\n\n        [$r, $g, $b] = $image->pickColor(14, 14)->toArray();\n        $this->assertEquals(107, $r);\n        $this->assertEquals(171, $g);\n        $this->assertEquals(140, $b);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Modifiers/PlaceModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\PlaceModifier;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\nuse Intervention\\Image\\Drivers\\Imagick\\Modifiers\\PlaceModifier as PlaceModifierImagick;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(PlaceModifier::class)]\n#[CoversClass(PlaceModifierImagick::class)]\nfinal class PlaceModifierTest extends ImagickTestCase\n{\n    public function testColorChange(): void\n    {\n        $image = $this->readTestImage('test.jpg');\n        $this->assertEquals('febc44', $image->pickColor(300, 25)->toHex());\n        $image->modify(new PlaceModifier($this->getTestResourcePath('circle.png'), 'top-right', 0, 0));\n        $this->assertEquals('33260e', $image->pickColor(300, 25)->toHex());\n    }\n\n    public function testColorChangeOpacityPng(): void\n    {\n        $image = $this->readTestImage('test.jpg');\n        $this->assertEquals('febc44', $image->pickColor(300, 25)->toHex());\n        $image->modify(new PlaceModifier($this->getTestResourcePath('circle.png'), 'top-right', 0, 0, 50));\n        $this->assertColor(152, 112, 40, 255, $image->pickColor(300, 25), tolerance: 1);\n        $this->assertColor(255, 202, 107, 255, $image->pickColor(274, 5), tolerance: 1);\n    }\n\n    public function testColorChangeOpacityJpeg(): void\n    {\n        $image = $this->createTestImage(16, 16)->fill('0000ff');\n        $this->assertEquals('0000ff', $image->pickColor(10, 10)->toHex());\n        $image->modify(new PlaceModifier($this->getTestResourcePath('exif.jpg'), opacity: 50));\n        $this->assertColor(127, 83, 127, 255, $image->pickColor(10, 10), tolerance: 1);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Modifiers/QuantizeColorsModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Exceptions\\InputException;\nuse Intervention\\Image\\Modifiers\\QuantizeColorsModifier;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\QuantizeColorsModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Imagick\\Modifiers\\QuantizeColorsModifier::class)]\nfinal class QuantizeColorsModifierTest extends ImagickTestCase\n{\n    public function testColorChange(): void\n    {\n        $image = $this->readTestImage('gradient.bmp');\n        $this->assertEquals(15, $image->core()->native()->getImageColors());\n        $image->modify(new QuantizeColorsModifier(4));\n        $this->assertEquals(4, $image->core()->native()->getImageColors());\n    }\n\n    public function testNoColorReduction(): void\n    {\n        $image = $this->readTestImage('gradient.bmp');\n        $this->assertEquals(15, $image->core()->native()->getImageColors());\n        $image->modify(new QuantizeColorsModifier(150));\n        $this->assertEquals(15, $image->core()->native()->getImageColors());\n    }\n\n    public function testInvalidColorInput(): void\n    {\n        $image = $this->readTestImage('gradient.bmp');\n        $this->expectException(InputException::class);\n        $image->modify(new QuantizeColorsModifier(0));\n    }\n\n    public function testVerifyColorValueAfterQuantization(): void\n    {\n        $image = $this->createTestImage(3, 2)->fill('f00');\n        $image->modify(new QuantizeColorsModifier(1));\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(1, 1));\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Modifiers/RemoveAnimationModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Exceptions\\InputException;\nuse Intervention\\Image\\Modifiers\\RemoveAnimationModifier;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\RemoveAnimationModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Imagick\\Modifiers\\RemoveAnimationModifier::class)]\nfinal class RemoveAnimationModifierTest extends ImagickTestCase\n{\n    public function testApply(): void\n    {\n        $image = $this->readTestImage('animation.gif');\n        $this->assertEquals(8, count($image));\n        $result = $image->modify(new RemoveAnimationModifier(2));\n        $this->assertEquals(1, count($image));\n        $this->assertEquals(1, count($result));\n    }\n\n    public function testApplyPercent(): void\n    {\n        $image = $this->readTestImage('animation.gif');\n        $this->assertEquals(8, count($image));\n        $result = $image->modify(new RemoveAnimationModifier('20%'));\n        $this->assertEquals(1, count($image));\n        $this->assertEquals(1, count($result));\n    }\n\n    public function testApplyNonAnimated(): void\n    {\n        $image = $this->readTestImage('test.jpg');\n        $this->assertEquals(1, count($image));\n        $result = $image->modify(new RemoveAnimationModifier());\n        $this->assertEquals(1, count($image));\n        $this->assertEquals(1, count($result));\n    }\n\n    public function testApplyInvalid(): void\n    {\n        $image = $this->readTestImage('animation.gif');\n        $this->expectException(InputException::class);\n        $image->modify(new RemoveAnimationModifier('test'));\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Modifiers/ResizeCanvasModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\ResizeCanvasModifier;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\ResizeCanvasModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Imagick\\Modifiers\\ResizeCanvasModifier::class)]\nfinal class ResizeCanvasModifierTest extends ImagickTestCase\n{\n    public function testModify(): void\n    {\n        $image = $this->createTestImage(1, 1);\n        $this->assertEquals(1, $image->width());\n        $this->assertEquals(1, $image->height());\n        $image->modify(new ResizeCanvasModifier(3, 3, 'ff0', 'center'));\n        $this->assertEquals(3, $image->width());\n        $this->assertEquals(3, $image->height());\n        $this->assertColor(255, 255, 0, 255, $image->pickColor(0, 0));\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(1, 1));\n        $this->assertColor(255, 255, 0, 255, $image->pickColor(2, 2));\n    }\n\n    public function testModifyWithTransparency(): void\n    {\n        $image = $this->readTestImage('tile.png');\n        $this->assertEquals(16, $image->width());\n        $this->assertEquals(16, $image->height());\n        $image->modify(new ResizeCanvasModifier(18, 18, 'ff0', 'center'));\n        $this->assertEquals(18, $image->width());\n        $this->assertEquals(18, $image->height());\n        $this->assertColor(255, 255, 0, 255, $image->pickColor(0, 0));\n        $this->assertColor(180, 224, 0, 255, $image->pickColor(1, 1));\n        $this->assertColor(180, 224, 0, 255, $image->pickColor(2, 2));\n        $this->assertColor(255, 255, 0, 255, $image->pickColor(17, 17));\n        $this->assertTransparency($image->pickColor(12, 1));\n\n        $image = $this->createTestImage(16, 16);\n        $image->modify(new ResizeCanvasModifier(32, 32, '00f5', 'center'));\n        $this->assertEquals(32, $image->width());\n        $this->assertEquals(32, $image->height());\n        $this->assertColor(0, 0, 255, 77, $image->pickColor(5, 5));\n        $this->assertColor(0, 0, 255, 77, $image->pickColor(16, 5));\n        $this->assertColor(0, 0, 255, 77, $image->pickColor(30, 5));\n        $this->assertColor(0, 0, 255, 77, $image->pickColor(5, 16));\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(16, 16));\n        $this->assertColor(0, 0, 255, 77, $image->pickColor(30, 16));\n        $this->assertColor(0, 0, 255, 77, $image->pickColor(5, 30));\n        $this->assertColor(0, 0, 255, 77, $image->pickColor(16, 30));\n        $this->assertColor(0, 0, 255, 77, $image->pickColor(30, 30));\n    }\n\n    public function testModifyEdge(): void\n    {\n        $image = $this->createTestImage(1, 1);\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(0, 0));\n        $image->modify(new ResizeCanvasModifier(null, 2, 'ff0', 'bottom'));\n        $this->assertEquals(1, $image->width());\n        $this->assertEquals(2, $image->height());\n        $this->assertColor(255, 255, 0, 255, $image->pickColor(0, 0));\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(0, 1));\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Modifiers/ResizeCanvasRelativeModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\ResizeCanvasRelativeModifier;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\ResizeCanvasRelativeModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Imagick\\Modifiers\\ResizeCanvasRelativeModifier::class)]\nfinal class ResizeCanvasRelativeModifierTest extends ImagickTestCase\n{\n    public function testModify(): void\n    {\n        $image = $this->createTestImage(1, 1);\n        $this->assertEquals(1, $image->width());\n        $this->assertEquals(1, $image->height());\n        $image->modify(new ResizeCanvasRelativeModifier(2, 2, 'ff0', 'center'));\n        $this->assertEquals(3, $image->width());\n        $this->assertEquals(3, $image->height());\n        $this->assertColor(255, 255, 0, 255, $image->pickColor(0, 0));\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(1, 1));\n        $this->assertColor(255, 255, 0, 255, $image->pickColor(2, 2));\n    }\n\n    public function testModifyWithTransparency(): void\n    {\n        $image = $this->readTestImage('tile.png');\n        $this->assertEquals(16, $image->width());\n        $this->assertEquals(16, $image->height());\n        $image->modify(new ResizeCanvasRelativeModifier(2, 2, 'ff0', 'center'));\n        $this->assertEquals(18, $image->width());\n        $this->assertEquals(18, $image->height());\n        $this->assertColor(255, 255, 0, 255, $image->pickColor(0, 0));\n        $this->assertColor(180, 224, 0, 255, $image->pickColor(1, 1));\n        $this->assertColor(180, 224, 0, 255, $image->pickColor(2, 2));\n        $this->assertColor(255, 255, 0, 255, $image->pickColor(17, 17));\n        $this->assertTransparency($image->pickColor(12, 1));\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Modifiers/ResizeModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\ResizeModifier;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\ResizeModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Imagick\\Modifiers\\ResizeModifier::class)]\nfinal class ResizeModifierTest extends ImagickTestCase\n{\n    public function testModify(): void\n    {\n        $image = $this->readTestImage('blocks.png');\n        $this->assertEquals(640, $image->width());\n        $this->assertEquals(480, $image->height());\n        $image->modify(new ResizeModifier(200, 100));\n        $this->assertEquals(200, $image->width());\n        $this->assertEquals(100, $image->height());\n        $this->assertColor(255, 0, 0, 255, $image->pickColor(150, 70));\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Modifiers/ResolutionModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\ResolutionModifier;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\ResolutionModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Imagick\\Modifiers\\ResolutionModifier::class)]\nfinal class ResolutionModifierTest extends ImagickTestCase\n{\n    public function testResolutionChange(): void\n    {\n        $image = $this->readTestImage('test.jpg');\n        $this->assertEquals(72.0, $image->resolution()->x());\n        $this->assertEquals(72.0, $image->resolution()->y());\n        $image->modify(new ResolutionModifier(1, 2));\n        $this->assertEquals(1.0, $image->resolution()->x());\n        $this->assertEquals(2.0, $image->resolution()->y());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Modifiers/RotateModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\RotateModifier;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\RotateModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Imagick\\Modifiers\\RotateModifier::class)]\nfinal class RotateModifierTest extends ImagickTestCase\n{\n    public function testRotate(): void\n    {\n        $image = $this->readTestImage('test.jpg');\n        $this->assertEquals(320, $image->width());\n        $this->assertEquals(240, $image->height());\n        $image->modify(new RotateModifier(90, 'fff'));\n        $this->assertEquals(240, $image->width());\n        $this->assertEquals(320, $image->height());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Modifiers/SharpenModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Modifiers;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\SharpenModifier;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\SharpenModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Imagick\\Modifiers\\SharpenModifier::class)]\nfinal class SharpenModifierTest extends ImagickTestCase\n{\n    public function testModify(): void\n    {\n        $image = $this->readTestImage('trim.png');\n        $this->assertEquals('60ab96', $image->pickColor(15, 14)->toHex());\n        $image->modify(new SharpenModifier(10));\n        $this->assertEquals('4faca6', $image->pickColor(15, 14)->toHex());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Modifiers/StripMetaModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Modifiers;\n\nuse Intervention\\Image\\Drivers\\Imagick\\Modifiers\\StripMetaModifier;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(StripMetaModifier::class)]\nfinal class StripMetaModifierTest extends ImagickTestCase\n{\n    public function testApply(): void\n    {\n        $image = $this->readTestImage('exif.jpg');\n        $this->assertEquals('Oliver Vogel', $image->exif('IFD0.Artist'));\n        $image->modify(new StripMetaModifier());\n        $this->assertNull($image->exif('IFD0.Artist'));\n        $result = $image->toJpeg();\n        $this->assertEmpty(exif_read_data($result->toFilePointer())['IFD0.Artist'] ?? null);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Modifiers/TextModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Modifiers;\n\nuse Intervention\\Image\\Drivers\\Imagick\\Driver;\nuse Intervention\\Image\\Drivers\\Imagick\\Modifiers\\TextModifier;\nuse Intervention\\Image\\Geometry\\Point;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\nuse Intervention\\Image\\Typography\\Font;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\TextModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Imagick\\Modifiers\\TextModifier::class)]\nfinal class TextModifierTest extends ImagickTestCase\n{\n    public function testTextColor(): void\n    {\n        $font = (new Font())->setColor('ff0055');\n\n        $modifier = new class ('test', new Point(), $font) extends TextModifier\n        {\n            public function test(): ColorInterface\n            {\n                return $this->textColor();\n            }\n        };\n\n        $modifier->setDriver(new Driver());\n\n        $this->assertInstanceOf(ColorInterface::class, $modifier->test());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/Imagick/Modifiers/TrimModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers\\Imagick\\Modifiers;\n\nuse Intervention\\Image\\Exceptions\\NotSupportedException;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Modifiers\\TrimModifier;\nuse Intervention\\Image\\Tests\\ImagickTestCase;\n\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(\\Intervention\\Image\\Modifiers\\TrimModifier::class)]\n#[CoversClass(\\Intervention\\Image\\Drivers\\Imagick\\Modifiers\\TrimModifier::class)]\nfinal class TrimModifierTest extends ImagickTestCase\n{\n    public function testTrim(): void\n    {\n        $image = $this->readTestImage('trim.png');\n        $this->assertEquals(50, $image->width());\n        $this->assertEquals(50, $image->height());\n        $image->modify(new TrimModifier());\n        $this->assertEquals(28, $image->width());\n        $this->assertEquals(28, $image->height());\n    }\n\n    public function testTrimGradient(): void\n    {\n        $image = $this->readTestImage('radial.png');\n        $this->assertEquals(50, $image->width());\n        $this->assertEquals(50, $image->height());\n        $image->modify(new TrimModifier(50));\n        $this->assertEquals(29, $image->width());\n        $this->assertEquals(29, $image->height());\n    }\n\n    public function testTrimHighTolerance(): void\n    {\n        $image = $this->readTestImage('trim.png');\n        $this->assertEquals(50, $image->width());\n        $this->assertEquals(50, $image->height());\n        $image->modify(new TrimModifier(1000000));\n        $this->assertEquals(1, $image->width());\n        $this->assertEquals(1, $image->height());\n        $this->assertColor(255, 255, 255, 0, $image->pickColor(0, 0));\n    }\n\n    public function testTrimAnimated(): void\n    {\n        $image = $this->readTestImage('animation.gif');\n        $this->expectException(NotSupportedException::class);\n        $image->modify(new TrimModifier());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/SpecializableAnalyzerTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers;\n\nuse Intervention\\Image\\Drivers\\SpecializableAnalyzer;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse Mockery;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\n\n#[CoversClass(SpecializableAnalyzer::class)]\nfinal class SpecializableAnalyzerTest extends BaseTestCase\n{\n    public function testAnalyze(): void\n    {\n        $analyzer = Mockery::mock(SpecializableAnalyzer::class)->makePartial();\n        $image = Mockery::mock(ImageInterface::class);\n        $image->shouldReceive('analyze')->andReturn('test');\n        $result = $analyzer->analyze($image);\n        $this->assertEquals('test', $result);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/SpecializableDecoderTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers;\n\nuse Intervention\\Image\\Drivers\\SpecializableDecoder;\nuse Intervention\\Image\\Exceptions\\DecoderException;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse Mockery;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\n\n#[CoversClass(SpecializableDecoder::class)]\nfinal class SpecializableDecoderTest extends BaseTestCase\n{\n    public function testDecode(): void\n    {\n        $decoder = Mockery::mock(SpecializableDecoder::class)->makePartial();\n        $this->expectException(DecoderException::class);\n        $decoder->decode(null);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Drivers/SpecializableModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Drivers;\n\nuse Intervention\\Image\\Drivers\\SpecializableModifier;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse Mockery;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\n\n#[CoversClass(SpecializableModifier::class)]\nfinal class SpecializableModifierTest extends BaseTestCase\n{\n    public function testApply(): void\n    {\n        $modifier = Mockery::mock(SpecializableModifier::class)->makePartial();\n        $image = Mockery::mock(ImageInterface::class);\n        $image->shouldReceive('modify')->andReturn($image);\n        $result = $modifier->apply($image);\n        $this->assertInstanceOf(ImageInterface::class, $result);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/EncodedImageTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse Intervention\\Image\\EncodedImage;\nuse Intervention\\Image\\Tests\\BaseTestCase;\n\n#[CoversClass(EncodedImage::class)]\nfinal class EncodedImageTest extends BaseTestCase\n{\n    public function testConstructor(): void\n    {\n        $image = new EncodedImage('foo');\n        $this->assertInstanceOf(EncodedImage::class, $image);\n    }\n\n    public function testSave(): void\n    {\n        $image = new EncodedImage('foo');\n        $path = __DIR__ . '/foo.tmp';\n        $this->assertFalse(file_exists($path));\n        $image->save($path);\n        $this->assertTrue(file_exists($path));\n        $this->assertEquals('foo', file_get_contents($path));\n        unlink($path);\n    }\n\n    public function testToDataUri(): void\n    {\n        $image = new EncodedImage('foo');\n        $this->assertEquals('data:application/octet-stream;base64,Zm9v', $image->toDataUri());\n    }\n\n    public function testToString(): void\n    {\n        $image = new EncodedImage('foo');\n        $this->assertEquals('foo', (string) $image);\n    }\n\n    public function testMediaType(): void\n    {\n        $image = new EncodedImage('foo');\n        $this->assertEquals('application/octet-stream', $image->mediaType());\n\n        $image = new EncodedImage($this->getTestResourceData(), 'image/jpeg');\n        $this->assertEquals('image/jpeg', $image->mediaType());\n    }\n\n    public function testMimetype(): void\n    {\n        $image = new EncodedImage('foo');\n        $this->assertEquals('application/octet-stream', $image->mimetype());\n\n        $image = new EncodedImage($this->getTestResourceData(), 'image/jpeg');\n        $this->assertEquals('image/jpeg', $image->mimetype());\n    }\n\n    public function testDebugInfo(): void\n    {\n        $info = (new EncodedImage('foo', 'image/png'))->__debugInfo();\n        $this->assertEquals('image/png', $info['mediaType']);\n        $this->assertEquals(3, $info['size']);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Encoders/FileExtensionEncoderTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Encoders;\n\nuse Generator;\nuse Intervention\\Image\\Encoders\\AvifEncoder;\nuse Intervention\\Image\\Encoders\\BmpEncoder;\nuse Intervention\\Image\\Encoders\\FileExtensionEncoder;\nuse Intervention\\Image\\Encoders\\GifEncoder;\nuse Intervention\\Image\\Encoders\\HeicEncoder;\nuse Intervention\\Image\\Encoders\\Jpeg2000Encoder;\nuse Intervention\\Image\\Encoders\\JpegEncoder;\nuse Intervention\\Image\\Encoders\\PngEncoder;\nuse Intervention\\Image\\Encoders\\TiffEncoder;\nuse Intervention\\Image\\Encoders\\WebpEncoder;\nuse Intervention\\Image\\Exceptions\\EncoderException;\nuse Intervention\\Image\\FileExtension;\nuse Intervention\\Image\\Interfaces\\EncoderInterface;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\n\n#[CoversClass(FileExtensionEncoder::class)]\nfinal class FileExtensionEncoderTest extends BaseTestCase\n{\n    /**\n     * @param $options array<string, int>\n     */\n    private function testEncoder(string|FileExtension $extension, array $options = []): EncoderInterface\n    {\n        $encoder = new class ($extension, ...$options) extends FileExtensionEncoder\n        {\n            public function __construct(string|FileExtension $extension, mixed ...$options)\n            {\n                parent::__construct($extension, ...$options);\n            }\n\n            public function test(string|FileExtension $extension): EncoderInterface\n            {\n                return $this->encoderByFileExtension($extension);\n            }\n        };\n\n        return $encoder->test($extension);\n    }\n\n    #[DataProvider('targetEncoderProvider')]\n    public function testEncoderByFileExtensionString(\n        string|FileExtension $fileExtension,\n        string $targetEncoderClassname,\n    ): void {\n        $this->assertInstanceOf(\n            $targetEncoderClassname,\n            $this->testEncoder($fileExtension),\n        );\n    }\n\n    public static function targetEncoderProvider(): Generator\n    {\n        yield ['webp', WebpEncoder::class];\n        yield ['avif', AvifEncoder::class];\n        yield ['jpeg', JpegEncoder::class];\n        yield ['jpg', JpegEncoder::class];\n        yield ['bmp', BmpEncoder::class];\n        yield ['gif', GifEncoder::class];\n        yield ['png', PngEncoder::class];\n        yield ['tiff', TiffEncoder::class];\n        yield ['tif', TiffEncoder::class];\n        yield ['jp2', Jpeg2000Encoder::class];\n        yield ['heic', HeicEncoder::class];\n        yield ['WEBP', WebpEncoder::class];\n        yield ['AVIF', AvifEncoder::class];\n        yield ['JPEG', JpegEncoder::class];\n        yield ['JPG', JpegEncoder::class];\n        yield ['BMP', BmpEncoder::class];\n        yield ['GIF', GifEncoder::class];\n        yield ['PNG', PngEncoder::class];\n        yield ['TIFF', TiffEncoder::class];\n        yield ['TIF', TiffEncoder::class];\n        yield ['JP2', Jpeg2000Encoder::class];\n        yield ['HEIC', HeicEncoder::class];\n        yield [FileExtension::WEBP, WebpEncoder::class];\n        yield [FileExtension::AVIF, AvifEncoder::class];\n        yield [FileExtension::JPG, JpegEncoder::class];\n        yield [FileExtension::BMP, BmpEncoder::class];\n        yield [FileExtension::GIF, GifEncoder::class];\n        yield [FileExtension::PNG, PngEncoder::class];\n        yield [FileExtension::TIF, TiffEncoder::class];\n        yield [FileExtension::TIFF, TiffEncoder::class];\n        yield [FileExtension::JP2, Jpeg2000Encoder::class];\n        yield [FileExtension::HEIC, HeicEncoder::class];\n    }\n\n    public function testArgumentsNotSupportedByTargetEncoder(): void\n    {\n        $encoder = $this->testEncoder(\n            'png',\n            [\n                'interlaced' => true, // is not ignored\n                'quality' => 10, // is ignored because png encoder has no quality argument\n            ],\n        );\n\n        $this->assertInstanceOf(PngEncoder::class, $encoder);\n        $this->assertTrue($encoder->interlaced);\n    }\n\n    public function testEncoderByFileExtensionUnknown(): void\n    {\n        $this->expectException(EncoderException::class);\n        $this->testEncoder('test');\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Encoders/MediaTypeEncoderTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Encoders;\n\nuse Generator;\nuse Intervention\\Image\\Encoders\\AvifEncoder;\nuse Intervention\\Image\\Encoders\\BmpEncoder;\nuse Intervention\\Image\\Encoders\\GifEncoder;\nuse Intervention\\Image\\Encoders\\HeicEncoder;\nuse Intervention\\Image\\Encoders\\Jpeg2000Encoder;\nuse Intervention\\Image\\Encoders\\JpegEncoder;\nuse Intervention\\Image\\Encoders\\MediaTypeEncoder;\nuse Intervention\\Image\\Encoders\\PngEncoder;\nuse Intervention\\Image\\Encoders\\TiffEncoder;\nuse Intervention\\Image\\Encoders\\WebpEncoder;\nuse Intervention\\Image\\Exceptions\\EncoderException;\nuse Intervention\\Image\\Interfaces\\EncoderInterface;\nuse Intervention\\Image\\MediaType;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\n\n#[CoversClass(MediaTypeEncoder::class)]\nfinal class MediaTypeEncoderTest extends BaseTestCase\n{\n    /**\n     * @param $options array<string, int>\n     */\n    private function testEncoder(string|MediaType $mediaType, array $options = []): EncoderInterface\n    {\n        $encoder = new class ($mediaType, ...$options) extends MediaTypeEncoder\n        {\n            public function __construct(string|MediaType $mediaType, mixed ...$options)\n            {\n                parent::__construct($mediaType, ...$options);\n            }\n\n            public function test(string|MediaType $mediaType): EncoderInterface\n            {\n                return $this->encoderByMediaType($mediaType);\n            }\n        };\n\n        return $encoder->test($mediaType);\n    }\n\n    #[DataProvider('targetEncoderProvider')]\n    public function testEncoderByMediaType(\n        string|MediaType $mediaType,\n        string $targetEncoderClassname,\n    ): void {\n        $this->assertInstanceOf(\n            $targetEncoderClassname,\n            $this->testEncoder($mediaType)\n        );\n    }\n\n    public static function targetEncoderProvider(): Generator\n    {\n        yield ['image/webp', WebpEncoder::class];\n        yield ['image/avif', AvifEncoder::class];\n        yield ['image/jpeg', JpegEncoder::class];\n        yield ['image/bmp', BmpEncoder::class];\n        yield ['image/gif', GifEncoder::class];\n        yield ['image/png', PngEncoder::class];\n        yield ['image/png', PngEncoder::class];\n        yield ['image/tiff', TiffEncoder::class];\n        yield ['image/jp2', Jpeg2000Encoder::class];\n        yield ['image/heic', HeicEncoder::class];\n        yield [MediaType::IMAGE_WEBP, WebpEncoder::class];\n        yield [MediaType::IMAGE_AVIF, AvifEncoder::class];\n        yield [MediaType::IMAGE_JPEG, JpegEncoder::class];\n        yield [MediaType::IMAGE_BMP, BmpEncoder::class];\n        yield [MediaType::IMAGE_GIF, GifEncoder::class];\n        yield [MediaType::IMAGE_PNG, PngEncoder::class];\n        yield [MediaType::IMAGE_TIFF, TiffEncoder::class];\n        yield [MediaType::IMAGE_JP2, Jpeg2000Encoder::class];\n        yield [MediaType::IMAGE_HEIC, HeicEncoder::class];\n        yield [MediaType::IMAGE_HEIF, HeicEncoder::class];\n    }\n\n    public function testArgumentsNotSupportedByTargetEncoder(): void\n    {\n        $encoder = $this->testEncoder(\n            'image/png',\n            [\n                'interlaced' => true, // is not ignored\n                'quality' => 10, // is ignored because png encoder has no quality argument\n            ],\n        );\n\n        $this->assertInstanceOf(PngEncoder::class, $encoder);\n        $this->assertTrue($encoder->interlaced);\n    }\n\n    public function testEncoderByFileExtensionUnknown(): void\n    {\n        $this->expectException(EncoderException::class);\n        $this->testEncoder('test');\n    }\n}\n"
  },
  {
    "path": "tests/Unit/FileExtensionTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit;\n\nuse Generator;\nuse Intervention\\Image\\Exceptions\\NotSupportedException;\nuse Intervention\\Image\\FileExtension;\nuse Intervention\\Image\\Format;\nuse Intervention\\Image\\MediaType;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\n\n#[CoversClass(FileExtension::class)]\nfinal class FileExtensionTest extends BaseTestCase\n{\n    public function testCreate(): void\n    {\n        $this->assertEquals(FileExtension::JPG, FileExtension::create(MediaType::IMAGE_JPEG));\n        $this->assertEquals(FileExtension::JPG, FileExtension::create(Format::JPEG));\n        $this->assertEquals(FileExtension::JPG, FileExtension::create(FileExtension::JPG));\n        $this->assertEquals(FileExtension::JPG, FileExtension::create('jpg'));\n        $this->assertEquals(FileExtension::JPEG, FileExtension::create('jpeg'));\n        $this->assertEquals(FileExtension::JPG, FileExtension::create('image/jpeg'));\n        $this->assertEquals(FileExtension::JPG, FileExtension::create('JPG'));\n        $this->assertEquals(FileExtension::JPEG, FileExtension::create('JPEG'));\n        $this->assertEquals(FileExtension::JPG, FileExtension::create('IMAGE/JPEG'));\n    }\n\n    public function testCreateUnknown(): void\n    {\n        $this->expectException(NotSupportedException::class);\n        FileExtension::create('foo');\n    }\n\n    public function testTryCreate(): void\n    {\n        $this->assertEquals(FileExtension::JPG, FileExtension::tryCreate(MediaType::IMAGE_JPEG));\n        $this->assertEquals(FileExtension::JPG, FileExtension::tryCreate(Format::JPEG));\n        $this->assertEquals(FileExtension::JPG, FileExtension::tryCreate(FileExtension::JPG));\n        $this->assertEquals(FileExtension::JPG, FileExtension::tryCreate('jpg'));\n        $this->assertEquals(FileExtension::JPEG, FileExtension::tryCreate('jpeg'));\n        $this->assertEquals(FileExtension::JPG, FileExtension::tryCreate('image/jpeg'));\n        $this->assertNull(FileExtension::tryCreate('no-format'));\n    }\n\n    public function testFormatJpeg(): void\n    {\n        $ext = FileExtension::JPEG;\n        $this->assertEquals(Format::JPEG, $ext->format());\n\n        $ext = FileExtension::JPG;\n        $this->assertEquals(Format::JPEG, $ext->format());\n    }\n\n    public function testFormatWebp(): void\n    {\n        $ext = FileExtension::WEBP;\n        $this->assertEquals(Format::WEBP, $ext->format());\n    }\n\n    public function testFormatGif(): void\n    {\n        $ext = FileExtension::GIF;\n        $this->assertEquals(Format::GIF, $ext->format());\n    }\n\n    public function testFormatPng(): void\n    {\n        $ext = FileExtension::PNG;\n        $this->assertEquals(Format::PNG, $ext->format());\n    }\n\n    public function testFormatAvif(): void\n    {\n        $ext = FileExtension::AVIF;\n        $this->assertEquals(Format::AVIF, $ext->format());\n    }\n\n    public function testFormatBmp(): void\n    {\n        $ext = FileExtension::BMP;\n        $this->assertEquals(Format::BMP, $ext->format());\n    }\n\n    public function testFormatTiff(): void\n    {\n        $ext = FileExtension::TIFF;\n        $this->assertEquals(Format::TIFF, $ext->format());\n\n        $ext = FileExtension::TIF;\n        $this->assertEquals(Format::TIFF, $ext->format());\n    }\n\n    public function testFormatJpeg2000(): void\n    {\n        $ext = FileExtension::JP2;\n        $this->assertEquals(Format::JP2, $ext->format());\n\n        $ext = FileExtension::J2K;\n        $this->assertEquals(Format::JP2, $ext->format());\n\n        $ext = FileExtension::J2C;\n        $this->assertEquals(Format::JP2, $ext->format());\n\n        $ext = FileExtension::JPG2;\n        $this->assertEquals(Format::JP2, $ext->format());\n\n        $ext = FileExtension::JP2K;\n        $this->assertEquals(Format::JP2, $ext->format());\n    }\n\n    public function testFormatHeic(): void\n    {\n        $ext = FileExtension::HEIC;\n        $this->assertEquals(Format::HEIC, $ext->format());\n\n        $ext = FileExtension::HEIF;\n        $this->assertEquals(Format::HEIC, $ext->format());\n    }\n\n    #[DataProvider('mediaTypesDataProvider')]\n    public function testMediatypes(FileExtension $extension, int $mediaTypeCount, MediaType $mediaType): void\n    {\n        $this->assertCount($mediaTypeCount, $extension->mediaTypes());\n        $this->assertEquals($mediaType, $extension->mediaType());\n    }\n\n    public static function mediaTypesDataProvider(): Generator\n    {\n        yield [FileExtension::JPEG, 4, MediaType::IMAGE_JPEG];\n        yield [FileExtension::WEBP, 2, MediaType::IMAGE_WEBP];\n        yield [FileExtension::GIF, 1, MediaType::IMAGE_GIF];\n        yield [FileExtension::PNG, 2, MediaType::IMAGE_PNG];\n        yield [FileExtension::AVIF, 2, MediaType::IMAGE_AVIF];\n        yield [FileExtension::BMP, 9, MediaType::IMAGE_BMP];\n        yield [FileExtension::TIFF, 1, MediaType::IMAGE_TIFF];\n        yield [FileExtension::TIF, 1, MediaType::IMAGE_TIFF];\n        yield [FileExtension::JP2, 4, MediaType::IMAGE_JP2];\n        yield [FileExtension::HEIC, 3, MediaType::IMAGE_HEIC];\n    }\n}\n"
  },
  {
    "path": "tests/Unit/FileTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse Intervention\\Image\\File;\nuse Intervention\\Image\\Tests\\BaseTestCase;\n\n#[CoversClass(File::class)]\nfinal class FileTest extends BaseTestCase\n{\n    public function testConstructor(): void\n    {\n        $file = new File();\n        $this->assertInstanceOf(File::class, $file);\n\n        $file = new File('foo');\n        $this->assertInstanceOf(File::class, $file);\n    }\n\n    public function testConstructorFromString(): void\n    {\n        $file = new File('foo');\n        $this->assertInstanceOf(File::class, $file);\n    }\n\n    public function testConstructorFromResource(): void\n    {\n        $file = new File(fopen('php://temp', 'r'));\n        $this->assertInstanceOf(File::class, $file);\n    }\n\n    public function testFromPath(): void\n    {\n        $file = File::fromPath($this->getTestResourcePath());\n        $this->assertInstanceOf(File::class, $file);\n        $this->assertTrue($file->size() > 0);\n    }\n\n    public function testSave(): void\n    {\n        $file = new File('foo');\n        $filenames = [\n            __DIR__ . '/01_file_' . strval(hrtime(true)) . '.test',\n            __DIR__ . '/02_file_' . strval(hrtime(true)) . '.test',\n        ];\n\n        foreach ($filenames as $name) {\n            $file->save($name);\n        }\n\n        foreach ($filenames as $name) {\n            $this->assertFileExists($name);\n            $this->assertEquals('foo', file_get_contents($name));\n            unlink($name);\n        }\n    }\n\n    public function testToString(): void\n    {\n        $file = new File('foo');\n        $string = $file->toString();\n        $this->assertEquals('foo', $string);\n        $this->assertEquals('foo', $string);\n    }\n\n    public function testToFilePointer(): void\n    {\n        $file = new File('foo');\n        $fp = $file->toFilePointer();\n        $this->assertIsResource($fp);\n    }\n\n    public function testSize(): void\n    {\n        $file = new File();\n        $this->assertEquals(0, $file->size());\n\n        $file = new File('foo');\n        $this->assertEquals(3, $file->size());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/FormatTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit;\n\nuse Intervention\\Image\\Encoders\\AvifEncoder;\nuse Intervention\\Image\\Encoders\\BmpEncoder;\nuse Intervention\\Image\\Encoders\\GifEncoder;\nuse Intervention\\Image\\Encoders\\HeicEncoder;\nuse Intervention\\Image\\Encoders\\Jpeg2000Encoder;\nuse Intervention\\Image\\Encoders\\JpegEncoder;\nuse Intervention\\Image\\Encoders\\PngEncoder;\nuse Intervention\\Image\\Encoders\\TiffEncoder;\nuse Intervention\\Image\\Encoders\\WebpEncoder;\nuse Intervention\\Image\\Exceptions\\NotSupportedException;\nuse Intervention\\Image\\FileExtension;\nuse Intervention\\Image\\Format;\nuse Intervention\\Image\\MediaType;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\n\n#[CoversClass(Format::class)]\nfinal class FormatTest extends BaseTestCase\n{\n    public function testCreate(): void\n    {\n        $this->assertEquals(Format::JPEG, Format::create(Format::JPEG));\n        $this->assertEquals(Format::JPEG, Format::create('jpg'));\n        $this->assertEquals(Format::JPEG, Format::create('jpeg'));\n        $this->assertEquals(Format::JPEG, Format::create('image/jpeg'));\n        $this->assertEquals(Format::GIF, Format::create('image/gif'));\n        $this->assertEquals(Format::JPEG, Format::create('JPG'));\n        $this->assertEquals(Format::JPEG, Format::create('JPEG'));\n        $this->assertEquals(Format::JPEG, Format::create('IMAGE/JPEG'));\n        $this->assertEquals(Format::GIF, Format::create('IMAGE/GIF'));\n        $this->assertEquals(Format::PNG, Format::create(FileExtension::PNG));\n        $this->assertEquals(Format::WEBP, Format::create(MediaType::IMAGE_WEBP));\n    }\n\n    public function testCreateUnknown(): void\n    {\n        $this->expectException(NotSupportedException::class);\n        Format::create('foo');\n    }\n\n    public function testTryCreate(): void\n    {\n        $this->assertEquals(Format::JPEG, Format::tryCreate(Format::JPEG));\n        $this->assertEquals(Format::JPEG, Format::tryCreate('jpg'));\n        $this->assertEquals(Format::JPEG, Format::tryCreate('jpeg'));\n        $this->assertEquals(Format::JPEG, Format::tryCreate('image/jpeg'));\n        $this->assertEquals(Format::GIF, Format::tryCreate('image/gif'));\n        $this->assertEquals(Format::PNG, Format::tryCreate(FileExtension::PNG));\n        $this->assertEquals(Format::WEBP, Format::tryCreate(MediaType::IMAGE_WEBP));\n        $this->assertNull(Format::tryCreate('no-format'));\n    }\n\n    public function testMediaTypesJpeg(): void\n    {\n        $format = Format::JPEG;\n        $mediaTypes = $format->mediaTypes();\n        $this->assertIsArray($mediaTypes);\n        $this->assertCount(4, $mediaTypes);\n\n        $this->assertEquals(MediaType::IMAGE_JPEG, $format->mediaType());\n    }\n\n    public function testMediaTypesWebp(): void\n    {\n        $format = Format::WEBP;\n        $mediaTypes = $format->mediaTypes();\n        $this->assertIsArray($mediaTypes);\n        $this->assertCount(2, $mediaTypes);\n\n        $this->assertEquals(MediaType::IMAGE_WEBP, $format->mediaType());\n    }\n\n    public function testMediaTypesFGif(): void\n    {\n        $format = Format::GIF;\n        $mediaTypes = $format->mediaTypes();\n        $this->assertIsArray($mediaTypes);\n        $this->assertCount(1, $mediaTypes);\n\n        $this->assertEquals(MediaType::IMAGE_GIF, $format->mediaType());\n    }\n\n    public function testMediaTypesPng(): void\n    {\n        $format = Format::PNG;\n        $mediaTypes = $format->mediaTypes();\n        $this->assertIsArray($mediaTypes);\n        $this->assertCount(2, $mediaTypes);\n\n        $this->assertEquals(MediaType::IMAGE_PNG, $format->mediaType());\n    }\n\n    public function testMediaTypesAvif(): void\n    {\n        $format = Format::AVIF;\n        $mediaTypes = $format->mediaTypes();\n        $this->assertIsArray($mediaTypes);\n        $this->assertCount(2, $mediaTypes);\n\n        $this->assertEquals(MediaType::IMAGE_AVIF, $format->mediaType());\n    }\n\n    public function testMediaTypesBmp(): void\n    {\n        $format = Format::BMP;\n        $mediaTypes = $format->mediaTypes();\n        $this->assertIsArray($mediaTypes);\n        $this->assertCount(9, $mediaTypes);\n\n        $this->assertEquals(MediaType::IMAGE_BMP, $format->mediaType());\n    }\n\n    public function testMediaTypesTiff(): void\n    {\n        $format = Format::TIFF;\n        $mediaTypes = $format->mediaTypes();\n        $this->assertIsArray($mediaTypes);\n        $this->assertCount(1, $mediaTypes);\n\n        $this->assertEquals(MediaType::IMAGE_TIFF, $format->mediaType());\n    }\n\n    public function testMediaTypesJpeg2000(): void\n    {\n        $format = Format::JP2;\n        $mediaTypes = $format->mediaTypes();\n        $this->assertIsArray($mediaTypes);\n        $this->assertCount(4, $mediaTypes);\n\n        $this->assertEquals(MediaType::IMAGE_JP2, $format->mediaType());\n    }\n\n    public function testMediaTypesHeic(): void\n    {\n        $format = Format::HEIC;\n        $mediaTypes = $format->mediaTypes();\n        $this->assertIsArray($mediaTypes);\n        $this->assertCount(3, $mediaTypes);\n\n        $this->assertEquals(MediaType::IMAGE_HEIC, $format->mediaType());\n    }\n\n    public function testEncoderJpeg(): void\n    {\n        $format = Format::JPEG;\n        $this->assertInstanceOf(JpegEncoder::class, $format->encoder());\n    }\n\n    public function testEncoderAvif(): void\n    {\n        $format = Format::AVIF;\n        $this->assertInstanceOf(AvifEncoder::class, $format->encoder());\n    }\n\n    public function testEncoderWebp(): void\n    {\n        $format = Format::WEBP;\n        $this->assertInstanceOf(WebpEncoder::class, $format->encoder());\n    }\n\n    public function testEncoderGif(): void\n    {\n        $format = Format::GIF;\n        $this->assertInstanceOf(GifEncoder::class, $format->encoder());\n    }\n\n    public function testEncoderPng(): void\n    {\n        $format = Format::PNG;\n        $this->assertInstanceOf(PngEncoder::class, $format->encoder());\n    }\n\n    public function testEncoderBitmap(): void\n    {\n        $format = Format::BMP;\n        $this->assertInstanceOf(BmpEncoder::class, $format->encoder());\n    }\n\n    public function testEncoderTiff(): void\n    {\n        $format = Format::TIFF;\n        $this->assertInstanceOf(TiffEncoder::class, $format->encoder());\n    }\n\n    public function testEncoderJpep2000(): void\n    {\n        $format = Format::JP2;\n        $this->assertInstanceOf(Jpeg2000Encoder::class, $format->encoder());\n    }\n\n    public function testEncoderHeic(): void\n    {\n        $format = Format::HEIC;\n        $this->assertInstanceOf(HeicEncoder::class, $format->encoder());\n    }\n\n    public function testFileExtensionsJpeg(): void\n    {\n        $format = Format::JPEG;\n        $extensions = $format->fileExtensions();\n        $this->assertIsArray($extensions);\n        $this->assertCount(2, $extensions);\n\n        $this->assertEquals(FileExtension::JPG, $format->fileExtension());\n    }\n\n    public function testFileExtensionsWebp(): void\n    {\n        $format = Format::WEBP;\n        $extensions = $format->fileExtensions();\n        $this->assertIsArray($extensions);\n        $this->assertCount(1, $extensions);\n\n        $this->assertEquals(FileExtension::WEBP, $format->fileExtension());\n    }\n\n    public function testFileExtensionsGif(): void\n    {\n        $format = Format::GIF;\n        $extensions = $format->fileExtensions();\n        $this->assertIsArray($extensions);\n        $this->assertCount(1, $extensions);\n\n        $this->assertEquals(FileExtension::GIF, $format->fileExtension());\n    }\n\n    public function testFileExtensionsPng(): void\n    {\n        $format = Format::PNG;\n        $extensions = $format->fileExtensions();\n        $this->assertIsArray($extensions);\n        $this->assertCount(1, $extensions);\n\n        $this->assertEquals(FileExtension::PNG, $format->fileExtension());\n    }\n\n    public function testFileExtensionsAvif(): void\n    {\n        $format = Format::AVIF;\n        $extensions = $format->fileExtensions();\n        $this->assertIsArray($extensions);\n        $this->assertCount(1, $extensions);\n\n        $this->assertEquals(FileExtension::AVIF, $format->fileExtension());\n    }\n\n    public function testFileExtensionsBmp(): void\n    {\n        $format = Format::BMP;\n        $extensions = $format->fileExtensions();\n        $this->assertIsArray($extensions);\n        $this->assertCount(1, $extensions);\n\n        $this->assertEquals(FileExtension::BMP, $format->fileExtension());\n    }\n\n    public function testFileExtensionsTiff(): void\n    {\n        $format = Format::TIFF;\n        $extensions = $format->fileExtensions();\n        $this->assertIsArray($extensions);\n        $this->assertCount(2, $extensions);\n\n        $this->assertEquals(FileExtension::TIF, $format->fileExtension());\n    }\n\n    public function testFileExtensionsJp2(): void\n    {\n        $format = Format::JP2;\n        $extensions = $format->fileExtensions();\n        $this->assertIsArray($extensions);\n        $this->assertCount(9, $extensions);\n\n        $this->assertEquals(FileExtension::JP2, $format->fileExtension());\n    }\n\n    public function testFileExtensionsHeic(): void\n    {\n        $format = Format::HEIC;\n        $extensions = $format->fileExtensions();\n        $this->assertIsArray($extensions);\n        $this->assertCount(2, $extensions);\n\n        $this->assertEquals(FileExtension::HEIC, $format->fileExtension());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Geometry/BezierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Geometry;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse Intervention\\Image\\Geometry\\Point;\nuse Intervention\\Image\\Geometry\\Bezier;\nuse Intervention\\Image\\Tests\\BaseTestCase;\n\n#[CoversClass(Bezier::class)]\nfinal class BezierTest extends BaseTestCase\n{\n    public function testConstructor(): void\n    {\n        $bezier = new Bezier([]);\n        $this->assertInstanceOf(Bezier::class, $bezier);\n        $this->assertEquals(0, $bezier->count());\n    }\n\n    public function testCount(): void\n    {\n        $bezier = new Bezier([\n            new Point(),\n            new Point(),\n            new Point(),\n            new Point()\n        ]);\n        $this->assertEquals(4, $bezier->count());\n    }\n\n    public function testArrayAccess(): void\n    {\n        $bezier = new Bezier([\n            new Point(),\n            new Point(),\n            new Point(),\n            new Point()\n        ]);\n        $this->assertInstanceOf(Point::class, $bezier[0]);\n        $this->assertInstanceOf(Point::class, $bezier[1]);\n        $this->assertInstanceOf(Point::class, $bezier[2]);\n        $this->assertInstanceOf(Point::class, $bezier[3]);\n    }\n\n    public function testAddPoint(): void\n    {\n        $bezier = new Bezier([\n            new Point(),\n            new Point()\n        ]);\n        $this->assertEquals(2, $bezier->count());\n        $result = $bezier->addPoint(new Point());\n        $this->assertEquals(3, $bezier->count());\n        $this->assertInstanceOf(Bezier::class, $result);\n    }\n\n    public function testFirst(): void\n    {\n        $bezier = new Bezier([\n            new Point(50, 45),\n            new Point(100, -49),\n            new Point(-100, 100),\n            new Point(200, 300),\n        ]);\n        $this->assertEquals(50, $bezier->first()->x());\n        $this->assertEquals(45, $bezier->first()->y());\n    }\n\n    public function testFirstEmpty(): void\n    {\n        $bezier = new Bezier();\n        $this->assertNull($bezier->first());\n    }\n\n    public function testSecond(): void\n    {\n        $bezier = new Bezier([\n            new Point(50, 45),\n            new Point(100, -49),\n            new Point(-100, 100),\n            new Point(200, 300),\n        ]);\n        $this->assertEquals(100, $bezier->second()->x());\n        $this->assertEquals(-49, $bezier->second()->y());\n    }\n\n    public function testSecondEmpty(): void\n    {\n        $bezier = new Bezier();\n        $this->assertNull($bezier->second());\n    }\n\n    public function testThird(): void\n    {\n        $bezier = new Bezier([\n            new Point(50, 45),\n            new Point(100, -49),\n            new Point(-100, 100),\n            new Point(200, 300),\n        ]);\n        $this->assertEquals(-100, $bezier->third()->x());\n        $this->assertEquals(100, $bezier->third()->y());\n    }\n\n    public function testThirdEmpty(): void\n    {\n        $bezier = new Bezier();\n        $this->assertNull($bezier->third());\n    }\n\n    public function testLast(): void\n    {\n        $bezier = new Bezier([\n            new Point(50, 45),\n            new Point(100, -49),\n            new Point(-100, 100),\n            new Point(200, 300),\n        ]);\n        $this->assertEquals(200, $bezier->last()->x());\n        $this->assertEquals(300, $bezier->last()->y());\n    }\n\n    public function testLastEmpty(): void\n    {\n        $bezier = new Bezier();\n        $this->assertNull($bezier->last());\n    }\n\n    public function testOffsetExists(): void\n    {\n        $bezier = new Bezier();\n        $this->assertFalse($bezier->offsetExists(0));\n        $this->assertFalse($bezier->offsetExists(1));\n        $bezier->addPoint(new Point(0, 0));\n        $this->assertTrue($bezier->offsetExists(0));\n        $this->assertFalse($bezier->offsetExists(1));\n    }\n\n    public function testOffsetSetUnset(): void\n    {\n        $bezier = new Bezier();\n        $bezier->offsetSet(0, new Point());\n        $bezier->offsetSet(2, new Point());\n        $this->assertTrue($bezier->offsetExists(0));\n        $this->assertFalse($bezier->offsetExists(1));\n        $this->assertTrue($bezier->offsetExists(2));\n        $bezier->offsetUnset(2);\n        $this->assertTrue($bezier->offsetExists(0));\n        $this->assertFalse($bezier->offsetExists(1));\n        $this->assertFalse($bezier->offsetExists(2));\n    }\n\n    public function testGetSetPivotPoint(): void\n    {\n        $bezier = new Bezier();\n        $this->assertInstanceOf(Point::class, $bezier->pivot());\n        $this->assertEquals(0, $bezier->pivot()->x());\n        $this->assertEquals(0, $bezier->pivot()->y());\n        $result = $bezier->setPivot(new Point(12, 34));\n        $this->assertInstanceOf(Bezier::class, $result);\n        $this->assertEquals(12, $bezier->pivot()->x());\n        $this->assertEquals(34, $bezier->pivot()->y());\n    }\n\n    public function testToArray(): void\n    {\n        $bezier = new Bezier([\n            new Point(50, 50),\n            new Point(100, 50),\n            new Point(-50, -100),\n            new Point(50, 100),\n        ]);\n        $this->assertEquals([50, 50, 100, 50, -50, -100, 50, 100], $bezier->toArray());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Geometry/CircleTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Geometry;\n\nuse Intervention\\Image\\Geometry\\Circle;\nuse Intervention\\Image\\Geometry\\Point;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\n\n#[CoversClass(Circle::class)]\nfinal class CircleTest extends BaseTestCase\n{\n    public function testConstructor(): void\n    {\n        $circle = new Circle(100, new Point(1, 2));\n        $this->assertInstanceOf(Circle::class, $circle);\n        $this->assertEquals(100, $circle->diameter());\n        $this->assertInstanceOf(Point::class, $circle->pivot());\n    }\n\n    public function testSetGetDiameter(): void\n    {\n        $circle = new Circle(100, new Point(1, 2));\n        $this->assertEquals(100, $circle->diameter());\n        $result = $circle->setDiameter(200);\n        $this->assertInstanceOf(Circle::class, $result);\n        $this->assertEquals(200, $result->diameter());\n        $this->assertEquals(200, $circle->diameter());\n    }\n\n    public function testSetGetRadius(): void\n    {\n        $circle = new Circle(100, new Point(1, 2));\n        $this->assertEquals(50, $circle->radius());\n        $result = $circle->setRadius(200);\n        $this->assertInstanceOf(Circle::class, $result);\n        $this->assertEquals(400, $result->diameter());\n        $this->assertEquals(400, $circle->diameter());\n        $this->assertEquals(200, $result->radius());\n        $this->assertEquals(200, $circle->radius());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Geometry/EllipseTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Geometry;\n\nuse Intervention\\Image\\Geometry\\Ellipse;\nuse Intervention\\Image\\Geometry\\Point;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\n\n#[CoversClass(Ellipse::class)]\nfinal class EllipseTest extends BaseTestCase\n{\n    public function testConstructor(): void\n    {\n        $ellipse = new Ellipse(10, 20, new Point(100, 200));\n        $this->assertInstanceOf(Ellipse::class, $ellipse);\n        $this->assertEquals(10, $ellipse->width());\n        $this->assertEquals(20, $ellipse->height());\n    }\n\n    public function testPosition(): void\n    {\n        $ellipse = new Ellipse(10, 20, new Point(100, 200));\n        $this->assertInstanceOf(Point::class, $ellipse->position());\n        $this->assertEquals(100, $ellipse->position()->x());\n        $this->assertEquals(200, $ellipse->position()->y());\n\n        $this->assertInstanceOf(Point::class, $ellipse->pivot());\n        $this->assertEquals(100, $ellipse->pivot()->x());\n        $this->assertEquals(200, $ellipse->pivot()->y());\n    }\n\n    public function testSetSize(): void\n    {\n        $ellipse = new Ellipse(10, 20, new Point(100, 200));\n        $this->assertEquals(10, $ellipse->width());\n        $this->assertEquals(20, $ellipse->height());\n        $result = $ellipse->setSize(100, 200);\n        $this->assertInstanceOf(Ellipse::class, $result);\n        $this->assertEquals(100, $ellipse->width());\n        $this->assertEquals(200, $ellipse->height());\n    }\n\n    public function testSetWidthHeight(): void\n    {\n        $ellipse = new Ellipse(10, 20, new Point(100, 200));\n        $this->assertEquals(10, $ellipse->width());\n        $this->assertEquals(20, $ellipse->height());\n        $result = $ellipse->setWidth(100);\n        $this->assertInstanceOf(Ellipse::class, $result);\n        $this->assertEquals(100, $ellipse->width());\n        $this->assertEquals(20, $ellipse->height());\n        $result = $ellipse->setHeight(200);\n        $this->assertInstanceOf(Ellipse::class, $result);\n        $this->assertEquals(100, $ellipse->width());\n        $this->assertEquals(200, $ellipse->height());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Geometry/Factories/BezierFactoryTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Geometry\\Factories;\n\nuse Intervention\\Image\\Geometry\\Factories\\BezierFactory;\nuse Intervention\\Image\\Geometry\\Bezier;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\n\n#[CoversClass(BezierFactory::class)]\nfinal class BezierFactoryTest extends BaseTestCase\n{\n    public function testFactoryCallback(): void\n    {\n        $factory = new BezierFactory(function ($bezier): void {\n            $bezier->background('f00');\n            $bezier->border('ff0', 10);\n            $bezier->point(300, 260);\n            $bezier->point(150, 335);\n            $bezier->point(300, 410);\n        });\n\n        $bezier = $factory();\n        $this->assertInstanceOf(Bezier::class, $bezier);\n        $this->assertTrue($bezier->hasBackgroundColor());\n        $this->assertEquals('f00', $bezier->backgroundColor());\n        $this->assertEquals('ff0', $bezier->borderColor());\n        $this->assertEquals(10, $bezier->borderSize());\n        $this->assertEquals(3, $bezier->count());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Geometry/Factories/CircleFactoryTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Geometry\\Factories;\n\nuse Intervention\\Image\\Geometry\\Ellipse;\nuse Intervention\\Image\\Geometry\\Factories\\CircleFactory;\nuse Intervention\\Image\\Geometry\\Point;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\n\n#[CoversClass(CircleFactory::class)]\nfinal class CircleFactoryTest extends BaseTestCase\n{\n    public function testFactoryCallback(): void\n    {\n        $factory = new CircleFactory(new Point(1, 2), function ($circle): void {\n            $circle->background('fff');\n            $circle->border('ccc', 10);\n            $circle->radius(100);\n            $circle->diameter(1000);\n        });\n\n        $circle = $factory();\n        $this->assertInstanceOf(Ellipse::class, $circle);\n        $this->assertTrue($circle->hasBackgroundColor());\n        $this->assertEquals('fff', $circle->backgroundColor());\n        $this->assertEquals('ccc', $circle->borderColor());\n        $this->assertEquals(10, $circle->borderSize());\n        $this->assertEquals(1000, $circle->width());\n        $this->assertEquals(1000, $circle->height());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Geometry/Factories/DrawableTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Geometry\\Factories;\n\nuse Intervention\\Image\\Geometry\\Factories\\BezierFactory;\nuse Intervention\\Image\\Geometry\\Factories\\CircleFactory;\nuse Intervention\\Image\\Geometry\\Factories\\Drawable;\nuse Intervention\\Image\\Geometry\\Factories\\EllipseFactory;\nuse Intervention\\Image\\Geometry\\Factories\\LineFactory;\nuse Intervention\\Image\\Geometry\\Factories\\PolygonFactory;\nuse Intervention\\Image\\Geometry\\Factories\\RectangleFactory;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\n\n#[CoversClass(BezierFactory::class)]\nfinal class DrawableTest extends BaseTestCase\n{\n    public function testBezier(): void\n    {\n        $this->assertInstanceOf(BezierFactory::class, Drawable::bezier());\n    }\n\n    public function testCircle(): void\n    {\n        $this->assertInstanceOf(CircleFactory::class, Drawable::circle());\n    }\n\n    public function testEllipse(): void\n    {\n        $this->assertInstanceOf(EllipseFactory::class, Drawable::ellipse());\n    }\n\n    public function testLine(): void\n    {\n        $this->assertInstanceOf(LineFactory::class, Drawable::line());\n    }\n\n    public function testPolygon(): void\n    {\n        $this->assertInstanceOf(PolygonFactory::class, Drawable::polygon());\n    }\n\n    public function testRectangle(): void\n    {\n        $this->assertInstanceOf(RectangleFactory::class, Drawable::rectangle());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Geometry/Factories/EllipseFactoryTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Geometry\\Factories;\n\nuse Intervention\\Image\\Geometry\\Ellipse;\nuse Intervention\\Image\\Geometry\\Factories\\EllipseFactory;\nuse Intervention\\Image\\Geometry\\Point;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\n\n#[CoversClass(EllipseFactory::class)]\nfinal class EllipseFactoryTest extends BaseTestCase\n{\n    public function testFactoryCallback(): void\n    {\n        $factory = new EllipseFactory(new Point(1, 2), function ($ellipse): void {\n            $ellipse->background('fff');\n            $ellipse->border('ccc', 10);\n            $ellipse->width(100);\n            $ellipse->height(200);\n            $ellipse->size(1000, 2000);\n        });\n\n        $ellipse = $factory();\n        $this->assertInstanceOf(Ellipse::class, $ellipse);\n        $this->assertTrue($ellipse->hasBackgroundColor());\n        $this->assertEquals('fff', $ellipse->backgroundColor());\n        $this->assertEquals('ccc', $ellipse->borderColor());\n        $this->assertEquals(10, $ellipse->borderSize());\n        $this->assertEquals(1000, $ellipse->width());\n        $this->assertEquals(2000, $ellipse->height());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Geometry/Factories/LineFactoryTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Geometry\\Factories;\n\nuse Intervention\\Image\\Geometry\\Factories\\LineFactory;\nuse Intervention\\Image\\Geometry\\Line;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\n\n#[CoversClass(LineFactory::class)]\nfinal class LineFactoryTest extends BaseTestCase\n{\n    public function testFactoryCallback(): void\n    {\n        $factory = new LineFactory(function ($line): void {\n            $line->color('fff');\n            $line->background('fff');\n            $line->border('fff', 10);\n            $line->width(10);\n            $line->from(100, 200);\n            $line->to(300, 400);\n        });\n\n        $line = $factory();\n        $this->assertInstanceOf(Line::class, $line);\n        $this->assertTrue($line->hasBackgroundColor());\n        $this->assertEquals('fff', $line->backgroundColor());\n        $this->assertEquals(100, $line->start()->x());\n        $this->assertEquals(200, $line->start()->y());\n        $this->assertEquals(300, $line->end()->x());\n        $this->assertEquals(400, $line->end()->y());\n        $this->assertEquals(10, $line->width());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Geometry/Factories/PolygonFactoryTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Geometry\\Factories;\n\nuse Intervention\\Image\\Geometry\\Factories\\PolygonFactory;\nuse Intervention\\Image\\Geometry\\Polygon;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\n\n#[CoversClass(PolygonFactory::class)]\nfinal class PolygonFactoryTest extends BaseTestCase\n{\n    public function testFactoryCallback(): void\n    {\n        $factory = new PolygonFactory(function ($polygon): void {\n            $polygon->background('fff');\n            $polygon->border('ccc', 10);\n            $polygon->point(1, 2);\n            $polygon->point(3, 4);\n            $polygon->point(5, 6);\n        });\n\n        $polygon = $factory();\n        $this->assertInstanceOf(Polygon::class, $polygon);\n        $this->assertTrue($polygon->hasBackgroundColor());\n        $this->assertEquals('fff', $polygon->backgroundColor());\n        $this->assertEquals('ccc', $polygon->borderColor());\n        $this->assertEquals(10, $polygon->borderSize());\n        $this->assertEquals(3, $polygon->count());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Geometry/Factories/RectangleFactoryTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Geometry\\Factories;\n\nuse Intervention\\Image\\Geometry\\Factories\\RectangleFactory;\nuse Intervention\\Image\\Geometry\\Point;\nuse Intervention\\Image\\Geometry\\Rectangle;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\n\n#[CoversClass(RectangleFactory::class)]\nfinal class RectangleFactoryTest extends BaseTestCase\n{\n    public function testFactoryCallback(): void\n    {\n        $factory = new RectangleFactory(new Point(1, 2), function ($rectangle): void {\n            $rectangle->background('fff');\n            $rectangle->border('ccc', 10);\n            $rectangle->width(100);\n            $rectangle->height(200);\n            $rectangle->size(1000, 2000);\n        });\n\n        $rectangle = $factory();\n        $this->assertInstanceOf(Rectangle::class, $rectangle);\n        $this->assertTrue($rectangle->hasBackgroundColor());\n        $this->assertEquals('fff', $rectangle->backgroundColor());\n        $this->assertEquals('ccc', $rectangle->borderColor());\n        $this->assertEquals(10, $rectangle->borderSize());\n        $this->assertEquals(1000, $rectangle->width());\n        $this->assertEquals(2000, $rectangle->height());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Geometry/LineTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Geometry;\n\nuse Intervention\\Image\\Geometry\\Line;\nuse Intervention\\Image\\Geometry\\Point;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\n\n#[CoversClass(Line::class)]\nfinal class LineTest extends BaseTestCase\n{\n    public function testConstructor(): void\n    {\n        $line = new Line(new Point(1, 2), new Point(3, 4), 10);\n        $this->assertInstanceOf(Line::class, $line);\n    }\n\n    public function testPosition(): void\n    {\n        $line = new Line(new Point(1, 2), new Point(3, 4), 10);\n        $this->assertEquals(1, $line->position()->x());\n        $this->assertEquals(2, $line->position()->y());\n    }\n\n    public function testSetGetStart(): void\n    {\n        $line = new Line(new Point(1, 2), new Point(3, 4), 10);\n        $this->assertEquals(1, $line->start()->x());\n        $this->assertEquals(2, $line->start()->y());\n        $result = $line->setStart(new Point(10, 20));\n        $this->assertInstanceOf(Line::class, $result);\n        $this->assertEquals(10, $line->start()->x());\n        $this->assertEquals(20, $line->start()->y());\n    }\n\n    public function testSetGetEnd(): void\n    {\n        $line = new Line(new Point(1, 2), new Point(3, 4), 10);\n        $this->assertEquals(3, $line->end()->x());\n        $this->assertEquals(4, $line->end()->y());\n        $result = $line->setEnd(new Point(30, 40));\n        $this->assertInstanceOf(Line::class, $result);\n        $this->assertEquals(30, $line->end()->x());\n        $this->assertEquals(40, $line->end()->y());\n    }\n\n    public function setFrom(): void\n    {\n        $line = new Line(new Point(1, 2), new Point(3, 4), 10);\n        $this->assertEquals(1, $line->start()->x());\n        $this->assertEquals(2, $line->start()->y());\n        $result = $line->from(10, 20);\n        $this->assertInstanceOf(Line::class, $result);\n        $this->assertEquals(10, $line->start()->x());\n        $this->assertEquals(20, $line->start()->y());\n    }\n\n    public function setTo(): void\n    {\n        $line = new Line(new Point(1, 2), new Point(3, 4), 10);\n        $this->assertEquals(3, $line->end()->x());\n        $this->assertEquals(4, $line->end()->y());\n        $result = $line->to(30, 40);\n        $this->assertInstanceOf(Line::class, $result);\n        $this->assertEquals(30, $line->end()->x());\n        $this->assertEquals(40, $line->end()->y());\n    }\n\n    public function testSetGetWidth(): void\n    {\n        $line = new Line(new Point(1, 2), new Point(3, 4), 10);\n        $this->assertEquals(10, $line->width());\n        $result = $line->setWidth(20);\n        $this->assertInstanceOf(Line::class, $result);\n        $this->assertEquals(20, $line->width());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Geometry/PixelTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Geometry;\n\nuse Intervention\\Image\\Colors\\Rgb\\Color;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse Intervention\\Image\\Geometry\\Pixel;\nuse Intervention\\Image\\Tests\\BaseTestCase;\n\n#[CoversClass(Pixel::class)]\nfinal class PixelTest extends BaseTestCase\n{\n    public function testSetGetBackground(): void\n    {\n        $color = new Color(255, 55, 0);\n        $pixel = new Pixel(new Color(0, 0, 0), 10, 12);\n        $result = $pixel->setBackgroundColor($color);\n        $this->assertEquals($color, $pixel->backgroundColor());\n        $this->assertInstanceOf(Pixel::class, $result);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Geometry/PointTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Geometry;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse Intervention\\Image\\Geometry\\Point;\nuse Intervention\\Image\\Tests\\BaseTestCase;\n\n#[CoversClass(Point::class)]\nfinal class PointTest extends BaseTestCase\n{\n    public function testConstructor(): void\n    {\n        $point = new Point();\n        $this->assertInstanceOf(Point::class, $point);\n        $this->assertEquals(0, $point->x());\n        $this->assertEquals(0, $point->y());\n    }\n\n    public function testConstructorWithParameters(): void\n    {\n        $point = new Point(40, 50);\n        $this->assertInstanceOf(Point::class, $point);\n        $this->assertEquals(40, $point->x());\n        $this->assertEquals(50, $point->y());\n    }\n\n    public function testIteration(): void\n    {\n        $point = new Point(40, 50);\n        foreach ($point as $value) {\n            $this->assertIsInt($value);\n        }\n    }\n\n    public function testGetSetX(): void\n    {\n        $point = new Point(0, 0);\n        $point->setX(100);\n        $this->assertEquals(100, $point->x());\n        $this->assertEquals(0, $point->y());\n    }\n\n    public function testGetSetY(): void\n    {\n        $point = new Point(0, 0);\n        $point->setY(100);\n        $this->assertEquals(0, $point->x());\n        $this->assertEquals(100, $point->y());\n    }\n\n    public function testmoveX(): void\n    {\n        $point = new Point(50, 50);\n        $point->moveX(100);\n        $this->assertEquals(150, $point->x());\n        $this->assertEquals(50, $point->y());\n    }\n\n    public function testmoveY(): void\n    {\n        $point = new Point(50, 50);\n        $point->moveY(100);\n        $this->assertEquals(50, $point->x());\n        $this->assertEquals(150, $point->y());\n    }\n\n    public function testSetPosition(): void\n    {\n        $point = new Point(0, 0);\n        $point->setPosition(100, 200);\n        $this->assertEquals(100, $point->x());\n        $this->assertEquals(200, $point->y());\n    }\n\n    public function testRotate(): void\n    {\n        $point = new Point(30, 0);\n        $point->rotate(90, new Point(0, 0));\n        $this->assertEquals(0, $point->x());\n        $this->assertEquals(30, $point->y());\n\n        $point->rotate(90, new Point(0, 0));\n        $this->assertEquals(-30, $point->x());\n        $this->assertEquals(0, $point->y());\n\n        $point = new Point(300, 200);\n        $point->rotate(90, new Point(0, 0));\n        $this->assertEquals(-200, $point->x());\n        $this->assertEquals(300, $point->y());\n\n        $point = new Point(0, 74);\n        $point->rotate(45, new Point(0, 0));\n        $this->assertEquals(-52, $point->x());\n        $this->assertEquals(52, $point->y());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Geometry/PolygonTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Geometry;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse Intervention\\Image\\Geometry\\Point;\nuse Intervention\\Image\\Geometry\\Polygon;\nuse Intervention\\Image\\Tests\\BaseTestCase;\n\n#[CoversClass(Polygon::class)]\nfinal class PolygonTest extends BaseTestCase\n{\n    public function testConstructor(): void\n    {\n        $poly = new Polygon([]);\n        $this->assertInstanceOf(Polygon::class, $poly);\n        $this->assertEquals(0, $poly->count());\n    }\n\n    public function testCount(): void\n    {\n        $poly = new Polygon([new Point(), new Point()]);\n        $this->assertEquals(2, $poly->count());\n    }\n\n    public function testArrayAccess(): void\n    {\n        $poly = new Polygon([new Point(), new Point()]);\n        $this->assertInstanceOf(Point::class, $poly[0]);\n        $this->assertInstanceOf(Point::class, $poly[1]);\n    }\n\n    public function testAddPoint(): void\n    {\n        $poly = new Polygon([new Point(), new Point()]);\n        $this->assertEquals(2, $poly->count());\n        $result = $poly->addPoint(new Point());\n        $this->assertEquals(3, $poly->count());\n        $this->assertInstanceOf(Polygon::class, $result);\n    }\n\n    public function testGetCenterPoint(): void\n    {\n        $poly = new Polygon([\n            new Point(0, 0),\n            new Point(20, 0),\n            new Point(20, -20),\n            new Point(0, -20),\n        ]);\n\n        $result = $poly->centerPoint();\n        $this->assertEquals(10, $result->x());\n        $this->assertEquals(-10, $result->y());\n\n        $poly = new Polygon([\n            new Point(0, 0),\n            new Point(300, 0),\n            new Point(300, -200),\n            new Point(0, -200),\n        ], new Point(0, 0));\n\n        $result = $poly->centerPoint();\n        $this->assertEquals(150, $result->x());\n        $this->assertEquals(-100, $result->y());\n    }\n\n    public function testGetWidth(): void\n    {\n        $poly = new Polygon([\n            new Point(12, 45),\n            new Point(-23, -49),\n            new Point(3, 566),\n        ]);\n\n        $this->assertEquals($poly->width(), 35);\n    }\n\n    public function testGetHeight(): void\n    {\n        $poly = new Polygon([\n            new Point(12, 45),\n            new Point(-23, -49),\n            new Point(3, 566),\n        ]);\n\n        $this->assertEquals(615, $poly->height());\n\n        $poly = new Polygon([\n            new Point(250, 207),\n            new Point(473, 207),\n            new Point(473, 250),\n            new Point(250, 250),\n        ], new Point(250, 250));\n\n        $this->assertEquals(43, $poly->height());\n    }\n\n    public function testFirst(): void\n    {\n        $poly = new Polygon([\n            new Point(12, 45),\n            new Point(-23, -49),\n            new Point(3, 566),\n        ]);\n\n        $this->assertEquals(12, $poly->first()->x());\n        $this->assertEquals(45, $poly->first()->y());\n    }\n\n    public function testFirstEmpty(): void\n    {\n        $poly = new Polygon();\n        $this->assertNull($poly->first());\n    }\n\n    public function testLast(): void\n    {\n        $poly = new Polygon([\n            new Point(12, 45),\n            new Point(-23, -49),\n            new Point(3, 566),\n        ]);\n\n        $this->assertEquals(3, $poly->last()->x());\n        $this->assertEquals(566, $poly->last()->y());\n    }\n\n    public function testLastEmpty(): void\n    {\n        $poly = new Polygon();\n        $this->assertNull($poly->last());\n    }\n\n    public function testOffsetExists(): void\n    {\n        $poly = new Polygon();\n        $this->assertFalse($poly->offsetExists(0));\n        $this->assertFalse($poly->offsetExists(1));\n        $poly->addPoint(new Point(0, 0));\n        $this->assertTrue($poly->offsetExists(0));\n        $this->assertFalse($poly->offsetExists(1));\n    }\n\n    public function testOffsetSetUnset(): void\n    {\n        $poly = new Polygon();\n        $poly->offsetSet(0, new Point());\n        $poly->offsetSet(2, new Point());\n        $this->assertTrue($poly->offsetExists(0));\n        $this->assertFalse($poly->offsetExists(1));\n        $this->assertTrue($poly->offsetExists(2));\n        $poly->offsetUnset(2);\n        $this->assertTrue($poly->offsetExists(0));\n        $this->assertFalse($poly->offsetExists(1));\n        $this->assertFalse($poly->offsetExists(2));\n    }\n\n    public function testGetSetPivotPoint(): void\n    {\n        $poly = new Polygon();\n        $this->assertInstanceOf(Point::class, $poly->pivot());\n        $this->assertEquals(0, $poly->pivot()->x());\n        $this->assertEquals(0, $poly->pivot()->y());\n        $result = $poly->setPivot(new Point(12, 34));\n        $this->assertInstanceOf(Polygon::class, $result);\n        $this->assertEquals(12, $poly->pivot()->x());\n        $this->assertEquals(34, $poly->pivot()->y());\n    }\n\n    public function testGetMostLeftPoint(): void\n    {\n        $poly = new Polygon([\n            new Point(0, 0),\n            new Point(300, 0),\n            new Point(300, -200),\n            new Point(-32, -200),\n        ], new Point(0, 0));\n\n        $result = $poly->mostLeftPoint();\n        $this->assertEquals(-32, $result->x());\n        $this->assertEquals(-200, $result->y());\n    }\n\n    public function testGetMostRightPoint(): void\n    {\n        $poly = new Polygon([\n            new Point(0, 0),\n            new Point(350, 0),\n            new Point(300, -200),\n            new Point(-32, -200),\n        ], new Point(0, 0));\n\n        $result = $poly->mostRightPoint();\n        $this->assertEquals(350, $result->x());\n        $this->assertEquals(0, $result->y());\n    }\n\n    public function testGetMostTopPoint(): void\n    {\n        $poly = new Polygon([\n            new Point(0, 100),\n            new Point(350, 0),\n            new Point(300, -200),\n            new Point(-32, 200),\n        ], new Point(0, 0));\n\n        $result = $poly->mostTopPoint();\n        $this->assertEquals(-32, $result->x());\n        $this->assertEquals(200, $result->y());\n    }\n\n    public function testGetMostBottomPoint(): void\n    {\n        $poly = new Polygon([\n            new Point(0, 100),\n            new Point(350, 0),\n            new Point(300, -200),\n            new Point(-32, 200),\n        ], new Point(0, 0));\n\n        $result = $poly->mostBottomPoint();\n        $this->assertEquals(300, $result->x());\n        $this->assertEquals(-200, $result->y());\n    }\n\n    public function testAlignCenter(): void\n    {\n        $poly = new Polygon([\n            new Point(0, 0),\n            new Point(300, 0),\n            new Point(300, -200),\n            new Point(0, -200),\n        ], new Point(0, 0));\n\n        $result = $poly->align('center');\n\n        $this->assertInstanceOf(Polygon::class, $result);\n        $this->assertEquals(-150, $result[0]->x());\n        $this->assertEquals(0, $result[0]->y());\n        $this->assertEquals(150, $result[1]->x());\n        $this->assertEquals(0, $result[1]->y());\n        $this->assertEquals(150, $result[2]->x());\n        $this->assertEquals(-200, $result[2]->y());\n        $this->assertEquals(-150, $result[3]->x());\n        $this->assertEquals(-200, $result[3]->y());\n\n        $poly = new Polygon([\n            new Point(0, 0),\n            new Point(300, 0),\n            new Point(300, -200),\n            new Point(0, -200),\n        ], new Point(-1000, -1000));\n\n        $result = $poly->align('center');\n\n        $this->assertInstanceOf(Polygon::class, $result);\n        $this->assertEquals(-1150, $result[0]->x());\n        $this->assertEquals(0, $result[0]->y());\n        $this->assertEquals(-850, $result[1]->x());\n        $this->assertEquals(0, $result[1]->y());\n        $this->assertEquals(-850, $result[2]->x());\n        $this->assertEquals(-200, $result[2]->y());\n        $this->assertEquals(-1150, $result[3]->x());\n        $this->assertEquals(-200, $result[3]->y());\n    }\n\n    public function testAlignLeft(): void\n    {\n        $poly = new Polygon([\n            new Point(0, 0),\n            new Point(300, 0),\n            new Point(300, -200),\n            new Point(0, -200),\n        ], new Point(100, 100));\n\n        $result = $poly->align('left');\n\n        $this->assertInstanceOf(Polygon::class, $result);\n        $this->assertEquals(100, $result[0]->x());\n        $this->assertEquals(0, $result[0]->y());\n        $this->assertEquals(400, $result[1]->x());\n        $this->assertEquals(0, $result[1]->y());\n        $this->assertEquals(400, $result[2]->x());\n        $this->assertEquals(-200, $result[2]->y());\n        $this->assertEquals(100, $result[3]->x());\n        $this->assertEquals(-200, $result[3]->y());\n\n        $poly = new Polygon([\n            new Point(0, 0),\n            new Point(300, 0),\n            new Point(300, -200),\n            new Point(0, -200),\n        ], new Point(-1000, -1000));\n\n        $result = $poly->align('left');\n\n        $this->assertInstanceOf(Polygon::class, $result);\n        $this->assertEquals(-1000, $result[0]->x());\n        $this->assertEquals(0, $result[0]->y());\n        $this->assertEquals(-700, $result[1]->x());\n        $this->assertEquals(0, $result[1]->y());\n        $this->assertEquals(-700, $result[2]->x());\n        $this->assertEquals(-200, $result[2]->y());\n        $this->assertEquals(-1000, $result[3]->x());\n        $this->assertEquals(-200, $result[3]->y());\n    }\n\n    public function testAlignRight(): void\n    {\n        $poly = new Polygon([\n            new Point(0, 0),\n            new Point(300, 0),\n            new Point(300, -200),\n            new Point(0, -200),\n        ], new Point(100, 100));\n\n        $result = $poly->align('right');\n\n        $this->assertInstanceOf(Polygon::class, $result);\n        $this->assertEquals(-200, $result[0]->x());\n        $this->assertEquals(0, $result[0]->y());\n        $this->assertEquals(100, $result[1]->x());\n        $this->assertEquals(0, $result[1]->y());\n        $this->assertEquals(100, $result[2]->x());\n        $this->assertEquals(-200, $result[2]->y());\n        $this->assertEquals(-200, $result[3]->x());\n        $this->assertEquals(-200, $result[3]->y());\n\n        $poly = new Polygon([\n            new Point(0, 0),\n            new Point(300, 0),\n            new Point(300, -200),\n            new Point(0, -200),\n        ], new Point(-1000, -1000));\n\n        $result = $poly->align('right');\n\n        $this->assertInstanceOf(Polygon::class, $result);\n        $this->assertEquals(-1300, $result[0]->x());\n        $this->assertEquals(0, $result[0]->y());\n        $this->assertEquals(-1000, $result[1]->x());\n        $this->assertEquals(0, $result[1]->y());\n        $this->assertEquals(-1000, $result[2]->x());\n        $this->assertEquals(-200, $result[2]->y());\n        $this->assertEquals(-1300, $result[3]->x());\n        $this->assertEquals(-200, $result[3]->y());\n    }\n\n    public function testValignMiddle(): void\n    {\n        $poly = new Polygon([\n            new Point(-21, -22),\n            new Point(91, -135),\n            new Point(113, -113),\n            new Point(0, 0),\n        ], new Point(250, 250));\n\n        $result = $poly->valign('middle');\n\n        $this->assertInstanceOf(Polygon::class, $result);\n        $this->assertEquals(-21, $result[0]->x());\n        $this->assertEquals(296, $result[0]->y());\n        $this->assertEquals(91, $result[1]->x());\n        $this->assertEquals(183, $result[1]->y());\n        $this->assertEquals(113, $result[2]->x());\n        $this->assertEquals(205, $result[2]->y());\n        $this->assertEquals(0, $result[3]->x());\n        $this->assertEquals(318, $result[3]->y());\n    }\n\n    public function testValignTop(): void\n    {\n        $poly = new Polygon([\n            new Point(-21, -22),\n            new Point(91, -135),\n            new Point(113, -113),\n            new Point(0, 0),\n        ], new Point(250, 250));\n\n        $result = $poly->valign('top');\n\n        $this->assertInstanceOf(Polygon::class, $result);\n        $this->assertEquals(-21, $result[0]->x());\n        $this->assertEquals(363, $result[0]->y());\n        $this->assertEquals(91, $result[1]->x());\n        $this->assertEquals(250, $result[1]->y());\n        $this->assertEquals(113, $result[2]->x());\n        $this->assertEquals(272, $result[2]->y());\n        $this->assertEquals(0, $result[3]->x());\n        $this->assertEquals(385, $result[3]->y());\n    }\n\n    public function testMovePoints(): void\n    {\n        $poly = new Polygon([\n            new Point(10, 20),\n            new Point(30, 40)\n        ]);\n\n        $result = $poly->movePointsX(100);\n        $this->assertEquals(110, $result[0]->x());\n        $this->assertEquals(20, $result[0]->y());\n        $this->assertEquals(130, $result[1]->x());\n        $this->assertEquals(40, $result[1]->y());\n\n        $result = $poly->movePointsY(200);\n        $this->assertEquals(110, $result[0]->x());\n        $this->assertEquals(220, $result[0]->y());\n        $this->assertEquals(130, $result[1]->x());\n        $this->assertEquals(240, $result[1]->y());\n    }\n\n    public function testRotate(): void\n    {\n        $poly = new Polygon([\n            new Point(0, 0),\n            new Point(50, 0),\n            new Point(50, -50),\n            new Point(0, -50),\n        ]);\n\n        $result = $poly->rotate(45);\n        $this->assertInstanceOf(Polygon::class, $result);\n        $this->assertEquals(0, $result[0]->x());\n        $this->assertEquals(0, $result[0]->y());\n        $this->assertEquals(35, $result[1]->x());\n        $this->assertEquals(35, $result[1]->y());\n        $this->assertEquals(70, $result[2]->x());\n        $this->assertEquals(0, $result[2]->y());\n        $this->assertEquals(35, $result[3]->x());\n        $this->assertEquals(-35, $result[3]->y());\n    }\n\n    public function testToArray(): void\n    {\n        $poly = new Polygon([\n            new Point(0, 0),\n            new Point(50, 0),\n            new Point(50, -50),\n            new Point(0, -50),\n        ]);\n\n        $this->assertEquals([0, 0, 50, 0, 50, -50, 0, -50], $poly->toArray());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Geometry/RectangleResizerTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Geometry;\n\nuse Generator;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse Intervention\\Image\\Geometry\\Point;\nuse Intervention\\Image\\Geometry\\Rectangle;\nuse Intervention\\Image\\Geometry\\Tools\\RectangleResizer;\nuse PHPUnit\\Framework\\TestCase;\n\n#[CoversClass(RectangleResizer::class)]\nfinal class RectangleResizerTest extends TestCase\n{\n    public function testMake(): void\n    {\n        $resizer = RectangleResizer::to();\n        $this->assertInstanceOf(RectangleResizer::class, $resizer);\n\n        $resizer = RectangleResizer::to(height: 100);\n        $this->assertInstanceOf(RectangleResizer::class, $resizer);\n\n        $resizer = RectangleResizer::to(100);\n        $this->assertInstanceOf(RectangleResizer::class, $resizer);\n\n        $resizer = RectangleResizer::to(100, 100);\n        $this->assertInstanceOf(RectangleResizer::class, $resizer);\n    }\n\n    public function testToWidth(): void\n    {\n        $resizer = new RectangleResizer();\n        $result = $resizer->toWidth(100);\n        $this->assertInstanceOf(RectangleResizer::class, $result);\n    }\n\n    public function testToHeight(): void\n    {\n        $resizer = new RectangleResizer();\n        $result = $resizer->toHeight(100);\n        $this->assertInstanceOf(RectangleResizer::class, $result);\n    }\n\n    public function testToSize(): void\n    {\n        $resizer = new RectangleResizer();\n        $resizer = $resizer->toSize(new Rectangle(200, 100));\n        $this->assertInstanceOf(RectangleResizer::class, $resizer);\n    }\n\n    /**\n     * @param $resizeParameters array<string, int>\n     */\n    #[DataProvider('resizeDataProvider')]\n    public function testResize(Rectangle $input, array $resizeParameters, Rectangle $result): void\n    {\n        $resizer = new RectangleResizer(...$resizeParameters);\n        $resized = $resizer->resize($input);\n        $this->assertEquals($result->width(), $resized->width());\n        $this->assertEquals($result->height(), $resized->height());\n    }\n\n    public static function resizeDataProvider(): Generator\n    {\n        yield [new Rectangle(300, 200), ['width' => 150], new Rectangle(150, 200)];\n        yield [new Rectangle(300, 200), ['height' => 150], new Rectangle(300, 150)];\n        yield [new Rectangle(300, 200), ['width' => 20, 'height' => 10], new Rectangle(20, 10)];\n        yield [new Rectangle(300, 200), [], new Rectangle(300, 200)];\n    }\n\n    /**\n     * @param $resizeParameters array<string, int>\n     */\n    #[DataProvider('resizeDownDataProvider')]\n    public function testResizeDown(Rectangle $input, array $resizeParameters, Rectangle $result): void\n    {\n        $resizer = new RectangleResizer(...$resizeParameters);\n        $resized = $resizer->resizeDown($input);\n        $this->assertEquals($result->width(), $resized->width());\n        $this->assertEquals($result->height(), $resized->height());\n    }\n\n    public static function resizeDownDataProvider(): Generator\n    {\n        yield [new Rectangle(800, 600), ['width' => 1000, 'height' => 2000], new Rectangle(800, 600)];\n        yield [new Rectangle(800, 600), ['width' => 400, 'height' => 1000], new Rectangle(400, 600)];\n        yield [new Rectangle(800, 600), ['width' => 1000, 'height' => 400], new Rectangle(800, 400)];\n        yield [new Rectangle(800, 600), ['width' => 400, 'height' => 300], new Rectangle(400, 300)];\n        yield [new Rectangle(800, 600), ['width' => 1000], new Rectangle(800, 600)];\n        yield [new Rectangle(800, 600), ['height' => 1000], new Rectangle(800, 600)];\n        yield [new Rectangle(800, 600), [], new Rectangle(800, 600)];\n    }\n\n    /**\n     * @param $resizeParameters array<string, int>\n     */\n    #[DataProvider('scaleDataProvider')]\n    public function testScale(Rectangle $input, array $resizeParameters, Rectangle $result): void\n    {\n        $resizer = new RectangleResizer(...$resizeParameters);\n        $resized = $resizer->scale($input);\n        $this->assertEquals($result->width(), $resized->width());\n        $this->assertEquals($result->height(), $resized->height());\n    }\n\n    public static function scaleDataProvider(): Generator\n    {\n        yield [new Rectangle(800, 600), ['width' => 1000, 'height' => 2000], new Rectangle(1000, 750)];\n        yield [new Rectangle(800, 600), ['width' => 2000, 'height' => 1000], new Rectangle(1333, 1000)];\n        yield [new Rectangle(800, 600), ['height' => 3000], new Rectangle(4000, 3000)];\n        yield [new Rectangle(800, 600), ['width' => 8000], new Rectangle(8000, 6000)];\n        yield [new Rectangle(800, 600), ['width' => 100, 'height' => 400], new Rectangle(100, 75)];\n        yield [new Rectangle(800, 600), ['width' => 400, 'height' => 100], new Rectangle(133, 100)];\n        yield [new Rectangle(800, 600), ['height' => 300], new Rectangle(400, 300)];\n        yield [new Rectangle(800, 600), ['width' => 80], new Rectangle(80, 60)];\n        yield [new Rectangle(640, 480), ['width' => 225], new Rectangle(225, 169)];\n        yield [new Rectangle(640, 480), ['width' => 223], new Rectangle(223, 167)];\n        yield [new Rectangle(600, 800), ['width' => 300, 'height' => 300], new Rectangle(225, 300)];\n        yield [new Rectangle(800, 600), ['width' => 400, 'height' => 10], new Rectangle(13, 10)];\n        yield [new Rectangle(800, 600), ['width' => 1000, 'height' => 1200], new Rectangle(1000, 750)];\n        yield [new Rectangle(12000, 12), ['width' => 4000, 'height' => 3000], new Rectangle(4000, 4)];\n        yield [new Rectangle(12, 12000), ['width' => 4000, 'height' => 3000], new Rectangle(3, 3000)];\n        yield [new Rectangle(12000, 6000), ['width' => 4000, 'height' => 3000], new Rectangle(4000, 2000)];\n        yield [new Rectangle(3, 3000), ['height' => 300], new Rectangle(1, 300)];\n        yield [new Rectangle(800, 600), [], new Rectangle(800, 600)];\n    }\n\n    /**\n     * @param $resizeParameters array<string, int>\n     */\n    #[DataProvider('scaleDownDataProvider')]\n    public function testScaleDown(Rectangle $input, array $resizeParameters, Rectangle $result): void\n    {\n        $resizer = new RectangleResizer(...$resizeParameters);\n        $resized = $resizer->scaleDown($input);\n        $this->assertEquals($result->width(), $resized->width());\n        $this->assertEquals($result->height(), $resized->height());\n    }\n\n    public static function scaleDownDataProvider(): Generator\n    {\n        yield [new Rectangle(800, 600), ['width' => 1000, 'height' => 2000], new Rectangle(800, 600)];\n        yield [new Rectangle(800, 600), ['width' => 1000, 'height' => 600], new Rectangle(800, 600)];\n        yield [new Rectangle(800, 600), ['width' => 1000, 'height' => 300], new Rectangle(400, 300)];\n        yield [new Rectangle(800, 600), ['width' => 400, 'height' => 1000], new Rectangle(400, 300)];\n        yield [new Rectangle(800, 600), ['width' => 400], new Rectangle(400, 300)];\n        yield [new Rectangle(800, 600), ['height' => 300], new Rectangle(400, 300)];\n        yield [new Rectangle(800, 600), ['width' => 1000], new Rectangle(800, 600)];\n        yield [new Rectangle(800, 600), ['height' => 1000], new Rectangle(800, 600)];\n        yield [new Rectangle(800, 600), ['width' => 100], new Rectangle(100, 75)];\n        yield [new Rectangle(800, 600), ['width' => 300, 'height' => 200], new Rectangle(267, 200)];\n        yield [new Rectangle(600, 800), ['width' => 300, 'height' => 300], new Rectangle(225, 300)];\n        yield [new Rectangle(800, 600), ['width' => 400, 'height' => 10], new Rectangle(13, 10)];\n        yield [new Rectangle(3, 3000), ['height' => 300], new Rectangle(1, 300)];\n        yield [new Rectangle(800, 600), [], new Rectangle(800, 600)];\n    }\n\n    #[DataProvider('coverDataProvider')]\n    public function testCover(Rectangle $origin, Rectangle $target, Rectangle $result): void\n    {\n        $resizer = new RectangleResizer();\n        $resizer->toSize($target);\n        $resized = $resizer->cover($origin);\n        $this->assertEquals($result->width(), $resized->width());\n        $this->assertEquals($result->height(), $resized->height());\n    }\n\n    public static function coverDataProvider(): Generator\n    {\n        yield [new Rectangle(800, 600), new Rectangle(100, 100), new Rectangle(133, 100)];\n        yield [new Rectangle(800, 600), new Rectangle(200, 100), new Rectangle(200, 150)];\n        yield [new Rectangle(800, 600), new Rectangle(100, 200), new Rectangle(267, 200)];\n        yield [new Rectangle(800, 600), new Rectangle(2000, 10), new Rectangle(2000, 1500)];\n        yield [new Rectangle(800, 600), new Rectangle(10, 2000), new Rectangle(2667, 2000)];\n        yield [new Rectangle(800, 600), new Rectangle(800, 600), new Rectangle(800, 600)];\n        yield [new Rectangle(400, 300), new Rectangle(120, 120), new Rectangle(160, 120)];\n        yield [new Rectangle(600, 800), new Rectangle(100, 100), new Rectangle(100, 133)];\n        yield [new Rectangle(100, 100), new Rectangle(800, 600), new Rectangle(800, 800)];\n    }\n\n    #[DataProvider('containDataProvider')]\n    public function testContain(Rectangle $origin, Rectangle $target, Rectangle $result): void\n    {\n        $resizer = new RectangleResizer();\n        $resizer->toSize($target);\n        $resized = $resizer->contain($origin);\n        $this->assertEquals($result->width(), $resized->width());\n        $this->assertEquals($result->height(), $resized->height());\n    }\n\n    public static function containDataProvider(): Generator\n    {\n        yield [new Rectangle(800, 600), new Rectangle(100, 100), new Rectangle(100, 75)];\n        yield [new Rectangle(800, 600), new Rectangle(200, 100), new Rectangle(133, 100)];\n        yield [new Rectangle(800, 600), new Rectangle(100, 200), new Rectangle(100, 75)];\n        yield [new Rectangle(800, 600), new Rectangle(2000, 10), new Rectangle(13, 10)];\n        yield [new Rectangle(800, 600), new Rectangle(10, 2000), new Rectangle(10, 8)];\n        yield [new Rectangle(800, 600), new Rectangle(800, 600), new Rectangle(800, 600)];\n        yield [new Rectangle(400, 300), new Rectangle(120, 120), new Rectangle(120, 90)];\n        yield [new Rectangle(600, 800), new Rectangle(100, 100), new Rectangle(75, 100)];\n        yield [new Rectangle(100, 100), new Rectangle(800, 600), new Rectangle(600, 600)];\n    }\n\n    #[DataProvider('cropDataProvider')]\n    public function testCrop(Rectangle $origin, Rectangle $target, string $position, Rectangle $result): void\n    {\n        $resizer = new RectangleResizer();\n        $resizer->toSize($target);\n        $resized = $resizer->crop($origin, $position);\n        $this->assertEquals($result->width(), $resized->width());\n        $this->assertEquals($result->height(), $resized->height());\n        $this->assertEquals($result->pivot()->x(), $resized->pivot()->x());\n        $this->assertEquals($result->pivot()->y(), $resized->pivot()->y());\n    }\n\n    public static function cropDataProvider(): Generator\n    {\n        yield [\n            new Rectangle(800, 600),\n            new Rectangle(100, 100),\n            'center',\n            new Rectangle(100, 100, new Point(350, 250))\n        ];\n        yield [\n            new Rectangle(800, 600),\n            new Rectangle(200, 100),\n            'center',\n            new Rectangle(200, 100, new Point(300, 250))\n        ];\n        yield [\n            new Rectangle(800, 600),\n            new Rectangle(100, 200),\n            'center',\n            new Rectangle(100, 200, new Point(350, 200))\n        ];\n        yield [\n            new Rectangle(800, 600),\n            new Rectangle(2000, 10),\n            'center',\n            new Rectangle(2000, 10, new Point(-600, 295))\n        ];\n        yield [\n            new Rectangle(800, 600),\n            new Rectangle(10, 2000),\n            'center',\n            new Rectangle(10, 2000, new Point(395, -700))\n        ];\n        yield [\n            new Rectangle(800, 600),\n            new Rectangle(800, 600),\n            'center',\n            new Rectangle(800, 600, new Point(0, 0))\n        ];\n        yield [\n            new Rectangle(400, 300),\n            new Rectangle(120, 120),\n            'center',\n            new Rectangle(120, 120, new Point(140, 90))\n        ];\n        yield [\n            new Rectangle(600, 800),\n            new Rectangle(100, 100),\n            'center',\n            new Rectangle(100, 100, new Point(250, 350))\n        ];\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Geometry/RectangleTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Geometry;\n\nuse Intervention\\Image\\Geometry\\Point;\nuse Intervention\\Image\\Geometry\\Rectangle;\nuse Intervention\\Image\\Interfaces\\PointInterface;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\n\n#[CoversClass(Rectangle::class)]\nfinal class RectangleTest extends BaseTestCase\n{\n    public function testConstructor(): void\n    {\n        $rectangle = new Rectangle(300, 200);\n        $this->assertEquals(0, $rectangle[0]->x());\n        $this->assertEquals(0, $rectangle[0]->y());\n        $this->assertEquals(300, $rectangle[1]->x());\n        $this->assertEquals(0, $rectangle[1]->y());\n        $this->assertEquals(300, $rectangle[2]->x());\n        $this->assertEquals(-200, $rectangle[2]->y());\n        $this->assertEquals(0, $rectangle[3]->x());\n        $this->assertEquals(-200, $rectangle[3]->y());\n        $this->assertEquals(300, $rectangle->width());\n        $this->assertEquals(200, $rectangle->height());\n    }\n\n    public function testSetSize(): void\n    {\n        $rectangle = new Rectangle(300, 200);\n        $rectangle->setSize(12, 34);\n        $this->assertEquals(12, $rectangle->width());\n        $this->assertEquals(34, $rectangle->height());\n    }\n\n    public function testSetWidth(): void\n    {\n        $rectangle = new Rectangle(300, 200);\n        $this->assertEquals(300, $rectangle->width());\n        $rectangle->setWidth(400);\n        $this->assertEquals(400, $rectangle->width());\n    }\n\n    public function testSetHeight(): void\n    {\n        $rectangle = new Rectangle(300, 200);\n        $this->assertEquals(200, $rectangle->height());\n        $rectangle->setHeight(800);\n        $this->assertEquals(800, $rectangle->height());\n    }\n\n    public function testGetAspectRatio(): void\n    {\n        $size = new Rectangle(800, 600);\n        $this->assertEquals(1.333, round($size->aspectRatio(), 3));\n\n        $size = new Rectangle(100, 100);\n        $this->assertEquals(1, $size->aspectRatio());\n\n        $size = new Rectangle(1920, 1080);\n        $this->assertEquals(1.778, round($size->aspectRatio(), 3));\n    }\n\n    public function testFitsInto(): void\n    {\n        $box = new Rectangle(800, 600);\n        $fits = $box->fitsInto(new Rectangle(100, 100));\n        $this->assertFalse($fits);\n\n        $box = new Rectangle(800, 600);\n        $fits = $box->fitsInto(new Rectangle(1000, 100));\n        $this->assertFalse($fits);\n\n        $box = new Rectangle(800, 600);\n        $fits = $box->fitsInto(new Rectangle(100, 1000));\n        $this->assertFalse($fits);\n\n        $box = new Rectangle(800, 600);\n        $fits = $box->fitsInto(new Rectangle(800, 600));\n        $this->assertTrue($fits);\n\n        $box = new Rectangle(800, 600);\n        $fits = $box->fitsInto(new Rectangle(1000, 1000));\n        $this->assertTrue($fits);\n\n        $box = new Rectangle(100, 100);\n        $fits = $box->fitsInto(new Rectangle(800, 600));\n        $this->assertTrue($fits);\n\n        $box = new Rectangle(100, 100);\n        $fits = $box->fitsInto(new Rectangle(80, 60));\n        $this->assertFalse($fits);\n    }\n\n    public function testIsLandscape(): void\n    {\n        $box = new Rectangle(100, 100);\n        $this->assertFalse($box->isLandscape());\n\n        $box = new Rectangle(100, 200);\n        $this->assertFalse($box->isLandscape());\n\n        $box = new Rectangle(300, 200);\n        $this->assertTrue($box->isLandscape());\n    }\n\n    public function testIsPortrait(): void\n    {\n        $box = new Rectangle(100, 100);\n        $this->assertFalse($box->isPortrait());\n\n        $box = new Rectangle(200, 100);\n        $this->assertFalse($box->isPortrait());\n\n        $box = new Rectangle(200, 300);\n        $this->assertTrue($box->isPortrait());\n    }\n\n    public function testSetGetPivot(): void\n    {\n        $box = new Rectangle(800, 600);\n        $pivot = $box->pivot();\n        $this->assertInstanceOf(Point::class, $pivot);\n        $this->assertEquals(0, $pivot->x());\n        $result = $box->setPivot(new Point(10, 0));\n        $this->assertInstanceOf(Rectangle::class, $result);\n        $this->assertEquals(10, $box->pivot()->x());\n    }\n\n    public function testAlignPivot(): void\n    {\n        $box = new Rectangle(640, 480);\n        $this->assertEquals(0, $box->pivot()->x());\n        $this->assertEquals(0, $box->pivot()->y());\n\n        $box->movePivot('top-left', 3, 3);\n        $this->assertEquals(3, $box->pivot()->x());\n        $this->assertEquals(3, $box->pivot()->y());\n\n        $box->movePivot('top', 3, 3);\n        $this->assertEquals(323, $box->pivot()->x());\n        $this->assertEquals(3, $box->pivot()->y());\n\n        $box->movePivot('top-right', 3, 3);\n        $this->assertEquals(637, $box->pivot()->x());\n        $this->assertEquals(3, $box->pivot()->y());\n\n        $box->movePivot('left', 3, 3);\n        $this->assertEquals(3, $box->pivot()->x());\n        $this->assertEquals(243, $box->pivot()->y());\n\n        $box->movePivot('center', 3, 3);\n        $this->assertEquals(323, $box->pivot()->x());\n        $this->assertEquals(243, $box->pivot()->y());\n\n        $box->movePivot('right', 3, 3);\n        $this->assertEquals(637, $box->pivot()->x());\n        $this->assertEquals(243, $box->pivot()->y());\n\n        $box->movePivot('bottom-left', 3, 3);\n        $this->assertEquals(3, $box->pivot()->x());\n        $this->assertEquals(477, $box->pivot()->y());\n\n        $box->movePivot('bottom', 3, 3);\n        $this->assertEquals(323, $box->pivot()->x());\n        $this->assertEquals(477, $box->pivot()->y());\n\n        $result = $box->movePivot('bottom-right', 3, 3);\n        $this->assertEquals(637, $box->pivot()->x());\n        $this->assertEquals(477, $box->pivot()->y());\n\n        $this->assertInstanceOf(Rectangle::class, $result);\n    }\n\n    public function testAlignPivotTo(): void\n    {\n        $container = new Rectangle(800, 600);\n        $size = new Rectangle(200, 100);\n        $size->alignPivotTo($container, 'center');\n        $this->assertEquals(300, $size->pivot()->x());\n        $this->assertEquals(250, $size->pivot()->y());\n\n        $container = new Rectangle(800, 600);\n        $size = new Rectangle(100, 100);\n        $size->alignPivotTo($container, 'center');\n        $this->assertEquals(350, $size->pivot()->x());\n        $this->assertEquals(250, $size->pivot()->y());\n\n        $container = new Rectangle(800, 600);\n        $size = new Rectangle(800, 600);\n        $size->alignPivotTo($container, 'center');\n        $this->assertEquals(0, $size->pivot()->x());\n        $this->assertEquals(0, $size->pivot()->y());\n\n        $container = new Rectangle(100, 100);\n        $size = new Rectangle(800, 600);\n        $size->alignPivotTo($container, 'center');\n        $this->assertEquals(-350, $size->pivot()->x());\n        $this->assertEquals(-250, $size->pivot()->y());\n\n        $container = new Rectangle(100, 100);\n        $size = new Rectangle(800, 600);\n        $size->alignPivotTo($container, 'bottom-right');\n        $this->assertEquals(-700, $size->pivot()->x());\n        $this->assertEquals(-500, $size->pivot()->y());\n    }\n\n    public function testgetRelativePositionTo(): void\n    {\n        $container = new Rectangle(800, 600);\n        $input = new Rectangle(200, 100);\n        $container->movePivot('top-left');\n        $input->movePivot('top-left');\n        $pos = $container->relativePositionTo($input);\n        $this->assertEquals(0, $pos->x());\n        $this->assertEquals(0, $pos->y());\n\n        $container = new Rectangle(800, 600);\n        $input = new Rectangle(200, 100);\n        $container->movePivot('center');\n        $input->movePivot('top-left');\n        $pos = $container->relativePositionTo($input);\n        $this->assertEquals(400, $pos->x());\n        $this->assertEquals(300, $pos->y());\n\n        $container = new Rectangle(800, 600);\n        $input = new Rectangle(200, 100);\n        $container->movePivot('bottom-right');\n        $input->movePivot('top-right');\n        $pos = $container->relativePositionTo($input);\n        $this->assertEquals(600, $pos->x());\n        $this->assertEquals(600, $pos->y());\n\n        $container = new Rectangle(800, 600);\n        $input = new Rectangle(200, 100);\n        $container->movePivot('center');\n        $input->movePivot('center');\n        $pos = $container->relativePositionTo($input);\n        $this->assertEquals(300, $pos->x());\n        $this->assertEquals(250, $pos->y());\n\n        $container = new Rectangle(100, 200);\n        $input = new Rectangle(100, 100);\n        $container->movePivot('center');\n        $input->movePivot('center');\n        $pos = $container->relativePositionTo($input);\n        $this->assertEquals(0, $pos->x());\n        $this->assertEquals(50, $pos->y());\n    }\n\n    public function testTopLeftPoint(): void\n    {\n        $rectangle = new Rectangle(800, 600);\n        $this->assertInstanceOf(PointInterface::class, $rectangle->topLeftPoint());\n    }\n\n    public function testBottomRightPoint(): void\n    {\n        $rectangle = new Rectangle(800, 600);\n        $this->assertInstanceOf(PointInterface::class, $rectangle->bottomRightPoint());\n    }\n\n    public function testResize(): void\n    {\n        $rectangle = new Rectangle(800, 600);\n        $result = $rectangle->resize(300, 200);\n        $this->assertInstanceOf(Rectangle::class, $result);\n        $this->assertEquals(300, $result->width());\n        $this->assertEquals(200, $result->height());\n    }\n\n    public function testResizeDown(): void\n    {\n        $rectangle = new Rectangle(800, 600);\n        $result = $rectangle->resizeDown(3000, 200);\n        $this->assertInstanceOf(Rectangle::class, $result);\n        $this->assertEquals(800, $result->width());\n        $this->assertEquals(200, $result->height());\n    }\n\n    public function testScale(): void\n    {\n        $rectangle = new Rectangle(800, 600);\n        $result = $rectangle->scale(height: 1200);\n        $this->assertInstanceOf(Rectangle::class, $result);\n        $this->assertEquals(800 * 2, $result->width());\n        $this->assertEquals(600 * 2, $result->height());\n    }\n\n    public function testScaleDown(): void\n    {\n        $rectangle = new Rectangle(800, 600);\n        $result = $rectangle->scaleDown(height: 1200);\n        $this->assertInstanceOf(Rectangle::class, $result);\n        $this->assertEquals(800, $result->width());\n        $this->assertEquals(600, $result->height());\n    }\n\n    public function testCover(): void\n    {\n        $rectangle = new Rectangle(800, 600);\n        $result = $rectangle->cover(400, 100);\n        $this->assertInstanceOf(Rectangle::class, $result);\n        $this->assertEquals(400, $result->width());\n        $this->assertEquals(300, $result->height());\n    }\n\n    public function testContain(): void\n    {\n        $rectangle = new Rectangle(800, 600);\n        $result = $rectangle->contain(1600, 1200);\n        $this->assertInstanceOf(Rectangle::class, $result);\n        $this->assertEquals(1600, $result->width());\n        $this->assertEquals(1200, $result->height());\n    }\n\n    public function testContainMax(): void\n    {\n        $rectangle = new Rectangle(800, 600);\n        $result = $rectangle->containMax(1600, 1200);\n        $this->assertInstanceOf(Rectangle::class, $result);\n        $this->assertEquals(800, $result->width());\n        $this->assertEquals(600, $result->height());\n    }\n\n    public function testDebugInfo(): void\n    {\n        $info = (new Rectangle(800, 600))->__debugInfo();\n        $this->assertEquals(800, $info['width']);\n        $this->assertEquals(600, $info['height']);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Geometry/Traits/HasBackgroundColorTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Geometry\\Traits;\n\nuse Intervention\\Image\\Geometry\\Traits\\HasBackgroundColor;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\n\n#[CoversClass(HasBackgroundColor::class)]\nfinal class HasBackgroundColorTest extends BaseTestCase\n{\n    public function getTestObject(): object\n    {\n        return new class () {\n            use HasBackgroundColor;\n        };\n    }\n\n    public function testSetGetBackgroundColor(): void\n    {\n        $object = $this->getTestObject();\n        $this->assertNull($object->backgroundColor());\n        $this->assertFalse($object->hasBackgroundColor());\n        $object->setBackgroundColor('fff');\n        $this->assertEquals('fff', $object->backgroundColor());\n        $this->assertTrue($object->hasBackgroundColor());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Geometry/Traits/HasBorderTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Geometry\\Traits;\n\nuse Intervention\\Image\\Geometry\\Traits\\HasBorder;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\n\n#[CoversClass(HasBorder::class)]\nfinal class HasBorderTest extends BaseTestCase\n{\n    public function getTestObject(): object\n    {\n        return new class () {\n            use HasBorder;\n        };\n    }\n\n    public function testSetBorder(): void\n    {\n        $object = $this->getTestObject();\n        $this->assertNull($object->borderColor());\n        $this->assertEquals(0, $object->borderSize());\n        $this->assertFalse($object->hasBorder());\n        $object->setBorder('fff', 10);\n        $this->assertEquals('fff', $object->borderColor());\n        $this->assertEquals(10, $object->borderSize());\n        $this->assertTrue($object->hasBorder());\n    }\n\n    public function testSetBorderSize(): void\n    {\n        $object = $this->getTestObject();\n        $this->assertEquals(0, $object->borderSize());\n        $object->setBorderSize(10);\n        $this->assertEquals(10, $object->borderSize());\n    }\n\n    public function testSetBorderColor(): void\n    {\n        $object = $this->getTestObject();\n        $this->assertNull($object->borderColor());\n        $object->setBorderColor('fff');\n        $this->assertEquals('fff', $object->borderColor());\n        $this->assertFalse($object->hasBorder());\n    }\n\n    public function testHasBorder(): void\n    {\n        $object = $this->getTestObject();\n        $this->assertFalse($object->hasBorder());\n        $object->setBorderColor('fff');\n        $this->assertFalse($object->hasBorder());\n        $object->setBorderSize(1);\n        $this->assertTrue($object->hasBorder());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/ImageManagerTestGd.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Decoders\\BinaryImageDecoder;\nuse Intervention\\Image\\Decoders\\FilePathImageDecoder;\nuse Intervention\\Image\\Drivers\\Gd\\Driver;\nuse Intervention\\Image\\ImageManager;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Tests\\BaseTestCase;\n\n#[CoversClass(ImageManager::class)]\n#[RequiresPhpExtension('gd')]\nfinal class ImageManagerTestGd extends BaseTestCase\n{\n    public function testConstructor(): void\n    {\n        $manager = new ImageManager(new Driver());\n        $this->assertInstanceOf(ImageManager::class, $manager);\n\n        $manager = new ImageManager(Driver::class);\n        $this->assertInstanceOf(ImageManager::class, $manager);\n    }\n\n    public function testWithDriver(): void\n    {\n        $manager = ImageManager::withDriver(new Driver());\n        $this->assertInstanceOf(ImageManager::class, $manager);\n\n        $manager = ImageManager::withDriver(Driver::class);\n        $this->assertInstanceOf(ImageManager::class, $manager);\n    }\n\n    public function testDriver(): void\n    {\n        $driver = new Driver();\n        $manager = ImageManager::withDriver($driver);\n        $this->assertEquals($driver, $manager->driver());\n    }\n\n    public function testDriverStatic(): void\n    {\n        $manager = ImageManager::gd();\n        $this->assertInstanceOf(ImageManager::class, $manager);\n    }\n\n    public function testCreate(): void\n    {\n        $manager = new ImageManager(Driver::class);\n        $image = $manager->create(5, 4);\n        $this->assertInstanceOf(ImageInterface::class, $image);\n    }\n\n    public function testAnimate(): void\n    {\n        $manager = new ImageManager(Driver::class);\n        $image = $manager->animate(function ($animation): void {\n            $animation->add($this->getTestResourcePath('red.gif'), .25);\n        });\n        $this->assertInstanceOf(ImageInterface::class, $image);\n    }\n\n    public function testRead(): void\n    {\n        $manager = new ImageManager(Driver::class);\n        $image = $manager->read($this->getTestResourcePath('red.gif'));\n        $this->assertInstanceOf(ImageInterface::class, $image);\n    }\n\n    public function testReadWithDecoderClassname(): void\n    {\n        $manager = new ImageManager(Driver::class);\n        $image = $manager->read($this->getTestResourcePath('red.gif'), FilePathImageDecoder::class);\n        $this->assertInstanceOf(ImageInterface::class, $image);\n    }\n\n    public function testReadWithDecoderInstance(): void\n    {\n        $manager = new ImageManager(Driver::class);\n        $image = $manager->read($this->getTestResourcePath('red.gif'), new FilePathImageDecoder());\n        $this->assertInstanceOf(ImageInterface::class, $image);\n    }\n\n    public function testReadWithDecoderClassnameArray(): void\n    {\n        $manager = new ImageManager(Driver::class);\n        $image = $manager->read($this->getTestResourcePath('red.gif'), [FilePathImageDecoder::class]);\n        $this->assertInstanceOf(ImageInterface::class, $image);\n    }\n\n    public function testReadWithDecoderInstanceArray(): void\n    {\n        $manager = new ImageManager(Driver::class);\n        $image = $manager->read($this->getTestResourcePath('red.gif'), [new FilePathImageDecoder()]);\n        $this->assertInstanceOf(ImageInterface::class, $image);\n    }\n\n    public function testReadWithDecoderInstanceArrayMultiple(): void\n    {\n        $manager = new ImageManager(Driver::class);\n        $image = $manager->read($this->getTestResourcePath('red.gif'), [\n            new BinaryImageDecoder(),\n            new FilePathImageDecoder(),\n        ]);\n        $this->assertInstanceOf(ImageInterface::class, $image);\n    }\n\n    public function testReadWithRotationAdjustment(): void\n    {\n        $manager = new ImageManager(Driver::class);\n        $image = $manager->read($this->getTestResourcePath('orientation.jpg'));\n        $this->assertColor(1, 0, 254, 255, $image->pickColor(3, 3));\n    }\n\n    public function testReadWithoutRotationAdjustment(): void\n    {\n        $manager = new ImageManager(Driver::class, autoOrientation: false);\n        $image = $manager->read($this->getTestResourcePath('orientation.jpg'));\n        $this->assertColor(250, 2, 3, 255, $image->pickColor(3, 3));\n    }\n\n    public function testReadAnimation(): void\n    {\n        $manager = new ImageManager(Driver::class);\n        $image = $manager->read($this->getTestResourcePath('animation.gif'));\n        $this->assertTrue($image->isAnimated());\n    }\n\n    public function testReadAnimationDiscarded(): void\n    {\n        $manager = new ImageManager(Driver::class, decodeAnimation: false);\n        $image = $manager->read($this->getTestResourcePath('animation.gif'));\n        $this->assertFalse($image->isAnimated());\n    }\n\n    public function testApplyBlendingColorDefault(): void\n    {\n        $manager = new ImageManager(Driver::class);\n        $image = $manager->read($this->getTestResourcePath('blocks.png'));\n        $result = $image->blendTransparency();\n        $this->assertColor(255, 255, 255, 255, $image->pickColor(530, 0));\n        $this->assertColor(255, 255, 255, 255, $result->pickColor(530, 0));\n    }\n\n    public function testApplyBlendingColorConfigured(): void\n    {\n        $manager = new ImageManager(Driver::class, blendingColor: 'ff5500');\n        $image = $manager->read($this->getTestResourcePath('blocks.png'));\n        $result = $image->blendTransparency();\n        $this->assertColor(255, 85, 0, 255, $image->pickColor(530, 0));\n        $this->assertColor(255, 85, 0, 255, $result->pickColor(530, 0));\n    }\n}\n"
  },
  {
    "path": "tests/Unit/ImageManagerTestImagick.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Intervention\\Image\\Decoders\\BinaryImageDecoder;\nuse Intervention\\Image\\Decoders\\FilePathImageDecoder;\nuse Intervention\\Image\\Drivers\\Imagick\\Driver;\nuse Intervention\\Image\\ImageManager;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Tests\\BaseTestCase;\n\n#[CoversClass(ImageManager::class)]\n#[RequiresPhpExtension('imagick')]\nfinal class ImageManagerTestImagick extends BaseTestCase\n{\n    public function testConstructor(): void\n    {\n        $manager = new ImageManager(new Driver());\n        $this->assertInstanceOf(ImageManager::class, $manager);\n\n        $manager = new ImageManager(Driver::class);\n        $this->assertInstanceOf(ImageManager::class, $manager);\n    }\n\n    public function testWithDriver(): void\n    {\n        $manager = ImageManager::withDriver(new Driver());\n        $this->assertInstanceOf(ImageManager::class, $manager);\n\n        $manager = ImageManager::withDriver(Driver::class);\n        $this->assertInstanceOf(ImageManager::class, $manager);\n    }\n\n    public function testDriver(): void\n    {\n        $driver = new Driver();\n        $manager = ImageManager::withDriver($driver);\n        $this->assertEquals($driver, $manager->driver());\n    }\n\n    public function testDriverStatic(): void\n    {\n        $manager = ImageManager::imagick();\n        $this->assertInstanceOf(ImageManager::class, $manager);\n    }\n\n    public function testCreate(): void\n    {\n        $manager = new ImageManager(Driver::class);\n        $image = $manager->create(5, 4);\n        $this->assertInstanceOf(ImageInterface::class, $image);\n    }\n\n    public function testAnimate(): void\n    {\n        $manager = new ImageManager(Driver::class);\n        $image = $manager->animate(function ($animation): void {\n            $animation->add($this->getTestResourcePath('red.gif'), .25);\n        });\n        $this->assertInstanceOf(ImageInterface::class, $image);\n    }\n\n    public function testRead(): void\n    {\n        $manager = new ImageManager(Driver::class);\n        $image = $manager->read($this->getTestResourcePath('red.gif'));\n        $this->assertInstanceOf(ImageInterface::class, $image);\n    }\n\n    public function testReadWithDecoderClassname(): void\n    {\n        $manager = new ImageManager(Driver::class);\n        $image = $manager->read($this->getTestResourcePath('red.gif'), FilePathImageDecoder::class);\n        $this->assertInstanceOf(ImageInterface::class, $image);\n    }\n\n    public function testReadWithDecoderInstance(): void\n    {\n        $manager = new ImageManager(Driver::class);\n        $image = $manager->read($this->getTestResourcePath('red.gif'), new FilePathImageDecoder());\n        $this->assertInstanceOf(ImageInterface::class, $image);\n    }\n\n    public function testReadWithDecoderClassnameArray(): void\n    {\n        $manager = new ImageManager(Driver::class);\n        $image = $manager->read($this->getTestResourcePath('red.gif'), [FilePathImageDecoder::class]);\n        $this->assertInstanceOf(ImageInterface::class, $image);\n    }\n\n    public function testReadWithDecoderInstanceArray(): void\n    {\n        $manager = new ImageManager(Driver::class);\n        $image = $manager->read($this->getTestResourcePath('red.gif'), [new FilePathImageDecoder()]);\n        $this->assertInstanceOf(ImageInterface::class, $image);\n    }\n\n    public function testReadWithDecoderInstanceArrayMultiple(): void\n    {\n        $manager = new ImageManager(Driver::class);\n        $image = $manager->read($this->getTestResourcePath('red.gif'), [\n            new BinaryImageDecoder(),\n            new FilePathImageDecoder(),\n        ]);\n        $this->assertInstanceOf(ImageInterface::class, $image);\n    }\n\n    public function testReadWithRotationAdjustment(): void\n    {\n        $manager = new ImageManager(Driver::class);\n        $image = $manager->read($this->getTestResourcePath('orientation.jpg'));\n        $this->assertColor(1, 0, 254, 255, $image->pickColor(3, 3));\n    }\n\n    public function testReadWithoutRotationAdjustment(): void\n    {\n        $manager = new ImageManager(Driver::class, autoOrientation: false);\n        $image = $manager->read($this->getTestResourcePath('orientation.jpg'));\n        $this->assertColor(250, 2, 3, 255, $image->pickColor(3, 3));\n    }\n\n    public function testReadAnimation(): void\n    {\n        $manager = new ImageManager(Driver::class);\n        $image = $manager->read($this->getTestResourcePath('animation.gif'));\n        $this->assertTrue($image->isAnimated());\n    }\n\n    public function testReadAnimationDiscarded(): void\n    {\n        $manager = new ImageManager(Driver::class, decodeAnimation: false);\n        $image = $manager->read($this->getTestResourcePath('animation.gif'));\n        $this->assertFalse($image->isAnimated());\n    }\n\n    public function testApplyBlendingColor(): void\n    {\n        $manager = new ImageManager(Driver::class);\n        $image = $manager->read($this->getTestResourcePath('blocks.png'));\n        $result = $image->blendTransparency();\n        $this->assertColor(255, 255, 255, 255, $image->pickColor(530, 0));\n        $this->assertColor(255, 255, 255, 255, $result->pickColor(530, 0));\n    }\n\n    public function testApplyBlendingColorConfigured(): void\n    {\n        $manager = new ImageManager(Driver::class, blendingColor: 'ff5500');\n        $image = $manager->read($this->getTestResourcePath('blocks.png'));\n        $result = $image->blendTransparency();\n        $this->assertColor(255, 85, 0, 255, $image->pickColor(530, 0));\n        $this->assertColor(255, 85, 0, 255, $result->pickColor(530, 0));\n    }\n}\n"
  },
  {
    "path": "tests/Unit/InputHandlerTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit;\n\nuse Generator;\nuse Intervention\\Image\\Colors\\Rgb\\Decoders\\HexColorDecoder;\nuse Intervention\\Image\\Drivers\\Gd\\Driver as GdDriver;\nuse Intervention\\Image\\Drivers\\Imagick\\Driver as ImagickDriver;\nuse Intervention\\Image\\Exceptions\\DecoderException;\nuse Intervention\\Image\\InputHandler;\nuse Intervention\\Image\\Interfaces\\ColorInterface;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\n\n#[RequiresPhpExtension('gd')]\n#[RequiresPhpExtension('imagick')]\n#[CoversClass(InputHandler::class)]\nclass InputHandlerTest extends BaseTestCase\n{\n    #[DataProvider('inputProvider')]\n    public function testHandleDefaultDecoders(string $driver, mixed $input, string $outputClassname): void\n    {\n        $handler = new InputHandler(driver: new $driver());\n        if ($outputClassname === ImageInterface::class || $outputClassname === ColorInterface::class) {\n            $this->assertInstanceOf($outputClassname, $handler->handle($input));\n        } else {\n            $this->expectException($outputClassname);\n            $handler->handle($input);\n        }\n    }\n\n    public static function inputProvider(): Generator\n    {\n        $base = [\n            [null, DecoderException::class],\n            ['', DecoderException::class],\n            ['fff', ColorInterface::class],\n            ['rgba(0, 0, 0, 0)', ColorInterface::class],\n            ['cmyk(0, 0, 0, 0)', ColorInterface::class],\n            ['hsv(0, 0, 0)', ColorInterface::class],\n            ['hsl(0, 0, 0)', ColorInterface::class],\n            ['transparent', ColorInterface::class],\n            ['steelblue', ColorInterface::class],\n            [self::getTestResourcePath(), ImageInterface::class],\n            [file_get_contents(self::getTestResourcePath()), ImageInterface::class],\n        ];\n\n        $drivers = [GdDriver::class, ImagickDriver::class];\n        foreach ($drivers as $driver) {\n            foreach ($base as $line) {\n                array_unshift($line, $driver); // prepend driver\n                yield $line;\n            }\n        }\n    }\n\n    public function testResolveWithoutDriver(): void\n    {\n        $handler = new InputHandler([new HexColorDecoder()]);\n        $result = $handler->handle('fff');\n        $this->assertInstanceOf(ColorInterface::class, $result);\n\n        $handler = new InputHandler([HexColorDecoder::class]);\n        $result = $handler->handle('fff');\n        $this->assertInstanceOf(ColorInterface::class, $result);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/MediaTypeTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit;\n\nuse Generator;\nuse Intervention\\Image\\Exceptions\\NotSupportedException;\nuse Intervention\\Image\\FileExtension;\nuse Intervention\\Image\\Format;\nuse Intervention\\Image\\MediaType;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\n\n#[CoversClass(MediaType::class)]\nfinal class MediaTypeTest extends BaseTestCase\n{\n    public function testCreate(): void\n    {\n        $this->assertEquals(MediaType::IMAGE_JPEG, MediaType::create(MediaType::IMAGE_JPEG));\n        $this->assertEquals(MediaType::IMAGE_JPEG, MediaType::create(Format::JPEG));\n        $this->assertEquals(MediaType::IMAGE_JPEG, MediaType::create(FileExtension::JPG));\n        $this->assertEquals(MediaType::IMAGE_JPEG, MediaType::create('jpg'));\n        $this->assertEquals(MediaType::IMAGE_JPEG, MediaType::create('jpeg'));\n        $this->assertEquals(MediaType::IMAGE_JPEG, MediaType::create('image/jpeg'));\n        $this->assertEquals(MediaType::IMAGE_JPEG, MediaType::create('JPG'));\n        $this->assertEquals(MediaType::IMAGE_JPEG, MediaType::create('JPEG'));\n        $this->assertEquals(MediaType::IMAGE_JPEG, MediaType::create('IMAGE/JPEG'));\n    }\n\n    public function testCreateUnknown(): void\n    {\n        $this->expectException(NotSupportedException::class);\n        MediaType::create('foo');\n    }\n\n    public function testTryCreate(): void\n    {\n        $this->assertEquals(MediaType::IMAGE_JPEG, MediaType::tryCreate(MediaType::IMAGE_JPEG));\n        $this->assertEquals(MediaType::IMAGE_JPEG, MediaType::tryCreate(Format::JPEG));\n        $this->assertEquals(MediaType::IMAGE_JPEG, MediaType::tryCreate(FileExtension::JPG));\n        $this->assertEquals(MediaType::IMAGE_JPEG, MediaType::tryCreate('jpg'));\n        $this->assertEquals(MediaType::IMAGE_JPEG, MediaType::tryCreate('jpeg'));\n        $this->assertEquals(MediaType::IMAGE_JPEG, MediaType::tryCreate('image/jpeg'));\n        $this->assertNull(Format::tryCreate('no-format'));\n    }\n\n    public function testFormatJpeg(): void\n    {\n        $mime = MediaType::IMAGE_JPEG;\n        $this->assertEquals(Format::JPEG, $mime->format());\n\n        $mime = MediaType::IMAGE_PJPEG;\n        $this->assertEquals(Format::JPEG, $mime->format());\n\n        $mime = MediaType::IMAGE_JPG;\n        $this->assertEquals(Format::JPEG, $mime->format());\n\n        $mime = MediaType::IMAGE_X_JPEG;\n        $this->assertEquals(Format::JPEG, $mime->format());\n    }\n\n    public function testFormatWebp(): void\n    {\n        $mime = MediaType::IMAGE_WEBP;\n        $this->assertEquals(Format::WEBP, $mime->format());\n\n        $mime = MediaType::IMAGE_X_WEBP;\n        $this->assertEquals(Format::WEBP, $mime->format());\n    }\n\n    public function testFormatGif(): void\n    {\n        $mime = MediaType::IMAGE_GIF;\n        $this->assertEquals(Format::GIF, $mime->format());\n    }\n\n    public function testFormatPng(): void\n    {\n        $mime = MediaType::IMAGE_PNG;\n        $this->assertEquals(Format::PNG, $mime->format());\n\n        $mime = MediaType::IMAGE_X_PNG;\n        $this->assertEquals(Format::PNG, $mime->format());\n    }\n\n    public function testFormatAvif(): void\n    {\n        $mime = MediaType::IMAGE_AVIF;\n        $this->assertEquals(Format::AVIF, $mime->format());\n\n        $mime = MediaType::IMAGE_X_AVIF;\n        $this->assertEquals(Format::AVIF, $mime->format());\n    }\n\n    public function testFormatBmp(): void\n    {\n        $mime = MediaType::IMAGE_BMP;\n        $this->assertEquals(Format::BMP, $mime->format());\n\n        $mime = MediaType::IMAGE_X_BMP;\n        $this->assertEquals(Format::BMP, $mime->format());\n\n        $mime = MediaType::IMAGE_X_BITMAP;\n        $this->assertEquals(Format::BMP, $mime->format());\n\n        $mime = MediaType::IMAGE_X_WIN_BITMAP;\n        $this->assertEquals(Format::BMP, $mime->format());\n\n        $mime = MediaType::IMAGE_X_WINDOWS_BMP;\n        $this->assertEquals(Format::BMP, $mime->format());\n\n        $mime = MediaType::IMAGE_X_BMP3;\n        $this->assertEquals(Format::BMP, $mime->format());\n    }\n\n    public function testFormatTiff(): void\n    {\n        $mime = MediaType::IMAGE_TIFF;\n        $this->assertEquals(Format::TIFF, $mime->format());\n    }\n\n    public function testFormatJpeg2000(): void\n    {\n        $mime = MediaType::IMAGE_JPM;\n        $this->assertEquals(Format::JP2, $mime->format());\n\n        $mime = MediaType::IMAGE_JPX;\n        $this->assertEquals(Format::JP2, $mime->format());\n\n        $mime = MediaType::IMAGE_JP2;\n        $this->assertEquals(Format::JP2, $mime->format());\n    }\n\n    public function testFormatHeic(): void\n    {\n        $mime = MediaType::IMAGE_HEIC;\n        $this->assertEquals(Format::HEIC, $mime->format());\n\n        $mime = MediaType::IMAGE_X_HEIC;\n        $this->assertEquals(Format::HEIC, $mime->format());\n\n        $mime = MediaType::IMAGE_HEIF;\n        $this->assertEquals(Format::HEIC, $mime->format());\n    }\n\n    #[DataProvider('fileExtensionsDataProvider')]\n    public function testFileExtensions(\n        MediaType $mediaType,\n        int $fileExtensionCount,\n        FileExtension $fileExtension\n    ): void {\n        $this->assertCount($fileExtensionCount, $mediaType->fileExtensions());\n        $this->assertEquals($fileExtension, $mediaType->fileExtension());\n    }\n\n    public static function fileExtensionsDataProvider(): Generator\n    {\n        yield [MediaType::IMAGE_JPEG, 2, FileExtension::JPG];\n        yield [MediaType::IMAGE_JPG, 2, FileExtension::JPG];\n        yield [MediaType::IMAGE_PJPEG, 2, FileExtension::JPG];\n        yield [MediaType::IMAGE_X_JPEG, 2, FileExtension::JPG];\n        yield [MediaType::IMAGE_WEBP, 1, FileExtension::WEBP];\n        yield [MediaType::IMAGE_X_WEBP, 1, FileExtension::WEBP];\n        yield [MediaType::IMAGE_GIF, 1, FileExtension::GIF];\n        yield [MediaType::IMAGE_PNG, 1, FileExtension::PNG];\n        yield [MediaType::IMAGE_X_PNG, 1, FileExtension::PNG];\n        yield [MediaType::IMAGE_AVIF, 1, FileExtension::AVIF];\n        yield [MediaType::IMAGE_X_AVIF, 1, FileExtension::AVIF];\n        yield [MediaType::IMAGE_BMP, 1, FileExtension::BMP];\n        yield [MediaType::IMAGE_MS_BMP, 1, FileExtension::BMP];\n        yield [MediaType::IMAGE_X_BITMAP, 1, FileExtension::BMP];\n        yield [MediaType::IMAGE_X_BMP, 1, FileExtension::BMP];\n        yield [MediaType::IMAGE_X_MS_BMP, 1, FileExtension::BMP];\n        yield [MediaType::IMAGE_X_WINDOWS_BMP, 1, FileExtension::BMP];\n        yield [MediaType::IMAGE_X_WIN_BITMAP, 1, FileExtension::BMP];\n        yield [MediaType::IMAGE_X_XBITMAP, 1, FileExtension::BMP];\n        yield [MediaType::IMAGE_X_BMP3, 1, FileExtension::BMP];\n        yield [MediaType::IMAGE_TIFF, 2, FileExtension::TIF];\n        yield [MediaType::IMAGE_JP2, 9, FileExtension::JP2];\n        yield [MediaType::IMAGE_JPX, 9, FileExtension::JP2];\n        yield [MediaType::IMAGE_JPM, 9, FileExtension::JP2];\n        yield [MediaType::IMAGE_HEIC, 2, FileExtension::HEIC];\n        yield [MediaType::IMAGE_X_HEIC, 2, FileExtension::HEIC];\n        yield [MediaType::IMAGE_HEIF, 2, FileExtension::HEIC];\n    }\n}\n"
  },
  {
    "path": "tests/Unit/ModifierStackTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse Intervention\\Image\\Modifiers\\GreyscaleModifier;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\ModifierInterface;\nuse Intervention\\Image\\ModifierStack;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse Mockery;\n\n#[CoversClass(ModifierStack::class)]\nfinal class ModifierStackTest extends BaseTestCase\n{\n    public function testConstructor(): void\n    {\n        $stack = new ModifierStack([]);\n        $this->assertInstanceOf(ModifierStack::class, $stack);\n    }\n\n    public function testPush(): void\n    {\n        $stack = new ModifierStack([]);\n        $result = $stack->push(new GreyscaleModifier());\n        $this->assertInstanceOf(ModifierStack::class, $result);\n    }\n\n    public function testApply(): void\n    {\n        $image = Mockery::mock(ImageInterface::class);\n\n        $modifier1 = Mockery::mock(ModifierInterface::class)->makePartial();\n        $modifier1->shouldReceive('apply')->once()->with($image);\n\n        $modifier2 = Mockery::mock(ModifierInterface::class)->makePartial();\n        $modifier2->shouldReceive('apply')->once()->with($image);\n\n        $stack = new ModifierStack([$modifier1, $modifier2]);\n        $result = $stack->apply($image);\n        $this->assertInstanceOf(ImageInterface::class, $result);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Modifiers/ColorspaceModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Modifiers;\n\nuse Intervention\\Image\\Colors\\Rgb\\Colorspace;\nuse Intervention\\Image\\Exceptions\\NotSupportedException;\nuse Intervention\\Image\\Interfaces\\ColorspaceInterface;\nuse Intervention\\Image\\Modifiers\\ColorspaceModifier;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\n\n#[CoversClass(ColorspaceModifier::class)]\nfinal class ColorspaceModifierTest extends BaseTestCase\n{\n    public function testTargetColorspace(): void\n    {\n        $modifier = new ColorspaceModifier(new Colorspace());\n        $this->assertInstanceOf(ColorspaceInterface::class, $modifier->targetColorspace());\n\n        $modifier = new ColorspaceModifier('rgb');\n        $this->assertInstanceOf(ColorspaceInterface::class, $modifier->targetColorspace());\n\n        $modifier = new ColorspaceModifier('cmyk');\n        $this->assertInstanceOf(ColorspaceInterface::class, $modifier->targetColorspace());\n\n        $modifier = new ColorspaceModifier('test');\n        $this->expectException(NotSupportedException::class);\n        $modifier->targetColorspace();\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Modifiers/PadModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Modifiers;\n\nuse Intervention\\Image\\Geometry\\Rectangle;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SizeInterface;\nuse Intervention\\Image\\Modifiers\\PadModifier;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse Mockery;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\n\n#[CoversClass(PadModifier::class)]\nfinal class PadModifierTest extends BaseTestCase\n{\n    public function testGetCropSize(): void\n    {\n        $modifier = new PadModifier(300, 200);\n        $image = Mockery::mock(ImageInterface::class);\n        $size = new Rectangle(300, 200);\n        $image->shouldReceive('size')->andReturn($size);\n        $this->assertInstanceOf(SizeInterface::class, $modifier->getCropSize($image));\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Modifiers/RemoveAnimationModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Modifiers;\n\nuse Generator;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Modifiers\\RemoveAnimationModifier;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse Mockery;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\n\n#[CoversClass(RemoveAnimationModifier::class)]\nfinal class RemoveAnimationModifierTest extends BaseTestCase\n{\n    #[DataProvider('normalizePositionProvider')]\n    public function testNormalizePosition(int|string $position, int $frames, int $normalized): void\n    {\n        $modifier = new class ($position) extends RemoveAnimationModifier\n        {\n            public function testResult(int $frames): int\n            {\n                $image = Mockery::mock(ImageInterface::class)->makePartial();\n                $image->shouldReceive('count')->andReturn($frames);\n\n                return $this->normalizePosition($image);\n            }\n        };\n\n        $this->assertEquals($normalized, $modifier->testResult($frames));\n    }\n\n    public static function normalizePositionProvider(): Generator\n    {\n        yield [0, 100, 0];\n        yield [10, 100, 10];\n        yield ['10', 100, 10];\n        yield ['0%', 100, 0];\n        yield ['50%', 100, 50];\n        yield ['100%', 100, 99];\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Modifiers/TextModifierTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Modifiers;\n\nuse Intervention\\Image\\Geometry\\Point;\nuse Intervention\\Image\\Interfaces\\FontInterface;\nuse Intervention\\Image\\Modifiers\\TextModifier;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse Intervention\\Image\\Typography\\Font;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\n\n#[CoversClass(TextModifier::class)]\nfinal class TextModifierTest extends BaseTestCase\n{\n    public function testStrokeOffsets(): void\n    {\n        $modifier = new class ('test', new Point(), new Font()) extends TextModifier\n        {\n            /**\n             * @return array<?Point>\n             */\n            public function testStrokeOffsets(FontInterface $font): array\n            {\n                return $this->strokeOffsets($font);\n            }\n        };\n\n        $this->assertEquals([], $modifier->testStrokeOffsets(new Font()));\n\n        $this->assertEquals([\n            new Point(-1, -1),\n            new Point(-1, 0),\n            new Point(-1, 1),\n            new Point(0, -1),\n            new Point(0, 0),\n            new Point(0, 1),\n            new Point(1, -1),\n            new Point(1, 0),\n            new Point(1, 1),\n        ], $modifier->testStrokeOffsets((new Font())->setStrokeWidth(1)));\n    }\n}\n"
  },
  {
    "path": "tests/Unit/OriginTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit;\n\nuse Intervention\\Image\\Origin;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\n\n#[CoversClass(Origin::class)]\nfinal class OriginTest extends BaseTestCase\n{\n    public function testFilePath(): void\n    {\n        $origin = new Origin('image/jpeg', $this->getTestResourcePath('example.jpg'));\n        $this->assertEquals($this->getTestResourcePath('example.jpg'), $origin->filePath());\n    }\n\n    public function testFileExtension(): void\n    {\n        $origin = new Origin('image/jpeg', $this->getTestResourcePath('example.jpg'));\n        $this->assertEquals('jpg', $origin->fileExtension());\n\n        $origin = new Origin('image/jpeg');\n        $this->assertEquals('', $origin->fileExtension());\n    }\n\n    public function testSetGetMediaType(): void\n    {\n        $origin = new Origin();\n        $this->assertEquals('application/octet-stream', $origin->mediaType());\n\n        $origin = new Origin('image/gif');\n        $this->assertEquals('image/gif', $origin->mediaType());\n        $this->assertEquals('image/gif', $origin->mimetype());\n        $result = $origin->setMediaType('image/jpeg');\n        $this->assertEquals('image/jpeg', $origin->mediaType());\n        $this->assertEquals('image/jpeg', $result->mediaType());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/ResolutionTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit;\n\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse Intervention\\Image\\Resolution;\nuse Intervention\\Image\\Tests\\BaseTestCase;\n\n#[CoversClass(Resolution::class)]\nfinal class ResolutionTest extends BaseTestCase\n{\n    public function testConstructor(): void\n    {\n        $resolution = new Resolution(1, 2);\n        $this->assertInstanceOf(Resolution::class, $resolution);\n    }\n\n    public function testIteration(): void\n    {\n        $resolution = new Resolution(1.2, 3.4);\n        foreach ($resolution as $value) {\n            $this->assertIsFloat($value);\n        }\n    }\n\n    public function testXY(): void\n    {\n        $resolution = new Resolution(1.2, 3.4);\n        $this->assertEquals(1.2, $resolution->x());\n        $this->assertEquals(3.4, $resolution->y());\n    }\n\n    public function testUnit(): void\n    {\n        $resolution = new Resolution(1, 1);\n        $this->assertEquals('dpi', $resolution->unit());\n\n        $resolution = new Resolution(1, 1, Resolution::PER_CM);\n        $this->assertEquals('dpcm', $resolution->unit());\n    }\n\n    public function testConversion(): void\n    {\n        $resolution = new Resolution(300, 150); // per inch\n        $this->assertEquals(300, $resolution->perInch()->x());\n        $this->assertEquals(150, $resolution->perInch()->y());\n\n        $resolution = new Resolution(300, 150); // per inch\n        $this->assertEquals(118.11, round($resolution->perCm()->x(), 2));\n        $this->assertEquals(59.06, round($resolution->perCm()->y(), 2));\n\n        $resolution = new Resolution(118.11024, 59.06, Resolution::PER_CM); // per cm\n        $this->assertEquals(300, round($resolution->perInch()->x()));\n        $this->assertEquals(150, round($resolution->perInch()->y()));\n    }\n\n    public function testToString(): void\n    {\n        $resolution = new Resolution(300, 150, Resolution::PER_CM);\n        $this->assertEquals('300.00 x 150.00 dpcm', $resolution->toString());\n\n        $resolution = new Resolution(300, 150, Resolution::PER_INCH);\n        $this->assertEquals('300.00 x 150.00 dpi', $resolution->toString());\n        $this->assertEquals('300.00 x 150.00 dpi', (string) $resolution);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Typography/FontFactoryTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Typography;\n\nuse Intervention\\Image\\Interfaces\\FontInterface;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse Intervention\\Image\\Typography\\Font;\nuse Intervention\\Image\\Typography\\FontFactory;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\n\n#[CoversClass(FontFactory::class)]\nfinal class FontFactoryTest extends BaseTestCase\n{\n    public function testBuildWithFont(): void\n    {\n        $font_file = $this->getTestResourcePath('test.ttf');\n        $factory = new FontFactory(new Font($font_file));\n        $result = $factory();\n        $this->assertInstanceOf(FontInterface::class, $result);\n        $this->assertEquals($font_file, $result->filename());\n    }\n\n    public function testBuildWithCallback(): void\n    {\n        $factory = new FontFactory(function (FontFactory $font): void {\n            $font->filename($this->getTestResourcePath('test.ttf'));\n            $font->color('#b01735');\n            $font->size(70);\n            $font->align('center');\n            $font->valign('middle');\n            $font->lineHeight(1.6);\n            $font->angle(10);\n            $font->wrap(100);\n            $font->stroke('ff5500', 4);\n        });\n\n        $result = $factory();\n        $this->assertInstanceOf(FontInterface::class, $result);\n        $this->assertEquals($this->getTestResourcePath('test.ttf'), $result->filename());\n        $this->assertEquals('#b01735', $result->color());\n        $this->assertEquals(70, $result->size());\n        $this->assertEquals('center', $result->alignment());\n        $this->assertEquals('middle', $result->valignment());\n        $this->assertEquals(1.6, $result->lineHeight());\n        $this->assertEquals(10, $result->angle());\n        $this->assertEquals(100, $result->wrapWidth());\n        $this->assertEquals(4, $result->strokeWidth());\n        $this->assertEquals('ff5500', $result->strokeColor());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Typography/FontTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Typography;\n\nuse Intervention\\Image\\Exceptions\\FontException;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse Intervention\\Image\\Typography\\Font;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\n\n#[CoversClass(Font::class)]\nfinal class FontTest extends BaseTestCase\n{\n    public function testConstructor(): void\n    {\n        $font = new Font('foo.ttf');\n        $this->assertInstanceOf(Font::class, $font);\n        $this->assertEquals('foo.ttf', $font->filename());\n    }\n\n    public function testSetGetSize(): void\n    {\n        $font = new Font();\n        $this->assertEquals(12, $font->size());\n        $result = $font->setSize(123);\n        $this->assertInstanceOf(Font::class, $result);\n        $this->assertEquals(123, $font->size());\n    }\n\n    public function testSetGetAngle(): void\n    {\n        $font = new Font();\n        $this->assertEquals(0, $font->angle());\n        $result = $font->setAngle(123);\n        $this->assertInstanceOf(Font::class, $result);\n        $this->assertEquals(123, $font->angle());\n    }\n\n    public function testSetGetFilename(): void\n    {\n        $font = new Font();\n        $this->assertEquals(null, $font->filename());\n        $this->assertFalse($font->hasFilename());\n        $filename = $this->getTestResourcePath();\n        $result = $font->setFilename($filename);\n        $this->assertTrue($font->hasFilename());\n        $this->assertInstanceOf(Font::class, $result);\n        $this->assertEquals($filename, $font->filename());\n    }\n\n    public function testSetGetColor(): void\n    {\n        $font = new Font();\n        $this->assertEquals('000000', $font->color());\n        $result = $font->setColor('fff');\n        $this->assertInstanceOf(Font::class, $result);\n        $this->assertEquals('fff', $font->color());\n    }\n\n    public function testSetGetAlignment(): void\n    {\n        $font = new Font();\n        $this->assertEquals('left', $font->alignment());\n        $result = $font->setAlignment('center');\n        $this->assertInstanceOf(Font::class, $result);\n        $this->assertEquals('center', $font->alignment());\n    }\n\n    public function testSetGetValignment(): void\n    {\n        $font = new Font();\n        $this->assertEquals('bottom', $font->valignment());\n        $result = $font->setValignment('center');\n        $this->assertInstanceOf(Font::class, $result);\n        $this->assertEquals('center', $font->valignment());\n    }\n\n    public function testSetGetLineHeight(): void\n    {\n        $font = new Font();\n        $this->assertEquals(1.25, $font->lineHeight());\n        $result = $font->setLineHeight(3.2);\n        $this->assertInstanceOf(Font::class, $result);\n        $this->assertEquals(3.2, $font->lineHeight());\n    }\n\n    public function testSetGetStrokeColor(): void\n    {\n        $font = new Font();\n        $this->assertEquals('ffffff', $font->strokeColor());\n        $result = $font->setStrokeColor('000000');\n        $this->assertInstanceOf(Font::class, $result);\n        $this->assertEquals('000000', $font->strokeColor());\n    }\n\n    public function testSetGetStrokeWidth(): void\n    {\n        $font = new Font();\n        $this->assertEquals(0, $font->strokeWidth());\n        $result = $font->setStrokeWidth(4);\n        $this->assertInstanceOf(Font::class, $result);\n        $this->assertEquals(4, $font->strokeWidth());\n    }\n\n    public function testSetStrokeWidthOutOfRange(): void\n    {\n        $font = new Font();\n        $this->expectException(FontException::class);\n        $font->setStrokeWidth(11);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Typography/LineTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Typography;\n\nuse Generator;\nuse Intervention\\Image\\Geometry\\Point;\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse Intervention\\Image\\Typography\\Line;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\n\n#[CoversClass(Line::class)]\nfinal class LineTest extends BaseTestCase\n{\n    public function testConstructor(): void\n    {\n        $line = new Line('foo');\n        $this->assertInstanceOf(Line::class, $line);\n    }\n\n    #[DataProvider('toStringDataProvider')]\n    public function testToString(string $text, int $words): void\n    {\n        $line = new Line($text);\n        $this->assertEquals($words, $line->count());\n        $this->assertEquals($text, (string) $line);\n    }\n\n    public function testSetGetPosition(): void\n    {\n        $line = new Line('foo');\n        $this->assertEquals(0, $line->position()->x());\n        $this->assertEquals(0, $line->position()->y());\n\n        $line->setPosition(new Point(10, 11));\n        $this->assertEquals(10, $line->position()->x());\n        $this->assertEquals(11, $line->position()->y());\n    }\n\n    public function testCount(): void\n    {\n        $line = new Line();\n        $this->assertEquals(0, $line->count());\n\n        $line = new Line(\"foo\");\n        $this->assertEquals(1, $line->count());\n\n        $line = new Line(\"foo bar\");\n        $this->assertEquals(2, $line->count());\n    }\n\n    public function testLength(): void\n    {\n        $line = new Line();\n        $this->assertEquals(0, $line->length());\n\n        $line = new Line(\"foo\");\n        $this->assertEquals(3, $line->length());\n\n        $line = new Line(\"foo bar.\");\n        $this->assertEquals(8, $line->length());\n\n        $line = new Line(\"🫷🙂🫸\");\n        $this->assertEquals(3, $line->length());\n    }\n\n    public function testAdd(): void\n    {\n        $line = new Line();\n        $this->assertEquals(0, $line->count());\n\n        $result = $line->add('foo');\n        $this->assertEquals(1, $line->count());\n        $this->assertEquals(1, $result->count());\n\n        $result = $line->add('bar');\n        $this->assertEquals(2, $line->count());\n        $this->assertEquals(2, $result->count());\n    }\n\n    public static function toStringDataProvider(): Generator\n    {\n        yield ['foo', 1];\n        yield ['foo bar', 2];\n        yield ['测试', 2]; // CJK Unified Ideographs\n        yield ['テスト', 3]; // japanese\n        yield ['ทดสอบ', 5]; // thai\n        yield ['这只是我写的一个测试。', 11]; // CJK Unified Ideographs\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Typography/TextBlockTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Intervention\\Image\\Tests\\Unit\\Typography;\n\nuse Intervention\\Image\\Tests\\BaseTestCase;\nuse Intervention\\Image\\Typography\\TextBlock;\nuse PHPUnit\\Framework\\Attributes\\CoversClass;\n\n#[CoversClass(TextBlock::class)]\nfinal class TextBlockTest extends BaseTestCase\n{\n    protected TextBlock $block;\n\n    protected function setUp(): void\n    {\n        $this->block = new TextBlock(<<<EOF\n            foo\n            FooBar\n            bar\n            EOF);\n    }\n\n    public function testCount(): void\n    {\n        $this->assertEquals(3, $this->block->count());\n    }\n\n    public function testLines(): void\n    {\n        $this->assertCount(3, $this->block->lines());\n    }\n\n    public function testGetLine(): void\n    {\n        $this->assertEquals('foo', $this->block->line(0));\n        $this->assertEquals('FooBar', $this->block->line(1));\n        $this->assertEquals('bar', $this->block->line(2));\n        $this->assertNull($this->block->line(20));\n    }\n\n    public function testLongestLine(): void\n    {\n        $result = $this->block->longestLine();\n        $this->assertEquals('FooBar', (string) $result);\n    }\n}\n"
  }
]