diff --git a/.gitattributes b/.gitattributes index 50b2c2bd..a874e9eb 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2,8 +2,11 @@ /.github export-ignore /tests export-ignore +/.github export-ignore /.gitattributes export-ignore /.gitignore export-ignore -/.travis.yml export-ignore /phpunit.xml export-ignore -/README.md export-ignore +/phpunit.xml.dist export-ignore +/readme.md export-ignore +/docker-compose.yml export-ignore +/Dockerfile export-ignore diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml new file mode 100644 index 00000000..c33fcdef --- /dev/null +++ b/.github/workflows/run-tests.yml @@ -0,0 +1,102 @@ +name: Tests + +on: [ push, pull_request ] + +jobs: + run: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + php: [ '8.1', '8.2', '8.3' ] + imagemagick: [ '6.9.12-55', '7.1.0-40' ] + imagick: [ '3.7.0' ] + stability: [ prefer-stable ] + + name: PHP ${{ matrix.php }} - ${{ matrix.stability }} - ImageMagick ${{ matrix.imagemagick }} + + steps: + - name: Checkout project + uses: actions/checkout@v2 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + extensions: mbstring, gd + coverage: none + + - name: Prepare environment for Imagemagick + run: | + sudo apt-get -y remove imagemagick imagemagick-6-common libmagic-dev + sudo apt-get update + sudo apt-get install -y libjpeg-dev libgif-dev libtiff-dev libpng-dev libwebp-dev libavif-dev libheif-dev + sudo apt-get install -y libmagickwand-dev + + - name: Cache ImageMagick + uses: actions/cache@v2 + id: cache-imagemagick + with: + path: /home/runner/im/imagemagick-${{ matrix.imagemagick }} + key: ${{ runner.os }}-ImageMagick-${{ matrix.imagemagick }}-${{ hashFiles('**/composer.json') }} + restore-keys: ${{ runner.os }}-ImageMagick-${{ matrix.imagemagick }}- + + - name: Check ImageMagick cache exists + uses: andstor/file-existence-action@v1 + id: cache-imagemagick-exists + with: + files: /home/runner/im/imagemagick-${{ matrix.imagemagick }} + + - name: Install ImageMagick + if: ( steps.cache-imagemagick.outputs.cache-hit != 'true' || steps.cache-imagemagick-exists.outputs.files_exists != 'true' ) + run: | + curl -o /tmp/ImageMagick.tar.xz -sL https://imagemagick.org/archive/releases/ImageMagick-${{ matrix.imagemagick }}.tar.xz + ( + cd /tmp || exit 1 + tar xf ImageMagick.tar.xz + cd ImageMagick-${{ matrix.imagemagick }} + sudo ./configure --prefix=/home/runner/im/imagemagick-${{ matrix.imagemagick }} + sudo make -j$(nproc) + sudo make install + ) + + - name: Install PHP ImageMagick extension + run: | + curl -o /tmp/imagick.tgz -sL http://pecl.php.net/get/imagick-${{ matrix.imagick }}.tgz + ( + cd /tmp || exit 1 + tar -xzf imagick.tgz + cd imagick-${{ matrix.imagick }} + phpize + sudo ./configure --with-imagick=/home/runner/im/imagemagick-${{ matrix.imagemagick }} + sudo make -j$(nproc) + sudo make install + ) + sudo bash -c 'echo "extension=imagick.so" >> /etc/php/${{ matrix.php }}/cli/php.ini' + php --ri imagick; + + - name: Get composer cache directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache composer dependencies + uses: actions/cache@v2 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-php-${{ matrix.php }}-composer-${{ matrix.stability }}-${{ hashFiles('**/composer.json') }} + restore-keys: ${{ runner.os }}-php-${{ matrix.php }}-composer-${{ matrix.stability }}- + + - name: Install dependencies + run: composer update --${{ matrix.stability }} --prefer-dist --no-interaction + + - name: Which Imagick Version + run: php -r 'var_dump(Imagick::getVersion());' + + - name: Supported Imagick Formats + run: php -r 'var_dump(Imagick::queryFormats());' + + - name: Execute tests + run: vendor/bin/phpunit --no-coverage + + - name: Run analyzer + run: vendor/bin/phpstan analyze --level=4 ./src diff --git a/.gitignore b/.gitignore index daaed11d..c7fe04e6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,7 @@ -.DS_Store -composer.lock -vendor/ -dev/ .idea/ +build/ +vendor/ +.DS_Store +.phpunit.result.cache +composer.lock +phpunit.xml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 86ddce95..00000000 --- a/.travis.yml +++ /dev/null @@ -1,36 +0,0 @@ -language: php - -sudo: false - -jobs: - include: - - dist: trusty - php: 5.4 - - dist: trusty - php: 5.5 - - dist: xenial - php: 5.6 - - dist: xenial - php: 7.0 - - dist: xenial - php: 7.1 - - dist: xenial - php: 7.2 - - dist: xenial - php: 7.3 - - dist: xenial - php: 7.4 - - dist: xenial - php: nightly - - dist: xenial - php: hhvm - allow_failures: - - php: nightly - - php: hhvm - -before_script: - - printf "\n" | pecl install imagick - - composer self-update || true - - composer install --prefer-dist --no-interaction --no-progress --no-suggest --optimize-autoloader - -script: vendor/bin/phpunit diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..b17cf7c3 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,36 @@ +FROM php:8-cli + +RUN apt update \ + && apt install -y \ + libpng-dev \ + libicu-dev \ + libavif-dev \ + libpq-dev \ + libzip-dev \ + zip \ + zlib1g-dev \ + locales \ + locales-all \ + libmagickwand-dev \ + libwebp-dev \ + && pecl install imagick \ + && docker-php-ext-configure gd --with-freetype --with-jpeg --with-webp --with-avif \ + && docker-php-ext-enable imagick \ + && docker-php-ext-install \ + intl \ + opcache \ + pdo \ + pdo_pgsql \ + pdo_mysql \ + pgsql \ + fileinfo \ + mysqli \ + gd \ + bcmath \ + exif \ + zip \ + && apt-get clean + +# install composer +# +RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer diff --git a/LICENSE b/LICENSE index bc444ba2..f20a0402 100644 --- a/LICENSE +++ b/LICENSE @@ -1,9 +1,9 @@ The MIT License (MIT) -Copyright (c) 2014 Oliver Vogel +Copyright (c) 2023 Oliver Vogel Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md deleted file mode 100755 index 37f94072..00000000 --- a/README.md +++ /dev/null @@ -1,55 +0,0 @@ -# Intervention Image - -Intervention Image is a **PHP image handling and manipulation** library providing an easier and expressive way to create, edit, and compose images. The package includes ServiceProviders and Facades for easy **Laravel** integration. - -[![Latest Version](https://img.shields.io/packagist/v/intervention/image.svg)](https://packagist.org/packages/intervention/image) -[![Build Status](https://travis-ci.org/Intervention/image.png?branch=master)](https://travis-ci.org/Intervention/image) -[![Monthly Downloads](https://img.shields.io/packagist/dm/intervention/image.svg)](https://packagist.org/packages/intervention/image/stats) - -## Requirements - -- PHP >=5.4 -- Fileinfo Extension - -## Supported Image Libraries - -- GD Library (>=2.0) -- Imagick PHP extension (>=6.5.7) - -## Getting started - -- [Installation](https://image.intervention.io/v2/introduction/installation) -- [Laravel Framework Integration](https://image.intervention.io/v2/introduction/installation#integration-in-laravel) -- [Basic Usage](https://image.intervention.io/v2/usage/overview#basic-usage) - -## Code Examples - -```php -// open an image file -$img = Image::make('public/foo.jpg'); - -// resize image instance -$img->resize(320, 240); - -// insert a watermark -$img->insert('public/watermark.png'); - -// save image in desired format -$img->save('public/bar.jpg'); -``` - -Refer to the [official documentation](http://image.intervention.io/) to learn more about Intervention Image. - -## Contributing - -Contributions to the Intervention Image library are welcome. Please note the following guidelines before submitting your pull request. - -- Follow [PSR-2](http://www.php-fig.org/psr/psr-2/) coding standards. -- Write tests for new functions and added features -- API calls should work consistently with both GD and Imagick drivers - -## License - -Intervention Image is licensed under the [MIT License](http://opensource.org/licenses/MIT). - -Copyright 2017 [Oliver Vogel](http://olivervogel.com/) diff --git a/composer.json b/composer.json index 6d4d360b..8678c723 100644 --- a/composer.json +++ b/composer.json @@ -1,8 +1,8 @@ { "name": "intervention/image", - "description": "Image handling and manipulation library with support for Laravel integration", - "homepage": "http://image.intervention.io/", - "keywords": ["image", "gd", "imagick", "laravel", "watermark", "thumbnail"], + "description": "PHP image manipulation", + "homepage": "https://image.intervention.io/", + "keywords": ["image", "gd", "imagick", "watermark", "thumbnail", "resize"], "license": "MIT", "authors": [ { @@ -12,36 +12,22 @@ } ], "require": { - "php": ">=5.4.0", - "ext-fileinfo": "*", - "guzzlehttp/psr7": "~1.1 || ^2.0" + "php": "^8.1", + "intervention/gif": "^3" }, "require-dev": { - "phpunit/phpunit": "^4.8 || ^5.7 || ^7.5.15", - "mockery/mockery": "~0.9.2" - }, - "suggest": { - "ext-gd": "to use GD library based image processing.", - "ext-imagick": "to use Imagick based image processing.", - "intervention/imagecache": "Caching extension for the Intervention Image library" + "phpunit/phpunit": "^9", + "mockery/mockery": "^1.6", + "phpstan/phpstan": "^1" }, "autoload": { "psr-4": { - "Intervention\\Image\\": "src/Intervention/Image" + "Intervention\\Image\\": "src" } }, - "extra": { - "branch-alias": { - "dev-master": "2.4-dev" - }, - "laravel": { - "providers": [ - "Intervention\\Image\\ImageServiceProvider" - ], - "aliases": { - "Image": "Intervention\\Image\\Facades\\Image" - } + "autoload-dev": { + "psr-4": { + "Intervention\\Image\\Tests\\": "tests" } - }, - "minimum-stability": "stable" + } } diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..8d90fbff --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,15 @@ +version: '3' + +services: + tests: + build: ./ + working_dir: /project + command: bash -c "composer install && ./vendor/bin/phpunit -vvv" + volumes: + - ./:/project + analysis: + build: ./ + working_dir: /project + command: bash -c "composer install && ./vendor/bin/phpstan analyze --level=4 ./src" + volumes: + - ./:/project diff --git a/phpunit.xml b/phpunit.xml index 3347b75b..0fa3ad89 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,18 +1,24 @@ ./tests/ + + + + src + + diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 00000000..63454441 --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,23 @@ + + + + + ./tests/ + + + + + + src + + + diff --git a/provides.json b/provides.json deleted file mode 100644 index a8cd1b6a..00000000 --- a/provides.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "providers": [ - "Intervention\\Image\\ImageServiceProvider" - ], - "aliases": [ - { - "alias": "Image", - "facade": "Intervention\\Image\\Facades\\Image" - } - ] -} diff --git a/readme.md b/readme.md new file mode 100644 index 00000000..7c54085e --- /dev/null +++ b/readme.md @@ -0,0 +1,86 @@ +# Intervention Image +## PHP Image Manipulation + +[![Latest Version](https://img.shields.io/packagist/v/intervention/image.svg)](https://packagist.org/packages/intervention/image) +[![Build Status](https://github.com/Intervention/image/actions/workflows/run-tests.yml/badge.svg)](https://github.com/Intervention/image/actions) +[![Monthly Downloads](https://img.shields.io/packagist/dm/intervention/image.svg)](https://packagist.org/packages/intervention/image/stats) + +Intervention Image is a **image handling and manipulation library written in +PHP** providing an easy and expressive way to create, edit, and compose +images. GD library or Imagick can be selected as the base layer for all +operations. + +- Simple interface for common image manipulation tasks +- Interchangable driver architecture +- Support for animated images +- Framework-agnostic +- PSR-12 compliant + +## Installation + +You can install this package easily with [Composer](https://getcomposer.org/). Just require the package with the following command: + +```bash +composer require intervention/image +``` + +## Getting started + +Learn the [basics](https://image.intervention.io/v3/basics/instantiation/) on +how to use Intervention Image and more with the [official +documentation](https://image.intervention.io/v3/). + +## Code Examples + +```php +// create image manager with desired driver +$manager = new ImageManager( + new Intervention\Image\Drivers\Gd\Driver() +); + +// open an image file +$image = $manager->read('images/example.gif'); + +// resize image instance +$image->resize(height: 300); + +// insert a watermark +$image->place('images/watermark.png'); + +// encode edited image +$encoded = $image->toJpg(); + +// save encoded image +$encoded->save('images/example.jpg'); +``` + +## Requirements + +- PHP >= 8.1 + +## Supported Image Libraries + +- GD Library +- Imagick PHP extension + +## Development & Testing + +With this package comes a Docker image to build a test suite and analysis +container. To build this container you have to have Docker installed on your +system. You can run all tests with this command. + +```bash +docker-compose run --rm --build tests +``` + +Run the static analyzer on the code base. + +```bash +docker-compose run --rm --build analysis +``` + +## License + +Intervention Image is licensed under the [MIT License](http://opensource.org/licenses/MIT). + +Copyright 2020 [Oliver Vogel](http://intervention.io/) diff --git a/src/Analyzers/AbstractAnalyzer.php b/src/Analyzers/AbstractAnalyzer.php new file mode 100644 index 00000000..74509e9b --- /dev/null +++ b/src/Analyzers/AbstractAnalyzer.php @@ -0,0 +1,19 @@ +analyze($this); + } +} diff --git a/src/Analyzers/ColorspaceAnalyzer.php b/src/Analyzers/ColorspaceAnalyzer.php new file mode 100644 index 00000000..6c560a31 --- /dev/null +++ b/src/Analyzers/ColorspaceAnalyzer.php @@ -0,0 +1,7 @@ +items); + } + + /** + * Returns Iterator + * + * @return Traversable + */ + public function getIterator(): Traversable + { + return new ArrayIterator($this->items); + } + + public function toArray(): array + { + return $this->items; + } + + /** + * Count items in collection + * + * @return integer + */ + public function count(): int + { + return count($this->items); + } + + /** + * Append new item to collection + * + * @param mixed $item + * @return CollectionInterface + */ + public function push($item): CollectionInterface + { + $this->items[] = $item; + + return $this; + } + + /** + * Return first item in collection + * + * @return mixed + */ + public function first(): mixed + { + if ($item = reset($this->items)) { + return $item; + } + + return null; + } + + /** + * Returns last item in collection + * + * @return mixed + */ + public function last(): mixed + { + if ($item = end($this->items)) { + return $item; + } + + return null; + } + + /** + * Return item at given position starting at 0 + * + * @param integer $key + * @return mixed + */ + public function getAtPosition(int $key = 0, $default = null): mixed + { + if ($this->count() == 0) { + return $default; + } + + $positions = array_values($this->items); + if (! array_key_exists($key, $positions)) { + return $default; + } + + return $positions[$key]; + } + + public function get(int|string $query, $default = null): mixed + { + if ($this->count() == 0) { + return $default; + } + + if (is_int($query) && array_key_exists($query, $this->items)) { + return $this->items[$query]; + } + + if (is_string($query) && strpos($query, '.') === false) { + return array_key_exists($query, $this->items) ? $this->items[$query] : $default; + } + + $query = explode('.', $query); + + $result = $default; + $items = $this->items; + foreach ($query as $key) { + if (!is_array($items) || !array_key_exists($key, $items)) { + $result = $default; + break; + } + + $result = $items[$key]; + $items = $result; + } + + return $result; + } + + public function map(callable $callback): self + { + $items = array_map(function ($item) use ($callback) { + return $callback($item); + }, $this->items); + + return new self($items); + } + + /** + * Run callback on each item of the collection an remove it if it does not return true + * + * @param callable $callback + * @return Collection + */ + public function filter(callable $callback): self + { + $items = array_filter($this->items, function ($item) use ($callback) { + return $callback($item); + }); + + return new self($items); + } + + public function pushEach(array $data, ?callable $callback = null): CollectionInterface + { + if (! is_iterable($data)) { + throw new RuntimeException('Unable to iterate given data.'); + } + + foreach ($data as $item) { + $this->push(is_callable($callback) ? $callback($item) : $item); + } + + return $this; + } + + public function empty(): CollectionInterface + { + $this->items = []; + + return $this; + } +} diff --git a/src/Colors/AbstractColor.php b/src/Colors/AbstractColor.php new file mode 100644 index 00000000..49d1dd2a --- /dev/null +++ b/src/Colors/AbstractColor.php @@ -0,0 +1,78 @@ +channels; + } + + public function channel(string $classname): ColorChannelInterface + { + $channels = array_filter($this->channels(), function (ColorChannelInterface $channel) use ($classname) { + return get_class($channel) == $classname; + }); + + if (count($channels) == 0) { + throw new ColorException('Channel ' . $classname . ' could not be found.'); + } + + return reset($channels); + } + + public function normalize(): array + { + return array_map(function (ColorChannelInterface $channel) { + return $channel->normalize(); + }, $this->channels()); + } + + /** + * {@inheritdoc} + * + * @see ColorInterface::toArray() + */ + public function toArray(): array + { + return array_map(function (ColorChannelInterface $channel) { + return $channel->value(); + }, $this->channels()); + } + + /** + * {@inheritdoc} + * + * @see ColorInterface::convertTo() + */ + public function convertTo(string|ColorspaceInterface $colorspace): ColorInterface + { + $colorspace = match (true) { + is_object($colorspace) => $colorspace, + default => new $colorspace(), + }; + + return $colorspace->importColor($this); + } + + /** + * {@inheritdoc} + * + * @see ColorInterface::__toString() + */ + public function __toString(): string + { + return $this->toString(); + } +} diff --git a/src/Colors/AbstractColorChannel.php b/src/Colors/AbstractColorChannel.php new file mode 100644 index 00000000..a2d0db7b --- /dev/null +++ b/src/Colors/AbstractColorChannel.php @@ -0,0 +1,91 @@ +value = $this->validate( + match (true) { + is_null($value) && is_numeric($normalized) => intval(round($normalized * $this->max())), + is_numeric($value) && is_null($normalized) => $value, + default => throw new ColorException('Color channels must either have a value or a normalized value') + } + ); + } + + /** + * Alias of value() + * + * @return int + */ + public function toInt(): int + { + return $this->value; + } + + /** + * {@inheritdoc} + * + * @see ColorChannelInterface::value() + */ + public function value(): int + { + return $this->value; + } + + /** + * {@inheritdoc} + * + * @see ColorChannelInterface::normalize() + */ + public function normalize($precision = 32): float + { + return round(($this->value() - $this->min()) / ($this->max() - $this->min()), $precision); + } + + /** + * {@inheritdoc} + * + * @see ColorChannelInterface::validate() + */ + public function validate(mixed $value): mixed + { + if ($value < $this->min() || $value > $this->max()) { + throw new ColorException('Color channel value must be in range ' . $this->min() . ' to ' . $this->max()); + } + + return $value; + } + + /** + * {@inheritdoc} + * + * @see ColorChannelInterface::toString() + */ + public function toString(): string + { + return (string) $this->value(); + } + + /** + * {@inheritdoc} + * + * @see ColorChannelInterface::__toString() + */ + public function __toString(): string + { + return $this->toString(); + } +} diff --git a/src/Colors/Cmyk/Channels/Cyan.php b/src/Colors/Cmyk/Channels/Cyan.php new file mode 100644 index 00000000..d0ac4612 --- /dev/null +++ b/src/Colors/Cmyk/Channels/Cyan.php @@ -0,0 +1,18 @@ +channels = [ + new Cyan($c), + new Magenta($m), + new Yellow($y), + new Key($k), + ]; + } + + public static function create(mixed $input): ColorInterface + { + return (new class ([ + Decoders\StringColorDecoder::class, + ]) extends AbstractInputHandler + { + })->handle($input); + } + + public function colorspace(): ColorspaceInterface + { + return new Colorspace(); + } + + public function toHex(string $prefix = ''): string + { + return $this->convertTo(RgbColorspace::class)->toHex($prefix); + } + + public function cyan(): ColorChannelInterface + { + return $this->channel(Cyan::class); + } + + public function magenta(): ColorChannelInterface + { + return $this->channel(Magenta::class); + } + + public function yellow(): ColorChannelInterface + { + return $this->channel(Yellow::class); + } + + public function key(): ColorChannelInterface + { + return $this->channel(Key::class); + } + + public function toString(): string + { + return sprintf( + 'cmyk(%d%%, %d%%, %d%%, %d%%)', + $this->cyan()->value(), + $this->magenta()->value(), + $this->yellow()->value(), + $this->key()->value() + ); + } + + public function isGreyscale(): bool + { + return 0 === array_sum([ + $this->cyan()->value(), + $this->magenta()->value(), + $this->yellow()->value(), + ]); + } +} diff --git a/src/Colors/Cmyk/Colorspace.php b/src/Colors/Cmyk/Colorspace.php new file mode 100644 index 00000000..e67072b2 --- /dev/null +++ b/src/Colors/Cmyk/Colorspace.php @@ -0,0 +1,64 @@ +value(); + }, self::$channels, $normalized); + + return new Color(...$values); + } + + /** + * {@inheritdoc} + * + * @see ColorspaceInterface::importColor() + */ + public function importColor(ColorInterface $color): ColorInterface + { + return match (get_class($color)) { + RgbColor::class => $this->importRgbColor($color), + HsvColor::class => $this->importRgbColor($color->convertTo(RgbColorspace::class)), + HslColor::class => $this->importRgbColor($color->convertTo(RgbColorspace::class)), + default => $color, + }; + } + + protected function importRgbColor(RgbColor $color): CmykColor + { + $c = (255 - $color->red()->value()) / 255.0 * 100; + $m = (255 - $color->green()->value()) / 255.0 * 100; + $y = (255 - $color->blue()->value()) / 255.0 * 100; + $k = intval(round(min([$c, $m, $y]))); + + $c = intval(round($c - $k)); + $m = intval(round($m - $k)); + $y = intval(round($y - $k)); + + return new CmykColor($c, $m, $y, $k); + } +} diff --git a/src/Colors/Cmyk/Decoders/StringColorDecoder.php b/src/Colors/Cmyk/Decoders/StringColorDecoder.php new file mode 100644 index 00000000..7bfafbee --- /dev/null +++ b/src/Colors/Cmyk/Decoders/StringColorDecoder.php @@ -0,0 +1,37 @@ +[0-9\.]+%?), ?(?P[0-9\.]+%?), ?(?P[0-9\.]+%?), ?(?P[0-9\.]+%?)\)$/i'; + if (preg_match($pattern, $input, $matches) != 1) { + throw new DecoderException('Unable to decode input'); + } + + $values = array_map(function ($value) { + return intval(round(floatval(trim(str_replace('%', '', $value))))); + }, [$matches['c'], $matches['m'], $matches['y'], $matches['k']]); + + return new Color(...$values); + } +} diff --git a/src/Colors/Hsl/Channels/Hue.php b/src/Colors/Hsl/Channels/Hue.php new file mode 100644 index 00000000..e795aebb --- /dev/null +++ b/src/Colors/Hsl/Channels/Hue.php @@ -0,0 +1,28 @@ +channels = [ + new Hue($h), + new Saturation($s), + new Luminance($l), + ]; + } + + public function colorspace(): ColorspaceInterface + { + return new Colorspace(); + } + + /** + * {@inheritdoc} + * + * @see ColorInterface::create() + */ + public static function create(mixed $input): ColorInterface + { + return (new class ([ + Decoders\StringColorDecoder::class, + ]) extends AbstractInputHandler + { + })->handle($input); + } + + /** + * Return the Hue channel + * + * @return ColorChannelInterface + */ + public function hue(): ColorChannelInterface + { + return $this->channel(Hue::class); + } + + /** + * Return the Saturation channel + * + * @return ColorChannelInterface + */ + public function saturation(): ColorChannelInterface + { + return $this->channel(Saturation::class); + } + + /** + * Return the Luminance channel + * + * @return ColorChannelInterface + */ + public function luminance(): ColorChannelInterface + { + return $this->channel(Luminance::class); + } + + public function toHex(string $prefix = ''): string + { + return $this->convertTo(RgbColorspace::class)->toHex($prefix); + } + + /** + * {@inheritdoc} + * + * @see ColorInterface::toString() + */ + public function toString(): string + { + return sprintf( + 'hsl(%d, %d%%, %d%%)', + $this->hue()->value(), + $this->saturation()->value(), + $this->luminance()->value() + ); + } + + /** + * {@inheritdoc} + * + * @see ColorInterface::isGreyscale() + */ + public function isGreyscale(): bool + { + return $this->saturation()->value() == 0; + } +} diff --git a/src/Colors/Hsl/Colorspace.php b/src/Colors/Hsl/Colorspace.php new file mode 100644 index 00000000..7a26cfde --- /dev/null +++ b/src/Colors/Hsl/Colorspace.php @@ -0,0 +1,109 @@ +value(); + }, self::$channels, $normalized); + + return new Color(...$values); + } + + public function importColor(ColorInterface $color): ColorInterface + { + return match (get_class($color)) { + CmykColor::class => $this->importRgbColor($color->convertTo(RgbColorspace::class)), + RgbColor::class => $this->importRgbColor($color), + HsvColor::class => $this->importHsvColor($color), + default => $color, + }; + } + + protected function importRgbColor(RgbColor $color): ColorInterface + { + // normalized values of rgb channels + $values = array_map(function ($channel) { + return $channel->normalize(); + }, $color->channels()); + + // take only RGB + $values = array_slice($values, 0, 3); + + // calculate Luminance + $min = min(...$values); + $max = max(...$values); + $luminance = ($max + $min) / 2; + $delta = $max - $min; + + // calculate saturation + $saturation = match (true) { + $delta == 0 => 0, + default => $delta / (1 - abs(2 * $luminance - 1)), + }; + + // calculate hue + list($r, $g, $b) = $values; + $hue = match (true) { + ($delta == 0) => 0, + ($max == $r) => 60 * fmod((($g - $b) / $delta), 6), + ($max == $g) => 60 * ((($b - $r) / $delta) + 2), + ($max == $b) => 60 * ((($r - $g) / $delta) + 4), + default => 0, + }; + + $hue = ($hue + 360) % 360; // normalize hue + + return new Color( + intval(round($hue)), + intval(round($saturation * 100)), + intval(round($luminance * 100)), + ); + } + + protected function importHsvColor(HsvColor $color): ColorInterface + { + // normalized values of hsv channels + list($h, $s, $v) = array_map(function ($channel) { + return $channel->normalize(); + }, $color->channels()); + + // calculate Luminance + $luminance = (2 - $s) * $v / 2; + + // calculate Saturation + $saturation = match (true) { + $luminance == 0 => $s, + $luminance == 1 => 0, + $luminance < .5 => $s * $v / ($luminance * 2), + default => $s * $v / (2 - $luminance * 2), + }; + + return new Color( + intval(round($h * 360)), + intval(round($saturation * 100)), + intval(round($luminance * 100)), + ); + } +} diff --git a/src/Colors/Hsl/Decoders/StringColorDecoder.php b/src/Colors/Hsl/Decoders/StringColorDecoder.php new file mode 100644 index 00000000..21944354 --- /dev/null +++ b/src/Colors/Hsl/Decoders/StringColorDecoder.php @@ -0,0 +1,40 @@ +[0-9\.]+), ?(?P[0-9\.]+%?), ?(?P[0-9\.]+%?)?\)$/i'; + if (preg_match($pattern, $input, $matches) != 1) { + throw new DecoderException('Unable to decode input'); + } + + $values = array_map(function ($value) { + return match (strpos($value, '%')) { + false => intval(trim($value)), + default => intval(trim(str_replace('%', '', $value))), + }; + }, [$matches['h'], $matches['s'], $matches['l']]); + + return new Color(...$values); + } +} diff --git a/src/Colors/Hsv/Channels/Hue.php b/src/Colors/Hsv/Channels/Hue.php new file mode 100644 index 00000000..d578e54d --- /dev/null +++ b/src/Colors/Hsv/Channels/Hue.php @@ -0,0 +1,28 @@ +channels = [ + new Hue($h), + new Saturation($s), + new Value($v), + ]; + } + + public function colorspace(): ColorspaceInterface + { + return new Colorspace(); + } + + /** + * {@inheritdoc} + * + * @see ColorInterface::create() + */ + public static function create(mixed $input): ColorInterface + { + return (new class ([ + Decoders\StringColorDecoder::class, + ]) extends AbstractInputHandler + { + })->handle($input); + } + + /** + * Return the Hue channel + * + * @return ColorChannelInterface + */ + public function hue(): ColorChannelInterface + { + return $this->channel(Hue::class); + } + + /** + * Return the Saturation channel + * + * @return ColorChannelInterface + */ + public function saturation(): ColorChannelInterface + { + return $this->channel(Saturation::class); + } + + /** + * Return the Value channel + * + * @return ColorChannelInterface + */ + public function value(): ColorChannelInterface + { + return $this->channel(Value::class); + } + + public function toHex(string $prefix = ''): string + { + return $this->convertTo(RgbColorspace::class)->toHex($prefix); + } + + /** + * {@inheritdoc} + * + * @see ColorInterface::toString() + */ + public function toString(): string + { + return sprintf( + 'hsv(%d, %d%%, %d%%)', + $this->hue()->value(), + $this->saturation()->value(), + $this->value()->value() + ); + } + + /** + * {@inheritdoc} + * + * @see ColorInterface::isGreyscale() + */ + public function isGreyscale(): bool + { + return $this->saturation()->value() == 0; + } +} diff --git a/src/Colors/Hsv/Colorspace.php b/src/Colors/Hsv/Colorspace.php new file mode 100644 index 00000000..229ffaf8 --- /dev/null +++ b/src/Colors/Hsv/Colorspace.php @@ -0,0 +1,102 @@ +value(); + }, self::$channels, $normalized); + + return new Color(...$values); + } + + /** + * {@inheritdoc} + * + * @see ColorspaceInterface::importColor() + */ + public function importColor(ColorInterface $color): ColorInterface + { + return match (get_class($color)) { + CmykColor::class => $this->importRgbColor($color->convertTo(RgbColorspace::class)), + RgbColor::class => $this->importRgbColor($color), + HslColor::class => $this->importHslColor($color), + default => $color, + }; + } + + protected function importRgbColor(RgbColor $color): ColorInterface + { + // normalized values of rgb channels + $values = array_map(function ($channel) { + return $channel->normalize(); + }, $color->channels()); + + // take only RGB + $values = array_slice($values, 0, 3); + + // calculate chroma + $min = min(...$values); + $max = max(...$values); + $chroma = $max - $min; + + // calculate value + $v = 100 * $max; + + if ($chroma == 0) { + // greyscale color + return new Color(0, 0, intval(round($v))); + } + + // calculate saturation + $s = 100 * ($chroma / $max); + + // calculate hue + list($r, $g, $b) = $values; + $h = match (true) { + ($r == $min) => 3 - (($g - $b) / $chroma), + ($b == $min) => 1 - (($r - $g) / $chroma), + default => 5 - (($b - $r) / $chroma), + } * 60; + + return new Color( + intval(round($h)), + intval(round($s)), + intval(round($v)) + ); + } + + protected function importHslColor(HslColor $color): ColorInterface + { + // normalized values of hsl channels + list($h, $s, $l) = array_map(function ($channel) { + return $channel->normalize(); + }, $color->channels()); + + $v = $l + $s * min($l, 1 - $l); + $s = ($v == 0) ? 0 : 2 * (1 - $l / $v); + + return $this->colorFromNormalized([$h, $s, $v]); + } +} diff --git a/src/Colors/Hsv/Decoders/StringColorDecoder.php b/src/Colors/Hsv/Decoders/StringColorDecoder.php new file mode 100644 index 00000000..395396b9 --- /dev/null +++ b/src/Colors/Hsv/Decoders/StringColorDecoder.php @@ -0,0 +1,40 @@ +[0-9\.]+), ?(?P[0-9\.]+%?), ?(?P[0-9\.]+%?)?\)$/i'; + if (preg_match($pattern, $input, $matches) != 1) { + throw new DecoderException('Unable to decode input'); + } + + $values = array_map(function ($value) { + return match (strpos($value, '%')) { + false => intval(trim($value)), + default => intval(trim(str_replace('%', '', $value))), + }; + }, [$matches['h'], $matches['s'], $matches['v']]); + + return new Color(...$values); + } +} diff --git a/src/Colors/Profile.php b/src/Colors/Profile.php new file mode 100644 index 00000000..55194f45 --- /dev/null +++ b/src/Colors/Profile.php @@ -0,0 +1,10 @@ +normalize(), 6)); + } +} diff --git a/src/Colors/Rgb/Channels/Blue.php b/src/Colors/Rgb/Channels/Blue.php new file mode 100644 index 00000000..b83be821 --- /dev/null +++ b/src/Colors/Rgb/Channels/Blue.php @@ -0,0 +1,8 @@ +channels = [ + new Red($r), + new Green($g), + new Blue($b), + new Alpha($a), + ]; + } + + public function colorspace(): ColorspaceInterface + { + return new Colorspace(); + } + + /** + * {@inheritdoc} + * + * @see ColorInterface::create() + */ + public static function create(mixed $input): ColorInterface + { + return (new class ([ + Decoders\HexColorDecoder::class, + Decoders\StringColorDecoder::class, + Decoders\TransparentColorDecoder::class, + Decoders\HtmlColornameDecoder::class, + ]) extends AbstractInputHandler + { + })->handle($input); + } + + /** + * Return the RGB red color channel + * + * @return ColorChannelInterface + */ + public function red(): ColorChannelInterface + { + return $this->channel(Red::class); + } + + /** + * Return the RGB green color channel + * + * @return ColorChannelInterface + */ + public function green(): ColorChannelInterface + { + return $this->channel(Green::class); + } + + /** + * Return the RGB blue color channel + * + * @return ColorChannelInterface + */ + public function blue(): ColorChannelInterface + { + return $this->channel(Blue::class); + } + + /** + * Return the colors alpha channel + * + * @return ColorChannelInterface + */ + public function alpha(): ColorChannelInterface + { + return $this->channel(Alpha::class); + } + + /** + * {@inheritdoc} + * + * @see ColorInterface::toHex() + */ + public function toHex(string $prefix = ''): string + { + if ($this->isFullyOpaque()) { + return sprintf( + '%s%02x%02x%02x', + $prefix, + $this->red()->value(), + $this->green()->value(), + $this->blue()->value() + ); + } + + return sprintf( + '%s%02x%02x%02x%02x', + $prefix, + $this->red()->value(), + $this->green()->value(), + $this->blue()->value(), + $this->alpha()->value() + ); + } + + public function isFullyOpaque(): bool + { + return $this->alpha()->value() === 255; + } + + /** + * {@inheritdoc} + * + * @see ColorInterface::toString() + */ + public function toString(): string + { + if ($this->isFullyOpaque()) { + return sprintf( + 'rgb(%d, %d, %d)', + $this->red()->value(), + $this->green()->value(), + $this->blue()->value() + ); + } + + return sprintf( + 'rgba(%d, %d, %d, %.1F)', + $this->red()->value(), + $this->green()->value(), + $this->blue()->value(), + $this->alpha()->normalize(), + ); + } + + /** + * {@inheritdoc} + * + * @see ColorInterface::isGreyscale() + */ + public function isGreyscale(): bool + { + $values = [$this->red()->value(), $this->green()->value(), $this->blue()->value()]; + + return count(array_unique($values, SORT_REGULAR)) === 1; + } +} diff --git a/src/Colors/Rgb/Colorspace.php b/src/Colors/Rgb/Colorspace.php new file mode 100644 index 00000000..12487e71 --- /dev/null +++ b/src/Colors/Rgb/Colorspace.php @@ -0,0 +1,112 @@ +value(); + }, self::$channels, $normalized); + + return new Color(...$values); + } + + /** + * {@inheritdoc} + * + * @see ColorspaceInterface::importColor() + */ + public function importColor(ColorInterface $color): ColorInterface + { + return match (get_class($color)) { + CmykColor::class => $this->importCmykColor($color), + HsvColor::class => $this->importHsvColor($color), + HslColor::class => $this->importHslColor($color), + default => $color, + }; + } + + protected function importCmykColor(CmykColor $color): ColorInterface + { + return new Color( + (int) (255 * (1 - $color->cyan()->normalize()) * (1 - $color->key()->normalize())), + (int) (255 * (1 - $color->magenta()->normalize()) * (1 - $color->key()->normalize())), + (int) (255 * (1 - $color->yellow()->normalize()) * (1 - $color->key()->normalize())), + ); + } + + protected function importHsvColor(HsvColor $color): ColorInterface + { + $chroma = $color->value()->normalize() * $color->saturation()->normalize(); + $hue = $color->hue()->normalize() * 6; + $x = $chroma * (1 - abs(fmod($hue, 2) - 1)); + + // connect channel values + $values = match (true) { + $hue < 1 => [$chroma, $x, 0], + $hue < 2 => [$x, $chroma, 0], + $hue < 3 => [0, $chroma, $x], + $hue < 4 => [0, $x, $chroma], + $hue < 5 => [$x, 0, $chroma], + default => [$chroma, 0, $x], + }; + + // add to each value + $values = array_map(function ($value) use ($color, $chroma) { + return $value + ($color->value()->normalize() - $chroma); + }, $values); + + array_push($values, 1); // append alpha channel value + + return $this->colorFromNormalized($values); + } + + protected function importHslColor(HslColor $color): ColorInterface + { + // normalized values of hsl channels + list($h, $s, $l) = array_map(function ($channel) { + return $channel->normalize(); + }, $color->channels()); + + $c = (1 - abs(2 * $l - 1)) * $s; + $x = $c * (1 - abs(fmod($h * 6, 2) - 1)); + $m = $l - $c / 2; + + $values = match (true) { + $h < 1 / 6 => [$c, $x, 0], + $h < 2 / 6 => [$x, $c, 0], + $h < 3 / 6 => [0, $c, $x], + $h < 4 / 6 => [0, $x, $c], + $h < 5 / 6 => [$x, 0, $c], + default => [$c, 0, $x], + }; + + $values = array_map(function ($value) use ($m) { + return $value + $m; + }, $values); + + array_push($values, 1); // append alpha channel value + + return $this->colorFromNormalized($values); + } +} diff --git a/src/Colors/Rgb/Decoders/HexColorDecoder.php b/src/Colors/Rgb/Decoders/HexColorDecoder.php new file mode 100644 index 00000000..e00c14ba --- /dev/null +++ b/src/Colors/Rgb/Decoders/HexColorDecoder.php @@ -0,0 +1,48 @@ +[a-f\d]{3}(?:[a-f\d]?|(?:[a-f\d]{3}(?:[a-f\d]{2})?)?)\b)$/i'; + if (preg_match($pattern, $input, $matches) != 1) { + throw new DecoderException('Unable to decode input'); + } + + $values = str_split($matches['hex']); + $values = match (strlen($matches['hex'])) { + 3, 4 => str_split($matches['hex']), + 6, 8 => str_split($matches['hex'], 2), + default => throw new DecoderException('Unable to decode input'), + }; + + $values = array_map(function ($value) { + return match (strlen($value)) { + 1 => hexdec($value . $value), + 2 => hexdec($value), + default => throw new DecoderException('Unable to decode input'), + }; + }, $values); + + return new Color(...$values); + } +} diff --git a/src/Colors/Rgb/Decoders/HtmlColornameDecoder.php b/src/Colors/Rgb/Decoders/HtmlColornameDecoder.php new file mode 100644 index 00000000..fa4ea630 --- /dev/null +++ b/src/Colors/Rgb/Decoders/HtmlColornameDecoder.php @@ -0,0 +1,172 @@ + '#ffa07a', + 'salmon' => '#fa8072', + 'darksalmon' => '#e9967a', + 'lightcoral' => '#f08080', + 'indianred' => '#cd5c5c', + 'crimson' => '#dc143c', + 'firebrick' => '#b22222', + 'red' => '#ff0000', + 'darkred' => '#8b0000', + 'coral' => '#ff7f50', + 'tomato' => '#ff6347', + 'orangered' => '#ff4500', + 'gold' => '#ffd700', + 'orange' => '#ffa500', + 'darkorange' => '#ff8c00', + 'lightyellow' => '#ffffe0', + 'lemonchiffon' => '#fffacd', + 'lightgoldenrodyellow' => '#fafad2', + 'papayawhip' => '#ffefd5', + 'moccasin' => '#ffe4b5', + 'peachpuff' => '#ffdab9', + 'palegoldenrod' => '#eee8aa', + 'khaki' => '#f0e68c', + 'darkkhaki' => '#bdb76b', + 'yellow' => '#ffff00', + 'lawngreen' => '#7cfc00', + 'chartreuse' => '#7fff00', + 'limegreen' => '#32cd32', + 'lime' => '#00ff00', + 'forestgreen' => '#228b22', + 'green' => '#008000', + 'darkgreen' => '#006400', + 'greenyellow' => '#adff2f', + 'yellowgreen' => '#9acd32', + 'springgreen' => '#00ff7f', + 'mediumspringgreen' => '#00fa9a', + 'lightgreen' => '#90ee90', + 'palegreen' => '#98fb98', + 'darkseagreen' => '#8fbc8f', + 'mediumseagre' => 'en #3cb371', + 'seagreen' => '#2e8b57', + 'olive' => '#808000', + 'darkolivegreen' => '#556b2f', + 'olivedrab' => '#6b8e23', + 'lightcyan' => '#e0ffff', + 'cyan' => '#00ffff', + 'aqua' => '#00ffff', + 'aquamarine' => '#7fffd4', + 'mediumaquamarine' => '#66cdaa', + 'paleturquoise' => '#afeeee', + 'turquoise' => '#40e0d0', + 'mediumturquoise' => '#48d1cc', + 'darkturquoise' => '#00ced1', + 'lightseagreen' => '#20b2aa', + 'cadetblue' => '#5f9ea0', + 'darkcyan' => '#008b8b', + 'teal' => '#008080', + 'powderblue' => '#b0e0e6', + 'lightblue' => '#add8e6', + 'lightskyblue' => '#87cefa', + 'skyblue' => '#87ceeb', + 'deepskyblue' => '#00bfff', + 'lightsteelblue' => '#b0c4de', + 'dodgerblue' => '#1e90ff', + 'cornflowerblue' => '#6495ed', + 'steelblue' => '#4682b4', + 'royalblue' => '#4169e1', + 'blue' => '#0000ff', + 'mediumblue' => '#0000cd', + 'darkblue' => '#00008b', + 'navy' => '#000080', + 'midnightblue' => '#191970', + 'mediumslateblue' => '#7b68ee', + 'slateblue' => '#6a5acd', + 'darkslateblue' => '#483d8b', + 'lavender' => '#e6e6fa', + 'thistle' => '#d8bfd8', + 'plum' => '#dda0dd', + 'violet' => '#ee82ee', + 'orchid' => '#da70d6', + 'fuchsia' => '#ff00ff', + 'magenta' => '#ff00ff', + 'mediumorchid' => '#ba55d3', + 'mediumpurple' => '#9370db', + 'blueviolet' => '#8a2be2', + 'darkviolet' => '#9400d3', + 'darkorchid' => '#9932cc', + 'darkmagenta' => '#8b008b', + 'purple' => '#800080', + 'indigo' => '#4b0082', + 'pink' => '#ffc0cb', + 'lightpink' => '#ffb6c1', + 'hotpink' => '#ff69b4', + 'deeppink' => '#ff1493', + 'palevioletred' => '#db7093', + 'mediumvioletred' => '#c71585', + 'white' => '#ffffff', + 'snow' => '#fffafa', + 'honeydew' => '#f0fff0', + 'mintcream' => '#f5fffa', + 'azure' => '#f0ffff', + 'aliceblue' => '#f0f8ff', + 'ghostwhite' => '#f8f8ff', + 'whitesmoke' => '#f5f5f5', + 'seashell' => '#fff5ee', + 'beige' => '#f5f5dc', + 'oldlace' => '#fdf5e6', + 'floralwhite' => '#fffaf0', + 'ivory' => '#fffff0', + 'antiquewhite' => '#faebd7', + 'linen' => '#faf0e6', + 'lavenderblush' => '#fff0f5', + 'mistyrose' => '#ffe4e1', + 'gainsboro' => '#dcdcdc', + 'lightgray' => '#d3d3d3', + 'silver' => '#c0c0c0', + 'darkgray' => '#a9a9a9', + 'gray' => '#808080', + 'dimgray' => '#696969', + 'lightslategray' => '#778899', + 'slategray' => '#708090', + 'darkslategray' => '#2f4f4f', + 'black' => '#000000', + 'cornsilk' => '#fff8dc', + 'blanchedalmond' => '#ffebcd', + 'bisque' => '#ffe4c4', + 'navajowhite' => '#ffdead', + 'wheat' => '#f5deb3', + 'burlywood' => '#deb887', + 'tan' => '#d2b48c', + 'rosybrown' => '#bc8f8f', + 'sandybrown' => '#f4a460', + 'goldenrod' => '#daa520', + 'peru' => '#cd853f', + 'chocolate' => '#d2691e', + 'saddlebrown' => '#8b4513', + 'sienna' => '#a0522d', + 'brown' => '#a52a2a', + 'maroon' => '#800000', + ]; + + /** + * Decode html color names + * + * @param mixed $input + * @return ImageInterface|ColorInterface + */ + public function decode($input): ImageInterface|ColorInterface + { + if (! is_string($input)) { + throw new DecoderException('Unable to decode input'); + } + + if (!array_key_exists(strtolower($input), static::$names)) { + throw new DecoderException('Unable to decode input'); + } + + return parent::decode(static::$names[strtolower($input)]); + } +} diff --git a/src/Colors/Rgb/Decoders/StringColorDecoder.php b/src/Colors/Rgb/Decoders/StringColorDecoder.php new file mode 100644 index 00000000..f262bb20 --- /dev/null +++ b/src/Colors/Rgb/Decoders/StringColorDecoder.php @@ -0,0 +1,49 @@ +[0-9\.]+%?), ?(?P[0-9\.]+%?), ?(?P[0-9\.]+%?)(?:, ?(?P(?:1)|(?:1\.0*)|(?:0)|(?:0?\.\d+%?)|(?:\d{1,3}%)))?\)$/i'; + if (preg_match($pattern, $input, $matches) != 1) { + throw new DecoderException('Unable to decode input'); + } + + // rgb values + $values = array_map(function ($value) { + return match (strpos($value, '%')) { + false => intval(trim($value)), + default => intval(round(floatval(trim(str_replace('%', '', $value))) / 100 * 255)), + }; + }, [$matches['r'], $matches['g'], $matches['b']]); + + // alpha value + if (array_key_exists('a', $matches)) { + $values[] = match (true) { + strpos($matches['a'], '%') => round(intval(trim(str_replace('%', '', $matches['a']))) / 2.55), + default => intval(round(floatval(trim($matches['a'])) * 255)), + }; + } + + return new Color(...$values); + } +} diff --git a/src/Colors/Rgb/Decoders/TransparentColorDecoder.php b/src/Colors/Rgb/Decoders/TransparentColorDecoder.php new file mode 100644 index 00000000..e5248879 --- /dev/null +++ b/src/Colors/Rgb/Decoders/TransparentColorDecoder.php @@ -0,0 +1,23 @@ +decode($input); + } catch (DecoderException $e) { + if (!$this->hasSuccessor()) { + throw new DecoderException($e->getMessage()); + } + + return $this->successor->handle($input); + } + + return $decoded; + } + + /** + * Determine if current decoder has a successor + * + * @return bool + */ + protected function hasSuccessor(): bool + { + return $this->successor !== null; + } + + /** + * Return media type (MIME) of given input + * + * @param string $input + * @return string + */ + protected function mediaType(string $input): string + { + $pointer = $this->buildFilePointer($input); + $type = mime_content_type($pointer); + fclose($pointer); + + return $type; + } + + /** + * Extract and return EXIF data from given image data string + * + * @param string $image_data + * @return CollectionInterface + */ + protected function extractExifData(string $image_data): CollectionInterface + { + if (!function_exists('exif_read_data')) { + return new Collection(); + } + + try { + $pointer = $this->buildFilePointer($image_data); + $data = @exif_read_data($pointer, null, true); + fclose($pointer); + } catch (Exception $e) { + $data = []; + } + + return new Collection(is_array($data) ? $data : []); + } + + /** + * Determine if given input is base64 encoded data + * + * @param mixed $input + * @return bool + */ + protected function isValidBase64(mixed $input): bool + { + if (!is_string($input)) { + return false; + } + + return base64_encode(base64_decode($input)) === str_replace(["\n", "\r"], '', $input); + } + + /** + * Parse data uri + * + * @param mixed $value + * @return object + */ + protected function parseDataUri($value): object + { + $pattern = "/^data:(?P\w+\/[-+.\w]+)?" . + "(?P(;[-\w]+=[-\w]+)*)(?P;base64)?,(?P.*)/"; + + $result = preg_match($pattern, $value, $matches); + + return new class ($matches, $result) + { + private $matches; + private $result; + + public function __construct($matches, $result) + { + $this->matches = $matches; + $this->result = $result; + } + + public function isValid(): bool + { + return (bool) $this->result; + } + + public function mediaType(): ?string + { + if (isset($this->matches['mediatype']) && !empty($this->matches['mediatype'])) { + return $this->matches['mediatype']; + } + + return null; + } + + public function hasMediaType(): bool + { + return !empty($this->mediaType()); + } + + public function parameters(): array + { + if (isset($this->matches['parameters']) && !empty($this->matches['parameters'])) { + return explode(';', trim($this->matches['parameters'], ';')); + } + + return []; + } + + public function isBase64Encoded(): bool + { + if (isset($this->matches['base64']) && $this->matches['base64'] === ';base64') { + return true; + } + + return false; + } + + public function data(): ?string + { + if (isset($this->matches['data']) && !empty($this->matches['data'])) { + return $this->matches['data']; + } + + return null; + } + }; + } +} diff --git a/src/Drivers/AbstractDrawModifier.php b/src/Drivers/AbstractDrawModifier.php new file mode 100644 index 00000000..d8dbd6bc --- /dev/null +++ b/src/Drivers/AbstractDrawModifier.php @@ -0,0 +1,41 @@ +drawable->position(); + } + + public function backgroundColor(): ColorInterface + { + try { + $color = $this->driver()->handleInput($this->drawable->backgroundColor()); + } catch (DecoderException $e) { + return $this->driver()->handleInput('transparent'); + } + + return $color; + } + + public function borderColor(): ColorInterface + { + try { + $color = $this->driver()->handleInput($this->drawable->borderColor()); + } catch (DecoderException $e) { + return $this->driver()->handleInput('transparent'); + } + + return $color; + } +} diff --git a/src/Drivers/AbstractDriver.php b/src/Drivers/AbstractDriver.php new file mode 100644 index 00000000..d21252a2 --- /dev/null +++ b/src/Drivers/AbstractDriver.php @@ -0,0 +1,62 @@ +isExternal($input)) { + return $input; + } + + $driver_namespace = (new ReflectionClass($this))->getNamespaceName(); + $class_path = substr(get_class($input), strlen("Intervention\\Image\\")); + $specialized = $driver_namespace . "\\" . $class_path; + + if (! class_exists($specialized)) { + throw new NotSupportedException( + "Class '" . $class_path . "' is not supported by " . $this->id() . " driver." + ); + } + + return new $specialized($input, $this); + } + + /** + * Determine if given object is external custom modifier, analyzer or encoder + * + * @param object $input + * @return bool + */ + private function isExternal(object $input): bool + { + if ($input instanceof AbstractModifier) { + return false; + } + + if ($input instanceof AbstractAnalyzer) { + return false; + } + + if ($input instanceof AbstractEncoder) { + return false; + } + + return true; + } +} diff --git a/src/Drivers/AbstractInputHandler.php b/src/Drivers/AbstractInputHandler.php new file mode 100644 index 00000000..5eae3eb6 --- /dev/null +++ b/src/Drivers/AbstractInputHandler.php @@ -0,0 +1,52 @@ +decoders = count($decoders) ? $decoders : $this->decoders; + } + + /** + * {@inheritdoc} + * + * @see InputHandlerInterface::handle() + */ + public function handle($input): ImageInterface|ColorInterface + { + return $this->chain()->handle($input); + } + + /** + * Stack the decoder array into a nested decoder object + * + * @return AbstractDecoder + */ + protected function chain(): AbstractDecoder + { + if (count($this->decoders) == 0) { + throw new DecoderException('No decoders found in ' . get_class($this)); + } + + // get instance of last decoder in stack + list($classname) = array_slice(array_reverse($this->decoders), 0, 1); + $chain = new $classname(); + + // build decoder chain + foreach (array_slice(array_reverse($this->decoders), 1) as $classname) { + $chain = new $classname($chain); + } + + return $chain; + } +} diff --git a/src/Drivers/AbstractTextModifier.php b/src/Drivers/AbstractTextModifier.php new file mode 100644 index 00000000..01c9af0c --- /dev/null +++ b/src/Drivers/AbstractTextModifier.php @@ -0,0 +1,93 @@ +fontSizeInPixels() * $this->font->lineHeight())); + } + + public function capHeight(): int + { + return $this->boxSize('T')->height(); + } + + public function fontSizeInPixels(): int + { + return $this->boxSize('Hy')->height(); + } + + /** + * Build TextBlock object from text string and align every line + * according to text writers font object and position. + * + * @return TextBlock + */ + public function alignedTextBlock(Point $position, string $text): TextBlock + { + $lines = new TextBlock($text); + $boundingBox = $this->boundingBox($lines, $position); + $pivot = $boundingBox->last(); + + $leading = $this->leadingInPixels(); + $blockWidth = $this->lineWidth($lines->longestLine()); + + $x = $pivot->x(); + $y = $this->font->hasFilename() ? $pivot->y() + $this->capHeight() : $pivot->y(); + $x_adjustment = 0; + + foreach ($lines as $line) { + $line_width = $this->lineWidth($line); + $x_adjustment = $this->font->alignment() == 'left' ? 0 : $blockWidth - $line_width; + $x_adjustment = $this->font->alignment() == 'right' ? intval(round($x_adjustment)) : $x_adjustment; + $x_adjustment = $this->font->alignment() == 'center' ? intval(round($x_adjustment / 2)) : $x_adjustment; + $position = new Point($x + $x_adjustment, $y); + $position->rotate($this->font->angle(), $pivot); + $line->setPosition($position); + $y += $leading; + } + + return $lines; + } + + public function boundingBox(TextBlock $block, Point $pivot = null): Polygon + { + $pivot = $pivot ? $pivot : new Point(); + + // bounding box + $box = (new Rectangle( + $this->lineWidth($block->longestLine()), + $this->leadingInPixels() * ($block->count() - 1) + $this->capHeight() + )); + + // set pivot + $box->setPivot($pivot); + + // align + $box->align($this->font->alignment()); + $box->valign($this->font->valignment()); + + $box->rotate($this->font->angle()); + + return $box; + } + + private function lineWidth(Line $line): int + { + return $this->boxSize((string) $line)->width(); + } +} diff --git a/src/Drivers/DriverSpecializedAnalyzer.php b/src/Drivers/DriverSpecializedAnalyzer.php new file mode 100644 index 00000000..9f69f7d1 --- /dev/null +++ b/src/Drivers/DriverSpecializedAnalyzer.php @@ -0,0 +1,31 @@ +driver; + } + + /** + * Magic method to read attributes of underlying analyzer + * + * @param string $name + * @return mixed + */ + public function __get(string $name): mixed + { + return $this->analyzer->$name; + } +} diff --git a/src/Drivers/DriverSpecializedEncoder.php b/src/Drivers/DriverSpecializedEncoder.php new file mode 100644 index 00000000..3bda2cb3 --- /dev/null +++ b/src/Drivers/DriverSpecializedEncoder.php @@ -0,0 +1,47 @@ +driver; + } + + /** + * Magic method to read attributes of underlying endcoder + * + * @param string $name + * @return mixed + */ + public function __get(string $name): mixed + { + return $this->encoder->$name; + } + + /** + * Get return value of callback through output buffer + * + * @param callable $callback + * @return string + */ + protected function getBuffered(callable $callback): string + { + ob_start(); + $callback(); + $buffer = ob_get_contents(); + ob_end_clean(); + + return $buffer; + } +} diff --git a/src/Drivers/DriverSpecializedModifier.php b/src/Drivers/DriverSpecializedModifier.php new file mode 100644 index 00000000..8f71a3b8 --- /dev/null +++ b/src/Drivers/DriverSpecializedModifier.php @@ -0,0 +1,43 @@ +driver; + } + + /** + * Magic method to read attributes of underlying modifier + * + * @param string $name + * @return mixed + */ + public function __get(string $name): mixed + { + return $this->modifier->$name; + } + + /** + * Magic method to call methods of underlying modifier + * + * @param string $name + * @param array $arguments + * @return mixed + */ + public function __call(string $name, array $arguments): mixed + { + return $this->modifier->$name(...$arguments); + } +} diff --git a/src/Drivers/Gd/Analyzers/ColorspaceAnalyzer.php b/src/Drivers/Gd/Analyzers/ColorspaceAnalyzer.php new file mode 100644 index 00000000..c35b40aa --- /dev/null +++ b/src/Drivers/Gd/Analyzers/ColorspaceAnalyzer.php @@ -0,0 +1,15 @@ +core()->native()); + } +} diff --git a/src/Drivers/Gd/Analyzers/PixelColorAnalyzer.php b/src/Drivers/Gd/Analyzers/PixelColorAnalyzer.php new file mode 100644 index 00000000..a6cb2ab3 --- /dev/null +++ b/src/Drivers/Gd/Analyzers/PixelColorAnalyzer.php @@ -0,0 +1,39 @@ +colorAt( + $image->colorspace(), + $image->core()->frame($this->frame_key)->native() + ); + } + + protected function colorAt(ColorspaceInterface $colorspace, GdImage $gd): ColorInterface + { + $index = @imagecolorat($gd, $this->x, $this->y); + + if ($index === false) { + throw new GeometryException( + 'The specified position is not in the valid image area.' + ); + } + + return $this->driver()->colorProcessor($colorspace)->nativeToColor($index); + } +} diff --git a/src/Drivers/Gd/Analyzers/PixelColorsAnalyzer.php b/src/Drivers/Gd/Analyzers/PixelColorsAnalyzer.php new file mode 100644 index 00000000..10e28f92 --- /dev/null +++ b/src/Drivers/Gd/Analyzers/PixelColorsAnalyzer.php @@ -0,0 +1,27 @@ +colorspace(); + + foreach ($image as $frame) { + $colors->push( + parent::colorAt($colorspace, $frame->native()) + ); + } + + return $colors; + } +} diff --git a/src/Drivers/Gd/Analyzers/ResolutionAnalyzer.php b/src/Drivers/Gd/Analyzers/ResolutionAnalyzer.php new file mode 100644 index 00000000..04a07f92 --- /dev/null +++ b/src/Drivers/Gd/Analyzers/ResolutionAnalyzer.php @@ -0,0 +1,15 @@ +core()->native())); + } +} diff --git a/src/Drivers/Gd/Analyzers/WidthAnalyzer.php b/src/Drivers/Gd/Analyzers/WidthAnalyzer.php new file mode 100644 index 00000000..242dec6d --- /dev/null +++ b/src/Drivers/Gd/Analyzers/WidthAnalyzer.php @@ -0,0 +1,14 @@ +core()->native()); + } +} diff --git a/src/Drivers/Gd/ColorProcessor.php b/src/Drivers/Gd/ColorProcessor.php new file mode 100644 index 00000000..caceff21 --- /dev/null +++ b/src/Drivers/Gd/ColorProcessor.php @@ -0,0 +1,78 @@ +convertTo($this->colorspace); + + // gd only supports rgb so the channels can be accessed directly + $r = $color->channel(Red::class)->value(); + $g = $color->channel(Green::class)->value(); + $b = $color->channel(Blue::class)->value(); + $a = $color->channel(Alpha::class)->value(); + + // convert alpha value to gd alpha + // ([opaque]255-0[transparent]) to ([opaque]0-127[transparent]) + $a = (int) $this->convertRange($a, 0, 255, 127, 0); + + return ($a << 24) + ($r << 16) + ($g << 8) + $b; + } + + public function nativeToColor(mixed $value): ColorInterface + { + if (! is_int($value)) { + throw new ColorException("GD driver can only decode colors in integer format."); + } + + $a = ($value >> 24) & 0xFF; + $r = ($value >> 16) & 0xFF; + $g = ($value >> 8) & 0xFF; + $b = $value & 0xFF; + + // convert gd apha integer to intervention alpha integer + // ([opaque]0-127[transparent]) to ([opaque]255-0[transparent]) + $a = (int) static::convertRange($a, 127, 0, 0, 255); + + return new Color($r, $g, $b, $a); + } + + /** + * Convert input in range (min) to (max) to the corresponding value + * in target range (targetMin) to (targetMax). + * + * @param float|int $input + * @param float|int $min + * @param float|int $max + * @param float|int $targetMin + * @param float|int $targetMax + * @return float|int + */ + protected function convertRange( + float|int $input, + float|int $min, + float|int $max, + float|int $targetMin, + float|int $targetMax + ): float|int { + return ceil(((($input - $min) * ($targetMax - $targetMin)) / ($max - $min)) + $targetMin); + } +} diff --git a/src/Drivers/Gd/Core.php b/src/Drivers/Gd/Core.php new file mode 100644 index 00000000..71c024e9 --- /dev/null +++ b/src/Drivers/Gd/Core.php @@ -0,0 +1,58 @@ +push($frame); + + return $this; + } + + public function native(): mixed + { + return $this->first()->native(); + } + + public function setNative(mixed $native): self + { + $this->empty()->push(new Frame($native)); + + return $this; + } + + public function frame(int $position): FrameInterface + { + return $this->getAtPosition($position); + } + + public function loops(): int + { + return $this->loops; + } + + public function setLoops(int $loops): self + { + $this->loops = $loops; + + return $this; + } + + public function first(): FrameInterface + { + return parent::first(); + } + + public function last(): FrameInterface + { + return parent::last(); + } +} diff --git a/src/Drivers/Gd/Decoders/Base64ImageDecoder.php b/src/Drivers/Gd/Decoders/Base64ImageDecoder.php new file mode 100644 index 00000000..2ab1be19 --- /dev/null +++ b/src/Drivers/Gd/Decoders/Base64ImageDecoder.php @@ -0,0 +1,20 @@ +isValidBase64($input)) { + throw new DecoderException('Unable to decode input'); + } + + return parent::decode(base64_decode($input)); + } +} diff --git a/src/Drivers/Gd/Decoders/BinaryImageDecoder.php b/src/Drivers/Gd/Decoders/BinaryImageDecoder.php new file mode 100644 index 00000000..00500b18 --- /dev/null +++ b/src/Drivers/Gd/Decoders/BinaryImageDecoder.php @@ -0,0 +1,96 @@ +mediaType($input) == 'image/gif') { + return $this->decodeGif($input); // decode (animated) gif + } + + // build image instance + $image = new Image( + new Driver(), + $this->coreFromString($input), + $this->extractExifData($input) + ); + + // fix image orientation + return match ($image->exif('IFD0.Orientation')) { + 2 => $image->flip(), + 3 => $image->rotate(180), + 4 => $image->rotate(180)->flip(), + 5 => $image->rotate(270)->flip(), + 6 => $image->rotate(270), + 7 => $image->rotate(90)->flip(), + 8 => $image->rotate(90), + default => $image + }; + } + + private function coreFromString(string $input): Core + { + $data = @imagecreatefromstring($input); + + if ($data === false) { + throw new DecoderException('Unable to decode input'); + } + + if (!imageistruecolor($data)) { + imagepalettetotruecolor($data); + } + + imagesavealpha($data, true); + + return new Core([ + new Frame($data) + ]); + } + + private function decodeGif(string $input): ImageInterface + { + $gif = GifDecoder::decode($input); + + if (!$gif->isAnimated()) { + return new Image( + new Driver(), + $this->coreFromString($input) + ); + } + + $splitter = GifSplitter::create($gif)->split(); + $delays = $splitter->getDelays(); + + // build core + $core = new Core(); + $core->setLoops($gif->getMainApplicationExtension()?->getLoops()); + foreach ($splitter->coalesceToResources() as $key => $data) { + $core->push( + (new Frame($data))->setDelay($delays[$key] / 100) + ); + } + + return new Image( + new Driver(), + $core + ); + } +} diff --git a/src/Drivers/Gd/Decoders/ColorObjectDecoder.php b/src/Drivers/Gd/Decoders/ColorObjectDecoder.php new file mode 100644 index 00000000..5dd821d9 --- /dev/null +++ b/src/Drivers/Gd/Decoders/ColorObjectDecoder.php @@ -0,0 +1,21 @@ +parseDataUri($input); + + if (! $uri->isValid()) { + throw new DecoderException('Unable to decode input'); + } + + if ($uri->isBase64Encoded()) { + return parent::decode(base64_decode($uri->data())); + } + + return parent::decode(urldecode($uri->data())); + } +} diff --git a/src/Drivers/Gd/Decoders/FilePathImageDecoder.php b/src/Drivers/Gd/Decoders/FilePathImageDecoder.php new file mode 100644 index 00000000..a826734b --- /dev/null +++ b/src/Drivers/Gd/Decoders/FilePathImageDecoder.php @@ -0,0 +1,29 @@ +getRealPath()); + } +} diff --git a/src/Drivers/Gd/Driver.php b/src/Drivers/Gd/Driver.php new file mode 100644 index 00000000..7c38b8f3 --- /dev/null +++ b/src/Drivers/Gd/Driver.php @@ -0,0 +1,105 @@ +core->add( + $this->driver->handleInput($source)->core()->first()->setDelay($delay) + ); + + return $this; + } + + public function __invoke(): ImageInterface + { + return new Image( + $this->driver, + $this->core + ); + } + }; + + $init($animation); + + return call_user_func($animation); + } + + /** + * {@inheritdoc} + * + * @see DriverInterface::handleInput() + */ + public function handleInput(mixed $input): ImageInterface|ColorInterface + { + return (new InputHandler())->handle($input); + } + + /** + * {@inheritdoc} + * + * @see DriverInterface::colorProcessor() + */ + public function colorProcessor(ColorspaceInterface $colorspace): ColorProcessorInterface + { + return new ColorProcessor($colorspace); + } +} diff --git a/src/Drivers/Gd/Encoders/AvifEncoder.php b/src/Drivers/Gd/Encoders/AvifEncoder.php new file mode 100644 index 00000000..975fcbca --- /dev/null +++ b/src/Drivers/Gd/Encoders/AvifEncoder.php @@ -0,0 +1,23 @@ +core()->native(); + $data = $this->getBuffered(function () use ($gd) { + imageavif($gd, null, $this->quality); + }); + + return new EncodedImage($data, 'image/avif'); + } +} diff --git a/src/Drivers/Gd/Encoders/BmpEncoder.php b/src/Drivers/Gd/Encoders/BmpEncoder.php new file mode 100644 index 00000000..68fcecfe --- /dev/null +++ b/src/Drivers/Gd/Encoders/BmpEncoder.php @@ -0,0 +1,25 @@ +modify(new LimitColorsModifier($this->color_limit)); + $gd = $image->core()->native(); + $data = $this->getBuffered(function () use ($gd) { + imagebmp($gd, null, false); + }); + + return new EncodedImage($data, 'image/bmp'); + } +} diff --git a/src/Drivers/Gd/Encoders/GifEncoder.php b/src/Drivers/Gd/Encoders/GifEncoder.php new file mode 100644 index 00000000..6337f277 --- /dev/null +++ b/src/Drivers/Gd/Encoders/GifEncoder.php @@ -0,0 +1,48 @@ +isAnimated()) { + return $this->encodeAnimated($image); + } + + $image = $image->modify(new LimitColorsModifier($this->color_limit)); + $gd = $image->core()->native(); + $data = $this->getBuffered(function () use ($gd) { + imagegif($gd); + }); + + return new EncodedImage($data, 'image/gif'); + } + + protected function encodeAnimated(ImageInterface $image): EncodedImage + { + $builder = GifBuilder::canvas( + $image->width(), + $image->height(), + $image->loops() + ); + + foreach ($image as $frame) { + $builder->addFrame( + $this->encode($frame->toImage($image->driver())), + $frame->delay() + ); + } + + return new EncodedImage($builder->encode(), 'image/gif'); + } +} diff --git a/src/Drivers/Gd/Encoders/JpegEncoder.php b/src/Drivers/Gd/Encoders/JpegEncoder.php new file mode 100644 index 00000000..3493f67e --- /dev/null +++ b/src/Drivers/Gd/Encoders/JpegEncoder.php @@ -0,0 +1,23 @@ +core()->native(); + $data = $this->getBuffered(function () use ($gd) { + imagejpeg($gd, null, $this->quality); + }); + + return new EncodedImage($data, 'image/jpeg'); + } +} diff --git a/src/Drivers/Gd/Encoders/PngEncoder.php b/src/Drivers/Gd/Encoders/PngEncoder.php new file mode 100644 index 00000000..6c2f3844 --- /dev/null +++ b/src/Drivers/Gd/Encoders/PngEncoder.php @@ -0,0 +1,25 @@ +modify(new LimitColorsModifier($this->color_limit)); + $gd = $image->core()->native(); + $data = $this->getBuffered(function () use ($gd) { + imagepng($gd, null, -1); + }); + + return new EncodedImage($data, 'image/png'); + } +} diff --git a/src/Drivers/Gd/Encoders/WebpEncoder.php b/src/Drivers/Gd/Encoders/WebpEncoder.php new file mode 100644 index 00000000..d6a1ef76 --- /dev/null +++ b/src/Drivers/Gd/Encoders/WebpEncoder.php @@ -0,0 +1,23 @@ +core()->native(); + $data = $this->getBuffered(function () use ($gd) { + imagewebp($gd, null, $this->quality); + }); + + return new EncodedImage($data, 'image/webp'); + } +} diff --git a/src/Drivers/Gd/Frame.php b/src/Drivers/Gd/Frame.php new file mode 100644 index 00000000..5ac6c460 --- /dev/null +++ b/src/Drivers/Gd/Frame.php @@ -0,0 +1,102 @@ +native = $native; + + return $this; + } + + public function native(): GdImage + { + return $this->native; + } + + public function size(): SizeInterface + { + return new Rectangle(imagesx($this->native), imagesy($this->native)); + } + + public function delay(): float + { + return $this->delay; + } + + public function setDelay(float $delay): FrameInterface + { + $this->delay = $delay; + + return $this; + } + + public function dispose(): int + { + return $this->dispose; + } + + public function setDispose(int $dispose): FrameInterface + { + $this->dispose = $dispose; + + return $this; + } + + public function setOffset(int $left, int $top): FrameInterface + { + $this->offset_left = $left; + $this->offset_top = $top; + + return $this; + } + + public function offsetLeft(): int + { + return $this->offset_left; + } + + public function setOffsetLeft(int $offset): FrameInterface + { + $this->offset_left = $offset; + + return $this; + } + + public function offsetTop(): int + { + return $this->offset_top; + } + + public function setOffsetTop(int $offset): FrameInterface + { + $this->offset_top = $offset; + + return $this; + } +} diff --git a/src/Drivers/Gd/InputHandler.php b/src/Drivers/Gd/InputHandler.php new file mode 100644 index 00000000..50a0e55f --- /dev/null +++ b/src/Drivers/Gd/InputHandler.php @@ -0,0 +1,41 @@ +amount; $i++) { + imagefilter($frame->native(), IMG_FILTER_GAUSSIAN_BLUR); + } + } + + return $image; + } +} diff --git a/src/Drivers/Gd/Modifiers/BrightnessModifier.php b/src/Drivers/Gd/Modifiers/BrightnessModifier.php new file mode 100644 index 00000000..9e6c97e4 --- /dev/null +++ b/src/Drivers/Gd/Modifiers/BrightnessModifier.php @@ -0,0 +1,21 @@ +native(), IMG_FILTER_BRIGHTNESS, intval($this->level * 2.55)); + } + + return $image; + } +} diff --git a/src/Drivers/Gd/Modifiers/ColorizeModifier.php b/src/Drivers/Gd/Modifiers/ColorizeModifier.php new file mode 100644 index 00000000..99424cd1 --- /dev/null +++ b/src/Drivers/Gd/Modifiers/ColorizeModifier.php @@ -0,0 +1,28 @@ +red * 2.55); + $green = round($this->green * 2.55); + $blue = round($this->blue * 2.55); + + foreach ($image as $frame) { + imagefilter($frame->native(), IMG_FILTER_COLORIZE, $red, $green, $blue); + } + + return $image; + } +} diff --git a/src/Drivers/Gd/Modifiers/ColorspaceModifier.php b/src/Drivers/Gd/Modifiers/ColorspaceModifier.php new file mode 100644 index 00000000..12e067c9 --- /dev/null +++ b/src/Drivers/Gd/Modifiers/ColorspaceModifier.php @@ -0,0 +1,25 @@ +targetColorspace(), RgbColorspace::class)) { + throw new NotSupportedException( + 'Only RGB colorspace is supported with GD driver.' + ); + } + + return $image; + } +} diff --git a/src/Drivers/Gd/Modifiers/ContainModifier.php b/src/Drivers/Gd/Modifiers/ContainModifier.php new file mode 100644 index 00000000..5f8ea556 --- /dev/null +++ b/src/Drivers/Gd/Modifiers/ContainModifier.php @@ -0,0 +1,90 @@ +getCropSize($image); + $resize = $this->getResizeSize($image); + $background = $this->driver()->handleInput($this->background); + + foreach ($image as $frame) { + $this->modify($frame, $crop, $resize, $background); + } + + return $image; + } + + protected function modify( + FrameInterface $frame, + SizeInterface $crop, + SizeInterface $resize, + ColorInterface $background + ): void { + // create new gd image + $modified = $this->driver()->createImage( + $resize->width(), + $resize->height() + )->modify( + new FillModifier($background) + )->core()->native(); + + // make image area transparent to keep transparency + // even if background-color is set + $transparent = imagecolorallocatealpha( + $modified, + $background->channel(Red::class)->value(), + $background->channel(Green::class)->value(), + $background->channel(Blue::class)->value(), + 127, + ); + imagealphablending($modified, false); // do not blend / just overwrite + imagecolortransparent($modified, $transparent); + imagefilledrectangle( + $modified, + $crop->pivot()->x(), + $crop->pivot()->y(), + $crop->pivot()->x() + $crop->width() - 1, + $crop->pivot()->y() + $crop->height() - 1, + $transparent + ); + + // copy image from original with blending alpha + imagealphablending($modified, true); + imagecopyresampled( + $modified, + $frame->native(), + $crop->pivot()->x(), + $crop->pivot()->y(), + 0, + 0, + $crop->width(), + $crop->height(), + $frame->size()->width(), + $frame->size()->height() + ); + + // set new content as recource + $frame->setNative($modified); + } +} diff --git a/src/Drivers/Gd/Modifiers/ContrastModifier.php b/src/Drivers/Gd/Modifiers/ContrastModifier.php new file mode 100644 index 00000000..d6cfba69 --- /dev/null +++ b/src/Drivers/Gd/Modifiers/ContrastModifier.php @@ -0,0 +1,21 @@ +native(), IMG_FILTER_CONTRAST, ($this->level * -1)); + } + + return $image; + } +} diff --git a/src/Drivers/Gd/Modifiers/CoverDownModifier.php b/src/Drivers/Gd/Modifiers/CoverDownModifier.php new file mode 100644 index 00000000..cec3b683 --- /dev/null +++ b/src/Drivers/Gd/Modifiers/CoverDownModifier.php @@ -0,0 +1,17 @@ +scaleDown($this->width, $this->height); + } +} diff --git a/src/Drivers/Gd/Modifiers/CoverModifier.php b/src/Drivers/Gd/Modifiers/CoverModifier.php new file mode 100644 index 00000000..0aa33a47 --- /dev/null +++ b/src/Drivers/Gd/Modifiers/CoverModifier.php @@ -0,0 +1,66 @@ +getCropSize($image); + $resize = $this->getResizeSize($crop); + + foreach ($image as $frame) { + $this->modifyFrame($frame, $crop, $resize); + } + + return $image; + } + + protected function modifyFrame(FrameInterface $frame, SizeInterface $crop, SizeInterface $resize): void + { + // create new image + $modified = $this->driver()->createImage( + $resize->width(), + $resize->height() + )->core()->native(); + + // get original image + $original = $frame->native(); + + // preserve transparency + $transIndex = imagecolortransparent($original); + + if ($transIndex != -1) { + $rgba = imagecolorsforindex($modified, $transIndex); + $transColor = imagecolorallocatealpha($modified, $rgba['red'], $rgba['green'], $rgba['blue'], 127); + imagefill($modified, 0, 0, $transColor); + imagecolortransparent($modified, $transColor); + } + + // copy content from resource + imagecopyresampled( + $modified, + $original, + 0, + 0, + $crop->pivot()->x(), + $crop->pivot()->y(), + $resize->width(), + $resize->height(), + $crop->width(), + $crop->height() + ); + + // set new content as resource + $frame->setNative($modified); + } +} diff --git a/src/Drivers/Gd/Modifiers/CropModifier.php b/src/Drivers/Gd/Modifiers/CropModifier.php new file mode 100644 index 00000000..dd3daa05 --- /dev/null +++ b/src/Drivers/Gd/Modifiers/CropModifier.php @@ -0,0 +1,66 @@ +crop($image); + + foreach ($image as $frame) { + $this->cropFrame($frame, $crop); + } + + return $image; + } + + protected function cropFrame(FrameInterface $frame, SizeInterface $resizeTo): void + { + // create new image + $modified = $this->driver() + ->createImage($resizeTo->width(), $resizeTo->height()) + ->core() + ->native(); + + // get original image + $original = $frame->native(); + + // preserve transparency + $transIndex = imagecolortransparent($original); + + if ($transIndex != -1) { + $rgba = imagecolorsforindex($modified, $transIndex); + $transColor = imagecolorallocatealpha($modified, $rgba['red'], $rgba['green'], $rgba['blue'], 127); + imagefill($modified, 0, 0, $transColor); + imagecolortransparent($modified, $transColor); + } + + // copy content from resource + imagecopyresampled( + $modified, + $original, + 0, + 0, + $resizeTo->pivot()->x() + $this->offset_x, + $resizeTo->pivot()->y() + $this->offset_y, + $resizeTo->width(), + $resizeTo->height(), + $resizeTo->width(), + $resizeTo->height(), + ); + + // set new content as recource + $frame->setNative($modified); + } +} diff --git a/src/Drivers/Gd/Modifiers/DrawEllipseModifier.php b/src/Drivers/Gd/Modifiers/DrawEllipseModifier.php new file mode 100644 index 00000000..9f83e0dd --- /dev/null +++ b/src/Drivers/Gd/Modifiers/DrawEllipseModifier.php @@ -0,0 +1,67 @@ +drawable->hasBorder()) { + // slightly smaller ellipse to keep 1px bordered edges clean + if ($this->drawable->hasBackgroundColor()) { + imagefilledellipse( + $frame->native(), + $this->position()->x(), + $this->position()->y(), + $this->drawable->width() - 1, + $this->drawable->height() - 1, + $this->driver()->colorProcessor($image->colorspace())->colorToNative( + $this->backgroundColor() + ) + ); + } + + // gd's imageellipse ignores imagesetthickness + // so i use imagearc with 360 degrees instead. + imagesetthickness( + $frame->native(), + $this->drawable->borderSize(), + ); + + imagearc( + $frame->native(), + $this->position()->x(), + $this->position()->y(), + $this->drawable->width(), + $this->drawable->height(), + 0, + 360, + $this->driver()->colorProcessor($image->colorspace())->colorToNative( + $this->borderColor() + ) + ); + } else { + imagefilledellipse( + $frame->native(), + $this->position()->x(), + $this->position()->y(), + $this->drawable->width(), + $this->drawable->height(), + $this->driver()->colorProcessor($image->colorspace())->colorToNative( + $this->backgroundColor() + ) + ); + } + } + + return $image; + } +} diff --git a/src/Drivers/Gd/Modifiers/DrawLineModifier.php b/src/Drivers/Gd/Modifiers/DrawLineModifier.php new file mode 100644 index 00000000..abbfc66f --- /dev/null +++ b/src/Drivers/Gd/Modifiers/DrawLineModifier.php @@ -0,0 +1,33 @@ +native(), + $this->drawable->start()->x(), + $this->drawable->start()->y(), + $this->drawable->end()->x(), + $this->drawable->end()->y(), + $this->driver()->colorProcessor($image->colorspace())->colorToNative( + $this->backgroundColor() + ) + ); + } + + return $image; + } +} diff --git a/src/Drivers/Gd/Modifiers/DrawPixelModifier.php b/src/Drivers/Gd/Modifiers/DrawPixelModifier.php new file mode 100644 index 00000000..5dbfec78 --- /dev/null +++ b/src/Drivers/Gd/Modifiers/DrawPixelModifier.php @@ -0,0 +1,32 @@ +driver()->colorProcessor($image->colorspace())->colorToNative( + $this->driver()->handleInput($this->color) + ); + + foreach ($image as $frame) { + imagesetpixel( + $frame->native(), + $this->position->x(), + $this->position->y(), + $color + ); + } + + return $image; + } +} diff --git a/src/Drivers/Gd/Modifiers/DrawPolygonModifier.php b/src/Drivers/Gd/Modifiers/DrawPolygonModifier.php new file mode 100644 index 00000000..3e9d0691 --- /dev/null +++ b/src/Drivers/Gd/Modifiers/DrawPolygonModifier.php @@ -0,0 +1,45 @@ +drawable->hasBackgroundColor()) { + imagefilledpolygon( + $frame->native(), + $this->drawable->toArray(), + $this->driver()->colorProcessor($image->colorspace())->colorToNative( + $this->backgroundColor() + ) + ); + } + + if ($this->drawable->hasBorder()) { + imagesetthickness($frame->native(), $this->drawable->borderSize()); + imagepolygon( + $frame->native(), + $this->drawable->toArray(), + $this->driver()->colorProcessor($image->colorspace())->colorToNative( + $this->borderColor() + ) + ); + } + } + + return $image; + } +} diff --git a/src/Drivers/Gd/Modifiers/DrawRectangleModifier.php b/src/Drivers/Gd/Modifiers/DrawRectangleModifier.php new file mode 100644 index 00000000..393b9e8f --- /dev/null +++ b/src/Drivers/Gd/Modifiers/DrawRectangleModifier.php @@ -0,0 +1,54 @@ +drawable->hasBackgroundColor()) { + imagefilledrectangle( + $frame->native(), + $this->position()->x(), + $this->position()->y(), + $this->position()->x() + $this->drawable->width(), + $this->position()->y() + $this->drawable->height(), + $this->driver()->colorProcessor($image->colorspace())->colorToNative( + $this->backgroundColor() + ) + ); + } + + // draw border + if ($this->drawable->hasBorder()) { + imagesetthickness($frame->native(), $this->drawable->borderSize()); + imagerectangle( + $frame->native(), + $this->position()->x(), + $this->position()->y(), + $this->position()->x() + $this->drawable->width(), + $this->position()->y() + $this->drawable->height(), + $this->driver()->colorProcessor($image->colorspace())->colorToNative( + $this->borderColor() + ) + ); + } + } + + return $image; + } +} diff --git a/src/Drivers/Gd/Modifiers/FillModifier.php b/src/Drivers/Gd/Modifiers/FillModifier.php new file mode 100644 index 00000000..4d2f14bd --- /dev/null +++ b/src/Drivers/Gd/Modifiers/FillModifier.php @@ -0,0 +1,61 @@ +color($image); + + foreach ($image as $frame) { + if ($this->hasPosition()) { + $this->floodFillWithColor($frame, $color); + } else { + $this->fillAllWithColor($frame, $color); + } + } + + return $image; + } + + private function color(ImageInterface $image): int + { + return $this->driver()->colorProcessor($image->colorspace())->colorToNative( + $this->driver()->handleInput($this->color) + ); + } + + private function floodFillWithColor(Frame $frame, int $color): void + { + imagefill( + $frame->native(), + $this->position->x(), + $this->position->y(), + $color + ); + } + + private function fillAllWithColor(Frame $frame, int $color): void + { + imagealphablending($frame->native(), true); + imagefilledrectangle( + $frame->native(), + 0, + 0, + $frame->size()->width() - 1, + $frame->size()->height() - 1, + $color + ); + } +} diff --git a/src/Drivers/Gd/Modifiers/FlipModifier.php b/src/Drivers/Gd/Modifiers/FlipModifier.php new file mode 100644 index 00000000..f24556ad --- /dev/null +++ b/src/Drivers/Gd/Modifiers/FlipModifier.php @@ -0,0 +1,18 @@ +native(), IMG_FLIP_VERTICAL); + } + + return $image; + } +} diff --git a/src/Drivers/Gd/Modifiers/FlopModifier.php b/src/Drivers/Gd/Modifiers/FlopModifier.php new file mode 100644 index 00000000..db756a27 --- /dev/null +++ b/src/Drivers/Gd/Modifiers/FlopModifier.php @@ -0,0 +1,18 @@ +native(), IMG_FLIP_HORIZONTAL); + } + + return $image; + } +} diff --git a/src/Drivers/Gd/Modifiers/GammaModifier.php b/src/Drivers/Gd/Modifiers/GammaModifier.php new file mode 100644 index 00000000..bab4f7f1 --- /dev/null +++ b/src/Drivers/Gd/Modifiers/GammaModifier.php @@ -0,0 +1,21 @@ +native(), 1, $this->gamma); + } + + return $image; + } +} diff --git a/src/Drivers/Gd/Modifiers/GreyscaleModifier.php b/src/Drivers/Gd/Modifiers/GreyscaleModifier.php new file mode 100644 index 00000000..be625492 --- /dev/null +++ b/src/Drivers/Gd/Modifiers/GreyscaleModifier.php @@ -0,0 +1,18 @@ +native(), IMG_FILTER_GRAYSCALE); + } + + return $image; + } +} diff --git a/src/Drivers/Gd/Modifiers/InvertModifier.php b/src/Drivers/Gd/Modifiers/InvertModifier.php new file mode 100644 index 00000000..6e3b926d --- /dev/null +++ b/src/Drivers/Gd/Modifiers/InvertModifier.php @@ -0,0 +1,18 @@ +native(), IMG_FILTER_NEGATE); + } + + return $image; + } +} diff --git a/src/Drivers/Gd/Modifiers/LimitColorsModifier.php b/src/Drivers/Gd/Modifiers/LimitColorsModifier.php new file mode 100644 index 00000000..2b0cdc02 --- /dev/null +++ b/src/Drivers/Gd/Modifiers/LimitColorsModifier.php @@ -0,0 +1,59 @@ +limit === 0) { + return $image; + } + + // limit is over threshold: no reduction + if ($this->limit > $this->threshold) { + return $image; + } + + $width = $image->width(); + $height = $image->height(); + + foreach ($image as $frame) { + // create empty gd + $reduced = imagecreatetruecolor($width, $height); + + // create matte + $matte = imagecolorallocatealpha($reduced, 255, 255, 255, 127); + + // fill with matte + imagefill($reduced, 0, 0, $matte); + + imagealphablending($reduced, false); + + // set transparency and get transparency index + imagecolortransparent($reduced, $matte); + + // copy original image + imagecopy($reduced, $frame->native(), 0, 0, 0, 0, $width, $height); + + // reduce limit by one to include possible transparency in palette + $limit = imagecolortransparent($frame->native()) === -1 ? $this->limit : $this->limit - 1; + + // decrease colors + imagetruecolortopalette($reduced, true, $limit); + + $frame->setNative($reduced); + } + + + return $image; + } +} diff --git a/src/Drivers/Gd/Modifiers/PadModifier.php b/src/Drivers/Gd/Modifiers/PadModifier.php new file mode 100644 index 00000000..7559d948 --- /dev/null +++ b/src/Drivers/Gd/Modifiers/PadModifier.php @@ -0,0 +1,7 @@ +native(), IMG_FILTER_PIXELATE, $this->size, true); + } + + return $image; + } +} diff --git a/src/Drivers/Gd/Modifiers/PlaceModifier.php b/src/Drivers/Gd/Modifiers/PlaceModifier.php new file mode 100644 index 00000000..e37399a2 --- /dev/null +++ b/src/Drivers/Gd/Modifiers/PlaceModifier.php @@ -0,0 +1,38 @@ +driver()->handleInput($this->element); + $position = $this->getPosition($image, $watermark); + + foreach ($image as $frame) { + imagealphablending($frame->native(), true); + imagecopy( + $frame->native(), + $watermark->core()->native(), + $position->x(), + $position->y(), + 0, + 0, + $watermark->width(), + $watermark->height() + ); + } + + return $image; + } +} diff --git a/src/Drivers/Gd/Modifiers/ProfileModifier.php b/src/Drivers/Gd/Modifiers/ProfileModifier.php new file mode 100644 index 00000000..a97190b7 --- /dev/null +++ b/src/Drivers/Gd/Modifiers/ProfileModifier.php @@ -0,0 +1,21 @@ +core()->setNative( + $this->chosenFrame($image, $this->position)->native() + ); + + return $image; + } +} diff --git a/src/Drivers/Gd/Modifiers/ResizeCanvasModifier.php b/src/Drivers/Gd/Modifiers/ResizeCanvasModifier.php new file mode 100644 index 00000000..42a5a0cb --- /dev/null +++ b/src/Drivers/Gd/Modifiers/ResizeCanvasModifier.php @@ -0,0 +1,85 @@ +cropSize($image); + $background = $this->driver()->handleInput($this->background); + + foreach ($image as $frame) { + $this->modify($frame, $resize, $background); + } + + return $image; + } + + protected function modify( + FrameInterface $frame, + SizeInterface $resize, + ColorInterface $background, + ): void { + // create new gd image + $modified = $this->driver()->createImage( + $resize->width(), + $resize->height() + )->modify( + new FillModifier($background) + )->core()->native(); + + // make image area transparent to keep transparency + // even if background-color is set + $transparent = imagecolorallocatealpha( + $modified, + $background->channel(Red::class)->value(), + $background->channel(Green::class)->value(), + $background->channel(Blue::class)->value(), + 127, + ); + + imagealphablending($modified, false); // do not blend / just overwrite + imagecolortransparent($modified, $transparent); + imagefilledrectangle( + $modified, + $resize->pivot()->x() * -1, + $resize->pivot()->y() * -1, + $resize->pivot()->x() * -1 + $frame->size()->width() - 1, + $resize->pivot()->y() * -1 + $frame->size()->height() - 1, + $transparent + ); + + // copy image from original with blending alpha + imagealphablending($modified, true); + imagecopyresampled( + $modified, + $frame->native(), + $resize->pivot()->x() * -1, + $resize->pivot()->y() * -1, + 0, + 0, + $frame->size()->width(), + $frame->size()->height(), + $frame->size()->width(), + $frame->size()->height() + ); + + // set new content as recource + $frame->setNative($modified); + } +} diff --git a/src/Drivers/Gd/Modifiers/ResizeCanvasRelativeModifier.php b/src/Drivers/Gd/Modifiers/ResizeCanvasRelativeModifier.php new file mode 100644 index 00000000..4269d566 --- /dev/null +++ b/src/Drivers/Gd/Modifiers/ResizeCanvasRelativeModifier.php @@ -0,0 +1,14 @@ +size()->resizeDown($this->width, $this->height); + } +} diff --git a/src/Drivers/Gd/Modifiers/ResizeModifier.php b/src/Drivers/Gd/Modifiers/ResizeModifier.php new file mode 100644 index 00000000..c13e4d25 --- /dev/null +++ b/src/Drivers/Gd/Modifiers/ResizeModifier.php @@ -0,0 +1,72 @@ +getAdjustedSize($image); + foreach ($image as $frame) { + $this->resizeFrame($frame, $resizeTo); + } + + return $image; + } + + private function resizeFrame(FrameInterface $frame, SizeInterface $resizeTo): void + { + // create new image + $modified = imagecreatetruecolor( + $resizeTo->width(), + $resizeTo->height() + ); + + // get current GDImage + $current = $frame->native(); + + // preserve transparency + $transIndex = imagecolortransparent($current); + + if ($transIndex != -1) { + $rgba = imagecolorsforindex($modified, $transIndex); + $transColor = imagecolorallocatealpha($modified, $rgba['red'], $rgba['green'], $rgba['blue'], 127); + imagefill($modified, 0, 0, $transColor); + imagecolortransparent($modified, $transColor); + } else { + imagealphablending($modified, false); + imagesavealpha($modified, true); + } + + // copy content from resource + imagecopyresampled( + $modified, + $current, + $resizeTo->pivot()->x(), + $resizeTo->pivot()->y(), + 0, + 0, + $resizeTo->width(), + $resizeTo->height(), + $frame->size()->width(), + $frame->size()->height() + ); + + // set new content as recource + $frame->setNative($modified); + } + + protected function getAdjustedSize(ImageInterface $image): SizeInterface + { + return $image->size()->resize($this->width, $this->height); + } +} diff --git a/src/Drivers/Gd/Modifiers/ResolutionModifier.php b/src/Drivers/Gd/Modifiers/ResolutionModifier.php new file mode 100644 index 00000000..3544a9ff --- /dev/null +++ b/src/Drivers/Gd/Modifiers/ResolutionModifier.php @@ -0,0 +1,25 @@ +x)); + $y = intval(round($this->y)); + + foreach ($image as $frame) { + imageresolution($frame->native(), $x, $y); + } + + return $image; + } +} diff --git a/src/Drivers/Gd/Modifiers/RotateModifier.php b/src/Drivers/Gd/Modifiers/RotateModifier.php new file mode 100644 index 00000000..3d953267 --- /dev/null +++ b/src/Drivers/Gd/Modifiers/RotateModifier.php @@ -0,0 +1,108 @@ +driver()->handleInput($this->background); + + foreach ($image as $frame) { + $this->modifyFrame($frame, $background); + } + + return $image; + } + + /** + * Apply rotation modification on given frame, given background + * color is used for newly create image areas + * + * @param FrameInterface $frame + * @param ColorInterface $background + * @return void + */ + protected function modifyFrame(FrameInterface $frame, ColorInterface $background): void + { + // get transparent color from frame core + $transparent = match ($transparent = imagecolortransparent($frame->native())) { + -1 => imagecolorallocatealpha( + $frame->native(), + $background->channel(Red::class)->value(), + $background->channel(Green::class)->value(), + $background->channel(Blue::class)->value(), + 127 + ), + default => $transparent, + }; + + // rotate original image against transparent background + $rotated = imagerotate( + $frame->native(), + $this->rotationAngle(), + $transparent + ); + + // create size from original after rotation + $container = (new Rectangle( + imagesx($rotated), + imagesy($rotated), + ))->movePivot('center'); + + // create size from original and rotate points + $cutout = (new Rectangle( + imagesx($frame->native()), + imagesy($frame->native()), + $container->pivot() + ))->align('center') + ->valign('center') + ->rotate($this->rotationAngle() * -1); + + // create new gd image + $modified = $this->driver()->createImage( + imagesx($rotated), + imagesy($rotated) + )->modify(new FillModifier($background)) + ->core() + ->native(); + + // draw the cutout on new gd image to have a transparent + // background where the rotated image will be placed + imagealphablending($modified, false); + imagefilledpolygon( + $modified, + $cutout->toArray(), + imagecolortransparent($modified) + ); + + // place rotated image on new gd image + imagealphablending($modified, true); + imagecopy( + $modified, + $rotated, + 0, + 0, + 0, + 0, + imagesx($rotated), + imagesy($rotated) + ); + + $frame->setNative($modified); + } +} diff --git a/src/Drivers/Gd/Modifiers/ScaleDownModifier.php b/src/Drivers/Gd/Modifiers/ScaleDownModifier.php new file mode 100644 index 00000000..53f19929 --- /dev/null +++ b/src/Drivers/Gd/Modifiers/ScaleDownModifier.php @@ -0,0 +1,18 @@ +size()->scaleDown($this->width, $this->height); + } +} diff --git a/src/Drivers/Gd/Modifiers/ScaleModifier.php b/src/Drivers/Gd/Modifiers/ScaleModifier.php new file mode 100644 index 00000000..ef00d6a6 --- /dev/null +++ b/src/Drivers/Gd/Modifiers/ScaleModifier.php @@ -0,0 +1,18 @@ +size()->scale($this->width, $this->height); + } +} diff --git a/src/Drivers/Gd/Modifiers/SharpenModifier.php b/src/Drivers/Gd/Modifiers/SharpenModifier.php new file mode 100644 index 00000000..05d6c955 --- /dev/null +++ b/src/Drivers/Gd/Modifiers/SharpenModifier.php @@ -0,0 +1,35 @@ +matrix(); + foreach ($image as $frame) { + imageconvolution($frame->native(), $matrix, 1, 0); + } + + return $image; + } + + private function matrix(): array + { + $min = $this->amount >= 10 ? $this->amount * -0.01 : 0; + $max = $this->amount * -0.025; + $abs = ((4 * $min + 4 * $max) * -1) + 1; + + return [ + [$min, $max, $min], + [$max, $abs, $max], + [$min, $max, $min] + ]; + } +} diff --git a/src/Drivers/Gd/Modifiers/TextModifier.php b/src/Drivers/Gd/Modifiers/TextModifier.php new file mode 100644 index 00000000..54059be5 --- /dev/null +++ b/src/Drivers/Gd/Modifiers/TextModifier.php @@ -0,0 +1,133 @@ +alignedTextBlock($this->position, $this->text); + + $color = $this->driver()->colorProcessor($image->colorspace())->colorToNative( + $this->driver()->handleInput($this->font->color()) + ); + + foreach ($image as $frame) { + if ($this->font->hasFilename()) { + foreach ($lines as $line) { + imagettftext( + $frame->native(), + $this->adjustedFontSize(), + $this->font->angle() * -1, + $line->position()->x(), + $line->position()->y(), + $color, + $this->font->filename(), + $line + ); + } + } else { + foreach ($lines as $line) { + imagestring( + $frame->native(), + $this->getGdFont(), + $line->position()->x(), + $line->position()->y(), + $line, + $color + ); + } + } + } + + return $image; + } + + /** + * Calculate size of bounding box of given text + * + * @return Polygon + */ + protected function boxSize(string $text): Polygon + { + if (!$this->font->hasFilename()) { + // calculate box size from gd font + $box = new Rectangle(0, 0); + $chars = mb_strlen($text); + if ($chars > 0) { + $box->setWidth($chars * $this->getGdFontWidth()); + $box->setHeight($this->getGdFontHeight()); + } + return $box; + } + + // calculate box size from font file with angle 0 + $box = imageftbbox( + $this->adjustedFontSize(), + 0, + $this->font->filename(), + $text + ); + + // build polygon from points + $polygon = new Polygon(); + $polygon->addPoint(new Point($box[6], $box[7])); + $polygon->addPoint(new Point($box[4], $box[5])); + $polygon->addPoint(new Point($box[2], $box[3])); + $polygon->addPoint(new Point($box[0], $box[1])); + + return $polygon; + } + + private function adjustedFontSize(): float + { + return floatval(ceil($this->font->size() * .75)); + } + + private function getGdFont(): int + { + if (is_numeric($this->font->filename())) { + return intval($this->font->filename()); + } + + return 1; + } + + private function getGdFontWidth(): int + { + return $this->getGdFont() + 4; + } + + private function getGdFontHeight(): int + { + switch ($this->getGdFont()) { + case 2: + return 14; + + case 3: + return 14; + + case 4: + return 16; + + case 5: + return 16; + + default: + case 1: + return 8; + } + } +} diff --git a/src/Drivers/Imagick/Analyzers/ColorspaceAnalyzer.php b/src/Drivers/Imagick/Analyzers/ColorspaceAnalyzer.php new file mode 100644 index 00000000..d9bff5db --- /dev/null +++ b/src/Drivers/Imagick/Analyzers/ColorspaceAnalyzer.php @@ -0,0 +1,20 @@ +core()->native()->getImageColorspace()) { + Imagick::COLORSPACE_CMYK => new CmykColorspace(), + default => new RgbColorspace(), + }; + } +} diff --git a/src/Drivers/Imagick/Analyzers/HeightAnalyzer.php b/src/Drivers/Imagick/Analyzers/HeightAnalyzer.php new file mode 100644 index 00000000..93a90594 --- /dev/null +++ b/src/Drivers/Imagick/Analyzers/HeightAnalyzer.php @@ -0,0 +1,14 @@ +core()->native()->getImageHeight(); + } +} diff --git a/src/Drivers/Imagick/Analyzers/PixelColorAnalyzer.php b/src/Drivers/Imagick/Analyzers/PixelColorAnalyzer.php new file mode 100644 index 00000000..f4005ecd --- /dev/null +++ b/src/Drivers/Imagick/Analyzers/PixelColorAnalyzer.php @@ -0,0 +1,34 @@ +colorAt( + $image->colorspace(), + $image->core()->frame($this->frame_key)->native() + ); + } + + protected function colorAt(ColorspaceInterface $colorspace, Imagick $imagick): ColorInterface + { + return $this->driver() + ->colorProcessor($colorspace) + ->nativeToColor( + $imagick->getImagePixelColor($this->x, $this->y) + ); + } +} diff --git a/src/Drivers/Imagick/Analyzers/PixelColorsAnalyzer.php b/src/Drivers/Imagick/Analyzers/PixelColorsAnalyzer.php new file mode 100644 index 00000000..65b71a5f --- /dev/null +++ b/src/Drivers/Imagick/Analyzers/PixelColorsAnalyzer.php @@ -0,0 +1,27 @@ +colorspace(); + + foreach ($image as $frame) { + $colors->push( + parent::colorAt($colorspace, $frame->native()) + ); + } + + return $colors; + } +} diff --git a/src/Drivers/Imagick/Analyzers/ProfileAnalyzer.php b/src/Drivers/Imagick/Analyzers/ProfileAnalyzer.php new file mode 100644 index 00000000..d763147e --- /dev/null +++ b/src/Drivers/Imagick/Analyzers/ProfileAnalyzer.php @@ -0,0 +1,22 @@ +core()->native()->getImageProfiles('icc'); + + if (!array_key_exists('icc', $profiles)) { + throw new ColorException('No ICC profile found in image.'); + } + + return new Profile($profiles['icc']); + } +} diff --git a/src/Drivers/Imagick/Analyzers/ResolutionAnalyzer.php b/src/Drivers/Imagick/Analyzers/ResolutionAnalyzer.php new file mode 100644 index 00000000..8335315c --- /dev/null +++ b/src/Drivers/Imagick/Analyzers/ResolutionAnalyzer.php @@ -0,0 +1,15 @@ +core()->native()->getImageResolution()); + } +} diff --git a/src/Drivers/Imagick/Analyzers/WidthAnalyzer.php b/src/Drivers/Imagick/Analyzers/WidthAnalyzer.php new file mode 100644 index 00000000..16246298 --- /dev/null +++ b/src/Drivers/Imagick/Analyzers/WidthAnalyzer.php @@ -0,0 +1,14 @@ +core()->native()->getImageWidth(); + } +} diff --git a/src/Drivers/Imagick/ColorProcessor.php b/src/Drivers/Imagick/ColorProcessor.php new file mode 100644 index 00000000..fba6f38e --- /dev/null +++ b/src/Drivers/Imagick/ColorProcessor.php @@ -0,0 +1,42 @@ +convertTo($this->colorspace) + ); + } + + public function nativeToColor(mixed $native): ColorInterface + { + return match (get_class($this->colorspace)) { + CmykColorspace::class => $this->colorspace->colorFromNormalized([ + $native->getColorValue(Imagick::COLOR_CYAN), + $native->getColorValue(Imagick::COLOR_MAGENTA), + $native->getColorValue(Imagick::COLOR_YELLOW), + $native->getColorValue(Imagick::COLOR_BLACK), + ]), + default => $this->colorspace->colorFromNormalized([ + $native->getColorValue(Imagick::COLOR_RED), + $native->getColorValue(Imagick::COLOR_GREEN), + $native->getColorValue(Imagick::COLOR_BLUE), + $native->getColorValue(Imagick::COLOR_ALPHA), + ]), + }; + } +} diff --git a/src/Drivers/Imagick/Core.php b/src/Drivers/Imagick/Core.php new file mode 100644 index 00000000..6fde6d7b --- /dev/null +++ b/src/Drivers/Imagick/Core.php @@ -0,0 +1,123 @@ +native(); + + $imagick->setImageDelay($frame->delay()); + $imagick->setImageDispose($frame->dispose()); + + $size = $frame->size(); + $imagick->setImagePage( + $size->width(), + $size->height(), + $frame->offsetLeft(), + $frame->offsetTop() + ); + + $this->imagick->addImage($imagick); + + return $this; + } + + public function count(): int + { + return $this->imagick->getNumberImages(); + } + + public function current(): mixed + { + $this->imagick->setIteratorIndex($this->iteratorIndex); + + return new Frame($this->imagick->current()); + } + + public function next(): void + { + $this->iteratorIndex = $this->iteratorIndex + 1; + } + + public function key(): mixed + { + return $this->iteratorIndex; + } + + public function valid(): bool + { + try { + $result = $this->imagick->setIteratorIndex($this->iteratorIndex); + } catch (ImagickException $e) { + return false; + } + + return $result; + } + + public function rewind(): void + { + $this->iteratorIndex = 0; + } + + public function native(): mixed + { + return $this->imagick; + } + + public function setNative(mixed $native): CoreInterface + { + $this->imagick = $native; + + return $this; + } + + public function frame(int $position): FrameInterface + { + foreach ($this->imagick as $core) { + if ($core->getIteratorIndex() == $position) { + return new Frame($core); + } + } + + throw new AnimationException('Frame #' . $position . ' is not be found in the image.'); + } + + public function loops(): int + { + return $this->imagick->getImageIterations(); + } + + public function setLoops(int $loops): CoreInterface + { + $this->imagick = $this->imagick->coalesceImages(); + $this->imagick->setImageIterations($loops); + + return $this; + } + + public function first(): FrameInterface + { + return $this->frame(0); + } + + public function last(): FrameInterface + { + return $this->frame($this->count()); + } +} diff --git a/src/Drivers/Imagick/Decoders/Base64ImageDecoder.php b/src/Drivers/Imagick/Decoders/Base64ImageDecoder.php new file mode 100644 index 00000000..2fc347c6 --- /dev/null +++ b/src/Drivers/Imagick/Decoders/Base64ImageDecoder.php @@ -0,0 +1,20 @@ +isValidBase64($input)) { + throw new DecoderException('Unable to decode input'); + } + + return parent::decode(base64_decode($input)); + } +} diff --git a/src/Drivers/Imagick/Decoders/BinaryImageDecoder.php b/src/Drivers/Imagick/Decoders/BinaryImageDecoder.php new file mode 100644 index 00000000..1887ccd1 --- /dev/null +++ b/src/Drivers/Imagick/Decoders/BinaryImageDecoder.php @@ -0,0 +1,59 @@ +readImageBlob($input); + } catch (ImagickException $e) { + throw new DecoderException('Unable to decode input'); + } + + $imagick = $imagick->coalesceImages(); + + // fix image orientation + switch ($imagick->getImageOrientation()) { + case Imagick::ORIENTATION_BOTTOMRIGHT: + $imagick->rotateimage("#000", 180); + break; + + case Imagick::ORIENTATION_RIGHTTOP: + $imagick->rotateimage("#000", 90); + break; + + case Imagick::ORIENTATION_LEFTBOTTOM: + $imagick->rotateimage("#000", -90); + break; + } + + // set new orientation in image + $imagick->setImageOrientation(Imagick::ORIENTATION_TOPLEFT); + + $image = new Image( + new Driver(), + new Core($imagick), + $this->extractExifData($input) + ); + + return $image; + } +} diff --git a/src/Drivers/Imagick/Decoders/ColorObjectDecoder.php b/src/Drivers/Imagick/Decoders/ColorObjectDecoder.php new file mode 100644 index 00000000..099c7766 --- /dev/null +++ b/src/Drivers/Imagick/Decoders/ColorObjectDecoder.php @@ -0,0 +1,21 @@ +parseDataUri($input); + + if (! $uri->isValid()) { + throw new DecoderException('Unable to decode input'); + } + + if ($uri->isBase64Encoded()) { + return parent::decode(base64_decode($uri->data())); + } + + return parent::decode(urldecode($uri->data())); + } +} diff --git a/src/Drivers/Imagick/Decoders/FilePathImageDecoder.php b/src/Drivers/Imagick/Decoders/FilePathImageDecoder.php new file mode 100644 index 00000000..f1d7346e --- /dev/null +++ b/src/Drivers/Imagick/Decoders/FilePathImageDecoder.php @@ -0,0 +1,29 @@ +getRealPath()); + } +} diff --git a/src/Drivers/Imagick/Driver.php b/src/Drivers/Imagick/Driver.php new file mode 100644 index 00000000..823007ab --- /dev/null +++ b/src/Drivers/Imagick/Driver.php @@ -0,0 +1,107 @@ +newImage($width, $height, $background, 'png'); + $imagick->setType(Imagick::IMGTYPE_UNDEFINED); + $imagick->setImageType(Imagick::IMGTYPE_UNDEFINED); + $imagick->setColorspace(Imagick::COLORSPACE_SRGB); + $imagick->setImageResolution(96, 96); + + return new Image($this, new Core($imagick)); + } + + /** + * {@inheritdoc} + * + * @see DriverInterface::createAnimation() + */ + public function createAnimation(callable $init): ImageInterface + { + $imagick = new Imagick(); + $imagick->setFormat('gif'); + + $animation = new class ($this, $imagick) + { + public function __construct( + protected DriverInterface $driver, + public Imagick $imagick + ) { + } + + public function add($source, float $delay = 1): self + { + $native = $this->driver->handleInput($source)->core()->native(); + $native->setImageDelay($delay * 100); + + $this->imagick->addImage($native); + + return $this; + } + + public function __invoke(): ImageInterface + { + return new Image( + $this->driver, + new Core($this->imagick) + ); + } + }; + + $init($animation); + + return call_user_func($animation); + } + + /** + * {@inheritdoc} + * + * @see DriverInterface::handleInput() + */ + public function handleInput(mixed $input): ImageInterface|ColorInterface + { + return (new InputHandler())->handle($input); + } + + /** + * {@inheritdoc} + * + * @see DriverInterface::colorProcessor() + */ + public function colorProcessor(ColorspaceInterface $colorspace): ColorProcessorInterface + { + return new ColorProcessor($colorspace); + } +} diff --git a/src/Drivers/Imagick/Encoders/AvifEncoder.php b/src/Drivers/Imagick/Encoders/AvifEncoder.php new file mode 100644 index 00000000..e3e574fd --- /dev/null +++ b/src/Drivers/Imagick/Encoders/AvifEncoder.php @@ -0,0 +1,30 @@ +core()->native(); + $imagick->setFormat($format); + $imagick->setImageFormat($format); + $imagick->setCompression($compression); + $imagick->setImageCompression($compression); + $imagick->setCompressionQuality($this->quality); + $imagick->setImageCompressionQuality($this->quality); + + return new EncodedImage($imagick->getImagesBlob(), 'image/avif'); + } +} diff --git a/src/Drivers/Imagick/Encoders/BmpEncoder.php b/src/Drivers/Imagick/Encoders/BmpEncoder.php new file mode 100644 index 00000000..3096cae4 --- /dev/null +++ b/src/Drivers/Imagick/Encoders/BmpEncoder.php @@ -0,0 +1,30 @@ +modify(new LimitColorsModifier($this->color_limit)); + $imagick = $image->core()->native(); + $imagick->setFormat($format); + $imagick->setImageFormat($format); + $imagick->setCompression($compression); + $imagick->setImageCompression($compression); + + return new EncodedImage($imagick->getImagesBlob(), 'image/bmp'); + } +} diff --git a/src/Drivers/Imagick/Encoders/GifEncoder.php b/src/Drivers/Imagick/Encoders/GifEncoder.php new file mode 100644 index 00000000..09f23404 --- /dev/null +++ b/src/Drivers/Imagick/Encoders/GifEncoder.php @@ -0,0 +1,33 @@ +modify(new LimitColorsModifier($this->color_limit)); + + + $format = 'gif'; + $compression = Imagick::COMPRESSION_LZW; + + $imagick = $image->core()->native(); + + $imagick->setFormat($format); + $imagick->setImageFormat($format); + $imagick->setCompression($compression); + $imagick->setImageCompression($compression); + + return new EncodedImage($imagick->getImagesBlob(), 'image/gif'); + } +} diff --git a/src/Drivers/Imagick/Encoders/JpegEncoder.php b/src/Drivers/Imagick/Encoders/JpegEncoder.php new file mode 100644 index 00000000..cf9719bb --- /dev/null +++ b/src/Drivers/Imagick/Encoders/JpegEncoder.php @@ -0,0 +1,32 @@ +core()->native(); + $imagick->setImageBackgroundColor('white'); + $imagick->setBackgroundColor('white'); + $imagick->setFormat($format); + $imagick->setImageFormat($format); + $imagick->setCompression($compression); + $imagick->setImageCompression($compression); + $imagick->setCompressionQuality($this->quality); + $imagick->setImageCompressionQuality($this->quality); + + return new EncodedImage($imagick->getImagesBlob(), 'image/jpeg'); + } +} diff --git a/src/Drivers/Imagick/Encoders/PngEncoder.php b/src/Drivers/Imagick/Encoders/PngEncoder.php new file mode 100644 index 00000000..9a0da771 --- /dev/null +++ b/src/Drivers/Imagick/Encoders/PngEncoder.php @@ -0,0 +1,30 @@ +modify(new LimitColorsModifier($this->color_limit)); + $imagick = $image->core()->native(); + $imagick->setFormat($format); + $imagick->setImageFormat($format); + $imagick->setCompression($compression); + $imagick->setImageCompression($compression); + + return new EncodedImage($imagick->getImagesBlob(), 'image/png'); + } +} diff --git a/src/Drivers/Imagick/Encoders/WebpEncoder.php b/src/Drivers/Imagick/Encoders/WebpEncoder.php new file mode 100644 index 00000000..12d81de2 --- /dev/null +++ b/src/Drivers/Imagick/Encoders/WebpEncoder.php @@ -0,0 +1,33 @@ +core()->native(); + $imagick->setImageBackgroundColor(new ImagickPixel('transparent')); + + $imagick = $imagick->mergeImageLayers(Imagick::LAYERMETHOD_MERGE); + $imagick->setFormat($format); + $imagick->setImageFormat($format); + $imagick->setCompression($compression); + $imagick->setImageCompression($compression); + $imagick->setImageCompressionQuality($this->quality); + + return new EncodedImage($imagick->getImagesBlob(), 'image/webp'); + } +} diff --git a/src/Drivers/Imagick/Frame.php b/src/Drivers/Imagick/Frame.php new file mode 100644 index 00000000..f957b962 --- /dev/null +++ b/src/Drivers/Imagick/Frame.php @@ -0,0 +1,164 @@ +native())); + } + + /** + * {@inheritdoc} + * + * @see DriverInterface::setNative() + */ + public function setNative($native): FrameInterface + { + $this->native = $native; + + return $this; + } + + /** + * {@inheritdoc} + * + * @see DriverInterface::native() + */ + public function native(): Imagick + { + return $this->native; + } + + /** + * {@inheritdoc} + * + * @see DriverInterface::size() + */ + public function size(): SizeInterface + { + return new Rectangle( + $this->native->getImageWidth(), + $this->native->getImageHeight() + ); + } + + /** + * {@inheritdoc} + * + * @see DriverInterface::delay() + */ + public function delay(): float + { + return $this->native->getImageDelay() / 100; + } + + /** + * {@inheritdoc} + * + * @see DriverInterface::setDelay() + */ + public function setDelay(float $delay): FrameInterface + { + $this->native->setImageDelay(intval(round($delay * 100))); + + return $this; + } + + /** + * {@inheritdoc} + * + * @see DriverInterface::dispose() + */ + public function dispose(): int + { + return $this->native->getImageDispose(); + } + + /** + * {@inheritdoc} + * + * @see DriverInterface::setDispose() + */ + public function setDispose(int $dispose): FrameInterface + { + $this->native->setImageDispose($dispose); + + return $this; + } + + /** + * {@inheritdoc} + * + * @see DriverInterface::setOffset() + */ + public function setOffset(int $left, int $top): FrameInterface + { + $this->native->setImagePage( + $this->native->getImageWidth(), + $this->native->getImageHeight(), + $left, + $top + ); + + return $this; + } + + /** + * {@inheritdoc} + * + * @see DriverInterface::offsetLeft() + */ + public function offsetLeft(): int + { + return $this->native->getImagePage()['x']; + } + + /** + * {@inheritdoc} + * + * @see DriverInterface::setOffsetLeft() + */ + public function setOffsetLeft(int $offset): FrameInterface + { + return $this->setOffset($offset, $this->offsetTop()); + } + + /** + * {@inheritdoc} + * + * @see DriverInterface::offsetTop() + */ + public function offsetTop(): int + { + return $this->native->getImagePage()['y']; + } + + /** + * {@inheritdoc} + * + * @see DriverInterface::setOffsetTop() + */ + public function setOffsetTop(int $offset): FrameInterface + { + return $this->setOffset($this->offsetLeft(), $offset); + } +} diff --git a/src/Drivers/Imagick/InputHandler.php b/src/Drivers/Imagick/InputHandler.php new file mode 100644 index 00000000..621585a1 --- /dev/null +++ b/src/Drivers/Imagick/InputHandler.php @@ -0,0 +1,41 @@ +native()->blurImage(1 * $this->amount, 0.5 * $this->amount); + } + + return $image; + } +} diff --git a/src/Drivers/Imagick/Modifiers/BrightnessModifier.php b/src/Drivers/Imagick/Modifiers/BrightnessModifier.php new file mode 100644 index 00000000..f82c456d --- /dev/null +++ b/src/Drivers/Imagick/Modifiers/BrightnessModifier.php @@ -0,0 +1,21 @@ +native()->modulateImage(100 + $this->level, 100, 100); + } + + return $image; + } +} diff --git a/src/Drivers/Imagick/Modifiers/ColorizeModifier.php b/src/Drivers/Imagick/Modifiers/ColorizeModifier.php new file mode 100644 index 00000000..b8987597 --- /dev/null +++ b/src/Drivers/Imagick/Modifiers/ColorizeModifier.php @@ -0,0 +1,36 @@ +normalizeLevel($this->red); + $green = $this->normalizeLevel($this->green); + $blue = $this->normalizeLevel($this->blue); + + foreach ($image as $frame) { + $qrange = $frame->native()->getQuantumRange(); + $frame->native()->levelImage(0, $red, $qrange['quantumRangeLong'], Imagick::CHANNEL_RED); + $frame->native()->levelImage(0, $green, $qrange['quantumRangeLong'], Imagick::CHANNEL_GREEN); + $frame->native()->levelImage(0, $blue, $qrange['quantumRangeLong'], Imagick::CHANNEL_BLUE); + } + + return $image; + } + + private function normalizeLevel(int $level): int + { + return $level > 0 ? intval(round($level / 5)) : intval(round(($level + 100) / 100)); + } +} diff --git a/src/Drivers/Imagick/Modifiers/ColorspaceModifier.php b/src/Drivers/Imagick/Modifiers/ColorspaceModifier.php new file mode 100644 index 00000000..eee6ba6f --- /dev/null +++ b/src/Drivers/Imagick/Modifiers/ColorspaceModifier.php @@ -0,0 +1,43 @@ + Imagick::COLORSPACE_SRGB, + CmykColorspace::class => Imagick::COLORSPACE_CMYK, + ]; + + public function apply(ImageInterface $image): ImageInterface + { + $colorspace = $this->targetColorspace(); + + $imagick = $image->core()->native(); + $imagick->transformImageColorspace( + $this->getImagickColorspace($colorspace) + ); + + return $image; + } + + private function getImagickColorspace(ColorspaceInterface $colorspace): int + { + if (!array_key_exists(get_class($colorspace), self::$mapping)) { + throw new NotSupportedException('Given colorspace is not supported.'); + } + + return self::$mapping[get_class($colorspace)]; + } +} diff --git a/src/Drivers/Imagick/Modifiers/ContainModifier.php b/src/Drivers/Imagick/Modifiers/ContainModifier.php new file mode 100644 index 00000000..a39eea4a --- /dev/null +++ b/src/Drivers/Imagick/Modifiers/ContainModifier.php @@ -0,0 +1,101 @@ +getCropSize($image); + $resize = $this->getResizeSize($image); + $transparent = new ImagickPixel('transparent'); + $background = $this->driver()->colorProcessor($image->colorspace())->colorToNative( + $this->driver()->handleInput($this->background) + ); + + foreach ($image as $frame) { + $frame->native()->scaleImage( + $crop->width(), + $crop->height(), + ); + + $frame->native()->setBackgroundColor($transparent); + $frame->native()->setImageBackgroundColor($transparent); + + $frame->native()->extentImage( + $resize->width(), + $resize->height(), + $crop->pivot()->x() * -1, + $crop->pivot()->y() * -1 + ); + + if ($resize->width() > $crop->width()) { + // fill new emerged background + $draw = new ImagickDraw(); + $draw->setFillColor($background); + + $delta = abs($crop->pivot()->x()); + + if ($delta > 0) { + $draw->rectangle( + 0, + 0, + $delta - 1, + $resize->height() + ); + } + + $draw->rectangle( + $crop->width() + $delta, + 0, + $resize->width(), + $resize->height() + ); + + $frame->native()->drawImage($draw); + } + + if ($resize->height() > $crop->height()) { + // fill new emerged background + $draw = new ImagickDraw(); + $draw->setFillColor($background); + + $delta = abs($crop->pivot()->y()); + + if ($delta > 0) { + $draw->rectangle( + 0, + 0, + $resize->width(), + $delta - 1 + ); + } + + $draw->rectangle( + 0, + $crop->height() + $delta, + $resize->width(), + $resize->height() + ); + + $frame->native()->drawImage($draw); + } + } + + return $image; + } +} diff --git a/src/Drivers/Imagick/Modifiers/ContrastModifier.php b/src/Drivers/Imagick/Modifiers/ContrastModifier.php new file mode 100644 index 00000000..d5e38d74 --- /dev/null +++ b/src/Drivers/Imagick/Modifiers/ContrastModifier.php @@ -0,0 +1,21 @@ +native()->sigmoidalContrastImage($this->level > 0, abs($this->level / 4), 0); + } + + return $image; + } +} diff --git a/src/Drivers/Imagick/Modifiers/CoverDownModifier.php b/src/Drivers/Imagick/Modifiers/CoverDownModifier.php new file mode 100644 index 00000000..5cbb9338 --- /dev/null +++ b/src/Drivers/Imagick/Modifiers/CoverDownModifier.php @@ -0,0 +1,17 @@ +scaleDown($this->width, $this->height); + } +} diff --git a/src/Drivers/Imagick/Modifiers/CoverModifier.php b/src/Drivers/Imagick/Modifiers/CoverModifier.php new file mode 100644 index 00000000..8e5c09f1 --- /dev/null +++ b/src/Drivers/Imagick/Modifiers/CoverModifier.php @@ -0,0 +1,36 @@ +getCropSize($image); + $resize = $this->getResizeSize($crop); + + foreach ($image as $frame) { + $frame->native()->extentImage( + $crop->width(), + $crop->height(), + $crop->pivot()->x(), + $crop->pivot()->y() + ); + + $frame->native()->scaleImage( + $resize->width(), + $resize->height() + ); + } + + return $image; + } +} diff --git a/src/Drivers/Imagick/Modifiers/CropModifier.php b/src/Drivers/Imagick/Modifiers/CropModifier.php new file mode 100644 index 00000000..a4becc1b --- /dev/null +++ b/src/Drivers/Imagick/Modifiers/CropModifier.php @@ -0,0 +1,31 @@ +crop($image); + + foreach ($image as $frame) { + $frame->native()->extentImage( + $crop->width(), + $crop->height(), + $crop->pivot()->x() + $this->offset_x, + $crop->pivot()->y() + $this->offset_y + ); + } + + return $image; + } +} diff --git a/src/Drivers/Imagick/Modifiers/DrawEllipseModifier.php b/src/Drivers/Imagick/Modifiers/DrawEllipseModifier.php new file mode 100644 index 00000000..aa435af6 --- /dev/null +++ b/src/Drivers/Imagick/Modifiers/DrawEllipseModifier.php @@ -0,0 +1,48 @@ +driver()->colorProcessor($image->colorspace())->colorToNative( + $this->backgroundColor() + ); + + $border_color = $this->driver()->colorProcessor($image->colorspace())->colorToNative( + $this->borderColor() + ); + + foreach ($image as $frame) { + $drawing = new ImagickDraw(); + $drawing->setFillColor($background_color); + + if ($this->drawable->hasBorder()) { + $drawing->setStrokeWidth($this->drawable->borderSize()); + $drawing->setStrokeColor($border_color); + } + + $drawing->ellipse( + $this->position()->x(), + $this->position()->y(), + $this->drawable->width() / 2, + $this->drawable->height() / 2, + 0, + 360 + ); + + $frame->native()->drawImage($drawing); + } + + return $image; + } +} diff --git a/src/Drivers/Imagick/Modifiers/DrawLineModifier.php b/src/Drivers/Imagick/Modifiers/DrawLineModifier.php new file mode 100644 index 00000000..997014b3 --- /dev/null +++ b/src/Drivers/Imagick/Modifiers/DrawLineModifier.php @@ -0,0 +1,40 @@ +setStrokeWidth($this->drawable->width()); + $drawing->setStrokeColor( + $this->driver()->colorProcessor($image->colorspace())->colorToNative( + $this->backgroundColor() + ) + ); + + $drawing->line( + $this->drawable->start()->x(), + $this->drawable->start()->y(), + $this->drawable->end()->x(), + $this->drawable->end()->y(), + ); + + foreach ($image as $frame) { + $frame->native()->drawImage($drawing); + } + + return $image; + } +} diff --git a/src/Drivers/Imagick/Modifiers/DrawPixelModifier.php b/src/Drivers/Imagick/Modifiers/DrawPixelModifier.php new file mode 100644 index 00000000..982a0f74 --- /dev/null +++ b/src/Drivers/Imagick/Modifiers/DrawPixelModifier.php @@ -0,0 +1,32 @@ +driver()->colorProcessor($image->colorspace())->colorToNative( + $this->driver()->handleInput($this->color) + ); + + $pixel = new ImagickDraw(); + $pixel->setFillColor($color); + $pixel->point($this->position->x(), $this->position->y()); + + foreach ($image as $frame) { + $frame->native()->drawImage($pixel); + } + + return $image; + } +} diff --git a/src/Drivers/Imagick/Modifiers/DrawPolygonModifier.php b/src/Drivers/Imagick/Modifiers/DrawPolygonModifier.php new file mode 100644 index 00000000..b76cda94 --- /dev/null +++ b/src/Drivers/Imagick/Modifiers/DrawPolygonModifier.php @@ -0,0 +1,58 @@ +drawable->hasBackgroundColor()) { + $background_color = $this->driver()->colorProcessor($image->colorspace())->colorToNative( + $this->backgroundColor() + ); + + $drawing->setFillColor($background_color); + } + + if ($this->drawable->hasBorder()) { + $border_color = $this->driver()->colorProcessor($image->colorspace())->colorToNative( + $this->borderColor() + ); + + $drawing->setStrokeColor($border_color); + $drawing->setStrokeWidth($this->drawable->borderSize()); + } + + $drawing->polygon($this->points()); + + foreach ($image as $frame) { + $frame->native()->drawImage($drawing); + } + + return $image; + } + + private function points(): array + { + $points = []; + foreach ($this->drawable as $point) { + $points[] = ['x' => $point->x(), 'y' => $point->y()]; + } + + return $points; + } +} diff --git a/src/Drivers/Imagick/Modifiers/DrawRectangleModifier.php b/src/Drivers/Imagick/Modifiers/DrawRectangleModifier.php new file mode 100644 index 00000000..afa573ea --- /dev/null +++ b/src/Drivers/Imagick/Modifiers/DrawRectangleModifier.php @@ -0,0 +1,52 @@ +driver()->colorProcessor($image->colorspace())->colorToNative( + $this->backgroundColor() + ); + + $border_color = $this->driver()->colorProcessor($image->colorspace())->colorToNative( + $this->borderColor() + ); + + $drawing->setFillColor($background_color); + if ($this->drawable->hasBorder()) { + $drawing->setStrokeColor($border_color); + $drawing->setStrokeWidth($this->drawable->borderSize()); + } + + // build rectangle + $drawing->rectangle( + $this->position()->x(), + $this->position()->y(), + $this->position()->x() + $this->drawable->width(), + $this->position()->y() + $this->drawable->height() + ); + + foreach ($image as $frame) { + $frame->native()->drawImage($drawing); + } + + return $image; + } +} diff --git a/src/Drivers/Imagick/Modifiers/FillModifier.php b/src/Drivers/Imagick/Modifiers/FillModifier.php new file mode 100644 index 00000000..d33d9746 --- /dev/null +++ b/src/Drivers/Imagick/Modifiers/FillModifier.php @@ -0,0 +1,68 @@ +driver()->handleInput($this->color); + $pixel = $this->driver() + ->colorProcessor($image->colorspace()) + ->colorToNative($color); + + foreach ($image as $frame) { + if ($this->hasPosition()) { + $this->floodFillWithColor($frame, $pixel); + } else { + $this->fillAllWithColor($frame, $pixel); + } + } + + return $image; + } + + private function floodFillWithColor(Frame $frame, ImagickPixel $pixel): void + { + $target = $frame->native()->getImagePixelColor( + $this->position->x(), + $this->position->y() + ); + + $frame->native()->floodfillPaintImage( + $pixel, + 100, + $target, + $this->position->x(), + $this->position->y(), + false, + Imagick::CHANNEL_ALL + ); + } + + private function fillAllWithColor(Frame $frame, ImagickPixel $pixel): void + { + $draw = new ImagickDraw(); + $draw->setFillColor($pixel); + $draw->rectangle( + 0, + 0, + $frame->native()->getImageWidth(), + $frame->native()->getImageHeight() + ); + $frame->native()->drawImage($draw); + } +} diff --git a/src/Drivers/Imagick/Modifiers/FlipModifier.php b/src/Drivers/Imagick/Modifiers/FlipModifier.php new file mode 100644 index 00000000..e9a6bcc9 --- /dev/null +++ b/src/Drivers/Imagick/Modifiers/FlipModifier.php @@ -0,0 +1,18 @@ +native()->flipImage(); + } + + return $image; + } +} diff --git a/src/Drivers/Imagick/Modifiers/FlopModifier.php b/src/Drivers/Imagick/Modifiers/FlopModifier.php new file mode 100644 index 00000000..33827476 --- /dev/null +++ b/src/Drivers/Imagick/Modifiers/FlopModifier.php @@ -0,0 +1,18 @@ +native()->flopImage(); + } + + return $image; + } +} diff --git a/src/Drivers/Imagick/Modifiers/GammaModifier.php b/src/Drivers/Imagick/Modifiers/GammaModifier.php new file mode 100644 index 00000000..548d3007 --- /dev/null +++ b/src/Drivers/Imagick/Modifiers/GammaModifier.php @@ -0,0 +1,21 @@ +native()->gammaImage($this->gamma); + } + + return $image; + } +} diff --git a/src/Drivers/Imagick/Modifiers/GreyscaleModifier.php b/src/Drivers/Imagick/Modifiers/GreyscaleModifier.php new file mode 100644 index 00000000..d12c1e3b --- /dev/null +++ b/src/Drivers/Imagick/Modifiers/GreyscaleModifier.php @@ -0,0 +1,18 @@ +native()->modulateImage(100, 0, 100); + } + + return $image; + } +} diff --git a/src/Drivers/Imagick/Modifiers/InvertModifier.php b/src/Drivers/Imagick/Modifiers/InvertModifier.php new file mode 100644 index 00000000..0131df91 --- /dev/null +++ b/src/Drivers/Imagick/Modifiers/InvertModifier.php @@ -0,0 +1,18 @@ +native()->negateImage(false); + } + + return $image; + } +} diff --git a/src/Drivers/Imagick/Modifiers/LimitColorsModifier.php b/src/Drivers/Imagick/Modifiers/LimitColorsModifier.php new file mode 100644 index 00000000..39129506 --- /dev/null +++ b/src/Drivers/Imagick/Modifiers/LimitColorsModifier.php @@ -0,0 +1,38 @@ +limit === 0) { + return $image; + } + + // limit is over threshold: no reduction + if ($this->limit > $this->threshold) { + return $image; + } + + foreach ($image as $frame) { + $frame->native()->quantizeImage( + $this->limit, + $frame->native()->getImageColorspace(), + 0, + false, + false + ); + } + + return $image; + } +} diff --git a/src/Drivers/Imagick/Modifiers/PadModifier.php b/src/Drivers/Imagick/Modifiers/PadModifier.php new file mode 100644 index 00000000..578ec10b --- /dev/null +++ b/src/Drivers/Imagick/Modifiers/PadModifier.php @@ -0,0 +1,7 @@ +pixelateFrame($frame); + } + + return $image; + } + + protected function pixelateFrame(Frame $frame): void + { + $size = $frame->size(); + + $frame->native()->scaleImage( + round(max(1, ($size->width() / $this->size))), + round(max(1, ($size->height() / $this->size))) + ); + + $frame->native()->scaleImage($size->width(), $size->height()); + } +} diff --git a/src/Drivers/Imagick/Modifiers/PlaceModifier.php b/src/Drivers/Imagick/Modifiers/PlaceModifier.php new file mode 100644 index 00000000..8b0d7ad5 --- /dev/null +++ b/src/Drivers/Imagick/Modifiers/PlaceModifier.php @@ -0,0 +1,34 @@ +driver()->handleInput($this->element); + $position = $this->getPosition($image, $watermark); + + foreach ($image as $frame) { + $frame->native()->compositeImage( + $watermark->core()->native(), + Imagick::COMPOSITE_DEFAULT, + $position->x(), + $position->y() + ); + } + + return $image; + } +} diff --git a/src/Drivers/Imagick/Modifiers/ProfileModifier.php b/src/Drivers/Imagick/Modifiers/ProfileModifier.php new file mode 100644 index 00000000..c8be88b2 --- /dev/null +++ b/src/Drivers/Imagick/Modifiers/ProfileModifier.php @@ -0,0 +1,26 @@ +core()->native(); + $result = $imagick->profileImage('icc', (string) $this->profile); + + if ($result === false) { + throw new ColorException('ICC color profile could not be set.'); + } + + return $image; + } +} diff --git a/src/Drivers/Imagick/Modifiers/ProfileRemovalModifier.php b/src/Drivers/Imagick/Modifiers/ProfileRemovalModifier.php new file mode 100644 index 00000000..6a4a79af --- /dev/null +++ b/src/Drivers/Imagick/Modifiers/ProfileRemovalModifier.php @@ -0,0 +1,22 @@ +core()->native(); + $result = $imagick->profileImage('icc', null); + + if ($result === false) { + throw new ColorException('ICC color profile could not be removed.'); + } + + return $image; + } +} diff --git a/src/Drivers/Imagick/Modifiers/RemoveAnimationModifier.php b/src/Drivers/Imagick/Modifiers/RemoveAnimationModifier.php new file mode 100644 index 00000000..15147b17 --- /dev/null +++ b/src/Drivers/Imagick/Modifiers/RemoveAnimationModifier.php @@ -0,0 +1,27 @@ +chosenFrame($image, $this->position); + $imagick->addImage($frame->native()->getImage()); + + // set new imagick to image + $image->core()->setNative($imagick); + + return $image; + } +} diff --git a/src/Drivers/Imagick/Modifiers/ResizeCanvasModifier.php b/src/Drivers/Imagick/Modifiers/ResizeCanvasModifier.php new file mode 100644 index 00000000..11e29d6b --- /dev/null +++ b/src/Drivers/Imagick/Modifiers/ResizeCanvasModifier.php @@ -0,0 +1,87 @@ +size(); + $resize = $this->cropSize($image); + + $background = $this->driver()->colorProcessor($image->colorspace())->colorToNative( + $this->driver()->handleInput($this->background) + ); + + foreach ($image as $frame) { + $frame->native()->extentImage( + $resize->width(), + $resize->height(), + $resize->pivot()->x(), + $resize->pivot()->y() + ); + + if ($resize->width() > $size->width()) { + // fill new emerged background + $draw = new ImagickDraw(); + $draw->setFillColor($background); + + $delta = abs($resize->pivot()->x()); + + if ($delta > 0) { + $draw->rectangle( + 0, + 0, + $delta - 1, + $resize->height() + ); + } + + $draw->rectangle( + $size->width() + $delta, + 0, + $resize->width(), + $resize->height() + ); + $frame->native()->drawImage($draw); + } + + if ($resize->height() > $size->height()) { + // fill new emerged background + $draw = new ImagickDraw(); + $draw->setFillColor($background); + + $delta = abs($resize->pivot()->y()); + + if ($delta > 0) { + $draw->rectangle( + 0, + 0, + $resize->width(), + $delta - 1 + ); + } + + $draw->rectangle( + 0, + $size->height() + $delta, + $resize->width(), + $resize->height() + ); + + $frame->native()->drawImage($draw); + } + } + + return $image; + } +} diff --git a/src/Drivers/Imagick/Modifiers/ResizeCanvasRelativeModifier.php b/src/Drivers/Imagick/Modifiers/ResizeCanvasRelativeModifier.php new file mode 100644 index 00000000..fe42d704 --- /dev/null +++ b/src/Drivers/Imagick/Modifiers/ResizeCanvasRelativeModifier.php @@ -0,0 +1,14 @@ +size()->resizeDown($this->width, $this->height); + } +} diff --git a/src/Drivers/Imagick/Modifiers/ResizeModifier.php b/src/Drivers/Imagick/Modifiers/ResizeModifier.php new file mode 100644 index 00000000..d016643a --- /dev/null +++ b/src/Drivers/Imagick/Modifiers/ResizeModifier.php @@ -0,0 +1,33 @@ +getAdjustedSize($image); + + foreach ($image as $frame) { + $frame->native()->scaleImage( + $resizeTo->width(), + $resizeTo->height() + ); + } + + return $image; + } + + protected function getAdjustedSize(ImageInterface $image): SizeInterface + { + return $image->size()->resize($this->width, $this->height); + } +} diff --git a/src/Drivers/Imagick/Modifiers/ResolutionModifier.php b/src/Drivers/Imagick/Modifiers/ResolutionModifier.php new file mode 100644 index 00000000..fd44dec8 --- /dev/null +++ b/src/Drivers/Imagick/Modifiers/ResolutionModifier.php @@ -0,0 +1,21 @@ +core()->native(); + $imagick->setImageResolution($this->x, $this->y); + + return $image; + } +} diff --git a/src/Drivers/Imagick/Modifiers/RotateModifier.php b/src/Drivers/Imagick/Modifiers/RotateModifier.php new file mode 100644 index 00000000..b7f15a12 --- /dev/null +++ b/src/Drivers/Imagick/Modifiers/RotateModifier.php @@ -0,0 +1,29 @@ +driver()->colorProcessor($image->colorspace())->colorToNative( + $this->driver()->handleInput($this->background) + ); + + foreach ($image as $frame) { + $frame->native()->rotateImage( + $background, + $this->rotationAngle() * -1 + ); + } + + return $image; + } +} diff --git a/src/Drivers/Imagick/Modifiers/ScaleDownModifier.php b/src/Drivers/Imagick/Modifiers/ScaleDownModifier.php new file mode 100644 index 00000000..b4ce6945 --- /dev/null +++ b/src/Drivers/Imagick/Modifiers/ScaleDownModifier.php @@ -0,0 +1,18 @@ +size()->scaleDown($this->width, $this->height); + } +} diff --git a/src/Drivers/Imagick/Modifiers/ScaleModifier.php b/src/Drivers/Imagick/Modifiers/ScaleModifier.php new file mode 100644 index 00000000..9a85b1fb --- /dev/null +++ b/src/Drivers/Imagick/Modifiers/ScaleModifier.php @@ -0,0 +1,18 @@ +size()->scale($this->width, $this->height); + } +} diff --git a/src/Drivers/Imagick/Modifiers/SharpenModifier.php b/src/Drivers/Imagick/Modifiers/SharpenModifier.php new file mode 100644 index 00000000..25ed5a90 --- /dev/null +++ b/src/Drivers/Imagick/Modifiers/SharpenModifier.php @@ -0,0 +1,21 @@ +native()->unsharpMaskImage(1, 1, $this->amount / 6.25, 0); + } + + return $image; + } +} diff --git a/src/Drivers/Imagick/Modifiers/TextModifier.php b/src/Drivers/Imagick/Modifiers/TextModifier.php new file mode 100644 index 00000000..068d1391 --- /dev/null +++ b/src/Drivers/Imagick/Modifiers/TextModifier.php @@ -0,0 +1,90 @@ +alignedTextBlock($this->position, $this->text); + + $color = $this->driver()->colorProcessor($image->colorspace())->colorToNative( + $this->driver()->handleInput($this->font->color()) + ); + + $draw = $this->toImagickDraw($color); + + foreach ($image as $frame) { + foreach ($lines as $line) { + $frame->native()->annotateImage( + $draw, + $line->position()->x(), + $line->position()->y(), + $this->font->angle(), + $line + ); + } + } + + return $image; + } + + /** + * Calculate box size of current font + * + * @return Polygon + */ + protected function boxSize(string $text): Polygon + { + // no text - no box size + if (mb_strlen($text) === 0) { + return (new Rectangle(0, 0)); + } + + $draw = $this->toImagickDraw(); + $draw->setStrokeAntialias(true); + $draw->setTextAntialias(true); + $dimensions = (new Imagick())->queryFontMetrics($draw, $text); + + return (new Rectangle( + intval(round($dimensions['textWidth'])), + intval(round($dimensions['ascender'] + $dimensions['descender'])), + )); + } + + private function toImagickDraw(?ImagickPixel $color = null): ImagickDraw + { + if (!$this->font->hasFilename()) { + throw new FontException('No font file specified.'); + } + + $draw = new ImagickDraw(); + $draw->setStrokeAntialias(true); + $draw->setTextAntialias(true); + $draw->setFont($this->font->filename()); + $draw->setFontSize($this->font->size()); + $draw->setTextAlignment(Imagick::ALIGN_LEFT); + + if ($color) { + $draw->setFillColor($color); + } + + return $draw; + } +} diff --git a/src/EncodedImage.php b/src/EncodedImage.php new file mode 100644 index 00000000..17f28037 --- /dev/null +++ b/src/EncodedImage.php @@ -0,0 +1,40 @@ +mimetype; + } + + /** + * Transform encoded image data into an data uri string + * + * @return string + */ + public function toDataUri(): string + { + return sprintf('data:%s;base64,%s', $this->mimetype, base64_encode($this->data)); + } +} diff --git a/src/Encoders/AbstractEncoder.php b/src/Encoders/AbstractEncoder.php new file mode 100644 index 00000000..418e07ac --- /dev/null +++ b/src/Encoders/AbstractEncoder.php @@ -0,0 +1,20 @@ +encode($this); + } +} diff --git a/src/Encoders/AvifEncoder.php b/src/Encoders/AvifEncoder.php new file mode 100644 index 00000000..53a9e49b --- /dev/null +++ b/src/Encoders/AvifEncoder.php @@ -0,0 +1,10 @@ +data; + } + + /** + * Create file pointer from encoded image + * + * @return resource + */ + public function toFilePointer() + { + return $this->buildFilePointer($this->toString()); + } + + /** + * Return byte size of encoded image + * + * @return int + */ + public function size(): int + { + return mb_strlen($this->data); + } + + /** + * Cast encoded image object to string + * + * @return string + */ + public function __toString(): string + { + return $this->toString(); + } +} diff --git a/src/Geometry/Circle.php b/src/Geometry/Circle.php new file mode 100644 index 00000000..06d10757 --- /dev/null +++ b/src/Geometry/Circle.php @@ -0,0 +1,39 @@ +setWidth($diameter); + $this->setHeight($diameter); + } + + public function setDiameter(int $diameter): self + { + $this->setWidth($diameter); + $this->setHeight($diameter); + + return $this; + } + + public function diameter(): int + { + return $this->diameter; + } + + public function setRadius(int $radius): self + { + return $this->setDiameter(intval($radius * 2)); + } + + public function radius(): int + { + return intval($this->diameter / 2); + } +} diff --git a/src/Geometry/Ellipse.php b/src/Geometry/Ellipse.php new file mode 100644 index 00000000..bccbdfb8 --- /dev/null +++ b/src/Geometry/Ellipse.php @@ -0,0 +1,60 @@ +pivot; + } + + public function pivot(): PointInterface + { + return $this->pivot; + } + + public function setSize(int $width, int $height): self + { + return $this->setWidth($width)->setHeight($height); + } + + public function setWidth(int $width): self + { + $this->width = $width; + + return $this; + } + + public function setHeight(int $height): self + { + $this->height = $height; + + return $this; + } + + public function width(): int + { + return $this->width; + } + + public function height(): int + { + return $this->height; + } +} diff --git a/src/Geometry/Factories/CircleFactory.php b/src/Geometry/Factories/CircleFactory.php new file mode 100644 index 00000000..74340fd6 --- /dev/null +++ b/src/Geometry/Factories/CircleFactory.php @@ -0,0 +1,20 @@ +ellipse->setSize($radius * 2, $radius * 2); + + return $this; + } + + public function diameter(int $diameter): self + { + $this->ellipse->setSize($diameter, $diameter); + + return $this; + } +} diff --git a/src/Geometry/Factories/EllipseFactory.php b/src/Geometry/Factories/EllipseFactory.php new file mode 100644 index 00000000..12662572 --- /dev/null +++ b/src/Geometry/Factories/EllipseFactory.php @@ -0,0 +1,46 @@ +ellipse = is_a($init, Ellipse::class) ? $init : new Ellipse(0, 0, $pivot); + + if (is_callable($init)) { + $init($this); + } + } + + public function size(int $width, int $height): self + { + $this->ellipse->setSize($width, $height); + + return $this; + } + + public function background(mixed $color): self + { + $this->ellipse->setBackgroundColor($color); + + return $this; + } + + public function border(mixed $color, int $size = 1): self + { + $this->ellipse->setBorder($color, $size); + + return $this; + } + + public function __invoke(): Ellipse + { + return $this->ellipse; + } +} diff --git a/src/Geometry/Factories/LineFactory.php b/src/Geometry/Factories/LineFactory.php new file mode 100644 index 00000000..db846633 --- /dev/null +++ b/src/Geometry/Factories/LineFactory.php @@ -0,0 +1,71 @@ +line = is_a($init, Line::class) ? $init : new Line(new Point(), new Point()); + + if (is_callable($init)) { + $init($this); + } + } + + public function color(mixed $color): self + { + $this->line->setBackgroundColor($color); + $this->line->setBorderColor($color); + + return $this; + } + + public function background(mixed $color): self + { + $this->line->setBackgroundColor($color); + $this->line->setBorderColor($color); + + return $this; + } + + public function border(mixed $color, int $size = 1): self + { + $this->line->setBackgroundColor($color); + $this->line->setBorderColor($color); + $this->line->setWidth($size); + + return $this; + } + + public function width(int $size): self + { + $this->line->setWidth($size); + + return $this; + } + + public function from(int $x, int $y): self + { + $this->line->setStart(new Point($x, $y)); + + return $this; + } + + public function to(int $x, int $y): self + { + $this->line->setEnd(new Point($x, $y)); + + return $this; + } + + public function __invoke(): Line + { + return $this->line; + } +} diff --git a/src/Geometry/Factories/PolygonFactory.php b/src/Geometry/Factories/PolygonFactory.php new file mode 100644 index 00000000..e7c501aa --- /dev/null +++ b/src/Geometry/Factories/PolygonFactory.php @@ -0,0 +1,46 @@ +polygon = is_a($init, Polygon::class) ? $init : new Polygon([]); + + if (is_callable($init)) { + $init($this); + } + } + + public function point(int $x, int $y): self + { + $this->polygon->addPoint(new Point($x, $y)); + + return $this; + } + + public function background(mixed $color): self + { + $this->polygon->setBackgroundColor($color); + + return $this; + } + + public function border(mixed $color, int $size = 1): self + { + $this->polygon->setBorder($color, $size); + + return $this; + } + + public function __invoke(): Polygon + { + return $this->polygon; + } +} diff --git a/src/Geometry/Factories/RectangleFactory.php b/src/Geometry/Factories/RectangleFactory.php new file mode 100644 index 00000000..ceeb0672 --- /dev/null +++ b/src/Geometry/Factories/RectangleFactory.php @@ -0,0 +1,60 @@ +rectangle = is_a($init, Rectangle::class) ? $init : new Rectangle(0, 0, $pivot); + + if (is_callable($init)) { + $init($this); + } + } + + public function size(int $width, int $height): self + { + $this->rectangle->setSize($width, $height); + + return $this; + } + + public function width(int $width): self + { + $this->rectangle->setWidth($width); + + return $this; + } + + public function height(int $height): self + { + $this->rectangle->setHeight($height); + + return $this; + } + + public function background(mixed $color): self + { + $this->rectangle->setBackgroundColor($color); + + return $this; + } + + public function border(mixed $color, int $size = 1): self + { + $this->rectangle->setBorder($color, $size); + + return $this; + } + + public function __invoke(): Rectangle + { + return $this->rectangle; + } +} diff --git a/src/Geometry/Line.php b/src/Geometry/Line.php new file mode 100644 index 00000000..58f030c3 --- /dev/null +++ b/src/Geometry/Line.php @@ -0,0 +1,78 @@ +start; + } + + public function width(): int + { + return $this->width; + } + + public function setWidth(int $width): self + { + $this->width = $width; + + return $this; + } + + public function start(): Point + { + return $this->start; + } + + public function end(): Point + { + return $this->end; + } + + public function setStart(Point $start): self + { + $this->start = $start; + + return $this; + } + + public function from(int $x, int $y): self + { + $this->start()->setX($x); + $this->start()->setY($y); + + return $this; + } + + public function to(int $x, int $y): self + { + $this->end()->setX($x); + $this->end()->setY($y); + + return $this; + } + + public function setEnd(Point $end): self + { + $this->end = $end; + + return $this; + } +} diff --git a/src/Geometry/Pixel.php b/src/Geometry/Pixel.php new file mode 100644 index 00000000..eaa2326c --- /dev/null +++ b/src/Geometry/Pixel.php @@ -0,0 +1,27 @@ +background = $background; + + return $this; + } + + public function backgroundColor(): ColorInterface + { + return $this->background; + } +} diff --git a/src/Geometry/Point.php b/src/Geometry/Point.php new file mode 100644 index 00000000..11b48c9e --- /dev/null +++ b/src/Geometry/Point.php @@ -0,0 +1,120 @@ +x = $x; + + return $this; + } + + /** + * Get X coordinate + * + * @return integer + */ + public function x(): int + { + return $this->x; + } + + /** + * Sets Y coordinate + * + * @param integer $y + */ + public function setY(int $y): self + { + $this->y = $y; + + return $this; + } + + /** + * Get Y coordinate + * + * @return integer + */ + public function y(): int + { + return $this->y; + } + + /** + * Move X coordinate + * + * @param integer $value + */ + public function moveX(int $value): self + { + $this->x += $value; + + return $this; + } + + /** + * Move Y coordinate + * + * @param integer $value + */ + public function moveY(int $value): self + { + $this->y += $value; + + return $this; + } + + public function move(int $x, int $y): self + { + return $this->moveX($x)->moveY($y); + } + + /** + * Sets both X and Y coordinate + * + * @param integer $x + * @param integer $y + * @return Point + */ + public function setPosition(int $x, int $y): self + { + $this->setX($x); + $this->setY($y); + + return $this; + } + + /** + * Rotate point ccw around pivot + * + * @param float $angle + * @param Point $pivot + * @return Point + */ + public function rotate(float $angle, Point $pivot): self + { + $sin = round(sin(deg2rad($angle)), 6); + $cos = round(cos(deg2rad($angle)), 6); + + return $this->setPosition( + intval($cos * ($this->x - $pivot->x) - $sin * ($this->y - $pivot->y) + $pivot->x), + intval($sin * ($this->x - $pivot->x) + $cos * ($this->y - $pivot->y) + $pivot->y) + ); + } +} diff --git a/src/Geometry/Polygon.php b/src/Geometry/Polygon.php new file mode 100644 index 00000000..f5ba2804 --- /dev/null +++ b/src/Geometry/Polygon.php @@ -0,0 +1,423 @@ +pivot; + } + + public function getIterator(): Traversable + { + return new ArrayIterator($this->points); + } + + /** + * Return current pivot point + * + * @return PointInterface + */ + public function pivot(): PointInterface + { + return $this->pivot; + } + + /** + * Change pivot point to given point + * + * @param Point $pivot + * @return Polygon + */ + public function setPivot(Point $pivot): self + { + $this->pivot = $pivot; + + return $this; + } + + /** + * Return first point of polygon + * + * @return ?Point + */ + public function first(): ?Point + { + if ($point = reset($this->points)) { + return $point; + } + + return null; + } + + /** + * Return last point of polygon + * + * @return ?Point + */ + public function last(): ?Point + { + if ($point = end($this->points)) { + return $point; + } + + return null; + } + + /** + * Return polygon's point count + * + * @return int + */ + public function count(): int + { + return count($this->points); + } + + /** + * Determine if point exists at given offset + * + * @param mixed $offset + * @return bool + */ + public function offsetExists($offset): bool + { + return array_key_exists($offset, $this->points); + } + + /** + * Return point at given offset + * + * @param mixed $offset + * @return Point + */ + public function offsetGet($offset): mixed + { + return $this->points[$offset]; + } + + /** + * Set point at given offset + * + * @param mixed $offset + * @param Point $value + * @return void + */ + public function offsetSet($offset, $value): void + { + $this->points[$offset] = $value; + } + + /** + * Unset offset at given offset + * + * @param mixed $offset + * @return void + */ + public function offsetUnset($offset): void + { + unset($this->points[$offset]); + } + + /** + * Add given point to polygon + * + * @param Point $point + * @return Polygon + */ + public function addPoint(Point $point): self + { + $this->points[] = $point; + + return $this; + } + + /** + * Calculate total horizontal span of polygon + * + * @return int + */ + public function width(): int + { + return abs($this->mostLeftPoint()->x() - $this->mostRightPoint()->x()); + } + + /** + * Calculate total vertical span of polygon + * + * @return int + */ + public function height(): int + { + return abs($this->mostBottomPoint()->y() - $this->mostTopPoint()->y()); + } + + /** + * Return most left point of all points in polygon + * + * @return Point + */ + public function mostLeftPoint(): Point + { + $points = []; + foreach ($this->points as $point) { + $points[] = $point; + } + + usort($points, function ($a, $b) { + if ($a->x() === $b->x()) { + return 0; + } + return ($a->x() < $b->x()) ? -1 : 1; + }); + + return $points[0]; + } + + /** + * Return most right point in polygon + * + * @return Point + */ + public function mostRightPoint(): Point + { + $points = []; + foreach ($this->points as $point) { + $points[] = $point; + } + + usort($points, function ($a, $b) { + if ($a->x() === $b->x()) { + return 0; + } + return ($a->x() > $b->x()) ? -1 : 1; + }); + + return $points[0]; + } + + /** + * Return most top point in polygon + * + * @return Point + */ + public function mostTopPoint(): Point + { + $points = []; + foreach ($this->points as $point) { + $points[] = $point; + } + + usort($points, function ($a, $b) { + if ($a->y() === $b->y()) { + return 0; + } + return ($a->y() > $b->y()) ? -1 : 1; + }); + + return $points[0]; + } + + /** + * Return most bottom point in polygon + * + * @return Point + */ + public function mostBottomPoint(): Point + { + $points = []; + foreach ($this->points as $point) { + $points[] = $point; + } + + usort($points, function ($a, $b) { + if ($a->y() === $b->y()) { + return 0; + } + return ($a->y() < $b->y()) ? -1 : 1; + }); + + return $points[0]; + } + + /** + * Return point in absolute center of the polygon + * + * @return Point + */ + public function centerPoint(): Point + { + return new Point( + $this->mostRightPoint()->x() - (intval(round($this->width() / 2))), + $this->mostTopPoint()->y() - (intval(round($this->height() / 2))) + ); + } + + /** + * Align all points of polygon horizontally to given position around pivot point + * + * @param string $position + * @return Polygon + */ + public function align(string $position): self + { + switch (strtolower($position)) { + case 'center': + case 'middle': + $diff = ($this->centerPoint()->x() - $this->pivot()->x()); + break; + + case 'right': + $diff = ($this->mostRightPoint()->x() - $this->pivot()->x()); + break; + + default: + case 'left': + $diff = ($this->mostLeftPoint()->x() - $this->pivot()->x()); + break; + } + + foreach ($this->points as $point) { + $point->setX( + intval($point->x() - $diff) + ); + } + + return $this; + } + + /** + * Align all points of polygon vertically to given position around pivot point + * + * @param string $position + * @return Polygon + */ + public function valign(string $position): self + { + switch (strtolower($position)) { + case 'center': + case 'middle': + $diff = ($this->centerPoint()->y() - $this->pivot()->y()); + break; + + case 'top': + $diff = ($this->mostTopPoint()->y() - $this->pivot()->y()) - $this->height(); + break; + + default: + case 'bottom': + $diff = ($this->mostBottomPoint()->y() - $this->pivot()->y()) + $this->height(); + break; + } + + foreach ($this->points as $point) { + $point->setY( + intval($point->y() - $diff), + ); + } + + return $this; + } + + /** + * Rotate points of polygon around pivot point with given angle + * + * @param float $angle + * @return Polygon + */ + public function rotate(float $angle): self + { + $sin = sin(deg2rad($angle)); + $cos = cos(deg2rad($angle)); + + foreach ($this->points as $point) { + // translate point to pivot + $point->setX( + intval($point->x() - $this->pivot()->x()), + ); + $point->setY( + intval($point->y() - $this->pivot()->y()), + ); + + // rotate point + $x = $point->x() * $cos - $point->y() * $sin; + $y = $point->x() * $sin + $point->y() * $cos; + + // translate point back + $point->setX( + intval($x + $this->pivot()->x()), + ); + $point->setY( + intval($y + $this->pivot()->y()), + ); + } + + return $this; + } + + /** + * Move all points by given amount on the x-axis + * + * @param int $amount + * @return Polygon + */ + public function movePointsX(int $amount): self + { + foreach ($this->points as $point) { + $point->moveX($amount); + } + + return $this; + } + + /** + * Move all points by given amount on the y-axis + * + * @param int $amount + * @return Polygon + */ + public function movePointsY(int $amount): self + { + foreach ($this->points as $point) { + $point->moveY($amount); + } + + return $this; + } + + /** + * Return array of all x/y values of all points of polygon + * + * @return array + */ + public function toArray(): array + { + $coordinates = []; + foreach ($this->points as $point) { + $coordinates[] = $point->x(); + $coordinates[] = $point->y(); + } + + return $coordinates; + } +} diff --git a/src/Geometry/Rectangle.php b/src/Geometry/Rectangle.php new file mode 100644 index 00000000..31bbaa37 --- /dev/null +++ b/src/Geometry/Rectangle.php @@ -0,0 +1,231 @@ +addPoint(new Point($this->pivot->x(), $this->pivot->y())); + $this->addPoint(new Point($this->pivot->x() + $width, $this->pivot->y())); + $this->addPoint(new Point($this->pivot->x() + $width, $this->pivot->y() - $height)); + $this->addPoint(new Point($this->pivot->x(), $this->pivot->y() - $height)); + } + + public function setSize(int $width, int $height): self + { + return $this->setWidth($width)->setHeight($height); + } + + public function setWidth(int $width): self + { + $this[1]->setX($this[0]->x() + $width); + $this[2]->setX($this[3]->x() + $width); + + return $this; + } + + public function setHeight(int $height): self + { + $this[2]->setY($this[1]->y() + $height); + $this[3]->setY($this[0]->y() + $height); + + return $this; + } + + public function pivot(): PointInterface + { + return $this->pivot; + } + + public function setPivot(PointInterface $pivot): self + { + $this->pivot = $pivot; + + return $this; + } + + public function movePivot(string $position, int $offset_x = 0, int $offset_y = 0): self + { + switch (strtolower($position)) { + case 'top': + case 'top-center': + case 'top-middle': + case 'center-top': + case 'middle-top': + $x = intval(round($this->width() / 2)) + $offset_x; + $y = 0 + $offset_y; + break; + + case 'top-right': + case 'right-top': + $x = $this->width() - $offset_x; + $y = 0 + $offset_y; + break; + + case 'left': + case 'left-center': + case 'left-middle': + case 'center-left': + case 'middle-left': + $x = 0 + $offset_x; + $y = intval(round($this->height() / 2)) + $offset_y; + break; + + case 'right': + case 'right-center': + case 'right-middle': + case 'center-right': + case 'middle-right': + $x = $this->width() - $offset_x; + $y = intval(round($this->height() / 2)) + $offset_y; + break; + + case 'bottom-left': + case 'left-bottom': + $x = 0 + $offset_x; + $y = $this->height() - $offset_y; + break; + + case 'bottom': + case 'bottom-center': + case 'bottom-middle': + case 'center-bottom': + case 'middle-bottom': + $x = intval(round($this->width() / 2)) + $offset_x; + $y = $this->height() - $offset_y; + break; + + case 'bottom-right': + case 'right-bottom': + $x = $this->width() - $offset_x; + $y = $this->height() - $offset_y; + break; + + case 'center': + case 'middle': + case 'center-center': + case 'middle-middle': + $x = intval(round($this->width() / 2)) + $offset_x; + $y = intval(round($this->height() / 2)) + $offset_y; + break; + + default: + case 'top-left': + case 'left-top': + $x = 0 + $offset_x; + $y = 0 + $offset_y; + break; + } + + $this->pivot->setPosition($x, $y); + + return $this; + } + + public function alignPivotTo(SizeInterface $size, string $position): self + { + $reference = new self($size->width(), $size->height()); + $reference->movePivot($position); + + $this->movePivot($position)->setPivot( + $reference->relativePositionTo($this) + ); + + return $this; + } + + public function relativePositionTo(SizeInterface $rectangle): PointInterface + { + return new Point( + $this->pivot()->x() - $rectangle->pivot()->x(), + $this->pivot()->y() - $rectangle->pivot()->y() + ); + } + + public function aspectRatio(): float + { + return $this->width() / $this->height(); + } + + public function fitsInto(SizeInterface $size): bool + { + if ($this->width() > $size->width()) { + return false; + } + + if ($this->height() > $size->height()) { + return false; + } + + return true; + } + + public function isLandscape(): bool + { + return $this->width() > $this->height(); + } + + public function isPortrait(): bool + { + return $this->width() < $this->height(); + } + + public function topLeftPoint(): PointInterface + { + return $this->points[0]; + } + + public function bottomRightPoint(): PointInterface + { + return $this->points[2]; + } + + protected function resizer(?int $width = null, ?int $height = null): RectangleResizer + { + return new RectangleResizer($width, $height); + } + + public function resize(?int $width = null, ?int $height = null): SizeInterface + { + return $this->resizer($width, $height)->resize($this); + } + + public function resizeDown(?int $width = null, ?int $height = null): SizeInterface + { + return $this->resizer($width, $height)->resizeDown($this); + } + + public function scale(?int $width = null, ?int $height = null): SizeInterface + { + return $this->resizer($width, $height)->scale($this); + } + + public function scaleDown(?int $width = null, ?int $height = null): SizeInterface + { + return $this->resizer($width, $height)->scaleDown($this); + } + + public function cover(int $width, int $height): SizeInterface + { + return $this->resizer($width, $height)->cover($this); + } + + public function contain(int $width, int $height): SizeInterface + { + return $this->resizer($width, $height)->contain($this); + } + + public function containMax(int $width, int $height): SizeInterface + { + return $this->resizer($width, $height)->containDown($this); + } +} diff --git a/src/Geometry/Tools/RectangleResizer.php b/src/Geometry/Tools/RectangleResizer.php new file mode 100644 index 00000000..38292da1 --- /dev/null +++ b/src/Geometry/Tools/RectangleResizer.php @@ -0,0 +1,280 @@ +width); + } + + protected function getTargetWidth(): ?int + { + return $this->hasTargetWidth() ? $this->width : null; + } + + protected function hasTargetHeight(): bool + { + return is_integer($this->height); + } + + protected function getTargetHeight(): ?int + { + return $this->hasTargetHeight() ? $this->height : null; + } + + protected function getTargetSize(): SizeInterface + { + if (!$this->hasTargetWidth() || !$this->hasTargetHeight()) { + throw new GeometryException('Target size needs width and height.'); + } + + return new Rectangle($this->width, $this->height); + } + + public function toWidth(int $width): self + { + $this->width = $width; + + return $this; + } + + public function toHeight(int $height): self + { + $this->height = $height; + + return $this; + } + + public function toSize(SizeInterface $size): self + { + $this->width = $size->width(); + $this->height = $size->height(); + + return $this; + } + + protected function getProportionalWidth(SizeInterface $size): int + { + if (!$this->hasTargetHeight()) { + return $size->width(); + } + + return (int) round($this->height * $size->aspectRatio()); + } + + protected function getProportionalHeight(SizeInterface $size): int + { + if (!$this->hasTargetWidth()) { + return $size->height(); + } + + return (int) round($this->width / $size->aspectRatio()); + } + + public function resize(SizeInterface $size): SizeInterface + { + $resized = new Rectangle($size->width(), $size->height()); + + if ($width = $this->getTargetWidth()) { + $resized->setWidth($width); + } + + if ($height = $this->getTargetHeight()) { + $resized->setHeight($height); + } + + return $resized; + } + + public function resizeDown(SizeInterface $size): SizeInterface + { + $resized = new Rectangle($size->width(), $size->height()); + + if ($width = $this->getTargetWidth()) { + $resized->setWidth( + min($width, $size->width()) + ); + } + + if ($height = $this->getTargetHeight()) { + $resized->setHeight( + min($height, $size->height()) + ); + } + + return $resized; + } + + public function scale(SizeInterface $size): SizeInterface + { + $resized = new Rectangle($size->width(), $size->height()); + + if ($this->hasTargetWidth() && $this->hasTargetHeight()) { + $resized->setWidth(min( + $this->getProportionalWidth($size), + $this->getTargetWidth() + )); + $resized->setHeight(min( + $this->getProportionalHeight($size), + $this->getTargetHeight() + )); + } elseif ($this->hasTargetWidth()) { + $resized->setWidth($this->getTargetWidth()); + $resized->setHeight($this->getProportionalHeight($size)); + } elseif ($this->hasTargetHeight()) { + $resized->setWidth($this->getProportionalWidth($size)); + $resized->setHeight($this->getTargetHeight()); + } + + return $resized; + } + + public function scaleDown(SizeInterface $size): SizeInterface + { + $resized = new Rectangle($size->width(), $size->height()); + + if ($this->hasTargetWidth() && $this->hasTargetHeight()) { + $resized->setWidth(min( + $this->getProportionalWidth($size), + $this->getTargetWidth(), + $size->width() + )); + $resized->setHeight(min( + $this->getProportionalHeight($size), + $this->getTargetHeight(), + $size->height() + )); + } elseif ($this->hasTargetWidth()) { + $resized->setWidth(min( + $this->getTargetWidth(), + $size->width() + )); + $resized->setHeight(min( + $this->getProportionalHeight($size), + $size->height() + )); + } elseif ($this->hasTargetHeight()) { + $resized->setWidth(min( + $this->getProportionalWidth($size), + $size->width() + )); + $resized->setHeight(min( + $this->getTargetHeight(), + $size->height() + )); + } + + return $resized; + } + + /** + * Scale given size to cover target size + * + * @param SizeInterface $size Size to be resized + * @return SizeInterface + */ + public function cover(SizeInterface $size): SizeInterface + { + $resized = new Rectangle($size->width(), $size->height()); + + // auto height + $resized->setWidth($this->getTargetWidth()); + $resized->setHeight($this->getProportionalHeight($size)); + + if ($resized->fitsInto($this->getTargetSize())) { + // auto width + $resized->setWidth($this->getProportionalWidth($size)); + $resized->setHeight($this->getTargetHeight()); + } + + return $resized; + } + + /** + * Scale given size to contain target size + * + * @param SizeInterface $size Size to be resized + * @return SizeInterface + */ + public function contain(SizeInterface $size): SizeInterface + { + $resized = new Rectangle($size->width(), $size->height()); + + // auto height + $resized->setWidth($this->getTargetWidth()); + $resized->setHeight($this->getProportionalHeight($size)); + + if (!$resized->fitsInto($this->getTargetSize())) { + // auto width + $resized->setWidth($this->getProportionalWidth($size)); + $resized->setHeight($this->getTargetHeight()); + } + + return $resized; + } + + /** + * Scale given size to contain target size but prevent upsizing + * + * @param SizeInterface $size Size to be resized + * @return SizeInterface + */ + public function containDown(SizeInterface $size): SizeInterface + { + $resized = new Rectangle($size->width(), $size->height()); + + // auto height + $resized->setWidth( + min($size->width(), $this->getTargetWidth()) + ); + + $resized->setHeight( + min($size->height(), $this->getProportionalHeight($size)) + ); + + if (!$resized->fitsInto($this->getTargetSize())) { + // auto width + $resized->setWidth( + min($size->width(), $this->getProportionalWidth($size)) + ); + $resized->setHeight( + min($size->height(), $this->getTargetHeight()) + ); + } + + return $resized; + } + + /** + * Crop target size out of given size at given position (i.e. move the pivot point) + * + * @param SizeInterface $size + * @param string $position + * @return SizeInterface + */ + public function crop(SizeInterface $size, string $position = 'top-left'): SizeInterface + { + return $this->resize($size)->alignPivotTo( + $size->movePivot($position), + $position + ); + } +} diff --git a/src/Geometry/Traits/HasBackgroundColor.php b/src/Geometry/Traits/HasBackgroundColor.php new file mode 100644 index 00000000..4426ead0 --- /dev/null +++ b/src/Geometry/Traits/HasBackgroundColor.php @@ -0,0 +1,25 @@ +backgroundColor = $color; + + return $this; + } + + public function backgroundColor(): mixed + { + return $this->backgroundColor; + } + + public function hasBackgroundColor(): bool + { + return !empty($this->backgroundColor); + } +} diff --git a/src/Geometry/Traits/HasBorder.php b/src/Geometry/Traits/HasBorder.php new file mode 100644 index 00000000..67142f5a --- /dev/null +++ b/src/Geometry/Traits/HasBorder.php @@ -0,0 +1,43 @@ +setBorderSize($size)->setBorderColor($color); + } + + public function setBorderSize(int $size): self + { + $this->borderSize = $size; + + return $this; + } + + public function borderSize(): int + { + return $this->borderSize; + } + + public function setBorderColor(mixed $color): self + { + $this->borderColor = $color; + + return $this; + } + + public function borderColor(): mixed + { + return $this->borderColor; + } + + public function hasBorder(): bool + { + return $this->borderSize > 0 && !is_null($this->borderColor); + } +} diff --git a/src/Image.php b/src/Image.php new file mode 100644 index 00000000..6601b21a --- /dev/null +++ b/src/Image.php @@ -0,0 +1,777 @@ +driver; + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::core() + */ + public function core(): CoreInterface + { + return $this->core; + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::count() + */ + public function count(): int + { + return $this->core->count(); + } + + /** + * Implementation of IteratorAggregate + * + * @return Traversable + */ + public function getIterator(): Traversable + { + return $this->core; + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::isAnimated() + */ + public function isAnimated(): bool + { + return $this->count() > 1; + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::removeAnimation( + */ + public function removeAnimation(int|string $position = 0): ImageInterface + { + return $this->modify(new RemoveAnimationModifier($position)); + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::loops() + */ + public function loops(): int + { + return $this->core->loops(); + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::setLoops() + */ + public function setLoops(int $loops): ImageInterface + { + $this->core->setLoops($loops); + + return $this; + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::exif() + */ + public function exif(?string $query = null): mixed + { + return is_null($query) ? $this->exif : $this->exif->get($query); + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::modify() + */ + public function modify(ModifierInterface $modifier): ImageInterface + { + return $this->driver->resolve($modifier)->apply($this); + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::analyze() + */ + public function analyze(AnalyzerInterface $analyzer): mixed + { + return $this->driver->resolve($analyzer)->analyze($this); + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::encode() + */ + public function encode(EncoderInterface $encoder): EncodedImage + { + return $this->driver->resolve($encoder)->encode($this); + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::width() + */ + public function width(): int + { + return $this->analyze(new WidthAnalyzer()); + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::height() + */ + public function height(): int + { + return $this->analyze(new HeightAnalyzer()); + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::size() + */ + public function size(): SizeInterface + { + return new Rectangle($this->width(), $this->height()); + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::colorspace() + */ + public function colorspace(): ColorspaceInterface + { + return $this->analyze(new ColorspaceAnalyzer()); + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::setColorspace() + */ + public function setColorspace(string|ColorspaceInterface $colorspace): ImageInterface + { + return $this->modify(new ColorspaceModifier($colorspace)); + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::resolution() + */ + public function resolution(): ResolutionInterface + { + return $this->analyze(new ResolutionAnalyzer()); + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::setResolution() + */ + public function setResolution(float $x, float $y): ImageInterface + { + return $this->modify(new ResolutionModifier($x, $y)); + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::pickColor() + */ + public function pickColor(int $x, int $y, int $frame_key = 0): ColorInterface + { + return $this->analyze(new PixelColorAnalyzer($x, $y, $frame_key)); + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::pickColors() + */ + public function pickColors(int $x, int $y): CollectionInterface + { + return $this->analyze(new PixelColorsAnalyzer($x, $y)); + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::profile() + */ + public function profile(): ProfileInterface + { + return $this->analyze(new ProfileAnalyzer()); + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::setProfile() + */ + public function setProfile(ProfileInterface $profile): ImageInterface + { + return $this->modify(new ProfileModifier($profile)); + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::removeProfile() + */ + public function removeProfile(): ImageInterface + { + return $this->modify(new ProfileRemovalModifier()); + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::sharpen() + */ + public function sharpen(int $amount = 10): ImageInterface + { + return $this->modify(new SharpenModifier($amount)); + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::invert() + */ + public function invert(): ImageInterface + { + return $this->modify(new InvertModifier()); + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::pixelate() + */ + public function pixelate(int $size): ImageInterface + { + return $this->modify(new PixelateModifier($size)); + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::greyscale() + */ + public function greyscale(): ImageInterface + { + return $this->modify(new GreyscaleModifier()); + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::brightness() + */ + public function brightness(int $level): ImageInterface + { + return $this->modify(new BrightnessModifier($level)); + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::contrast() + */ + public function contrast(int $level): ImageInterface + { + return $this->modify(new ContrastModifier($level)); + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::gamma() + */ + public function gamma(float $gamma): ImageInterface + { + return $this->modify(new GammaModifier($gamma)); + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::colorize() + */ + public function colorize(int $red = 0, int $green = 0, int $blue = 0): ImageInterface + { + return $this->modify(new ColorizeModifier($red, $green, $blue)); + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::flip() + */ + public function flip(): ImageInterface + { + return $this->modify(new FlipModifier()); + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::flop() + */ + public function flop(): ImageInterface + { + return $this->modify(new FlopModifier()); + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::blur() + */ + public function blur(int $amount = 5): ImageInterface + { + return $this->modify(new BlurModifier($amount)); + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::rotate() + */ + public function rotate(float $angle, mixed $background = 'ffffff'): ImageInterface + { + return $this->modify(new RotateModifier($angle, $background)); + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::text() + */ + public function text(string $text, int $x, int $y, callable|FontInterface $font): ImageInterface + { + return $this->modify( + new TextModifier( + $text, + new Point($x, $y), + call_user_func(new FontFactory($font)), + ), + ); + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::resize() + */ + public function resize(?int $width = null, ?int $height = null): ImageInterface + { + return $this->modify(new ResizeModifier($width, $height)); + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::resizeDown() + */ + public function resizeDown(?int $width = null, ?int $height = null): ImageInterface + { + return $this->modify(new ResizeDownModifier($width, $height)); + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::scale() + */ + public function scale(?int $width = null, ?int $height = null): ImageInterface + { + return $this->modify(new ScaleModifier($width, $height)); + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::scaleDown() + */ + public function scaleDown(?int $width = null, ?int $height = null): ImageInterface + { + return $this->modify(new ScaleDownModifier($width, $height)); + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::cover() + */ + public function cover(int $width, int $height, string $position = 'center'): ImageInterface + { + return $this->modify(new CoverModifier($width, $height, $position)); + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::coverDown() + */ + public function coverDown(int $width, int $height, string $position = 'center'): ImageInterface + { + return $this->modify(new CoverDownModifier($width, $height, $position)); + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::resizeCanvas() + */ + public function resizeCanvas( + ?int $width = null, + ?int $height = null, + mixed $background = 'ffffff', + string $position = 'center' + ): ImageInterface { + return $this->modify(new ResizeCanvasModifier($width, $height, $background, $position)); + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::resizeCanvasRelative() + */ + public function resizeCanvasRelative( + ?int $width = null, + ?int $height = null, + mixed $background = 'ffffff', + string $position = 'center' + ): ImageInterface { + return $this->modify(new ResizeCanvasRelativeModifier($width, $height, $background, $position)); + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::padDown() + */ + public function pad( + int $width, + int $height, + mixed $background = 'ffffff', + string $position = 'center' + ): ImageInterface { + return $this->modify(new PadModifier($width, $height, $background, $position)); + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::pad() + */ + public function contain( + int $width, + int $height, + mixed $background = 'ffffff', + string $position = 'center' + ): ImageInterface { + return $this->modify(new ContainModifier($width, $height, $background, $position)); + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::crop() + */ + public function crop( + int $width, + int $height, + int $offset_x = 0, + int $offset_y = 0, + string $position = 'top-left' + ): ImageInterface { + return $this->modify(new CropModifier($width, $height, $offset_x, $offset_y, $position)); + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::place() + */ + public function place( + mixed $element, + string $position = 'top-left', + int $offset_x = 0, + int $offset_y = 0 + ): ImageInterface { + return $this->modify(new PlaceModifier($element, $position, $offset_x, $offset_y)); + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::fill() + */ + public function fill(mixed $color, ?int $x = null, ?int $y = null): ImageInterface + { + return $this->modify( + new FillModifier( + $color, + (is_null($x) || is_null($y)) ? null : new Point($x, $y), + ), + ); + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::drawPixel() + */ + public function drawPixel(int $x, int $y, mixed $color): ImageInterface + { + return $this->modify(new DrawPixelModifier(new Point($x, $y), $color)); + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::drawRectangle() + */ + public function drawRectangle(int $x, int $y, callable|Rectangle $init): ImageInterface + { + return $this->modify( + new DrawRectangleModifier( + call_user_func(new RectangleFactory(new Point($x, $y), $init)), + ), + ); + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::drawEllipse() + */ + public function drawEllipse(int $x, int $y, callable $init): ImageInterface + { + return $this->modify( + new DrawEllipseModifier( + call_user_func(new EllipseFactory(new Point($x, $y), $init)), + ), + ); + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::drawCircle() + */ + public function drawCircle(int $x, int $y, callable $init): ImageInterface + { + return $this->modify( + new DrawEllipseModifier( + call_user_func(new CircleFactory(new Point($x, $y), $init)), + ), + ); + } + + public function drawPolygon(callable $init): ImageInterface + { + return $this->modify( + new DrawPolygonModifier( + call_user_func(new PolygonFactory($init)), + ), + ); + } + + public function drawLine(callable $init): ImageInterface + { + return $this->modify( + new DrawLineModifier( + call_user_func(new LineFactory($init)), + ), + ); + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::toJpeg() + */ + public function toJpeg(int $quality = 75): EncodedImageInterface + { + return $this->encode(new JpegEncoder($quality)); + } + + /** + * Alias of self::toJpeg() + * + * @param int $quality + * @return EncodedImageInterface + */ + public function toJpg(int $quality = 75): EncodedImageInterface + { + return $this->toJpeg($quality); + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::toPng() + */ + public function toPng(int $color_limit = 0): EncodedImageInterface + { + return $this->encode(new PngEncoder($color_limit)); + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::toGif() + */ + public function toGif(int $color_limit = 0): EncodedImageInterface + { + return $this->encode(new GifEncoder($color_limit)); + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::toWebp() + */ + public function toWebp(int $quality = 75): EncodedImageInterface + { + return $this->encode(new WebpEncoder($quality)); + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::toBitmap() + */ + public function toBitmap(int $color_limit = 0): EncodedImageInterface + { + return $this->encode(new BmpEncoder($color_limit)); + } + + /** + * Alias if self::toBitmap() + * + * @param int $color_limit + * @return EncodedImageInterface + */ + public function toBmp(int $color_limit = 0): EncodedImageInterface + { + return $this->toBitmap($color_limit); + } + + /** + * {@inheritdoc} + * + * @see ImageInterface::toAvif() + */ + public function toAvif(int $quality = 75): EncodedImageInterface + { + return $this->encode(new AvifEncoder($quality)); + } +} diff --git a/src/ImageManager.php b/src/ImageManager.php new file mode 100644 index 00000000..ad93e39a --- /dev/null +++ b/src/ImageManager.php @@ -0,0 +1,106 @@ +driver = $this->resolveDriver($driver); + } + + /** + * Create image mangager with given driver + * + * @param string|DriverInterface $driver + * @return ImageManager + */ + public static function withDriver(string|DriverInterface $driver): self + { + return new self(self::resolveDriver($driver)); + } + + /** + * Create image manager with GD driver + * + * @return ImageManager + */ + public static function gd(): self + { + return self::withDriver(GdDriver::class); + } + + /** + * Create image manager with Imagick driver + * + * @return ImageManager + */ + public static function imagick(): self + { + return self::withDriver(ImagickDriver::class); + } + + /** + * Create new image instance with given width & height + * + * @param int $width + * @param int $height + * @return ImageInterface + */ + public function create(int $width, int $height): ImageInterface + { + return $this->driver->createImage($width, $height); + } + + /** + * Create new image instance from given source which can be one of the following + * + * - Path in filesystem + * - File Pointer resource + * - SplFileInfo object + * - Raw binary image data + * - Base64 encoded image data + * - Data Uri + * - Intervention\Image\Image Instance + * + * @param mixed $input + * @return ImageInterface + */ + public function read(mixed $input): ImageInterface + { + return $this->driver->handleInput($input); + } + + /** + * Create new animated image by given callback + * + * @param callable $init + * @return ImageInterface + */ + public function animate(callable $init): ImageInterface + { + return $this->driver->createAnimation($init); + } + + /** + * Return driver object + * + * @param string|DriverInterface $driver + * @return DriverInterface + */ + private static function resolveDriver(string|DriverInterface $driver): DriverInterface + { + if (is_object($driver)) { + return $driver; + } + + return new $driver(); + } +} diff --git a/src/Interfaces/AnalyzerInterface.php b/src/Interfaces/AnalyzerInterface.php new file mode 100644 index 00000000..4842827c --- /dev/null +++ b/src/Interfaces/AnalyzerInterface.php @@ -0,0 +1,14 @@ +parse($value); - } - - /** - * Parses given value as color - * - * @param mixed $value - * @return \Intervention\Image\AbstractColor - */ - public function parse($value) - { - switch (true) { - - case is_string($value): - $this->initFromString($value); - break; - - case is_int($value): - $this->initFromInteger($value); - break; - - case is_array($value): - $this->initFromArray($value); - break; - - case is_object($value): - $this->initFromObject($value); - break; - - case is_null($value): - $this->initFromArray([255, 255, 255, 0]); - break; - - default: - throw new NotReadableException( - "Color format ({$value}) cannot be read." - ); - } - - return $this; - } - - /** - * Formats current color instance into given format - * - * @param string $type - * @return mixed - */ - public function format($type) - { - switch (strtolower($type)) { - - case 'rgba': - return $this->getRgba(); - - case 'hex': - return $this->getHex('#'); - - case 'int': - case 'integer': - return $this->getInt(); - - case 'array': - return $this->getArray(); - - case 'obj': - case 'object': - return $this; - - default: - throw new NotSupportedException( - "Color format ({$type}) is not supported." - ); - } - } - - /** - * Reads RGBA values from string into array - * - * @param string $value - * @return array - */ - protected function rgbaFromString($value) - { - $result = false; - - // parse color string in hexidecimal format like #cccccc or cccccc or ccc - $hexPattern = '/^#?([a-f0-9]{1,2})([a-f0-9]{1,2})([a-f0-9]{1,2})$/i'; - - // parse color string in format rgb(140, 140, 140) - $rgbPattern = '/^rgb ?\(([0-9]{1,3}), ?([0-9]{1,3}), ?([0-9]{1,3})\)$/i'; - - // parse color string in format rgba(255, 0, 0, 0.5) - $rgbaPattern = '/^rgba ?\(([0-9]{1,3}), ?([0-9]{1,3}), ?([0-9]{1,3}), ?([0-9.]{1,4})\)$/i'; - - if (preg_match($hexPattern, $value, $matches)) { - $result = []; - $result[0] = strlen($matches[1]) == '1' ? hexdec($matches[1].$matches[1]) : hexdec($matches[1]); - $result[1] = strlen($matches[2]) == '1' ? hexdec($matches[2].$matches[2]) : hexdec($matches[2]); - $result[2] = strlen($matches[3]) == '1' ? hexdec($matches[3].$matches[3]) : hexdec($matches[3]); - $result[3] = 1; - } elseif (preg_match($rgbPattern, $value, $matches)) { - $result = []; - $result[0] = ($matches[1] >= 0 && $matches[1] <= 255) ? intval($matches[1]) : 0; - $result[1] = ($matches[2] >= 0 && $matches[2] <= 255) ? intval($matches[2]) : 0; - $result[2] = ($matches[3] >= 0 && $matches[3] <= 255) ? intval($matches[3]) : 0; - $result[3] = 1; - } elseif (preg_match($rgbaPattern, $value, $matches)) { - $result = []; - $result[0] = ($matches[1] >= 0 && $matches[1] <= 255) ? intval($matches[1]) : 0; - $result[1] = ($matches[2] >= 0 && $matches[2] <= 255) ? intval($matches[2]) : 0; - $result[2] = ($matches[3] >= 0 && $matches[3] <= 255) ? intval($matches[3]) : 0; - $result[3] = ($matches[4] >= 0 && $matches[4] <= 1) ? $matches[4] : 0; - } else { - throw new NotReadableException( - "Unable to read color ({$value})." - ); - } - - return $result; - } -} diff --git a/src/Intervention/Image/AbstractDecoder.php b/src/Intervention/Image/AbstractDecoder.php deleted file mode 100644 index e51d4da3..00000000 --- a/src/Intervention/Image/AbstractDecoder.php +++ /dev/null @@ -1,364 +0,0 @@ -data = $data; - } - - /** - * Init from given URL - * - * @param string $url - * @return \Intervention\Image\Image - */ - public function initFromUrl($url) - { - - $options = [ - 'http' => [ - 'method'=>"GET", - 'protocol_version'=>1.1, // force use HTTP 1.1 for service mesh environment with envoy - 'header'=>"Accept-language: en\r\n". - "User-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36\r\n" - ] - ]; - - $context = stream_context_create($options); - - - if ($data = @file_get_contents($url, false, $context)) { - return $this->initFromBinary($data); - } - - throw new NotReadableException( - "Unable to init from given url (".$url.")." - ); - } - - /** - * Init from given stream - * - * @param StreamInterface|resource $stream - * @return \Intervention\Image\Image - */ - public function initFromStream($stream) - { - if (!$stream instanceof StreamInterface) { - $stream = new Stream($stream); - } - - try { - $offset = $stream->tell(); - } catch (\RuntimeException $e) { - $offset = 0; - } - - $shouldAndCanSeek = $offset !== 0 && $stream->isSeekable(); - - if ($shouldAndCanSeek) { - $stream->rewind(); - } - - try { - $data = $stream->getContents(); - } catch (\RuntimeException $e) { - $data = null; - } - - if ($shouldAndCanSeek) { - $stream->seek($offset); - } - - if ($data) { - return $this->initFromBinary($data); - } - - throw new NotReadableException( - "Unable to init from given stream" - ); - } - - /** - * Determines if current source data is GD resource - * - * @return boolean - */ - public function isGdResource() - { - if (is_resource($this->data)) { - return (get_resource_type($this->data) == 'gd'); - } - - if ($this->data instanceof \GdImage) { - return true; - } - - return false; - } - - /** - * Determines if current source data is Imagick object - * - * @return boolean - */ - public function isImagick() - { - return is_a($this->data, 'Imagick'); - } - - /** - * Determines if current source data is Intervention\Image\Image object - * - * @return boolean - */ - public function isInterventionImage() - { - return is_a($this->data, '\Intervention\Image\Image'); - } - - /** - * Determines if current data is SplFileInfo object - * - * @return boolean - */ - public function isSplFileInfo() - { - return is_a($this->data, 'SplFileInfo'); - } - - /** - * Determines if current data is Symfony UploadedFile component - * - * @return boolean - */ - public function isSymfonyUpload() - { - return is_a($this->data, 'Symfony\Component\HttpFoundation\File\UploadedFile'); - } - - /** - * Determines if current source data is file path - * - * @return boolean - */ - public function isFilePath() - { - if (is_string($this->data)) { - try { - return is_file($this->data); - } catch (\Exception $e) { - return false; - } - } - - return false; - } - - /** - * Determines if current source data is url - * - * @return boolean - */ - public function isUrl() - { - return (bool) filter_var($this->data, FILTER_VALIDATE_URL); - } - - /** - * Determines if current source data is a stream resource - * - * @return boolean - */ - public function isStream() - { - if ($this->data instanceof StreamInterface) return true; - if (!is_resource($this->data)) return false; - if (get_resource_type($this->data) !== 'stream') return false; - - return true; - } - - /** - * Determines if current source data is binary data - * - * @return boolean - */ - public function isBinary() - { - if (is_string($this->data)) { - $mime = finfo_buffer(finfo_open(FILEINFO_MIME_TYPE), $this->data); - return (substr($mime, 0, 4) != 'text' && $mime != 'application/x-empty'); - } - - return false; - } - - /** - * Determines if current source data is data-url - * - * @return boolean - */ - public function isDataUrl() - { - $data = $this->decodeDataUrl($this->data); - - return is_null($data) ? false : true; - } - - /** - * Determines if current source data is base64 encoded - * - * @return boolean - */ - public function isBase64() - { - if (!is_string($this->data)) { - return false; - } - - return base64_encode(base64_decode($this->data)) === str_replace(["\n", "\r"], '', $this->data); - } - - /** - * Initiates new Image from Intervention\Image\Image - * - * @param Image $object - * @return \Intervention\Image\Image - */ - public function initFromInterventionImage($object) - { - return $object; - } - - /** - * Parses and decodes binary image data from data-url - * - * @param string $data_url - * @return string - */ - private function decodeDataUrl($data_url) - { - if (!is_string($data_url)) { - return null; - } - - $pattern = "/^data:(?:image\/[a-zA-Z\-\.]+)(?:charset=\".+\")?;base64,(?P.+)$/"; - preg_match($pattern, str_replace(["\n", "\r"], '', $data_url), $matches); - - if (is_array($matches) && array_key_exists('data', $matches)) { - return base64_decode($matches['data']); - } - - return null; - } - - /** - * Initiates new image from mixed data - * - * @param mixed $data - * @return \Intervention\Image\Image - */ - public function init($data) - { - $this->data = $data; - - switch (true) { - - case $this->isGdResource(): - return $this->initFromGdResource($this->data); - - case $this->isImagick(): - return $this->initFromImagick($this->data); - - case $this->isInterventionImage(): - return $this->initFromInterventionImage($this->data); - - case $this->isSplFileInfo(): - return $this->initFromPath($this->data->getRealPath()); - - case $this->isBinary(): - return $this->initFromBinary($this->data); - - case $this->isUrl(): - return $this->initFromUrl($this->data); - - case $this->isStream(): - return $this->initFromStream($this->data); - - case $this->isDataUrl(): - return $this->initFromBinary($this->decodeDataUrl($this->data)); - - case $this->isFilePath(): - return $this->initFromPath($this->data); - - // isBase64 has to be after isFilePath to prevent false positives - case $this->isBase64(): - return $this->initFromBinary(base64_decode($this->data)); - - default: - throw new NotReadableException("Image source not readable"); - } - } - - /** - * Decoder object transforms to string source data - * - * @return string - */ - public function __toString() - { - return (string) $this->data; - } -} diff --git a/src/Intervention/Image/AbstractDriver.php b/src/Intervention/Image/AbstractDriver.php deleted file mode 100644 index 6c591a79..00000000 --- a/src/Intervention/Image/AbstractDriver.php +++ /dev/null @@ -1,140 +0,0 @@ -decoder->init($data); - } - - /** - * Encodes given image - * - * @param Image $image - * @param string $format - * @param int $quality - * @return \Intervention\Image\Image - */ - public function encode($image, $format, $quality) - { - return $this->encoder->process($image, $format, $quality); - } - - /** - * Executes named command on given image - * - * @param Image $image - * @param string $name - * @param array $arguments - * @return \Intervention\Image\Commands\AbstractCommand - */ - public function executeCommand($image, $name, $arguments) - { - $commandName = $this->getCommandClassName($name); - $command = new $commandName($arguments); - $command->execute($image); - - return $command; - } - - /** - * Returns classname of given command name - * - * @param string $name - * @return string - */ - private function getCommandClassName($name) - { - if (extension_loaded('mbstring')) { - $name = mb_strtoupper(mb_substr($name, 0, 1)) . mb_substr($name, 1); - } else { - $name = strtoupper(substr($name, 0, 1)) . substr($name, 1); - } - - $drivername = $this->getDriverName(); - $classnameLocal = sprintf('\Intervention\Image\%s\Commands\%sCommand', $drivername, ucfirst($name)); - $classnameGlobal = sprintf('\Intervention\Image\Commands\%sCommand', ucfirst($name)); - - if (class_exists($classnameLocal)) { - return $classnameLocal; - } elseif (class_exists($classnameGlobal)) { - return $classnameGlobal; - } - - throw new NotSupportedException( - "Command ({$name}) is not available for driver ({$drivername})." - ); - } - - /** - * Returns name of current driver instance - * - * @return string - */ - public function getDriverName() - { - $reflect = new \ReflectionClass($this); - $namespace = $reflect->getNamespaceName(); - - return substr(strrchr($namespace, "\\"), 1); - } -} diff --git a/src/Intervention/Image/AbstractEncoder.php b/src/Intervention/Image/AbstractEncoder.php deleted file mode 100644 index c25f8bff..00000000 --- a/src/Intervention/Image/AbstractEncoder.php +++ /dev/null @@ -1,271 +0,0 @@ -setImage($image); - $this->setFormat($format); - $this->setQuality($quality); - - switch (strtolower($this->format)) { - - case 'data-url': - $this->result = $this->processDataUrl(); - break; - - case 'gif': - case 'image/gif': - $this->result = $this->processGif(); - break; - - case 'png': - case 'image/png': - case 'image/x-png': - $this->result = $this->processPng(); - break; - - case 'jpg': - case 'jpeg': - case 'jfif': - case 'image/jp2': - case 'image/jpg': - case 'image/jpeg': - case 'image/pjpeg': - case 'image/jfif': - $this->result = $this->processJpeg(); - break; - - case 'tif': - case 'tiff': - case 'image/tiff': - case 'image/tif': - case 'image/x-tif': - case 'image/x-tiff': - $this->result = $this->processTiff(); - break; - - case 'bmp': - case 'ms-bmp': - case 'x-bitmap': - case 'x-bmp': - case 'x-ms-bmp': - case 'x-win-bitmap': - case 'x-windows-bmp': - case 'x-xbitmap': - case 'image/ms-bmp': - case 'image/x-bitmap': - case 'image/x-bmp': - case 'image/x-ms-bmp': - case 'image/x-win-bitmap': - case 'image/x-windows-bmp': - case 'image/x-xbitmap': - $this->result = $this->processBmp(); - break; - - case 'ico': - case 'image/x-ico': - case 'image/x-icon': - case 'image/vnd.microsoft.icon': - $this->result = $this->processIco(); - break; - - case 'psd': - case 'image/vnd.adobe.photoshop': - $this->result = $this->processPsd(); - break; - - case 'webp': - case 'image/webp': - case 'image/x-webp': - $this->result = $this->processWebp(); - break; - - case 'avif': - case 'image/avif': - $this->result = $this->processAvif(); - break; - - case 'heic': - case 'image/heic': - case 'image/heif': - $this->result = $this->processHeic(); - break; - - default: - throw new NotSupportedException( - "Encoding format ({$this->format}) is not supported." - ); - } - - $this->setImage(null); - - return $image->setEncoded($this->result); - } - - /** - * Processes and returns encoded image as data-url string - * - * @return string - */ - protected function processDataUrl() - { - $mime = $this->image->mime ? $this->image->mime : 'image/png'; - - return sprintf('data:%s;base64,%s', - $mime, - base64_encode($this->process($this->image, $mime, $this->quality)) - ); - } - - /** - * Sets image to process - * - * @param Image $image - */ - protected function setImage($image) - { - $this->image = $image; - } - - /** - * Determines output format - * - * @param string $format - */ - protected function setFormat($format = null) - { - if ($format == '' && $this->image instanceof Image) { - $format = $this->image->mime; - } - - $this->format = $format ? $format : 'jpg'; - - return $this; - } - - /** - * Determines output quality - * - * @param int $quality - */ - protected function setQuality($quality) - { - $quality = is_null($quality) ? 90 : $quality; - $quality = $quality === 0 ? 1 : $quality; - - if ($quality < 0 || $quality > 100) { - throw new InvalidArgumentException( - 'Quality must range from 0 to 100.' - ); - } - - $this->quality = intval($quality); - - return $this; - } -} diff --git a/src/Intervention/Image/AbstractFont.php b/src/Intervention/Image/AbstractFont.php deleted file mode 100644 index 35c1825a..00000000 --- a/src/Intervention/Image/AbstractFont.php +++ /dev/null @@ -1,295 +0,0 @@ -text = $text; - } - - /** - * Set text to be written - * - * @param String $text - * @return self - */ - public function text($text) - { - $this->text = $text; - - return $this; - } - - /** - * Get text to be written - * - * @return String - */ - public function getText() - { - return $this->text; - } - - /** - * Set font size in pixels - * - * @param int $size - * @return self - */ - public function size($size) - { - $this->size = $size; - - return $this; - } - - /** - * Get font size in pixels - * - * @return int - */ - public function getSize() - { - return $this->size; - } - - /** - * Set color of text to be written - * - * @param mixed $color - * @return self - */ - public function color($color) - { - $this->color = $color; - - return $this; - } - - /** - * Get color of text - * - * @return mixed - */ - public function getColor() - { - return $this->color; - } - - /** - * Set rotation angle of text - * - * @param int $angle - * @return self - */ - public function angle($angle) - { - $this->angle = $angle; - - return $this; - } - - /** - * Get rotation angle of text - * - * @return int - */ - public function getAngle() - { - return $this->angle; - } - - /** - * Set horizontal text alignment - * - * @param string $align - * @return self - */ - public function align($align) - { - $this->align = $align; - - return $this; - } - - /** - * Get horizontal text alignment - * - * @return string - */ - public function getAlign() - { - return $this->align; - } - - /** - * Set vertical text alignment - * - * @param string $valign - * @return self - */ - public function valign($valign) - { - $this->valign = $valign; - - return $this; - } - - /** - * Get vertical text alignment - * - * @return string - */ - public function getValign() - { - return $this->valign; - } - - /** - * Set text kerning - * - * @param string $kerning - * @return void - */ - public function kerning($kerning) - { - $this->kerning = $kerning; - } - - /** - * Get kerning - * - * @return float - */ - public function getKerning() - { - return $this->kerning; - } - - /** - * Set path to font file - * - * @param string $file - * @return self - */ - public function file($file) - { - $this->file = $file; - - return $this; - } - - /** - * Get path to font file - * - * @return string - */ - public function getFile() - { - return $this->file; - } - - /** - * Checks if current font has access to an applicable font file - * - * @return boolean - */ - protected function hasApplicableFontFile() - { - if (is_string($this->file)) { - return file_exists($this->file); - } - - return false; - } - - /** - * Counts lines of text to be written - * - * @return int - */ - public function countLines() - { - return count(explode(PHP_EOL, $this->text)); - } -} diff --git a/src/Intervention/Image/AbstractShape.php b/src/Intervention/Image/AbstractShape.php deleted file mode 100644 index cd4a9f1c..00000000 --- a/src/Intervention/Image/AbstractShape.php +++ /dev/null @@ -1,71 +0,0 @@ -background = $color; - } - - /** - * Set border width and color of current shape - * - * @param int $width - * @param string $color - * @return void - */ - public function border($width, $color = null) - { - $this->border_width = is_numeric($width) ? intval($width) : 0; - $this->border_color = is_null($color) ? '#000000' : $color; - } - - /** - * Determines if current shape has border - * - * @return boolean - */ - public function hasBorder() - { - return ($this->border_width >= 1); - } -} diff --git a/src/Intervention/Image/Commands/AbstractCommand.php b/src/Intervention/Image/Commands/AbstractCommand.php deleted file mode 100644 index d9cdd748..00000000 --- a/src/Intervention/Image/Commands/AbstractCommand.php +++ /dev/null @@ -1,79 +0,0 @@ -arguments = $arguments; - } - - /** - * Creates new argument instance from given argument key - * - * @param int $key - * @return \Intervention\Image\Commands\Argument - */ - public function argument($key) - { - return new Argument($this, $key); - } - - /** - * Returns output data of current command - * - * @return mixed - */ - public function getOutput() - { - return $this->output ? $this->output : null; - } - - /** - * Determines if current instance has output data - * - * @return boolean - */ - public function hasOutput() - { - return ! is_null($this->output); - } - - /** - * Sets output data of current command - * - * @param mixed $value - */ - public function setOutput($value) - { - $this->output = $value; - } -} diff --git a/src/Intervention/Image/Commands/Argument.php b/src/Intervention/Image/Commands/Argument.php deleted file mode 100644 index 9538199f..00000000 --- a/src/Intervention/Image/Commands/Argument.php +++ /dev/null @@ -1,225 +0,0 @@ -command = $command; - $this->key = $key; - } - - /** - * Returns name of current arguments command - * - * @return string - */ - public function getCommandName() - { - preg_match("/\\\\([\w]+)Command$/", get_class($this->command), $matches); - return isset($matches[1]) ? lcfirst($matches[1]).'()' : 'Method'; - } - - /** - * Returns value of current argument - * - * @param mixed $default - * @return mixed - */ - public function value($default = null) - { - $arguments = $this->command->arguments; - - if (is_array($arguments)) { - return isset($arguments[$this->key]) ? $arguments[$this->key] : $default; - } - - return $default; - } - - /** - * Defines current argument as required - * - * @return \Intervention\Image\Commands\Argument - */ - public function required() - { - if ( ! array_key_exists($this->key, $this->command->arguments)) { - throw new InvalidArgumentException( - sprintf("Missing argument %d for %s", $this->key + 1, $this->getCommandName()) - ); - } - - return $this; - } - - /** - * Determines that current argument must be of given type - * - * @return \Intervention\Image\Commands\Argument - */ - public function type($type) - { - $valid = true; - $value = $this->value(); - - if ($value === null) { - return $this; - } - - switch (strtolower($type)) { - case 'bool': - case 'boolean': - $valid = \is_bool($value); - $message = '%s accepts only boolean values as argument %d.'; - break; - case 'int': - case 'integer': - $valid = \is_int($value); - $message = '%s accepts only integer values as argument %d.'; - break; - case 'num': - case 'numeric': - $valid = is_numeric($value); - $message = '%s accepts only numeric values as argument %d.'; - break; - case 'str': - case 'string': - $valid = \is_string($value); - $message = '%s accepts only string values as argument %d.'; - break; - case 'array': - $valid = \is_array($value); - $message = '%s accepts only array as argument %d.'; - break; - case 'closure': - $valid = is_a($value, '\Closure'); - $message = '%s accepts only Closure as argument %d.'; - break; - case 'digit': - $valid = $this->isDigit($value); - $message = '%s accepts only integer values as argument %d.'; - break; - } - - if (! $valid) { - $commandName = $this->getCommandName(); - $argument = $this->key + 1; - - if (isset($message)) { - $message = sprintf($message, $commandName, $argument); - } else { - $message = sprintf('Missing argument for %d.', $argument); - } - - throw new InvalidArgumentException( - $message - ); - } - - return $this; - } - - /** - * Determines that current argument value must be numeric between given values - * - * @return \Intervention\Image\Commands\Argument - */ - public function between($x, $y) - { - $value = $this->type('numeric')->value(); - - if (is_null($value)) { - return $this; - } - - $alpha = min($x, $y); - $omega = max($x, $y); - - if ($value < $alpha || $value > $omega) { - throw new InvalidArgumentException( - sprintf('Argument %d must be between %s and %s.', $this->key, $x, $y) - ); - } - - return $this; - } - - /** - * Determines that current argument must be over a minimum value - * - * @return \Intervention\Image\Commands\Argument - */ - public function min($value) - { - $v = $this->type('numeric')->value(); - - if (is_null($v)) { - return $this; - } - - if ($v < $value) { - throw new InvalidArgumentException( - sprintf('Argument %d must be at least %s.', $this->key, $value) - ); - } - - return $this; - } - - /** - * Determines that current argument must be under a maxiumum value - * - * @return \Intervention\Image\Commands\Argument - */ - public function max($value) - { - $v = $this->type('numeric')->value(); - - if (is_null($v)) { - return $this; - } - - if ($v > $value) { - throw new InvalidArgumentException( - sprintf('Argument %d may not be greater than %s.', $this->key, $value) - ); - } - - return $this; - } - - /** - * Checks if value is "PHP" integer (120 but also 120.0) - * - * @param mixed $value - * @return boolean - */ - private function isDigit($value) - { - return is_numeric($value) ? intval($value) == $value : false; - } -} diff --git a/src/Intervention/Image/Commands/ChecksumCommand.php b/src/Intervention/Image/Commands/ChecksumCommand.php deleted file mode 100644 index 9acc4030..00000000 --- a/src/Intervention/Image/Commands/ChecksumCommand.php +++ /dev/null @@ -1,29 +0,0 @@ -getSize(); - - for ($x=0; $x <= ($size->width-1); $x++) { - for ($y=0; $y <= ($size->height-1); $y++) { - $colors[] = $image->pickColor($x, $y, 'array'); - } - } - - $this->setOutput(md5(serialize($colors))); - - return true; - } -} diff --git a/src/Intervention/Image/Commands/CircleCommand.php b/src/Intervention/Image/Commands/CircleCommand.php deleted file mode 100644 index c627818e..00000000 --- a/src/Intervention/Image/Commands/CircleCommand.php +++ /dev/null @@ -1,35 +0,0 @@ -argument(0)->type('numeric')->required()->value(); - $x = $this->argument(1)->type('numeric')->required()->value(); - $y = $this->argument(2)->type('numeric')->required()->value(); - $callback = $this->argument(3)->type('closure')->value(); - - $circle_classname = sprintf('\Intervention\Image\%s\Shapes\CircleShape', - $image->getDriver()->getDriverName()); - - $circle = new $circle_classname($diameter); - - if ($callback instanceof Closure) { - $callback($circle); - } - - $circle->applyToImage($image, $x, $y); - - return true; - } -} diff --git a/src/Intervention/Image/Commands/EllipseCommand.php b/src/Intervention/Image/Commands/EllipseCommand.php deleted file mode 100644 index 4637e020..00000000 --- a/src/Intervention/Image/Commands/EllipseCommand.php +++ /dev/null @@ -1,36 +0,0 @@ -argument(0)->type('numeric')->required()->value(); - $height = $this->argument(1)->type('numeric')->required()->value(); - $x = $this->argument(2)->type('numeric')->required()->value(); - $y = $this->argument(3)->type('numeric')->required()->value(); - $callback = $this->argument(4)->type('closure')->value(); - - $ellipse_classname = sprintf('\Intervention\Image\%s\Shapes\EllipseShape', - $image->getDriver()->getDriverName()); - - $ellipse = new $ellipse_classname($width, $height); - - if ($callback instanceof Closure) { - $callback($ellipse); - } - - $ellipse->applyToImage($image, $x, $y); - - return true; - } -} diff --git a/src/Intervention/Image/Commands/ExifCommand.php b/src/Intervention/Image/Commands/ExifCommand.php deleted file mode 100644 index 063df6ef..00000000 --- a/src/Intervention/Image/Commands/ExifCommand.php +++ /dev/null @@ -1,61 +0,0 @@ -argument(0)->value(); - - // try to read exif data from image file - try { - if ($image->dirname && $image->basename) { - $stream = $image->dirname . '/' . $image->basename; - } elseif (version_compare(PHP_VERSION, '7.2.0', '>=')) { - // https://www.php.net/manual/en/function.exif-read-data.php#refsect1-function.exif-read-data-changelog - $stream = $image->stream()->detach(); - } else { - // https://bugs.php.net/bug.php?id=65187 - $stream = $image->encode('data-url')->encoded; - } - - $data = @exif_read_data($stream); - - if (!is_null($key) && is_array($data)) { - $data = array_key_exists($key, $data) ? $data[$key] : false; - } - - } catch (\Exception $e) { - throw new NotReadableException( - sprintf( - "Cannot read the Exif data from the filename (%s) provided ", - $image->dirname . '/' . $image->basename - ), - $e->getCode(), - $e - ); - } - - $this->setOutput($data); - return true; - } -} diff --git a/src/Intervention/Image/Commands/IptcCommand.php b/src/Intervention/Image/Commands/IptcCommand.php deleted file mode 100644 index b78a2a8e..00000000 --- a/src/Intervention/Image/Commands/IptcCommand.php +++ /dev/null @@ -1,68 +0,0 @@ -argument(0)->value(); - - $info = []; - @getimagesize($image->dirname .'/'. $image->basename, $info); - - $data = []; - - if (array_key_exists('APP13', $info)) { - $iptc = iptcparse($info['APP13']); - - if (is_array($iptc)) { - $data['DocumentTitle'] = isset($iptc["2#005"][0]) ? $iptc["2#005"][0] : null; - $data['Urgency'] = isset($iptc["2#010"][0]) ? $iptc["2#010"][0] : null; - $data['Category'] = isset($iptc["2#015"][0]) ? $iptc["2#015"][0] : null; - $data['Subcategories'] = isset($iptc["2#020"][0]) ? $iptc["2#020"][0] : null; - $data['Keywords'] = isset($iptc["2#025"][0]) ? $iptc["2#025"] : null; - $data['ReleaseDate'] = isset($iptc["2#030"][0]) ? $iptc["2#030"][0] : null; - $data['ReleaseTime'] = isset($iptc["2#035"][0]) ? $iptc["2#035"][0] : null; - $data['SpecialInstructions'] = isset($iptc["2#040"][0]) ? $iptc["2#040"][0] : null; - $data['CreationDate'] = isset($iptc["2#055"][0]) ? $iptc["2#055"][0] : null; - $data['CreationTime'] = isset($iptc["2#060"][0]) ? $iptc["2#060"][0] : null; - $data['AuthorByline'] = isset($iptc["2#080"][0]) ? $iptc["2#080"][0] : null; - $data['AuthorTitle'] = isset($iptc["2#085"][0]) ? $iptc["2#085"][0] : null; - $data['City'] = isset($iptc["2#090"][0]) ? $iptc["2#090"][0] : null; - $data['SubLocation'] = isset($iptc["2#092"][0]) ? $iptc["2#092"][0] : null; - $data['State'] = isset($iptc["2#095"][0]) ? $iptc["2#095"][0] : null; - $data['Country'] = isset($iptc["2#101"][0]) ? $iptc["2#101"][0] : null; - $data['OTR'] = isset($iptc["2#103"][0]) ? $iptc["2#103"][0] : null; - $data['Headline'] = isset($iptc["2#105"][0]) ? $iptc["2#105"][0] : null; - $data['Source'] = isset($iptc["2#110"][0]) ? $iptc["2#110"][0] : null; - $data['PhotoSource'] = isset($iptc["2#115"][0]) ? $iptc["2#115"][0] : null; - $data['Copyright'] = isset($iptc["2#116"][0]) ? $iptc["2#116"][0] : null; - $data['Caption'] = isset($iptc["2#120"][0]) ? $iptc["2#120"][0] : null; - $data['CaptionWriter'] = isset($iptc["2#122"][0]) ? $iptc["2#122"][0] : null; - } - } - - if (! is_null($key) && is_array($data)) { - $data = array_key_exists($key, $data) ? $data[$key] : false; - } - - $this->setOutput($data); - - return true; - } -} diff --git a/src/Intervention/Image/Commands/LineCommand.php b/src/Intervention/Image/Commands/LineCommand.php deleted file mode 100644 index a068c662..00000000 --- a/src/Intervention/Image/Commands/LineCommand.php +++ /dev/null @@ -1,36 +0,0 @@ -argument(0)->type('numeric')->required()->value(); - $y1 = $this->argument(1)->type('numeric')->required()->value(); - $x2 = $this->argument(2)->type('numeric')->required()->value(); - $y2 = $this->argument(3)->type('numeric')->required()->value(); - $callback = $this->argument(4)->type('closure')->value(); - - $line_classname = sprintf('\Intervention\Image\%s\Shapes\LineShape', - $image->getDriver()->getDriverName()); - - $line = new $line_classname($x2, $y2); - - if ($callback instanceof Closure) { - $callback($line); - } - - $line->applyToImage($image, $x1, $y1); - - return true; - } -} diff --git a/src/Intervention/Image/Commands/OrientateCommand.php b/src/Intervention/Image/Commands/OrientateCommand.php deleted file mode 100644 index 552482cb..00000000 --- a/src/Intervention/Image/Commands/OrientateCommand.php +++ /dev/null @@ -1,48 +0,0 @@ -exif('Orientation')) { - - case 2: - $image->flip(); - break; - - case 3: - $image->rotate(180); - break; - - case 4: - $image->rotate(180)->flip(); - break; - - case 5: - $image->rotate(270)->flip(); - break; - - case 6: - $image->rotate(270); - break; - - case 7: - $image->rotate(90)->flip(); - break; - - case 8: - $image->rotate(90); - break; - } - - return true; - } -} diff --git a/src/Intervention/Image/Commands/PolygonCommand.php b/src/Intervention/Image/Commands/PolygonCommand.php deleted file mode 100644 index a2fa9978..00000000 --- a/src/Intervention/Image/Commands/PolygonCommand.php +++ /dev/null @@ -1,49 +0,0 @@ -argument(0)->type('array')->required()->value(); - $callback = $this->argument(1)->type('closure')->value(); - - $vertices_count = count($points); - - // check if number if coordinates is even - if ($vertices_count % 2 !== 0) { - throw new InvalidArgumentException( - "The number of given polygon vertices must be even." - ); - } - - if ($vertices_count < 6) { - throw new InvalidArgumentException( - "You must have at least 3 points in your array." - ); - } - - $polygon_classname = sprintf('\Intervention\Image\%s\Shapes\PolygonShape', - $image->getDriver()->getDriverName()); - - $polygon = new $polygon_classname($points); - - if ($callback instanceof Closure) { - $callback($polygon); - } - - $polygon->applyToImage($image); - - return true; - } -} diff --git a/src/Intervention/Image/Commands/PsrResponseCommand.php b/src/Intervention/Image/Commands/PsrResponseCommand.php deleted file mode 100644 index 4e515351..00000000 --- a/src/Intervention/Image/Commands/PsrResponseCommand.php +++ /dev/null @@ -1,45 +0,0 @@ -argument(0)->value(); - $quality = $this->argument(1)->between(0, 100)->value(); - - //Encoded property will be populated at this moment - $stream = $image->stream($format, $quality); - - $mimetype = finfo_buffer( - finfo_open(FILEINFO_MIME_TYPE), - $image->getEncoded() - ); - - $this->setOutput(new Response( - 200, - [ - 'Content-Type' => $mimetype, - 'Content-Length' => strlen($image->getEncoded()) - ], - $stream - )); - - return true; - } -} diff --git a/src/Intervention/Image/Commands/RectangleCommand.php b/src/Intervention/Image/Commands/RectangleCommand.php deleted file mode 100644 index 24378b38..00000000 --- a/src/Intervention/Image/Commands/RectangleCommand.php +++ /dev/null @@ -1,36 +0,0 @@ -argument(0)->type('numeric')->required()->value(); - $y1 = $this->argument(1)->type('numeric')->required()->value(); - $x2 = $this->argument(2)->type('numeric')->required()->value(); - $y2 = $this->argument(3)->type('numeric')->required()->value(); - $callback = $this->argument(4)->type('closure')->value(); - - $rectangle_classname = sprintf('\Intervention\Image\%s\Shapes\RectangleShape', - $image->getDriver()->getDriverName()); - - $rectangle = new $rectangle_classname($x1, $y1, $x2, $y2); - - if ($callback instanceof Closure) { - $callback($rectangle); - } - - $rectangle->applyToImage($image, $x1, $y1); - - return true; - } -} diff --git a/src/Intervention/Image/Commands/ResponseCommand.php b/src/Intervention/Image/Commands/ResponseCommand.php deleted file mode 100644 index 7903b5af..00000000 --- a/src/Intervention/Image/Commands/ResponseCommand.php +++ /dev/null @@ -1,26 +0,0 @@ -argument(0)->value(); - $quality = $this->argument(1)->between(0, 100)->value(); - - $response = new Response($image, $format, $quality); - - $this->setOutput($response->make()); - - return true; - } -} diff --git a/src/Intervention/Image/Commands/StreamCommand.php b/src/Intervention/Image/Commands/StreamCommand.php deleted file mode 100644 index bc2ff9ef..00000000 --- a/src/Intervention/Image/Commands/StreamCommand.php +++ /dev/null @@ -1,39 +0,0 @@ -argument(0)->value(); - $quality = $this->argument(1)->between(0, 100)->value(); - $data = $image->encode($format, $quality)->getEncoded(); - - $this->setOutput($this->getStream($data)); - - return true; - } - - /** - * Create stream from given data - * - * @param string $data - * @return \Psr\Http\Message\StreamInterface - */ - protected function getStream($data) - { - if (class_exists(\GuzzleHttp\Psr7\Utils::class)) { - return \GuzzleHttp\Psr7\Utils::streamFor($data); // guzzlehttp/psr7 >= 2.0 - } - - return \GuzzleHttp\Psr7\stream_for($data); // guzzlehttp/psr7 < 2.0 - } -} diff --git a/src/Intervention/Image/Commands/TextCommand.php b/src/Intervention/Image/Commands/TextCommand.php deleted file mode 100644 index 3c60b4e7..00000000 --- a/src/Intervention/Image/Commands/TextCommand.php +++ /dev/null @@ -1,34 +0,0 @@ -argument(0)->required()->value(); - $x = $this->argument(1)->type('numeric')->value(0); - $y = $this->argument(2)->type('numeric')->value(0); - $callback = $this->argument(3)->type('closure')->value(); - - $fontclassname = sprintf('\Intervention\Image\%s\Font', - $image->getDriver()->getDriverName()); - - $font = new $fontclassname($text); - - if ($callback instanceof Closure) { - $callback($font); - } - - $font->applyToImage($image, $x, $y); - - return true; - } -} diff --git a/src/Intervention/Image/Constraint.php b/src/Intervention/Image/Constraint.php deleted file mode 100644 index 44bdd67a..00000000 --- a/src/Intervention/Image/Constraint.php +++ /dev/null @@ -1,92 +0,0 @@ -size = $size; - } - - /** - * Returns current size of constraint - * - * @return \Intervention\Image\Size - */ - public function getSize() - { - return $this->size; - } - - /** - * Fix the given argument in current constraint - * - * @param int $type - * @return void - */ - public function fix($type) - { - $this->fixed = ($this->fixed & ~(1 << $type)) | (1 << $type); - } - - /** - * Checks if given argument is fixed in current constraint - * - * @param int $type - * @return boolean - */ - public function isFixed($type) - { - return (bool) ($this->fixed & (1 << $type)); - } - - /** - * Fixes aspect ratio in current constraint - * - * @return void - */ - public function aspectRatio() - { - $this->fix(self::ASPECTRATIO); - } - - /** - * Fixes possibility to size up in current constraint - * - * @return void - */ - public function upsize() - { - $this->fix(self::UPSIZE); - } -} diff --git a/src/Intervention/Image/Exception/ImageException.php b/src/Intervention/Image/Exception/ImageException.php deleted file mode 100644 index 83e6b91f..00000000 --- a/src/Intervention/Image/Exception/ImageException.php +++ /dev/null @@ -1,8 +0,0 @@ -dirname = array_key_exists('dirname', $info) ? $info['dirname'] : null; - $this->basename = array_key_exists('basename', $info) ? $info['basename'] : null; - $this->extension = array_key_exists('extension', $info) ? $info['extension'] : null; - $this->filename = array_key_exists('filename', $info) ? $info['filename'] : null; - - if (file_exists($path) && is_file($path)) { - $this->mime = finfo_file(finfo_open(FILEINFO_MIME_TYPE), $path); - } - - return $this; - } - - /** - * Get file size - * - * @return mixed - */ - public function filesize() - { - $path = $this->basePath(); - - if (file_exists($path) && is_file($path)) { - return filesize($path); - } - - return false; - } - - /** - * Get fully qualified path - * - * @return string - */ - public function basePath() - { - if ($this->dirname && $this->basename) { - return ($this->dirname .'/'. $this->basename); - } - - return null; - } - -} diff --git a/src/Intervention/Image/Filters/DemoFilter.php b/src/Intervention/Image/Filters/DemoFilter.php deleted file mode 100644 index 4e8f92b8..00000000 --- a/src/Intervention/Image/Filters/DemoFilter.php +++ /dev/null @@ -1,44 +0,0 @@ -size = is_numeric($size) ? intval($size) : self::DEFAULT_SIZE; - } - - /** - * Applies filter effects to given image - * - * @param \Intervention\Image\Image $image - * @return \Intervention\Image\Image - */ - public function applyFilter(Image $image) - { - $image->pixelate($this->size); - $image->greyscale(); - - return $image; - } -} diff --git a/src/Intervention/Image/Filters/FilterInterface.php b/src/Intervention/Image/Filters/FilterInterface.php deleted file mode 100644 index 88f6cbfe..00000000 --- a/src/Intervention/Image/Filters/FilterInterface.php +++ /dev/null @@ -1,16 +0,0 @@ -a = ($value >> 24) & 0xFF; - $this->r = ($value >> 16) & 0xFF; - $this->g = ($value >> 8) & 0xFF; - $this->b = $value & 0xFF; - } - - /** - * Initiates color object from given array - * - * @param array $value - * @return \Intervention\Image\AbstractColor - */ - public function initFromArray($array) - { - $array = array_values($array); - - if (count($array) == 4) { - - // color array with alpha value - list($r, $g, $b, $a) = $array; - $this->a = $this->alpha2gd($a); - - } elseif (count($array) == 3) { - - // color array without alpha value - list($r, $g, $b) = $array; - $this->a = 0; - - } - - $this->r = $r; - $this->g = $g; - $this->b = $b; - } - - /** - * Initiates color object from given string - * - * @param string $value - * @return \Intervention\Image\AbstractColor - */ - public function initFromString($value) - { - if ($color = $this->rgbaFromString($value)) { - $this->r = $color[0]; - $this->g = $color[1]; - $this->b = $color[2]; - $this->a = $this->alpha2gd($color[3]); - } - } - - /** - * Initiates color object from given R, G and B values - * - * @param int $r - * @param int $g - * @param int $b - * @return \Intervention\Image\AbstractColor - */ - public function initFromRgb($r, $g, $b) - { - $this->r = intval($r); - $this->g = intval($g); - $this->b = intval($b); - $this->a = 0; - } - - /** - * Initiates color object from given R, G, B and A values - * - * @param int $r - * @param int $g - * @param int $b - * @param float $a - * @return \Intervention\Image\AbstractColor - */ - public function initFromRgba($r, $g, $b, $a = 1) - { - $this->r = intval($r); - $this->g = intval($g); - $this->b = intval($b); - $this->a = $this->alpha2gd($a); - } - - /** - * Initiates color object from given ImagickPixel object - * - * @param ImagickPixel $value - * @return \Intervention\Image\AbstractColor - */ - public function initFromObject($value) - { - throw new NotSupportedException( - "GD colors cannot init from ImagickPixel objects." - ); - } - - /** - * Calculates integer value of current color instance - * - * @return int - */ - public function getInt() - { - return ($this->a << 24) + ($this->r << 16) + ($this->g << 8) + $this->b; - } - - /** - * Calculates hexadecimal value of current color instance - * - * @param string $prefix - * @return string - */ - public function getHex($prefix = '') - { - return sprintf('%s%02x%02x%02x', $prefix, $this->r, $this->g, $this->b); - } - - /** - * Calculates RGB(A) in array format of current color instance - * - * @return array - */ - public function getArray() - { - return [$this->r, $this->g, $this->b, round(1 - $this->a / 127, 2)]; - } - - /** - * Calculates RGBA in string format of current color instance - * - * @return string - */ - public function getRgba() - { - return sprintf('rgba(%d, %d, %d, %.2F)', $this->r, $this->g, $this->b, round(1 - $this->a / 127, 2)); - } - - /** - * Determines if current color is different from given color - * - * @param AbstractColor $color - * @param int $tolerance - * @return boolean - */ - public function differs(AbstractColor $color, $tolerance = 0) - { - $color_tolerance = round($tolerance * 2.55); - $alpha_tolerance = round($tolerance * 1.27); - - $delta = [ - 'r' => abs($color->r - $this->r), - 'g' => abs($color->g - $this->g), - 'b' => abs($color->b - $this->b), - 'a' => abs($color->a - $this->a) - ]; - - return ( - $delta['r'] > $color_tolerance || - $delta['g'] > $color_tolerance || - $delta['b'] > $color_tolerance || - $delta['a'] > $alpha_tolerance - ); - } - - /** - * Convert rgba alpha (0-1) value to gd value (0-127) - * - * @param float $input - * @return int - */ - private function alpha2gd($input) - { - $oldMin = 0; - $oldMax = 1; - - $newMin = 127; - $newMax = 0; - - return ceil(((($input- $oldMin) * ($newMax - $newMin)) / ($oldMax - $oldMin)) + $newMin); - } -} diff --git a/src/Intervention/Image/Gd/Commands/BackupCommand.php b/src/Intervention/Image/Gd/Commands/BackupCommand.php deleted file mode 100644 index 310dc03a..00000000 --- a/src/Intervention/Image/Gd/Commands/BackupCommand.php +++ /dev/null @@ -1,25 +0,0 @@ -argument(0)->value(); - - // clone current image resource - $clone = clone $image; - $image->setBackup($clone->getCore(), $backupName); - - return true; - } -} diff --git a/src/Intervention/Image/Gd/Commands/BlurCommand.php b/src/Intervention/Image/Gd/Commands/BlurCommand.php deleted file mode 100644 index c4fca0ea..00000000 --- a/src/Intervention/Image/Gd/Commands/BlurCommand.php +++ /dev/null @@ -1,25 +0,0 @@ -argument(0)->between(0, 100)->value(1); - - for ($i=0; $i < intval($amount); $i++) { - imagefilter($image->getCore(), IMG_FILTER_GAUSSIAN_BLUR); - } - - return true; - } -} diff --git a/src/Intervention/Image/Gd/Commands/BrightnessCommand.php b/src/Intervention/Image/Gd/Commands/BrightnessCommand.php deleted file mode 100644 index a164ad3e..00000000 --- a/src/Intervention/Image/Gd/Commands/BrightnessCommand.php +++ /dev/null @@ -1,21 +0,0 @@ -argument(0)->between(-100, 100)->required()->value(); - - return imagefilter($image->getCore(), IMG_FILTER_BRIGHTNESS, round($level * 2.55,0)); - } -} diff --git a/src/Intervention/Image/Gd/Commands/ColorizeCommand.php b/src/Intervention/Image/Gd/Commands/ColorizeCommand.php deleted file mode 100644 index 410917b3..00000000 --- a/src/Intervention/Image/Gd/Commands/ColorizeCommand.php +++ /dev/null @@ -1,29 +0,0 @@ -argument(0)->between(-100, 100)->required()->value(); - $green = $this->argument(1)->between(-100, 100)->required()->value(); - $blue = $this->argument(2)->between(-100, 100)->required()->value(); - - // normalize colorize levels - $red = round($red * 2.55); - $green = round($green * 2.55); - $blue = round($blue * 2.55); - - // apply filter - return imagefilter($image->getCore(), IMG_FILTER_COLORIZE, $red, $green, $blue); - } -} diff --git a/src/Intervention/Image/Gd/Commands/ContrastCommand.php b/src/Intervention/Image/Gd/Commands/ContrastCommand.php deleted file mode 100644 index 916c41f8..00000000 --- a/src/Intervention/Image/Gd/Commands/ContrastCommand.php +++ /dev/null @@ -1,21 +0,0 @@ -argument(0)->between(-100, 100)->required()->value(); - - return imagefilter($image->getCore(), IMG_FILTER_CONTRAST, ($level * -1)); - } -} diff --git a/src/Intervention/Image/Gd/Commands/CropCommand.php b/src/Intervention/Image/Gd/Commands/CropCommand.php deleted file mode 100644 index b7f59542..00000000 --- a/src/Intervention/Image/Gd/Commands/CropCommand.php +++ /dev/null @@ -1,40 +0,0 @@ -argument(0)->type('digit')->required()->value(); - $height = $this->argument(1)->type('digit')->required()->value(); - $x = $this->argument(2)->type('digit')->value(); - $y = $this->argument(3)->type('digit')->value(); - - if (is_null($width) || is_null($height)) { - throw new \Intervention\Image\Exception\InvalidArgumentException( - "Width and height of cutout needs to be defined." - ); - } - - $cropped = new Size($width, $height); - $position = new Point($x, $y); - - // align boxes - if (is_null($x) && is_null($y)) { - $position = $image->getSize()->align('center')->relativePosition($cropped->align('center')); - } - - // crop image core - return $this->modify($image, 0, 0, $position->x, $position->y, $cropped->width, $cropped->height, $cropped->width, $cropped->height); - } -} diff --git a/src/Intervention/Image/Gd/Commands/DestroyCommand.php b/src/Intervention/Image/Gd/Commands/DestroyCommand.php deleted file mode 100644 index 4503d10f..00000000 --- a/src/Intervention/Image/Gd/Commands/DestroyCommand.php +++ /dev/null @@ -1,27 +0,0 @@ -getCore()); - - // destroy backups - foreach ($image->getBackups() as $backup) { - imagedestroy($backup); - } - - return true; - } -} diff --git a/src/Intervention/Image/Gd/Commands/FillCommand.php b/src/Intervention/Image/Gd/Commands/FillCommand.php deleted file mode 100644 index cf190821..00000000 --- a/src/Intervention/Image/Gd/Commands/FillCommand.php +++ /dev/null @@ -1,69 +0,0 @@ -argument(0)->value(); - $x = $this->argument(1)->type('digit')->value(); - $y = $this->argument(2)->type('digit')->value(); - - $width = $image->getWidth(); - $height = $image->getHeight(); - $resource = $image->getCore(); - - try { - - // set image tile filling - $source = new Decoder; - $tile = $source->init($filling); - imagesettile($image->getCore(), $tile->getCore()); - $filling = IMG_COLOR_TILED; - - } catch (\Intervention\Image\Exception\NotReadableException $e) { - - // set solid color filling - $color = new Color($filling); - $filling = $color->getInt(); - } - - imagealphablending($resource, true); - - if (is_int($x) && is_int($y)) { - - // resource should be visible through transparency - $base = $image->getDriver()->newImage($width, $height)->getCore(); - imagecopy($base, $resource, 0, 0, 0, 0, $width, $height); - - // floodfill if exact position is defined - imagefill($resource, $x, $y, $filling); - - // copy filled original over base - imagecopy($base, $resource, 0, 0, 0, 0, $width, $height); - - // set base as new resource-core - $image->setCore($base); - imagedestroy($resource); - - } else { - // fill whole image otherwise - imagefilledrectangle($resource, 0, 0, $width - 1, $height - 1, $filling); - } - - isset($tile) ? imagedestroy($tile->getCore()) : null; - - return true; - } -} diff --git a/src/Intervention/Image/Gd/Commands/FitCommand.php b/src/Intervention/Image/Gd/Commands/FitCommand.php deleted file mode 100644 index d861ad94..00000000 --- a/src/Intervention/Image/Gd/Commands/FitCommand.php +++ /dev/null @@ -1,32 +0,0 @@ -argument(0)->type('digit')->required()->value(); - $height = $this->argument(1)->type('digit')->value($width); - $constraints = $this->argument(2)->type('closure')->value(); - $position = $this->argument(3)->type('string')->value('center'); - - // calculate size - $cropped = $image->getSize()->fit(new Size($width, $height), $position); - $resized = clone $cropped; - $resized = $resized->resize($width, $height, $constraints); - - // modify image - $this->modify($image, 0, 0, $cropped->pivot->x, $cropped->pivot->y, $resized->getWidth(), $resized->getHeight(), $cropped->getWidth(), $cropped->getHeight()); - - return true; - } -} diff --git a/src/Intervention/Image/Gd/Commands/FlipCommand.php b/src/Intervention/Image/Gd/Commands/FlipCommand.php deleted file mode 100644 index aa8f230e..00000000 --- a/src/Intervention/Image/Gd/Commands/FlipCommand.php +++ /dev/null @@ -1,37 +0,0 @@ -argument(0)->value('h'); - - $size = $image->getSize(); - $dst = clone $size; - - switch (strtolower($mode)) { - case 2: - case 'v': - case 'vert': - case 'vertical': - $size->pivot->y = $size->height - 1; - $size->height = $size->height * (-1); - break; - - default: - $size->pivot->x = $size->width - 1; - $size->width = $size->width * (-1); - break; - } - - return $this->modify($image, 0, 0, $size->pivot->x, $size->pivot->y, $dst->width, $dst->height, $size->width, $size->height); - } -} diff --git a/src/Intervention/Image/Gd/Commands/GammaCommand.php b/src/Intervention/Image/Gd/Commands/GammaCommand.php deleted file mode 100644 index 7de0fb8a..00000000 --- a/src/Intervention/Image/Gd/Commands/GammaCommand.php +++ /dev/null @@ -1,21 +0,0 @@ -argument(0)->type('numeric')->required()->value(); - - return imagegammacorrect($image->getCore(), 1, $gamma); - } -} diff --git a/src/Intervention/Image/Gd/Commands/GetSizeCommand.php b/src/Intervention/Image/Gd/Commands/GetSizeCommand.php deleted file mode 100644 index 9eb7e209..00000000 --- a/src/Intervention/Image/Gd/Commands/GetSizeCommand.php +++ /dev/null @@ -1,25 +0,0 @@ -setOutput(new Size( - imagesx($image->getCore()), - imagesy($image->getCore()) - )); - - return true; - } -} diff --git a/src/Intervention/Image/Gd/Commands/GreyscaleCommand.php b/src/Intervention/Image/Gd/Commands/GreyscaleCommand.php deleted file mode 100644 index 12921e79..00000000 --- a/src/Intervention/Image/Gd/Commands/GreyscaleCommand.php +++ /dev/null @@ -1,19 +0,0 @@ -getCore(), IMG_FILTER_GRAYSCALE); - } -} diff --git a/src/Intervention/Image/Gd/Commands/HeightenCommand.php b/src/Intervention/Image/Gd/Commands/HeightenCommand.php deleted file mode 100644 index d31e9cde..00000000 --- a/src/Intervention/Image/Gd/Commands/HeightenCommand.php +++ /dev/null @@ -1,28 +0,0 @@ -argument(0)->type('digit')->required()->value(); - $additionalConstraints = $this->argument(1)->type('closure')->value(); - - $this->arguments[0] = null; - $this->arguments[1] = $height; - $this->arguments[2] = function ($constraint) use ($additionalConstraints) { - $constraint->aspectRatio(); - if(is_callable($additionalConstraints)) - $additionalConstraints($constraint); - }; - - return parent::execute($image); - } -} diff --git a/src/Intervention/Image/Gd/Commands/InsertCommand.php b/src/Intervention/Image/Gd/Commands/InsertCommand.php deleted file mode 100644 index 47c77039..00000000 --- a/src/Intervention/Image/Gd/Commands/InsertCommand.php +++ /dev/null @@ -1,34 +0,0 @@ -argument(0)->required()->value(); - $position = $this->argument(1)->type('string')->value(); - $x = $this->argument(2)->type('digit')->value(0); - $y = $this->argument(3)->type('digit')->value(0); - - // build watermark - $watermark = $image->getDriver()->init($source); - - // define insertion point - $image_size = $image->getSize()->align($position, $x, $y); - $watermark_size = $watermark->getSize()->align($position); - $target = $image_size->relativePosition($watermark_size); - - // insert image at position - imagealphablending($image->getCore(), true); - return imagecopy($image->getCore(), $watermark->getCore(), $target->x, $target->y, 0, 0, $watermark_size->width, $watermark_size->height); - } -} diff --git a/src/Intervention/Image/Gd/Commands/InterlaceCommand.php b/src/Intervention/Image/Gd/Commands/InterlaceCommand.php deleted file mode 100644 index e3461cb0..00000000 --- a/src/Intervention/Image/Gd/Commands/InterlaceCommand.php +++ /dev/null @@ -1,23 +0,0 @@ -argument(0)->type('bool')->value(true); - - imageinterlace($image->getCore(), $mode); - - return true; - } -} diff --git a/src/Intervention/Image/Gd/Commands/InvertCommand.php b/src/Intervention/Image/Gd/Commands/InvertCommand.php deleted file mode 100644 index 1a514f1d..00000000 --- a/src/Intervention/Image/Gd/Commands/InvertCommand.php +++ /dev/null @@ -1,19 +0,0 @@ -getCore(), IMG_FILTER_NEGATE); - } -} diff --git a/src/Intervention/Image/Gd/Commands/LimitColorsCommand.php b/src/Intervention/Image/Gd/Commands/LimitColorsCommand.php deleted file mode 100644 index 0baed7e9..00000000 --- a/src/Intervention/Image/Gd/Commands/LimitColorsCommand.php +++ /dev/null @@ -1,53 +0,0 @@ -argument(0)->value(); - $matte = $this->argument(1)->value(); - - // get current image size - $size = $image->getSize(); - - // create empty canvas - $resource = imagecreatetruecolor($size->width, $size->height); - - // define matte - if (is_null($matte)) { - $matte = imagecolorallocatealpha($resource, 255, 255, 255, 127); - } else { - $matte = $image->getDriver()->parseColor($matte)->getInt(); - } - - // fill with matte and copy original image - imagefill($resource, 0, 0, $matte); - - // set transparency - imagecolortransparent($resource, $matte); - - // copy original image - imagecopy($resource, $image->getCore(), 0, 0, 0, 0, $size->width, $size->height); - - if (is_numeric($count) && $count <= 256) { - // decrease colors - imagetruecolortopalette($resource, true, $count); - } - - // set new resource - $image->setCore($resource); - - return true; - } -} diff --git a/src/Intervention/Image/Gd/Commands/MaskCommand.php b/src/Intervention/Image/Gd/Commands/MaskCommand.php deleted file mode 100644 index 4c61429b..00000000 --- a/src/Intervention/Image/Gd/Commands/MaskCommand.php +++ /dev/null @@ -1,83 +0,0 @@ -argument(0)->value(); - $mask_w_alpha = $this->argument(1)->type('bool')->value(false); - - $image_size = $image->getSize(); - - // create empty canvas - $canvas = $image->getDriver()->newImage($image_size->width, $image_size->height, [0,0,0,0]); - - // build mask image from source - $mask = $image->getDriver()->init($mask_source); - $mask_size = $mask->getSize(); - - // resize mask to size of current image (if necessary) - if ($mask_size != $image_size) { - $mask->resize($image_size->width, $image_size->height); - } - - imagealphablending($canvas->getCore(), false); - - if ( ! $mask_w_alpha) { - // mask from greyscale image - imagefilter($mask->getCore(), IMG_FILTER_GRAYSCALE); - } - - // redraw old image pixel by pixel considering alpha map - for ($x=0; $x < $image_size->width; $x++) { - for ($y=0; $y < $image_size->height; $y++) { - - $color = $image->pickColor($x, $y, 'array'); - $alpha = $mask->pickColor($x, $y, 'array'); - - if ($mask_w_alpha) { - $alpha = $alpha[3]; // use alpha channel as mask - } else { - - if ($alpha[3] == 0) { // transparent as black - $alpha = 0; - } else { - - // $alpha = floatval(round((($alpha[0] + $alpha[1] + $alpha[3]) / 3) / 255, 2)); - - // image is greyscale, so channel doesn't matter (use red channel) - $alpha = floatval(round($alpha[0] / 255, 2)); - } - - } - - // preserve alpha of original image... - if ($color[3] < $alpha) { - $alpha = $color[3]; - } - - // replace alpha value - $color[3] = $alpha; - - // redraw pixel - $canvas->pixel($color, $x, $y); - } - } - - - // replace current image with masked instance - $image->setCore($canvas->getCore()); - - return true; - } -} diff --git a/src/Intervention/Image/Gd/Commands/OpacityCommand.php b/src/Intervention/Image/Gd/Commands/OpacityCommand.php deleted file mode 100644 index 48492d24..00000000 --- a/src/Intervention/Image/Gd/Commands/OpacityCommand.php +++ /dev/null @@ -1,31 +0,0 @@ -argument(0)->between(0, 100)->required()->value(); - - // get size of image - $size = $image->getSize(); - - // build temp alpha mask - $mask_color = sprintf('rgba(0, 0, 0, %.1F)', $transparency / 100); - $mask = $image->getDriver()->newImage($size->width, $size->height, $mask_color); - - // mask image - $image->mask($mask->getCore(), true); - - return true; - } -} diff --git a/src/Intervention/Image/Gd/Commands/PickColorCommand.php b/src/Intervention/Image/Gd/Commands/PickColorCommand.php deleted file mode 100644 index bad96f49..00000000 --- a/src/Intervention/Image/Gd/Commands/PickColorCommand.php +++ /dev/null @@ -1,37 +0,0 @@ -argument(0)->type('digit')->required()->value(); - $y = $this->argument(1)->type('digit')->required()->value(); - $format = $this->argument(2)->type('string')->value('array'); - - // pick color - $color = imagecolorat($image->getCore(), $x, $y); - - if ( ! imageistruecolor($image->getCore())) { - $color = imagecolorsforindex($image->getCore(), $color); - $color['alpha'] = round(1 - $color['alpha'] / 127, 2); - } - - $color = new Color($color); - - // format to output - $this->setOutput($color->format($format)); - - return true; - } -} diff --git a/src/Intervention/Image/Gd/Commands/PixelCommand.php b/src/Intervention/Image/Gd/Commands/PixelCommand.php deleted file mode 100644 index 2a90ce34..00000000 --- a/src/Intervention/Image/Gd/Commands/PixelCommand.php +++ /dev/null @@ -1,25 +0,0 @@ -argument(0)->required()->value(); - $color = new Color($color); - $x = $this->argument(1)->type('digit')->required()->value(); - $y = $this->argument(2)->type('digit')->required()->value(); - - return imagesetpixel($image->getCore(), $x, $y, $color->getInt()); - } -} diff --git a/src/Intervention/Image/Gd/Commands/PixelateCommand.php b/src/Intervention/Image/Gd/Commands/PixelateCommand.php deleted file mode 100644 index 0934797a..00000000 --- a/src/Intervention/Image/Gd/Commands/PixelateCommand.php +++ /dev/null @@ -1,21 +0,0 @@ -argument(0)->type('digit')->value(10); - - return imagefilter($image->getCore(), IMG_FILTER_PIXELATE, $size, true); - } -} diff --git a/src/Intervention/Image/Gd/Commands/ResetCommand.php b/src/Intervention/Image/Gd/Commands/ResetCommand.php deleted file mode 100644 index a68b75ea..00000000 --- a/src/Intervention/Image/Gd/Commands/ResetCommand.php +++ /dev/null @@ -1,39 +0,0 @@ -argument(0)->value(); - $backup = $image->getBackup($backupName); - - if (is_resource($backup) || $backup instanceof \GdImage) { - - // destroy current resource - imagedestroy($image->getCore()); - - // clone backup - $backup = $image->getDriver()->cloneCore($backup); - - // reset to new resource - $image->setCore($backup); - - return true; - } - - throw new RuntimeException( - "Backup not available. Call backup() before reset()." - ); - } -} diff --git a/src/Intervention/Image/Gd/Commands/ResizeCanvasCommand.php b/src/Intervention/Image/Gd/Commands/ResizeCanvasCommand.php deleted file mode 100644 index 73f3df30..00000000 --- a/src/Intervention/Image/Gd/Commands/ResizeCanvasCommand.php +++ /dev/null @@ -1,83 +0,0 @@ -argument(0)->type('digit')->required()->value(); - $height = $this->argument(1)->type('digit')->required()->value(); - $anchor = $this->argument(2)->value('center'); - $relative = $this->argument(3)->type('boolean')->value(false); - $bgcolor = $this->argument(4)->value(); - - $original_width = $image->getWidth(); - $original_height = $image->getHeight(); - - // check of only width or height is set - $width = is_null($width) ? $original_width : intval($width); - $height = is_null($height) ? $original_height : intval($height); - - // check on relative width/height - if ($relative) { - $width = $original_width + $width; - $height = $original_height + $height; - } - - // check for negative width/height - $width = ($width <= 0) ? $width + $original_width : $width; - $height = ($height <= 0) ? $height + $original_height : $height; - - // create new canvas - $canvas = $image->getDriver()->newImage($width, $height, $bgcolor); - - // set copy position - $canvas_size = $canvas->getSize()->align($anchor); - $image_size = $image->getSize()->align($anchor); - $canvas_pos = $image_size->relativePosition($canvas_size); - $image_pos = $canvas_size->relativePosition($image_size); - - if ($width <= $original_width) { - $dst_x = 0; - $src_x = $canvas_pos->x; - $src_w = $canvas_size->width; - } else { - $dst_x = $image_pos->x; - $src_x = 0; - $src_w = $original_width; - } - - if ($height <= $original_height) { - $dst_y = 0; - $src_y = $canvas_pos->y; - $src_h = $canvas_size->height; - } else { - $dst_y = $image_pos->y; - $src_y = 0; - $src_h = $original_height; - } - - // make image area transparent to keep transparency - // even if background-color is set - $transparent = imagecolorallocatealpha($canvas->getCore(), 255, 255, 255, 127); - imagealphablending($canvas->getCore(), false); // do not blend / just overwrite - imagefilledrectangle($canvas->getCore(), $dst_x, $dst_y, $dst_x + $src_w - 1, $dst_y + $src_h - 1, $transparent); - - // copy image into new canvas - imagecopy($canvas->getCore(), $image->getCore(), $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h); - - // set new core to canvas - $image->setCore($canvas->getCore()); - - return true; - } -} diff --git a/src/Intervention/Image/Gd/Commands/ResizeCommand.php b/src/Intervention/Image/Gd/Commands/ResizeCommand.php deleted file mode 100644 index e8ef7c75..00000000 --- a/src/Intervention/Image/Gd/Commands/ResizeCommand.php +++ /dev/null @@ -1,84 +0,0 @@ -argument(0)->value(); - $height = $this->argument(1)->value(); - $constraints = $this->argument(2)->type('closure')->value(); - - // resize box - $resized = $image->getSize()->resize($width, $height, $constraints); - - // modify image - $this->modify($image, 0, 0, 0, 0, $resized->getWidth(), $resized->getHeight(), $image->getWidth(), $image->getHeight()); - - return true; - } - - /** - * Wrapper function for 'imagecopyresampled' - * - * @param Image $image - * @param int $dst_x - * @param int $dst_y - * @param int $src_x - * @param int $src_y - * @param int $dst_w - * @param int $dst_h - * @param int $src_w - * @param int $src_h - * @return boolean - */ - protected function modify($image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h) - { - // create new image - $modified = imagecreatetruecolor(intval($dst_w), intval($dst_h)); - - // get current image - $resource = $image->getCore(); - - // preserve transparency - $transIndex = imagecolortransparent($resource); - - if ($transIndex != -1) { - $rgba = imagecolorsforindex($modified, $transIndex); - $transColor = imagecolorallocatealpha($modified, $rgba['red'], $rgba['green'], $rgba['blue'], 127); - imagefill($modified, 0, 0, $transColor); - imagecolortransparent($modified, $transColor); - } else { - imagealphablending($modified, false); - imagesavealpha($modified, true); - } - - // copy content from resource - $result = imagecopyresampled( - $modified, - $resource, - $dst_x, - $dst_y, - $src_x, - $src_y, - intval($dst_w), - intval($dst_h), - $src_w, - $src_h - ); - - // set new content as recource - $image->setCore($modified); - - return $result; - } -} diff --git a/src/Intervention/Image/Gd/Commands/RotateCommand.php b/src/Intervention/Image/Gd/Commands/RotateCommand.php deleted file mode 100644 index 682ec0d4..00000000 --- a/src/Intervention/Image/Gd/Commands/RotateCommand.php +++ /dev/null @@ -1,30 +0,0 @@ -argument(0)->type('numeric')->required()->value(); - $color = $this->argument(1)->value(); - $color = new Color($color); - - // restrict rotations beyond 360 degrees, since the end result is the same - $angle = fmod($angle, 360); - - // rotate image - $image->setCore(imagerotate($image->getCore(), $angle, $color->getInt())); - - return true; - } -} diff --git a/src/Intervention/Image/Gd/Commands/SharpenCommand.php b/src/Intervention/Image/Gd/Commands/SharpenCommand.php deleted file mode 100644 index 782e5650..00000000 --- a/src/Intervention/Image/Gd/Commands/SharpenCommand.php +++ /dev/null @@ -1,34 +0,0 @@ -argument(0)->between(0, 100)->value(10); - - // build matrix - $min = $amount >= 10 ? $amount * -0.01 : 0; - $max = $amount * -0.025; - $abs = ((4 * $min + 4 * $max) * -1) + 1; - $div = 1; - - $matrix = [ - [$min, $max, $min], - [$max, $abs, $max], - [$min, $max, $min] - ]; - - // apply the matrix - return imageconvolution($image->getCore(), $matrix, $div, 0); - } -} diff --git a/src/Intervention/Image/Gd/Commands/TrimCommand.php b/src/Intervention/Image/Gd/Commands/TrimCommand.php deleted file mode 100644 index 2e369752..00000000 --- a/src/Intervention/Image/Gd/Commands/TrimCommand.php +++ /dev/null @@ -1,176 +0,0 @@ -argument(0)->type('string')->value(); - $away = $this->argument(1)->value(); - $tolerance = $this->argument(2)->type('numeric')->value(0); - $feather = $this->argument(3)->type('numeric')->value(0); - - $width = $image->getWidth(); - $height = $image->getHeight(); - - // default values - $checkTransparency = false; - - // define borders to trim away - if (is_null($away)) { - $away = ['top', 'right', 'bottom', 'left']; - } elseif (is_string($away)) { - $away = [$away]; - } - - // lower border names - foreach ($away as $key => $value) { - $away[$key] = strtolower($value); - } - - // define base color position - switch (strtolower($base)) { - case 'transparent': - case 'trans': - $checkTransparency = true; - $base_x = 0; - $base_y = 0; - break; - - case 'bottom-right': - case 'right-bottom': - $base_x = $width - 1; - $base_y = $height - 1; - break; - - default: - case 'top-left': - case 'left-top': - $base_x = 0; - $base_y = 0; - break; - } - - // pick base color - if ($checkTransparency) { - $color = new Color; // color will only be used to compare alpha channel - } else { - $color = $image->pickColor($base_x, $base_y, 'object'); - } - - $top_x = 0; - $top_y = 0; - $bottom_x = $width; - $bottom_y = $height; - - // search upper part of image for colors to trim away - if (in_array('top', $away)) { - - for ($y=0; $y < ceil($height/2); $y++) { - for ($x=0; $x < $width; $x++) { - - $checkColor = $image->pickColor($x, $y, 'object'); - - if ($checkTransparency) { - $checkColor->r = $color->r; - $checkColor->g = $color->g; - $checkColor->b = $color->b; - } - - if ($color->differs($checkColor, $tolerance)) { - $top_y = max(0, $y - $feather); - break 2; - } - - } - } - - } - - // search left part of image for colors to trim away - if (in_array('left', $away)) { - - for ($x=0; $x < ceil($width/2); $x++) { - for ($y=$top_y; $y < $height; $y++) { - - $checkColor = $image->pickColor($x, $y, 'object'); - - if ($checkTransparency) { - $checkColor->r = $color->r; - $checkColor->g = $color->g; - $checkColor->b = $color->b; - } - - if ($color->differs($checkColor, $tolerance)) { - $top_x = max(0, $x - $feather); - break 2; - } - - } - } - - } - - // search lower part of image for colors to trim away - if (in_array('bottom', $away)) { - - for ($y=($height-1); $y >= floor($height/2)-1; $y--) { - for ($x=$top_x; $x < $width; $x++) { - - $checkColor = $image->pickColor($x, $y, 'object'); - - if ($checkTransparency) { - $checkColor->r = $color->r; - $checkColor->g = $color->g; - $checkColor->b = $color->b; - } - - if ($color->differs($checkColor, $tolerance)) { - $bottom_y = min($height, $y+1 + $feather); - break 2; - } - - } - } - - } - - // search right part of image for colors to trim away - if (in_array('right', $away)) { - - for ($x=($width-1); $x >= floor($width/2)-1; $x--) { - for ($y=$top_y; $y < $bottom_y; $y++) { - - $checkColor = $image->pickColor($x, $y, 'object'); - - if ($checkTransparency) { - $checkColor->r = $color->r; - $checkColor->g = $color->g; - $checkColor->b = $color->b; - } - - if ($color->differs($checkColor, $tolerance)) { - $bottom_x = min($width, $x+1 + $feather); - break 2; - } - - } - } - - } - - - // trim parts of image - return $this->modify($image, 0, 0, $top_x, $top_y, ($bottom_x-$top_x), ($bottom_y-$top_y), ($bottom_x-$top_x), ($bottom_y-$top_y)); - - } -} diff --git a/src/Intervention/Image/Gd/Commands/WidenCommand.php b/src/Intervention/Image/Gd/Commands/WidenCommand.php deleted file mode 100644 index 43000d5d..00000000 --- a/src/Intervention/Image/Gd/Commands/WidenCommand.php +++ /dev/null @@ -1,28 +0,0 @@ -argument(0)->type('digit')->required()->value(); - $additionalConstraints = $this->argument(1)->type('closure')->value(); - - $this->arguments[0] = $width; - $this->arguments[1] = null; - $this->arguments[2] = function ($constraint) use ($additionalConstraints) { - $constraint->aspectRatio(); - if(is_callable($additionalConstraints)) - $additionalConstraints($constraint); - }; - - return parent::execute($image); - } -} diff --git a/src/Intervention/Image/Gd/Decoder.php b/src/Intervention/Image/Gd/Decoder.php deleted file mode 100644 index f5c34aa5..00000000 --- a/src/Intervention/Image/Gd/Decoder.php +++ /dev/null @@ -1,171 +0,0 @@ -gdResourceToTruecolor($core); - - // build image - $image = $this->initFromGdResource($core); - $image->mime = $mime; - $image->setFileInfoFromPath($path); - - return $image; - } - - /** - * Initiates new image from GD resource - * - * @param Resource $resource - * @return \Intervention\Image\Image - */ - public function initFromGdResource($resource) - { - return new Image(new Driver, $resource); - } - - /** - * Initiates new image from Imagick object - * - * @param Imagick $object - * @return \Intervention\Image\Image - */ - public function initFromImagick(\Imagick $object) - { - throw new NotSupportedException( - "Gd driver is unable to init from Imagick object." - ); - } - - /** - * Initiates new image from binary data - * - * @param string $data - * @return \Intervention\Image\Image - */ - public function initFromBinary($binary) - { - $resource = @imagecreatefromstring($binary); - - if ($resource === false) { - throw new NotReadableException( - "Unable to init from given binary data." - ); - } - - $image = $this->initFromGdResource($resource); - $image->mime = finfo_buffer(finfo_open(FILEINFO_MIME_TYPE), $binary); - - return $image; - } - - /** - * Transform GD resource into Truecolor version - * - * @param resource $resource - * @return bool - */ - public function gdResourceToTruecolor(&$resource) - { - $width = imagesx($resource); - $height = imagesy($resource); - - // new canvas - $canvas = imagecreatetruecolor($width, $height); - - // fill with transparent color - imagealphablending($canvas, false); - $transparent = imagecolorallocatealpha($canvas, 255, 255, 255, 127); - imagefilledrectangle($canvas, 0, 0, $width, $height, $transparent); - imagecolortransparent($canvas, $transparent); - imagealphablending($canvas, true); - - // copy original - imagecopy($canvas, $resource, 0, 0, 0, 0, $width, $height); - imagedestroy($resource); - - $resource = $canvas; - - return true; - } -} diff --git a/src/Intervention/Image/Gd/Driver.php b/src/Intervention/Image/Gd/Driver.php deleted file mode 100644 index 5f2f23ea..00000000 --- a/src/Intervention/Image/Gd/Driver.php +++ /dev/null @@ -1,89 +0,0 @@ -coreAvailable()) { - throw new NotSupportedException( - "GD Library extension not available with this PHP installation." - ); - } - - $this->decoder = $decoder ? $decoder : new Decoder; - $this->encoder = $encoder ? $encoder : new Encoder; - } - - /** - * Creates new image instance - * - * @param int $width - * @param int $height - * @param mixed $background - * @return \Intervention\Image\Image - */ - public function newImage($width, $height, $background = null) - { - // create empty resource - $core = imagecreatetruecolor($width, $height); - $image = new Image(new static, $core); - - // set background color - $background = new Color($background); - imagefill($image->getCore(), 0, 0, $background->getInt()); - - return $image; - } - - /** - * Reads given string into color object - * - * @param string $value - * @return AbstractColor - */ - public function parseColor($value) - { - return new Color($value); - } - - /** - * Checks if core module installation is available - * - * @return boolean - */ - protected function coreAvailable() - { - return (extension_loaded('gd') && function_exists('gd_info')); - } - - /** - * Returns clone of given core - * - * @return mixed - */ - public function cloneCore($core) - { - $width = imagesx($core); - $height = imagesy($core); - $clone = imagecreatetruecolor($width, $height); - imagealphablending($clone, false); - imagesavealpha($clone, true); - $transparency = imagecolorallocatealpha($clone, 0, 0, 0, 127); - imagefill($clone, 0, 0, $transparency); - - imagecopy($clone, $core, 0, 0, 0, 0, $width, $height); - - return $clone; - } -} diff --git a/src/Intervention/Image/Gd/Encoder.php b/src/Intervention/Image/Gd/Encoder.php deleted file mode 100644 index 559d60dc..00000000 --- a/src/Intervention/Image/Gd/Encoder.php +++ /dev/null @@ -1,180 +0,0 @@ -image->getCore(), null, $this->quality); - $this->image->mime = image_type_to_mime_type(IMAGETYPE_JPEG); - $buffer = ob_get_contents(); - ob_end_clean(); - - return $buffer; - } - - /** - * Processes and returns encoded image as PNG string - * - * @return string - */ - protected function processPng() - { - ob_start(); - $resource = $this->image->getCore(); - imagealphablending($resource, false); - imagesavealpha($resource, true); - imagepng($resource, null, -1); - $this->image->mime = image_type_to_mime_type(IMAGETYPE_PNG); - $buffer = ob_get_contents(); - ob_end_clean(); - - return $buffer; - } - - /** - * Processes and returns encoded image as GIF string - * - * @return string - */ - protected function processGif() - { - ob_start(); - imagegif($this->image->getCore()); - $this->image->mime = image_type_to_mime_type(IMAGETYPE_GIF); - $buffer = ob_get_contents(); - ob_end_clean(); - - return $buffer; - } - - /** - * Processes and returns encoded image as WEBP string - * - * @return string - */ - protected function processWebp() - { - if ( ! function_exists('imagewebp')) { - throw new NotSupportedException( - "Webp format is not supported by PHP installation." - ); - } - - ob_start(); - imagepalettetotruecolor($this->image->getCore()); - imagealphablending($this->image->getCore(), true); - imagesavealpha($this->image->getCore(), true); - imagewebp($this->image->getCore(), null, $this->quality); - $this->image->mime = defined('IMAGETYPE_WEBP') ? image_type_to_mime_type(IMAGETYPE_WEBP) : 'image/webp'; - $buffer = ob_get_contents(); - ob_end_clean(); - - return $buffer; - } - - /** - * Processes and returns encoded image as TIFF string - * - * @return string - */ - protected function processTiff() - { - throw new NotSupportedException( - "TIFF format is not supported by Gd Driver." - ); - } - - /** - * Processes and returns encoded image as BMP string - * - * @return string - */ - protected function processBmp() - { - if ( ! function_exists('imagebmp')) { - throw new NotSupportedException( - "BMP format is not supported by PHP installation." - ); - } - - ob_start(); - imagebmp($this->image->getCore()); - $this->image->mime = defined('IMAGETYPE_BMP') ? image_type_to_mime_type(IMAGETYPE_BMP) : 'image/bmp'; - $buffer = ob_get_contents(); - ob_end_clean(); - - return $buffer; - } - - /** - * Processes and returns encoded image as ICO string - * - * @return string - */ - protected function processIco() - { - throw new NotSupportedException( - "ICO format is not supported by Gd Driver." - ); - } - - /** - * Processes and returns encoded image as PSD string - * - * @return string - */ - protected function processPsd() - { - throw new NotSupportedException( - "PSD format is not supported by Gd Driver." - ); - } - - /** - * Processes and returns encoded image as AVIF string - * - * @return string - */ - protected function processAvif() - { - if ( ! function_exists('imageavif')) { - throw new NotSupportedException( - "AVIF format is not supported by PHP installation." - ); - } - - ob_start(); - $resource = $this->image->getCore(); - imagepalettetotruecolor($resource); - imagealphablending($resource, true); - imagesavealpha($resource, true); - imageavif($resource, null, $this->quality); - $this->image->mime = defined('IMAGETYPE_AVIF') ? image_type_to_mime_type(IMAGETYPE_AVIF) : 'image/avif'; - $buffer = ob_get_contents(); - ob_end_clean(); - - return $buffer; - } - - /** - * Processes and returns encoded image as HEIC string - * - * @return string - */ - protected function processHeic() - { - throw new NotSupportedException( - "HEIC format is not supported by Gd Driver." - ); - } -} diff --git a/src/Intervention/Image/Gd/Font.php b/src/Intervention/Image/Gd/Font.php deleted file mode 100644 index 3f588878..00000000 --- a/src/Intervention/Image/Gd/Font.php +++ /dev/null @@ -1,277 +0,0 @@ -size * 0.75)); - } - - /** - * Filter function to access internal integer font values - * - * @return int - */ - private function getInternalFont() - { - $internalfont = is_null($this->file) ? 1 : $this->file; - $internalfont = is_numeric($internalfont) ? $internalfont : false; - - if ( ! in_array($internalfont, [1, 2, 3, 4, 5])) { - throw new NotSupportedException( - sprintf('Internal GD font (%s) not available. Use only 1-5.', $internalfont) - ); - } - - return intval($internalfont); - } - - /** - * Get width of an internal font character - * - * @return int - */ - private function getInternalFontWidth() - { - return $this->getInternalFont() + 4; - } - - /** - * Get height of an internal font character - * - * @return int - */ - private function getInternalFontHeight() - { - switch ($this->getInternalFont()) { - case 1: - return 8; - - case 2: - return 14; - - case 3: - return 14; - - case 4: - return 16; - - case 5: - return 16; - } - } - - /** - * Calculates bounding box of current font setting - * - * @return Array - */ - public function getBoxSize() - { - $box = []; - - if ($this->hasApplicableFontFile()) { - - // imagettfbbox() converts numeric entities to their respective - // character. Preserve any originally double encoded entities to be - // represented as is. - // eg: &#160; will render   rather than its character. - $this->text = preg_replace('/&(#(?:x[a-fA-F0-9]+|[0-9]+);)/', '&\1', $this->text); - $this->text = mb_encode_numericentity($this->text, array(0x0080, 0xffff, 0, 0xffff), 'UTF-8'); - - // get bounding box with angle 0 - $box = imagettfbbox($this->getPointSize(), 0, $this->file, $this->text); - - // rotate points manually - if ($this->angle != 0) { - - $angle = pi() * 2 - $this->angle * pi() * 2 / 360; - - for ($i=0; $i<4; $i++) { - $x = $box[$i * 2]; - $y = $box[$i * 2 + 1]; - $box[$i * 2] = cos($angle) * $x - sin($angle) * $y; - $box[$i * 2 + 1] = sin($angle) * $x + cos($angle) * $y; - } - } - - $box['width'] = intval(abs($box[4] - $box[0])); - $box['height'] = intval(abs($box[5] - $box[1])); - - } else { - - // get current internal font size - $width = $this->getInternalFontWidth(); - $height = $this->getInternalFontHeight(); - - if (strlen($this->text) == 0) { - // no text -> no boxsize - $box['width'] = 0; - $box['height'] = 0; - } else { - // calculate boxsize - $box['width'] = strlen($this->text) * $width; - $box['height'] = $height; - } - } - - return $box; - } - - /** - * Draws font to given image at given position - * - * @param Image $image - * @param int $posx - * @param int $posy - * @return void - */ - public function applyToImage(Image $image, $posx = 0, $posy = 0) - { - // parse text color - $color = new Color($this->color); - - if ($this->hasApplicableFontFile()) { - - if ($this->angle != 0 || is_string($this->align) || is_string($this->valign)) { - - $box = $this->getBoxSize(); - - $align = is_null($this->align) ? 'left' : strtolower($this->align); - $valign = is_null($this->valign) ? 'bottom' : strtolower($this->valign); - - // correction on position depending on v/h alignment - switch ($align.'-'.$valign) { - - case 'center-top': - $posx = $posx - round(($box[6]+$box[4])/2); - $posy = $posy - round(($box[7]+$box[5])/2); - break; - - case 'right-top': - $posx = $posx - $box[4]; - $posy = $posy - $box[5]; - break; - - case 'left-top': - $posx = $posx - $box[6]; - $posy = $posy - $box[7]; - break; - - case 'center-center': - case 'center-middle': - $posx = $posx - round(($box[0]+$box[4])/2); - $posy = $posy - round(($box[1]+$box[5])/2); - break; - - case 'right-center': - case 'right-middle': - $posx = $posx - round(($box[2]+$box[4])/2); - $posy = $posy - round(($box[3]+$box[5])/2); - break; - - case 'left-center': - case 'left-middle': - $posx = $posx - round(($box[0]+$box[6])/2); - $posy = $posy - round(($box[1]+$box[7])/2); - break; - - case 'center-bottom': - $posx = $posx - round(($box[0]+$box[2])/2); - $posy = $posy - round(($box[1]+$box[3])/2); - break; - - case 'right-bottom': - $posx = $posx - $box[2]; - $posy = $posy - $box[3]; - break; - - case 'left-bottom': - $posx = $posx - $box[0]; - $posy = $posy - $box[1]; - break; - } - } - - // enable alphablending for imagettftext - imagealphablending($image->getCore(), true); - - // draw ttf text - imagettftext($image->getCore(), $this->getPointSize(), $this->angle, $posx, $posy, $color->getInt(), $this->file, $this->text); - - } else { - - // get box size - $box = $this->getBoxSize(); - $width = $box['width']; - $height = $box['height']; - - // internal font specific position corrections - if ($this->getInternalFont() == 1) { - $top_correction = 1; - $bottom_correction = 2; - } elseif ($this->getInternalFont() == 3) { - $top_correction = 2; - $bottom_correction = 4; - } else { - $top_correction = 3; - $bottom_correction = 4; - } - - // x-position corrections for horizontal alignment - switch (strtolower($this->align)) { - case 'center': - $posx = ceil($posx - ($width / 2)); - break; - - case 'right': - $posx = ceil($posx - $width) + 1; - break; - } - - // y-position corrections for vertical alignment - switch (strtolower($this->valign)) { - case 'center': - case 'middle': - $posy = ceil($posy - ($height / 2)); - break; - - case 'top': - $posy = ceil($posy - $top_correction); - break; - - default: - case 'bottom': - $posy = round($posy - $height + $bottom_correction); - break; - } - - // draw text - imagestring($image->getCore(), $this->getInternalFont(), $posx, $posy, $this->text, $color->getInt()); - } - } - - /** - * Set text kerning - * - * @param string $kerning - * @return void - */ - public function kerning($kerning) - { - throw new \Intervention\Image\Exception\NotSupportedException( - "Kerning is not supported by GD driver." - ); - } - -} diff --git a/src/Intervention/Image/Gd/Shapes/CircleShape.php b/src/Intervention/Image/Gd/Shapes/CircleShape.php deleted file mode 100644 index c3c42144..00000000 --- a/src/Intervention/Image/Gd/Shapes/CircleShape.php +++ /dev/null @@ -1,40 +0,0 @@ -width = is_numeric($diameter) ? intval($diameter) : $this->diameter; - $this->height = is_numeric($diameter) ? intval($diameter) : $this->diameter; - $this->diameter = is_numeric($diameter) ? intval($diameter) : $this->diameter; - } - - /** - * Draw current circle on given image - * - * @param Image $image - * @param int $x - * @param int $y - * @return boolean - */ - public function applyToImage(Image $image, $x = 0, $y = 0) - { - return parent::applyToImage($image, $x, $y); - } -} diff --git a/src/Intervention/Image/Gd/Shapes/EllipseShape.php b/src/Intervention/Image/Gd/Shapes/EllipseShape.php deleted file mode 100644 index 78e5e4a5..00000000 --- a/src/Intervention/Image/Gd/Shapes/EllipseShape.php +++ /dev/null @@ -1,65 +0,0 @@ -width = is_numeric($width) ? intval($width) : $this->width; - $this->height = is_numeric($height) ? intval($height) : $this->height; - } - - /** - * Draw ellipse instance on given image - * - * @param Image $image - * @param int $x - * @param int $y - * @return boolean - */ - public function applyToImage(Image $image, $x = 0, $y = 0) - { - // parse background color - $background = new Color($this->background); - - if ($this->hasBorder()) { - // slightly smaller ellipse to keep 1px bordered edges clean - imagefilledellipse($image->getCore(), $x, $y, $this->width-1, $this->height-1, $background->getInt()); - - $border_color = new Color($this->border_color); - imagesetthickness($image->getCore(), $this->border_width); - - // gd's imageellipse doesn't respect imagesetthickness so i use imagearc with 359.9 degrees here - imagearc($image->getCore(), $x, $y, $this->width, $this->height, 0, 359.99, $border_color->getInt()); - } else { - imagefilledellipse($image->getCore(), $x, $y, $this->width, $this->height, $background->getInt()); - } - - return true; - } -} diff --git a/src/Intervention/Image/Gd/Shapes/LineShape.php b/src/Intervention/Image/Gd/Shapes/LineShape.php deleted file mode 100644 index ea38b513..00000000 --- a/src/Intervention/Image/Gd/Shapes/LineShape.php +++ /dev/null @@ -1,90 +0,0 @@ -x = is_numeric($x) ? intval($x) : $this->x; - $this->y = is_numeric($y) ? intval($y) : $this->y; - } - - /** - * Set current line color - * - * @param string $color - * @return void - */ - public function color($color) - { - $this->color = $color; - } - - /** - * Set current line width in pixels - * - * @param int $width - * @return void - */ - public function width($width) - { - throw new \Intervention\Image\Exception\NotSupportedException( - "Line width is not supported by GD driver." - ); - } - - /** - * Draw current instance of line to given endpoint on given image - * - * @param Image $image - * @param int $x - * @param int $y - * @return boolean - */ - public function applyToImage(Image $image, $x = 0, $y = 0) - { - $color = new Color($this->color); - imageline($image->getCore(), $x, $y, $this->x, $this->y, $color->getInt()); - - return true; - } -} diff --git a/src/Intervention/Image/Gd/Shapes/PolygonShape.php b/src/Intervention/Image/Gd/Shapes/PolygonShape.php deleted file mode 100644 index 5e14df40..00000000 --- a/src/Intervention/Image/Gd/Shapes/PolygonShape.php +++ /dev/null @@ -1,49 +0,0 @@ -points = $points; - } - - /** - * Draw polygon on given image - * - * @param Image $image - * @param int $x - * @param int $y - * @return boolean - */ - public function applyToImage(Image $image, $x = 0, $y = 0) - { - $background = new Color($this->background); - imagefilledpolygon($image->getCore(), $this->points, intval(count($this->points) / 2), $background->getInt()); - - if ($this->hasBorder()) { - $border_color = new Color($this->border_color); - imagesetthickness($image->getCore(), $this->border_width); - imagepolygon($image->getCore(), $this->points, intval(count($this->points) / 2), $border_color->getInt()); - } - - return true; - } -} diff --git a/src/Intervention/Image/Gd/Shapes/RectangleShape.php b/src/Intervention/Image/Gd/Shapes/RectangleShape.php deleted file mode 100644 index 5f69a7f9..00000000 --- a/src/Intervention/Image/Gd/Shapes/RectangleShape.php +++ /dev/null @@ -1,76 +0,0 @@ -x1 = is_numeric($x1) ? intval($x1) : $this->x1; - $this->y1 = is_numeric($y1) ? intval($y1) : $this->y1; - $this->x2 = is_numeric($x2) ? intval($x2) : $this->x2; - $this->y2 = is_numeric($y2) ? intval($y2) : $this->y2; - } - - /** - * Draw rectangle to given image at certain position - * - * @param Image $image - * @param int $x - * @param int $y - * @return boolean - */ - public function applyToImage(Image $image, $x = 0, $y = 0) - { - $background = new Color($this->background); - imagefilledrectangle($image->getCore(), $this->x1, $this->y1, $this->x2, $this->y2, $background->getInt()); - - if ($this->hasBorder()) { - $border_color = new Color($this->border_color); - imagesetthickness($image->getCore(), $this->border_width); - imagerectangle($image->getCore(), $this->x1, $this->y1, $this->x2, $this->y2, $border_color->getInt()); - } - - return true; - } -} diff --git a/src/Intervention/Image/Image.php b/src/Intervention/Image/Image.php deleted file mode 100644 index 3b26ea2a..00000000 --- a/src/Intervention/Image/Image.php +++ /dev/null @@ -1,370 +0,0 @@ -driver = $driver; - $this->core = $core; - } - - /** - * Magic method to catch all image calls - * usually any AbstractCommand - * - * @param string $name - * @param Array $arguments - * @return mixed - */ - public function __call($name, $arguments) - { - $command = $this->driver->executeCommand($this, $name, $arguments); - return $command->hasOutput() ? $command->getOutput() : $this; - } - - /** - * Starts encoding of current image - * - * @param string $format - * @param int $quality - * @return \Intervention\Image\Image - */ - public function encode($format = null, $quality = 90) - { - return $this->driver->encode($this, $format, $quality); - } - - /** - * Saves encoded image in filesystem - * - * @param string $path - * @param int $quality - * @param string $format - * @return \Intervention\Image\Image - */ - public function save($path = null, $quality = null, $format = null) - { - $path = is_null($path) ? $this->basePath() : $path; - - if (is_null($path)) { - throw new NotWritableException( - "Can't write to undefined path." - ); - } - - if ($format === null) { - $format = pathinfo($path, PATHINFO_EXTENSION); - } - - $data = $this->encode($format, $quality); - $saved = @file_put_contents($path, $data); - - if ($saved === false) { - throw new NotWritableException( - "Can't write image data to path ({$path})" - ); - } - - // set new file info - $this->setFileInfoFromPath($path); - - return $this; - } - - /** - * Runs a given filter on current image - * - * @param FiltersFilterInterface $filter - * @return \Intervention\Image\Image - */ - public function filter(Filters\FilterInterface $filter) - { - return $filter->applyFilter($this); - } - - /** - * Returns current image driver - * - * @return \Intervention\Image\AbstractDriver - */ - public function getDriver() - { - return $this->driver; - } - - /** - * Sets current image driver - * @param AbstractDriver $driver - */ - public function setDriver(AbstractDriver $driver) - { - $this->driver = $driver; - - return $this; - } - - /** - * Returns current image resource/obj - * - * @return mixed - */ - public function getCore() - { - return $this->core; - } - - /** - * Sets current image resource - * - * @param mixed $core - */ - public function setCore($core) - { - $this->core = $core; - - return $this; - } - - /** - * Returns current image backup - * - * @param string $name - * @return mixed - */ - public function getBackup($name = null) - { - $name = is_null($name) ? 'default' : $name; - - if ( ! $this->backupExists($name)) { - throw new RuntimeException( - "Backup with name ({$name}) not available. Call backup() before reset()." - ); - } - - return $this->backups[$name]; - } - - /** - * Returns all backups attached to image - * - * @return array - */ - public function getBackups() - { - return $this->backups; - } - - /** - * Sets current image backup - * - * @param mixed $resource - * @param string $name - * @return self - */ - public function setBackup($resource, $name = null) - { - $name = is_null($name) ? 'default' : $name; - - $this->backups[$name] = $resource; - - return $this; - } - - /** - * Checks if named backup exists - * - * @param string $name - * @return bool - */ - private function backupExists($name) - { - return array_key_exists($name, $this->backups); - } - - /** - * Checks if current image is already encoded - * - * @return boolean - */ - public function isEncoded() - { - return ! empty($this->encoded); - } - - /** - * Returns encoded image data of current image - * - * @return string - */ - public function getEncoded() - { - return $this->encoded; - } - - /** - * Sets encoded image buffer - * - * @param string $value - */ - public function setEncoded($value) - { - $this->encoded = $value; - - return $this; - } - - /** - * Calculates current image width - * - * @return int - */ - public function getWidth() - { - return $this->getSize()->width; - } - - /** - * Alias of getWidth() - * - * @return int - */ - public function width() - { - return $this->getWidth(); - } - - /** - * Calculates current image height - * - * @return int - */ - public function getHeight() - { - return $this->getSize()->height; - } - - /** - * Alias of getHeight - * - * @return int - */ - public function height() - { - return $this->getHeight(); - } - - /** - * Reads mime type - * - * @return string - */ - public function mime() - { - return $this->mime; - } - - /** - * Returns encoded image data in string conversion - * - * @return string - */ - public function __toString() - { - return $this->encoded; - } - - /** - * Cloning an image - */ - public function __clone() - { - $this->core = $this->driver->cloneCore($this->core); - } -} diff --git a/src/Intervention/Image/ImageManager.php b/src/Intervention/Image/ImageManager.php deleted file mode 100644 index 324fe7fa..00000000 --- a/src/Intervention/Image/ImageManager.php +++ /dev/null @@ -1,142 +0,0 @@ - 'gd' - ]; - - /** - * Creates new instance of Image Manager - * - * @param array $config - */ - public function __construct(array $config = []) - { - $this->checkRequirements(); - $this->configure($config); - } - - /** - * Overrides configuration settings - * - * @param array $config - * - * @return self - */ - public function configure(array $config = []) - { - $this->config = array_replace($this->config, $config); - - return $this; - } - - /** - * Initiates an Image instance from different input types - * - * @param mixed $data - * - * @return \Intervention\Image\Image - */ - public function make($data) - { - return $this->createDriver()->init($data); - } - - /** - * Creates an empty image canvas - * - * @param int $width - * @param int $height - * @param mixed $background - * - * @return \Intervention\Image\Image - */ - public function canvas($width, $height, $background = null) - { - return $this->createDriver()->newImage($width, $height, $background); - } - - /** - * Create new cached image and run callback - * (requires additional package intervention/imagecache) - * - * @param Closure $callback - * @param int $lifetime - * @param boolean $returnObj - * - * @return Image - */ - public function cache(Closure $callback, $lifetime = null, $returnObj = false) - { - if (class_exists('Intervention\\Image\\ImageCache')) { - // create imagecache - $imagecache = new ImageCache($this); - - // run callback - if (is_callable($callback)) { - $callback($imagecache); - } - - return $imagecache->get($lifetime, $returnObj); - } - - throw new MissingDependencyException( - "Please install package intervention/imagecache before running this function." - ); - } - - /** - * Creates a driver instance according to config settings - * - * @return \Intervention\Image\AbstractDriver - */ - private function createDriver() - { - if (is_string($this->config['driver'])) { - $drivername = ucfirst($this->config['driver']); - $driverclass = sprintf('Intervention\\Image\\%s\\Driver', $drivername); - - if (class_exists($driverclass)) { - return new $driverclass; - } - - throw new NotSupportedException( - "Driver ({$drivername}) could not be instantiated." - ); - } - - if ($this->config['driver'] instanceof AbstractDriver) { - return $this->config['driver']; - } - - throw new NotSupportedException( - "Unknown driver type." - ); - } - - /** - * Check if all requirements are available - * - * @return void - */ - private function checkRequirements() - { - if ( ! function_exists('finfo_buffer')) { - throw new MissingDependencyException( - "PHP Fileinfo extension must be installed/enabled to use Intervention Image." - ); - } - } -} diff --git a/src/Intervention/Image/ImageManagerStatic.php b/src/Intervention/Image/ImageManagerStatic.php deleted file mode 100644 index a1b56426..00000000 --- a/src/Intervention/Image/ImageManagerStatic.php +++ /dev/null @@ -1,88 +0,0 @@ -configure($config); - } - - /** - * Statically initiates an Image instance from different input types - * - * @param mixed $data - * - * @return \Intervention\Image\Image - * @throws \Intervention\Image\Exception\NotReadableException - */ - public static function make($data) - { - return self::getManager()->make($data); - } - - /** - * Statically creates an empty image canvas - * - * @param int $width - * @param int $height - * @param mixed $background - * - * @return \Intervention\Image\Image - */ - public static function canvas($width, $height, $background = null) - { - return self::getManager()->canvas($width, $height, $background); - } - - /** - * Create new cached image and run callback statically - * - * @param Closure $callback - * @param int $lifetime - * @param boolean $returnObj - * - * @return mixed - */ - public static function cache(Closure $callback, $lifetime = null, $returnObj = false) - { - return self::getManager()->cache($callback, $lifetime, $returnObj); - } -} diff --git a/src/Intervention/Image/ImageServiceProvider.php b/src/Intervention/Image/ImageServiceProvider.php deleted file mode 100644 index f99fe4a3..00000000 --- a/src/Intervention/Image/ImageServiceProvider.php +++ /dev/null @@ -1,87 +0,0 @@ -provider = $this->getProvider(); - } - - /** - * Bootstrap the application events. - * - * @return void - */ - public function boot() - { - if (method_exists($this->provider, 'boot')) { - return $this->provider->boot(); - } - } - - /** - * Register the service provider. - * - * @return void - */ - public function register() - { - return $this->provider->register(); - } - - /** - * Return ServiceProvider according to Laravel version - * - * @return \Intervention\Image\Provider\ProviderInterface - */ - private function getProvider() - { - if ($this->app instanceof LumenApplication) { - $provider = '\Intervention\Image\ImageServiceProviderLumen'; - } elseif (version_compare(IlluminateApplication::VERSION, '5.0', '<')) { - $provider = '\Intervention\Image\ImageServiceProviderLaravel4'; - } else { - $provider = '\Intervention\Image\ImageServiceProviderLaravelRecent'; - } - - return new $provider($this->app); - } - - /** - * Get the services provided by the provider. - * - * @return array - */ - public function provides() - { - return ['image']; - } -} diff --git a/src/Intervention/Image/ImageServiceProviderLaravel4.php b/src/Intervention/Image/ImageServiceProviderLaravel4.php deleted file mode 100755 index 3b1388f2..00000000 --- a/src/Intervention/Image/ImageServiceProviderLaravel4.php +++ /dev/null @@ -1,112 +0,0 @@ -package('intervention/image'); - - // try to create imagecache route only if imagecache is present - if (class_exists('Intervention\\Image\\ImageCache')) { - - $app = $this->app; - - // load imagecache config - $app['config']->package('intervention/imagecache', __DIR__.'/../../../../imagecache/src/config', 'imagecache'); - $config = $app['config']; - - // create dynamic manipulation route - if (is_string($config->get('imagecache::route'))) { - - // add original to route templates - $config->set('imagecache::templates.original', null); - - // setup image manipulator route - $app['router']->get($config->get('imagecache::route').'/{template}/{filename}', ['as' => 'imagecache', function ($template, $filename) use ($app, $config) { - - // disable session cookies for image route - $app['config']->set('session.driver', 'array'); - - // find file - foreach ($config->get('imagecache::paths') as $path) { - // don't allow '..' in filenames - $image_path = $path.'/'.str_replace('..', '', $filename); - if (file_exists($image_path) && is_file($image_path)) { - break; - } else { - $image_path = false; - } - } - - // abort if file not found - if ($image_path === false) { - $app->abort(404); - } - - // define template callback - $callback = $config->get("imagecache::templates.{$template}"); - - if (is_callable($callback) || class_exists($callback)) { - - // image manipulation based on callback - $content = $app['image']->cache(function ($image) use ($image_path, $callback) { - - switch (true) { - case is_callable($callback): - return $callback($image->make($image_path)); - break; - - case class_exists($callback): - return $image->make($image_path)->filter(new $callback); - break; - } - - }, $config->get('imagecache::lifetime')); - - } else { - - // get original image file contents - $content = file_get_contents($image_path); - } - - // define mime type - $mime = finfo_buffer(finfo_open(FILEINFO_MIME_TYPE), $content); - - // return http response - return new IlluminateResponse($content, 200, [ - 'Content-Type' => $mime, - 'Cache-Control' => 'max-age='.($config->get('imagecache::lifetime')*60).', public', - 'Etag' => md5($content) - ]); - - }])->where(['template' => join('|', array_keys($config->get('imagecache::templates'))), 'filename' => '[ \w\\.\\/\\-]+']); - } - } - } - - /** - * Register the service provider. - * - * @return void - */ - public function register() - { - $app = $this->app; - - $app['image'] = $app->share(function ($app) { - return new ImageManager($app['config']->get('image::config')); - }); - - $app->alias('image', 'Intervention\Image\ImageManager'); - } -} diff --git a/src/Intervention/Image/ImageServiceProviderLaravelRecent.php b/src/Intervention/Image/ImageServiceProviderLaravelRecent.php deleted file mode 100644 index 17a84d0a..00000000 --- a/src/Intervention/Image/ImageServiceProviderLaravelRecent.php +++ /dev/null @@ -1,106 +0,0 @@ -publishes([ - __DIR__.'/../../config/config.php' => config_path('image.php') - ]); - - // setup intervention/imagecache if package is installed - $this->cacheIsInstalled() ? $this->bootstrapImageCache() : null; - } - - /** - * Register the service provider. - * - * @return void - */ - public function register() - { - $app = $this->app; - - // merge default config - $this->mergeConfigFrom( - __DIR__.'/../../config/config.php', - 'image' - ); - - // create image - $app->singleton('image', function ($app) { - return new ImageManager($this->getImageConfig($app)); - }); - - $app->alias('image', 'Intervention\Image\ImageManager'); - } - - /** - * Bootstrap imagecache - * - * @return void - */ - protected function bootstrapImageCache() - { - $app = $this->app; - $config = __DIR__.'/../../../../imagecache/src/config/config.php'; - - $this->publishes([ - $config => config_path('imagecache.php') - ]); - - // merge default config - $this->mergeConfigFrom( - $config, - 'imagecache' - ); - - // imagecache route - if (is_string(config('imagecache.route'))) { - - $filename_pattern = '[ \w\\.\\/\\-\\@\(\)\=]+'; - - // route to access template applied image file - $app['router']->get(config('imagecache.route').'/{template}/{filename}', [ - 'uses' => 'Intervention\Image\ImageCacheController@getResponse', - 'as' => 'imagecache' - ])->where(['filename' => $filename_pattern]); - } - } - - /** - * Return image configuration as array - * - * @param Application $app - * @return array - */ - private function getImageConfig($app) - { - $config = $app['config']->get('image'); - - if (is_null($config)) { - return []; - } - - return $config; - } -} diff --git a/src/Intervention/Image/ImageServiceProviderLeague.php b/src/Intervention/Image/ImageServiceProviderLeague.php deleted file mode 100644 index b756a61f..00000000 --- a/src/Intervention/Image/ImageServiceProviderLeague.php +++ /dev/null @@ -1,42 +0,0 @@ -config = $config; - } - - /** - * Register the server provider. - * - * @return void - */ - public function register() - { - $this->getContainer()->share('Intervention\Image\ImageManager', function () { - return new ImageManager($this->config); - }); - } -} diff --git a/src/Intervention/Image/ImageServiceProviderLumen.php b/src/Intervention/Image/ImageServiceProviderLumen.php deleted file mode 100644 index 4a381ccd..00000000 --- a/src/Intervention/Image/ImageServiceProviderLumen.php +++ /dev/null @@ -1,34 +0,0 @@ -app; - - // merge default config - $this->mergeConfigFrom( - __DIR__.'/../../config/config.php', - 'image' - ); - - // set configuration - $app->configure('image'); - - // create image - $app->singleton('image',function ($app) { - return new ImageManager($app['config']->get('image')); - }); - - $app->alias('image', 'Intervention\Image\ImageManager'); - } -} diff --git a/src/Intervention/Image/Imagick/Color.php b/src/Intervention/Image/Imagick/Color.php deleted file mode 100644 index 98a35928..00000000 --- a/src/Intervention/Image/Imagick/Color.php +++ /dev/null @@ -1,279 +0,0 @@ -> 24) & 0xFF; - $r = ($value >> 16) & 0xFF; - $g = ($value >> 8) & 0xFF; - $b = $value & 0xFF; - $a = $this->rgb2alpha($a); - - $this->setPixel($r, $g, $b, $a); - } - - /** - * Initiates color object from given array - * - * @param array $value - * @return \Intervention\Image\AbstractColor - */ - public function initFromArray($array) - { - $array = array_values($array); - - if (count($array) == 4) { - - // color array with alpha value - list($r, $g, $b, $a) = $array; - - } elseif (count($array) == 3) { - - // color array without alpha value - list($r, $g, $b) = $array; - $a = 1; - } - - $this->setPixel($r, $g, $b, $a); - } - - /** - * Initiates color object from given string - * - * @param string $value - * - * @return \Intervention\Image\AbstractColor - */ - public function initFromString($value) - { - if ($color = $this->rgbaFromString($value)) { - $this->setPixel($color[0], $color[1], $color[2], $color[3]); - } - } - - /** - * Initiates color object from given ImagickPixel object - * - * @param ImagickPixel $value - * - * @return \Intervention\Image\AbstractColor - */ - public function initFromObject($value) - { - if (is_a($value, '\ImagickPixel')) { - $this->pixel = $value; - } - } - - /** - * Initiates color object from given R, G and B values - * - * @param int $r - * @param int $g - * @param int $b - * - * @return \Intervention\Image\AbstractColor - */ - public function initFromRgb($r, $g, $b) - { - $this->setPixel($r, $g, $b); - } - - /** - * Initiates color object from given R, G, B and A values - * - * @param int $r - * @param int $g - * @param int $b - * @param float $a - * - * @return \Intervention\Image\AbstractColor - */ - public function initFromRgba($r, $g, $b, $a) - { - $this->setPixel($r, $g, $b, $a); - } - - /** - * Calculates integer value of current color instance - * - * @return int - */ - public function getInt() - { - $r = $this->getRedValue(); - $g = $this->getGreenValue(); - $b = $this->getBlueValue(); - $a = intval(round($this->getAlphaValue() * 255)); - - return intval(($a << 24) + ($r << 16) + ($g << 8) + $b); - } - - /** - * Calculates hexadecimal value of current color instance - * - * @param string $prefix - * - * @return string - */ - public function getHex($prefix = '') - { - return sprintf('%s%02x%02x%02x', $prefix, - $this->getRedValue(), - $this->getGreenValue(), - $this->getBlueValue() - ); - } - - /** - * Calculates RGB(A) in array format of current color instance - * - * @return array - */ - public function getArray() - { - return [ - $this->getRedValue(), - $this->getGreenValue(), - $this->getBlueValue(), - $this->getAlphaValue() - ]; - } - - /** - * Calculates RGBA in string format of current color instance - * - * @return string - */ - public function getRgba() - { - return sprintf('rgba(%d, %d, %d, %.2F)', - $this->getRedValue(), - $this->getGreenValue(), - $this->getBlueValue(), - $this->getAlphaValue() - ); - } - - /** - * Determines if current color is different from given color - * - * @param AbstractColor $color - * @param int $tolerance - * @return boolean - */ - public function differs(AbstractColor $color, $tolerance = 0) - { - $color_tolerance = round($tolerance * 2.55); - $alpha_tolerance = round($tolerance); - - $delta = [ - 'r' => abs($color->getRedValue() - $this->getRedValue()), - 'g' => abs($color->getGreenValue() - $this->getGreenValue()), - 'b' => abs($color->getBlueValue() - $this->getBlueValue()), - 'a' => abs($color->getAlphaValue() - $this->getAlphaValue()) - ]; - - return ( - $delta['r'] > $color_tolerance || - $delta['g'] > $color_tolerance || - $delta['b'] > $color_tolerance || - $delta['a'] > $alpha_tolerance - ); - } - - /** - * Returns RGB red value of current color - * - * @return int - */ - public function getRedValue() - { - return intval(round($this->pixel->getColorValue(\Imagick::COLOR_RED) * 255)); - } - - /** - * Returns RGB green value of current color - * - * @return int - */ - public function getGreenValue() - { - return intval(round($this->pixel->getColorValue(\Imagick::COLOR_GREEN) * 255)); - } - - /** - * Returns RGB blue value of current color - * - * @return int - */ - public function getBlueValue() - { - return intval(round($this->pixel->getColorValue(\Imagick::COLOR_BLUE) * 255)); - } - - /** - * Returns RGB alpha value of current color - * - * @return float - */ - public function getAlphaValue() - { - return round($this->pixel->getColorValue(\Imagick::COLOR_ALPHA), 2); - } - - /** - * Initiates ImagickPixel from given RGBA values - * - * @return \ImagickPixel - */ - private function setPixel($r, $g, $b, $a = null) - { - $a = is_null($a) ? 1 : $a; - - return $this->pixel = new \ImagickPixel( - sprintf('rgba(%d, %d, %d, %.2F)', $r, $g, $b, $a) - ); - } - - /** - * Returns current color as ImagickPixel - * - * @return \ImagickPixel - */ - public function getPixel() - { - return $this->pixel; - } - - /** - * Calculates RGBA integer alpha value into float value - * - * @param int $value - * @return float - */ - private function rgb2alpha($value) - { - // (255 -> 1.0) / (0 -> 0.0) - return (float) round($value/255, 2); - } - -} diff --git a/src/Intervention/Image/Imagick/Commands/BackupCommand.php b/src/Intervention/Image/Imagick/Commands/BackupCommand.php deleted file mode 100644 index 76b4f72b..00000000 --- a/src/Intervention/Image/Imagick/Commands/BackupCommand.php +++ /dev/null @@ -1,25 +0,0 @@ -argument(0)->value(); - - // clone current image resource - $clone = clone $image; - $image->setBackup($clone->getCore(), $backupName); - - return true; - } -} diff --git a/src/Intervention/Image/Imagick/Commands/BlurCommand.php b/src/Intervention/Image/Imagick/Commands/BlurCommand.php deleted file mode 100644 index d2533e0e..00000000 --- a/src/Intervention/Image/Imagick/Commands/BlurCommand.php +++ /dev/null @@ -1,21 +0,0 @@ -argument(0)->between(0, 100)->value(1); - - return $image->getCore()->blurImage(1 * $amount, 0.5 * $amount); - } -} diff --git a/src/Intervention/Image/Imagick/Commands/BrightnessCommand.php b/src/Intervention/Image/Imagick/Commands/BrightnessCommand.php deleted file mode 100644 index 03ac8478..00000000 --- a/src/Intervention/Image/Imagick/Commands/BrightnessCommand.php +++ /dev/null @@ -1,21 +0,0 @@ -argument(0)->between(-100, 100)->required()->value(); - - return $image->getCore()->modulateImage(100 + $level, 100, 100); - } -} diff --git a/src/Intervention/Image/Imagick/Commands/ColorizeCommand.php b/src/Intervention/Image/Imagick/Commands/ColorizeCommand.php deleted file mode 100644 index 3a6506f6..00000000 --- a/src/Intervention/Image/Imagick/Commands/ColorizeCommand.php +++ /dev/null @@ -1,44 +0,0 @@ -argument(0)->between(-100, 100)->required()->value(); - $green = $this->argument(1)->between(-100, 100)->required()->value(); - $blue = $this->argument(2)->between(-100, 100)->required()->value(); - - // normalize colorize levels - $red = $this->normalizeLevel($red); - $green = $this->normalizeLevel($green); - $blue = $this->normalizeLevel($blue); - - $qrange = $image->getCore()->getQuantumRange(); - - // apply - $image->getCore()->levelImage(0, $red, $qrange['quantumRangeLong'], \Imagick::CHANNEL_RED); - $image->getCore()->levelImage(0, $green, $qrange['quantumRangeLong'], \Imagick::CHANNEL_GREEN); - $image->getCore()->levelImage(0, $blue, $qrange['quantumRangeLong'], \Imagick::CHANNEL_BLUE); - - return true; - } - - private function normalizeLevel($level) - { - if ($level > 0) { - return $level/5; - } else { - return ($level+100)/100; - } - } -} diff --git a/src/Intervention/Image/Imagick/Commands/ContrastCommand.php b/src/Intervention/Image/Imagick/Commands/ContrastCommand.php deleted file mode 100644 index c4847c61..00000000 --- a/src/Intervention/Image/Imagick/Commands/ContrastCommand.php +++ /dev/null @@ -1,21 +0,0 @@ -argument(0)->between(-100, 100)->required()->value(); - - return $image->getCore()->sigmoidalContrastImage($level > 0, $level / 4, 0); - } -} diff --git a/src/Intervention/Image/Imagick/Commands/CropCommand.php b/src/Intervention/Image/Imagick/Commands/CropCommand.php deleted file mode 100644 index 618edea7..00000000 --- a/src/Intervention/Image/Imagick/Commands/CropCommand.php +++ /dev/null @@ -1,45 +0,0 @@ -argument(0)->type('digit')->required()->value(); - $height = $this->argument(1)->type('digit')->required()->value(); - $x = $this->argument(2)->type('digit')->value(); - $y = $this->argument(3)->type('digit')->value(); - - if (is_null($width) || is_null($height)) { - throw new InvalidArgumentException( - "Width and height of cutout needs to be defined." - ); - } - - $cropped = new Size($width, $height); - $position = new Point($x, $y); - - // align boxes - if (is_null($x) && is_null($y)) { - $position = $image->getSize()->align('center')->relativePosition($cropped->align('center')); - } - - // crop image core - $image->getCore()->cropImage($cropped->width, $cropped->height, $position->x, $position->y); - $image->getCore()->setImagePage(0,0,0,0); - - return true; - } -} diff --git a/src/Intervention/Image/Imagick/Commands/DestroyCommand.php b/src/Intervention/Image/Imagick/Commands/DestroyCommand.php deleted file mode 100644 index 58c9556e..00000000 --- a/src/Intervention/Image/Imagick/Commands/DestroyCommand.php +++ /dev/null @@ -1,27 +0,0 @@ -getCore()->clear(); - - // destroy backups - foreach ($image->getBackups() as $backup) { - $backup->clear(); - } - - return true; - } -} diff --git a/src/Intervention/Image/Imagick/Commands/ExifCommand.php b/src/Intervention/Image/Imagick/Commands/ExifCommand.php deleted file mode 100644 index 521b38b0..00000000 --- a/src/Intervention/Image/Imagick/Commands/ExifCommand.php +++ /dev/null @@ -1,63 +0,0 @@ -preferExtension = false; - } - - /** - * Read Exif data from the given image - * - * @param \Intervention\Image\Image $image - * @return boolean - */ - public function execute($image) - { - if ($this->preferExtension && function_exists('exif_read_data')) { - return parent::execute($image); - } - - $core = $image->getCore(); - - if ( ! method_exists($core, 'getImageProperties')) { - throw new NotSupportedException( - "Reading Exif data is not supported by this PHP installation." - ); - } - - $requestedKey = $this->argument(0)->value(); - if ($requestedKey !== null) { - $this->setOutput($core->getImageProperty('exif:' . $requestedKey)); - return true; - } - - $exif = []; - $properties = $core->getImageProperties(); - foreach ($properties as $key => $value) { - if (substr($key, 0, 5) !== 'exif:') { - continue; - } - - $exif[substr($key, 5)] = $value; - } - - $this->setOutput($exif); - return true; - } -} diff --git a/src/Intervention/Image/Imagick/Commands/FillCommand.php b/src/Intervention/Image/Imagick/Commands/FillCommand.php deleted file mode 100644 index 82baac53..00000000 --- a/src/Intervention/Image/Imagick/Commands/FillCommand.php +++ /dev/null @@ -1,105 +0,0 @@ -argument(0)->value(); - $x = $this->argument(1)->type('digit')->value(); - $y = $this->argument(2)->type('digit')->value(); - - $imagick = $image->getCore(); - - try { - // set image filling - $source = new Decoder; - $filling = $source->init($filling); - - } catch (NotReadableException $e) { - - // set solid color filling - $filling = new Color($filling); - } - - // flood fill if coordinates are set - if (is_int($x) && is_int($y)) { - - // flood fill with texture - if ($filling instanceof Image) { - - // create tile - $tile = clone $image->getCore(); - - // mask away color at position - $tile->transparentPaintImage($tile->getImagePixelColor($x, $y), 0, 0, false); - - // create canvas - $canvas = clone $image->getCore(); - - // fill canvas with texture - $canvas = $canvas->textureImage($filling->getCore()); - - // merge canvas and tile - $canvas->compositeImage($tile, \Imagick::COMPOSITE_DEFAULT, 0, 0); - - // replace image core - $image->setCore($canvas); - - // flood fill with color - } elseif ($filling instanceof Color) { - - // create canvas with filling - $canvas = new \Imagick; - $canvas->newImage($image->getWidth(), $image->getHeight(), $filling->getPixel(), 'png'); - - // create tile to put on top - $tile = clone $image->getCore(); - - // mask away color at pos. - $tile->transparentPaintImage($tile->getImagePixelColor($x, $y), 0, 0, false); - - // save alpha channel of original image - $alpha = clone $image->getCore(); - - // merge original with canvas and tile - $image->getCore()->compositeImage($canvas, \Imagick::COMPOSITE_DEFAULT, 0, 0); - $image->getCore()->compositeImage($tile, \Imagick::COMPOSITE_DEFAULT, 0, 0); - - // restore alpha channel of original image - $image->getCore()->compositeImage($alpha, \Imagick::COMPOSITE_COPYOPACITY, 0, 0); - } - - } else { - - if ($filling instanceof Image) { - - // fill whole image with texture - $image->setCore($image->getCore()->textureImage($filling->getCore())); - - } elseif ($filling instanceof Color) { - - // fill whole image with color - $draw = new \ImagickDraw(); - $draw->setFillColor($filling->getPixel()); - $draw->rectangle(0, 0, $image->getWidth(), $image->getHeight()); - $image->getCore()->drawImage($draw); - } - } - - return true; - } -} diff --git a/src/Intervention/Image/Imagick/Commands/FitCommand.php b/src/Intervention/Image/Imagick/Commands/FitCommand.php deleted file mode 100644 index 6d62ba67..00000000 --- a/src/Intervention/Image/Imagick/Commands/FitCommand.php +++ /dev/null @@ -1,42 +0,0 @@ -argument(0)->type('digit')->required()->value(); - $height = $this->argument(1)->type('digit')->value($width); - $constraints = $this->argument(2)->type('closure')->value(); - $position = $this->argument(3)->type('string')->value('center'); - - // calculate size - $cropped = $image->getSize()->fit(new Size($width, $height), $position); - $resized = clone $cropped; - $resized = $resized->resize($width, $height, $constraints); - - // crop image - $image->getCore()->cropImage( - $cropped->width, - $cropped->height, - $cropped->pivot->x, - $cropped->pivot->y - ); - - // resize image - $image->getCore()->scaleImage($resized->getWidth(), $resized->getHeight()); - $image->getCore()->setImagePage(0,0,0,0); - - return true; - } -} diff --git a/src/Intervention/Image/Imagick/Commands/FlipCommand.php b/src/Intervention/Image/Imagick/Commands/FlipCommand.php deleted file mode 100644 index abae16ad..00000000 --- a/src/Intervention/Image/Imagick/Commands/FlipCommand.php +++ /dev/null @@ -1,27 +0,0 @@ -argument(0)->value('h'); - - if (in_array(strtolower($mode), [2, 'v', 'vert', 'vertical'])) { - // flip vertical - return $image->getCore()->flipImage(); - } else { - // flip horizontal - return $image->getCore()->flopImage(); - } - } -} diff --git a/src/Intervention/Image/Imagick/Commands/GammaCommand.php b/src/Intervention/Image/Imagick/Commands/GammaCommand.php deleted file mode 100644 index 200515f3..00000000 --- a/src/Intervention/Image/Imagick/Commands/GammaCommand.php +++ /dev/null @@ -1,21 +0,0 @@ -argument(0)->type('numeric')->required()->value(); - - return $image->getCore()->gammaImage($gamma); - } -} diff --git a/src/Intervention/Image/Imagick/Commands/GetSizeCommand.php b/src/Intervention/Image/Imagick/Commands/GetSizeCommand.php deleted file mode 100644 index ccccedb0..00000000 --- a/src/Intervention/Image/Imagick/Commands/GetSizeCommand.php +++ /dev/null @@ -1,28 +0,0 @@ -getCore(); - - $this->setOutput(new Size( - $core->getImageWidth(), - $core->getImageHeight() - )); - - return true; - } -} diff --git a/src/Intervention/Image/Imagick/Commands/GreyscaleCommand.php b/src/Intervention/Image/Imagick/Commands/GreyscaleCommand.php deleted file mode 100644 index df0ff5b5..00000000 --- a/src/Intervention/Image/Imagick/Commands/GreyscaleCommand.php +++ /dev/null @@ -1,19 +0,0 @@ -getCore()->modulateImage(100, 0, 100); - } -} diff --git a/src/Intervention/Image/Imagick/Commands/HeightenCommand.php b/src/Intervention/Image/Imagick/Commands/HeightenCommand.php deleted file mode 100644 index 0b61e50c..00000000 --- a/src/Intervention/Image/Imagick/Commands/HeightenCommand.php +++ /dev/null @@ -1,28 +0,0 @@ -argument(0)->type('digit')->required()->value(); - $additionalConstraints = $this->argument(1)->type('closure')->value(); - - $this->arguments[0] = null; - $this->arguments[1] = $height; - $this->arguments[2] = function ($constraint) use ($additionalConstraints) { - $constraint->aspectRatio(); - if(is_callable($additionalConstraints)) - $additionalConstraints($constraint); - }; - - return parent::execute($image); - } -} diff --git a/src/Intervention/Image/Imagick/Commands/InsertCommand.php b/src/Intervention/Image/Imagick/Commands/InsertCommand.php deleted file mode 100644 index 2a997436..00000000 --- a/src/Intervention/Image/Imagick/Commands/InsertCommand.php +++ /dev/null @@ -1,33 +0,0 @@ -argument(0)->required()->value(); - $position = $this->argument(1)->type('string')->value(); - $x = $this->argument(2)->type('digit')->value(0); - $y = $this->argument(3)->type('digit')->value(0); - - // build watermark - $watermark = $image->getDriver()->init($source); - - // define insertion point - $image_size = $image->getSize()->align($position, $x, $y); - $watermark_size = $watermark->getSize()->align($position); - $target = $image_size->relativePosition($watermark_size); - - // insert image at position - return $image->getCore()->compositeImage($watermark->getCore(), \Imagick::COMPOSITE_DEFAULT, $target->x, $target->y); - } -} diff --git a/src/Intervention/Image/Imagick/Commands/InterlaceCommand.php b/src/Intervention/Image/Imagick/Commands/InterlaceCommand.php deleted file mode 100644 index 913cab7e..00000000 --- a/src/Intervention/Image/Imagick/Commands/InterlaceCommand.php +++ /dev/null @@ -1,29 +0,0 @@ -argument(0)->type('bool')->value(true); - - if ($mode) { - $mode = \Imagick::INTERLACE_LINE; - } else { - $mode = \Imagick::INTERLACE_NO; - } - - $image->getCore()->setInterlaceScheme($mode); - - return true; - } -} diff --git a/src/Intervention/Image/Imagick/Commands/InvertCommand.php b/src/Intervention/Image/Imagick/Commands/InvertCommand.php deleted file mode 100644 index 1d134301..00000000 --- a/src/Intervention/Image/Imagick/Commands/InvertCommand.php +++ /dev/null @@ -1,19 +0,0 @@ -getCore()->negateImage(false); - } -} diff --git a/src/Intervention/Image/Imagick/Commands/LimitColorsCommand.php b/src/Intervention/Image/Imagick/Commands/LimitColorsCommand.php deleted file mode 100644 index 16f9b82e..00000000 --- a/src/Intervention/Image/Imagick/Commands/LimitColorsCommand.php +++ /dev/null @@ -1,59 +0,0 @@ -argument(0)->value(); - $matte = $this->argument(1)->value(); - - // get current image size - $size = $image->getSize(); - - // build 2 color alpha mask from original alpha - $alpha = clone $image->getCore(); - $alpha->separateImageChannel(\Imagick::CHANNEL_ALPHA); - $alpha->transparentPaintImage('#ffffff', 0, 0, false); - $alpha->separateImageChannel(\Imagick::CHANNEL_ALPHA); - $alpha->negateImage(false); - - if ($matte) { - - // get matte color - $mattecolor = $image->getDriver()->parseColor($matte)->getPixel(); - - // create matte image - $canvas = new \Imagick; - $canvas->newImage($size->width, $size->height, $mattecolor, 'png'); - - // lower colors of original and copy to matte - $image->getCore()->quantizeImage($count, \Imagick::COLORSPACE_RGB, 0, false, false); - $canvas->compositeImage($image->getCore(), \Imagick::COMPOSITE_DEFAULT, 0, 0); - - // copy new alpha to canvas - $canvas->compositeImage($alpha, \Imagick::COMPOSITE_COPYOPACITY, 0, 0); - - // replace core - $image->setCore($canvas); - - } else { - - $image->getCore()->quantizeImage($count, \Imagick::COLORSPACE_RGB, 0, false, false); - $image->getCore()->compositeImage($alpha, \Imagick::COMPOSITE_COPYOPACITY, 0, 0); - - } - - return true; - - } -} diff --git a/src/Intervention/Image/Imagick/Commands/MaskCommand.php b/src/Intervention/Image/Imagick/Commands/MaskCommand.php deleted file mode 100644 index af9d6b2f..00000000 --- a/src/Intervention/Image/Imagick/Commands/MaskCommand.php +++ /dev/null @@ -1,60 +0,0 @@ -argument(0)->value(); - $mask_w_alpha = $this->argument(1)->type('bool')->value(false); - - // get imagick - $imagick = $image->getCore(); - - // build mask image from source - $mask = $image->getDriver()->init($mask_source); - - // resize mask to size of current image (if necessary) - $image_size = $image->getSize(); - if ($mask->getSize() != $image_size) { - $mask->resize($image_size->width, $image_size->height); - } - - $imagick->setImageMatte(true); - - if ($mask_w_alpha) { - - // just mask with alpha map - $imagick->compositeImage($mask->getCore(), \Imagick::COMPOSITE_DSTIN, 0, 0); - - } else { - - // get alpha channel of original as greyscale image - $original_alpha = clone $imagick; - $original_alpha->separateImageChannel(\Imagick::CHANNEL_ALPHA); - - // use red channel from mask ask alpha - $mask_alpha = clone $mask->getCore(); - $mask_alpha->compositeImage($mask->getCore(), \Imagick::COMPOSITE_DEFAULT, 0, 0); - // $mask_alpha->setImageAlphaChannel(\Imagick::ALPHACHANNEL_DEACTIVATE); - $mask_alpha->separateImageChannel(\Imagick::CHANNEL_ALL); - - // combine both alphas from original and mask - $original_alpha->compositeImage($mask_alpha, \Imagick::COMPOSITE_COPYOPACITY, 0, 0); - - // mask the image with the alpha combination - $imagick->compositeImage($original_alpha, \Imagick::COMPOSITE_DSTIN, 0, 0); - } - - return true; - } -} diff --git a/src/Intervention/Image/Imagick/Commands/OpacityCommand.php b/src/Intervention/Image/Imagick/Commands/OpacityCommand.php deleted file mode 100644 index b4708d89..00000000 --- a/src/Intervention/Image/Imagick/Commands/OpacityCommand.php +++ /dev/null @@ -1,23 +0,0 @@ -argument(0)->between(0, 100)->required()->value(); - - $transparency = $transparency > 0 ? (100 / $transparency) : 1000; - - return $image->getCore()->evaluateImage(\Imagick::EVALUATE_DIVIDE, $transparency, \Imagick::CHANNEL_ALPHA); - } -} diff --git a/src/Intervention/Image/Imagick/Commands/PickColorCommand.php b/src/Intervention/Image/Imagick/Commands/PickColorCommand.php deleted file mode 100644 index 978a1284..00000000 --- a/src/Intervention/Image/Imagick/Commands/PickColorCommand.php +++ /dev/null @@ -1,30 +0,0 @@ -argument(0)->type('digit')->required()->value(); - $y = $this->argument(1)->type('digit')->required()->value(); - $format = $this->argument(2)->type('string')->value('array'); - - // pick color - $color = new Color($image->getCore()->getImagePixelColor($x, $y)); - - // format to output - $this->setOutput($color->format($format)); - - return true; - } -} diff --git a/src/Intervention/Image/Imagick/Commands/PixelCommand.php b/src/Intervention/Image/Imagick/Commands/PixelCommand.php deleted file mode 100644 index 6eb6ae71..00000000 --- a/src/Intervention/Image/Imagick/Commands/PixelCommand.php +++ /dev/null @@ -1,31 +0,0 @@ -argument(0)->required()->value(); - $color = new Color($color); - $x = $this->argument(1)->type('digit')->required()->value(); - $y = $this->argument(2)->type('digit')->required()->value(); - - // prepare pixel - $draw = new \ImagickDraw; - $draw->setFillColor($color->getPixel()); - $draw->point($x, $y); - - // apply pixel - return $image->getCore()->drawImage($draw); - } -} diff --git a/src/Intervention/Image/Imagick/Commands/PixelateCommand.php b/src/Intervention/Image/Imagick/Commands/PixelateCommand.php deleted file mode 100644 index 66a3205d..00000000 --- a/src/Intervention/Image/Imagick/Commands/PixelateCommand.php +++ /dev/null @@ -1,27 +0,0 @@ -argument(0)->type('digit')->value(10); - - $width = $image->getWidth(); - $height = $image->getHeight(); - - $image->getCore()->scaleImage(max(1, intval($width / $size)), max(1, intval($height / $size))); - $image->getCore()->scaleImage($width, $height); - - return true; - } -} diff --git a/src/Intervention/Image/Imagick/Commands/ResetCommand.php b/src/Intervention/Image/Imagick/Commands/ResetCommand.php deleted file mode 100644 index 77b7f336..00000000 --- a/src/Intervention/Image/Imagick/Commands/ResetCommand.php +++ /dev/null @@ -1,40 +0,0 @@ -argument(0)->value(); - - $backup = $image->getBackup($backupName); - - if ($backup instanceof \Imagick) { - - // destroy current core - $image->getCore()->clear(); - - // clone backup - $backup = clone $backup; - - // reset to new resource - $image->setCore($backup); - - return true; - } - - throw new RuntimeException( - "Backup not available. Call backup({$backupName}) before reset()." - ); - } -} diff --git a/src/Intervention/Image/Imagick/Commands/ResizeCanvasCommand.php b/src/Intervention/Image/Imagick/Commands/ResizeCanvasCommand.php deleted file mode 100644 index ecf07610..00000000 --- a/src/Intervention/Image/Imagick/Commands/ResizeCanvasCommand.php +++ /dev/null @@ -1,91 +0,0 @@ -argument(0)->type('digit')->required()->value(); - $height = $this->argument(1)->type('digit')->required()->value(); - $anchor = $this->argument(2)->value('center'); - $relative = $this->argument(3)->type('boolean')->value(false); - $bgcolor = $this->argument(4)->value(); - - $original_width = $image->getWidth(); - $original_height = $image->getHeight(); - - // check of only width or height is set - $width = is_null($width) ? $original_width : intval($width); - $height = is_null($height) ? $original_height : intval($height); - - // check on relative width/height - if ($relative) { - $width = $original_width + $width; - $height = $original_height + $height; - } - - // check for negative width/height - $width = ($width <= 0) ? $width + $original_width : $width; - $height = ($height <= 0) ? $height + $original_height : $height; - - // create new canvas - $canvas = $image->getDriver()->newImage($width, $height, $bgcolor); - - // set copy position - $canvas_size = $canvas->getSize()->align($anchor); - $image_size = $image->getSize()->align($anchor); - $canvas_pos = $image_size->relativePosition($canvas_size); - $image_pos = $canvas_size->relativePosition($image_size); - - if ($width <= $original_width) { - $dst_x = 0; - $src_x = $canvas_pos->x; - $src_w = $canvas_size->width; - } else { - $dst_x = $image_pos->x; - $src_x = 0; - $src_w = $original_width; - } - - if ($height <= $original_height) { - $dst_y = 0; - $src_y = $canvas_pos->y; - $src_h = $canvas_size->height; - } else { - $dst_y = $image_pos->y; - $src_y = 0; - $src_h = $original_height; - } - - // make image area transparent to keep transparency - // even if background-color is set - $rect = new \ImagickDraw; - $fill = $canvas->pickColor(0, 0, 'hex'); - $fill = $fill == '#ff0000' ? '#00ff00' : '#ff0000'; - $rect->setFillColor($fill); - $rect->rectangle($dst_x, $dst_y, $dst_x + $src_w - 1, $dst_y + $src_h - 1); - $canvas->getCore()->drawImage($rect); - $canvas->getCore()->transparentPaintImage($fill, 0, 0, false); - - $canvas->getCore()->setImageColorspace($image->getCore()->getImageColorspace()); - - // copy image into new canvas - $image->getCore()->cropImage($src_w, $src_h, $src_x, $src_y); - $canvas->getCore()->compositeImage($image->getCore(), \Imagick::COMPOSITE_DEFAULT, $dst_x, $dst_y); - $canvas->getCore()->setImagePage(0,0,0,0); - - // set new core to canvas - $image->setCore($canvas->getCore()); - - return true; - } -} diff --git a/src/Intervention/Image/Imagick/Commands/ResizeCommand.php b/src/Intervention/Image/Imagick/Commands/ResizeCommand.php deleted file mode 100644 index 3d4dc5be..00000000 --- a/src/Intervention/Image/Imagick/Commands/ResizeCommand.php +++ /dev/null @@ -1,29 +0,0 @@ -argument(0)->value(); - $height = $this->argument(1)->value(); - $constraints = $this->argument(2)->type('closure')->value(); - - // resize box - $resized = $image->getSize()->resize($width, $height, $constraints); - - // modify image - $image->getCore()->scaleImage($resized->getWidth(), $resized->getHeight()); - - return true; - } -} diff --git a/src/Intervention/Image/Imagick/Commands/RotateCommand.php b/src/Intervention/Image/Imagick/Commands/RotateCommand.php deleted file mode 100644 index b3e12a53..00000000 --- a/src/Intervention/Image/Imagick/Commands/RotateCommand.php +++ /dev/null @@ -1,30 +0,0 @@ -argument(0)->type('numeric')->required()->value(); - $color = $this->argument(1)->value(); - $color = new Color($color); - - // restrict rotations beyond 360 degrees, since the end result is the same - $angle = fmod($angle, 360); - - // rotate image - $image->getCore()->rotateImage($color->getPixel(), ($angle * -1)); - - return true; - } -} diff --git a/src/Intervention/Image/Imagick/Commands/SharpenCommand.php b/src/Intervention/Image/Imagick/Commands/SharpenCommand.php deleted file mode 100644 index bc5e393f..00000000 --- a/src/Intervention/Image/Imagick/Commands/SharpenCommand.php +++ /dev/null @@ -1,21 +0,0 @@ -argument(0)->between(0, 100)->value(10); - - return $image->getCore()->unsharpMaskImage(1, 1, $amount / 6.25, 0); - } -} diff --git a/src/Intervention/Image/Imagick/Commands/TrimCommand.php b/src/Intervention/Image/Imagick/Commands/TrimCommand.php deleted file mode 100644 index bdc897be..00000000 --- a/src/Intervention/Image/Imagick/Commands/TrimCommand.php +++ /dev/null @@ -1,121 +0,0 @@ -argument(0)->type('string')->value(); - $away = $this->argument(1)->value(); - $tolerance = $this->argument(2)->type('numeric')->value(0); - $feather = $this->argument(3)->type('numeric')->value(0); - - $width = $image->getWidth(); - $height = $image->getHeight(); - - $checkTransparency = false; - - // define borders to trim away - if (is_null($away)) { - $away = ['top', 'right', 'bottom', 'left']; - } elseif (is_string($away)) { - $away = [$away]; - } - - // lower border names - foreach ($away as $key => $value) { - $away[$key] = strtolower($value); - } - - // define base color position - switch (strtolower($base)) { - case 'transparent': - case 'trans': - $checkTransparency = true; - $base_x = 0; - $base_y = 0; - break; - - case 'bottom-right': - case 'right-bottom': - $base_x = $width - 1; - $base_y = $height - 1; - break; - - default: - case 'top-left': - case 'left-top': - $base_x = 0; - $base_y = 0; - break; - } - - // pick base color - if ($checkTransparency) { - $base_color = new Color; // color will only be used to compare alpha channel - } else { - $base_color = $image->pickColor($base_x, $base_y, 'object'); - } - - // trim on clone to get only coordinates - $trimed = clone $image->getCore(); - - // add border to trim specific color - $trimed->borderImage($base_color->getPixel(), 1, 1); - - // trim image - $trimed->trimImage(65850 / 100 * $tolerance); - - // get coordinates of trim - $imagePage = $trimed->getImagePage(); - list($crop_x, $crop_y) = [$imagePage['x']-1, $imagePage['y']-1]; - // $trimed->setImagePage(0, 0, 0, 0); - list($crop_width, $crop_height) = [$trimed->width, $trimed->height]; - - // adjust settings if right should not be trimed - if ( ! in_array('right', $away)) { - $crop_width = $crop_width + ($width - ($width - $crop_x)); - } - - // adjust settings if bottom should not be trimed - if ( ! in_array('bottom', $away)) { - $crop_height = $crop_height + ($height - ($height - $crop_y)); - } - - // adjust settings if left should not be trimed - if ( ! in_array('left', $away)) { - $crop_width = $crop_width + $crop_x; - $crop_x = 0; - } - - // adjust settings if top should not be trimed - if ( ! in_array('top', $away)) { - $crop_height = $crop_height + $crop_y; - $crop_y = 0; - } - - // add feather - $crop_width = min($width, ($crop_width + $feather * 2)); - $crop_height = min($height, ($crop_height + $feather * 2)); - $crop_x = max(0, ($crop_x - $feather)); - $crop_y = max(0, ($crop_y - $feather)); - - // finally crop based on page - $image->getCore()->cropImage($crop_width, $crop_height, $crop_x, $crop_y); - $image->getCore()->setImagePage(0,0,0,0); - - $trimed->destroy(); - - return true; - } -} diff --git a/src/Intervention/Image/Imagick/Commands/WidenCommand.php b/src/Intervention/Image/Imagick/Commands/WidenCommand.php deleted file mode 100644 index a1967534..00000000 --- a/src/Intervention/Image/Imagick/Commands/WidenCommand.php +++ /dev/null @@ -1,28 +0,0 @@ -argument(0)->type('digit')->required()->value(); - $additionalConstraints = $this->argument(1)->type('closure')->value(); - - $this->arguments[0] = $width; - $this->arguments[1] = null; - $this->arguments[2] = function ($constraint) use ($additionalConstraints) { - $constraint->aspectRatio(); - if(is_callable($additionalConstraints)) - $additionalConstraints($constraint); - }; - - return parent::execute($image); - } -} diff --git a/src/Intervention/Image/Imagick/Decoder.php b/src/Intervention/Image/Imagick/Decoder.php deleted file mode 100644 index f4dde9a8..00000000 --- a/src/Intervention/Image/Imagick/Decoder.php +++ /dev/null @@ -1,124 +0,0 @@ -setBackgroundColor(new \ImagickPixel('transparent')); - $core->readImage($path); - $core->setImageType(defined('\Imagick::IMGTYPE_TRUECOLORALPHA') ? \Imagick::IMGTYPE_TRUECOLORALPHA : \Imagick::IMGTYPE_TRUECOLORMATTE); - - } catch (\ImagickException $e) { - throw new \Intervention\Image\Exception\NotReadableException( - "Unable to read image from path ({$path}).", - 0, - $e - ); - } - - // build image - $image = $this->initFromImagick($core); - $image->setFileInfoFromPath($path); - - return $image; - } - - /** - * Initiates new image from GD resource - * - * @param Resource $resource - * @return \Intervention\Image\Image - */ - public function initFromGdResource($resource) - { - throw new NotSupportedException( - 'Imagick driver is unable to init from GD resource.' - ); - } - - /** - * Initiates new image from Imagick object - * - * @param Imagick $object - * @return \Intervention\Image\Image - */ - public function initFromImagick(\Imagick $object) - { - // currently animations are not supported - // so all images are turned into static - $object = $this->removeAnimation($object); - - // reset image orientation - $object->setImageOrientation(\Imagick::ORIENTATION_UNDEFINED); - - return new Image(new Driver, $object); - } - - /** - * Initiates new image from binary data - * - * @param string $data - * @return \Intervention\Image\Image - */ - public function initFromBinary($binary) - { - $core = new \Imagick; - - try { - $core->setBackgroundColor(new \ImagickPixel('transparent')); - - $core->readImageBlob($binary); - - } catch (\ImagickException $e) { - throw new NotReadableException( - "Unable to read image from binary data.", - 0, - $e - ); - } - - // build image - $image = $this->initFromImagick($core); - $image->mime = finfo_buffer(finfo_open(FILEINFO_MIME_TYPE), $binary); - - return $image; - } - - /** - * Turns object into one frame Imagick object - * by removing all frames except first - * - * @param Imagick $object - * @return Imagick - */ - private function removeAnimation(\Imagick $object) - { - $imagick = new \Imagick; - - foreach ($object as $frame) { - $imagick->addImage($frame->getImage()); - break; - } - - $object->destroy(); - - return $imagick; - } -} diff --git a/src/Intervention/Image/Imagick/Driver.php b/src/Intervention/Image/Imagick/Driver.php deleted file mode 100644 index bb26ca0f..00000000 --- a/src/Intervention/Image/Imagick/Driver.php +++ /dev/null @@ -1,74 +0,0 @@ -coreAvailable()) { - throw new NotSupportedException( - "ImageMagick module not available with this PHP installation." - ); - } - - $this->decoder = $decoder ? $decoder : new Decoder; - $this->encoder = $encoder ? $encoder : new Encoder; - } - - /** - * Creates new image instance - * - * @param int $width - * @param int $height - * @param mixed $background - * @return \Intervention\Image\Image - */ - public function newImage($width, $height, $background = null) - { - $background = new Color($background); - - // create empty core - $core = new \Imagick; - $core->newImage($width, $height, $background->getPixel(), 'png'); - $core->setType(\Imagick::IMGTYPE_UNDEFINED); - $core->setImageType(\Imagick::IMGTYPE_UNDEFINED); - $core->setColorspace(\Imagick::COLORSPACE_UNDEFINED); - - // build image - $image = new Image(new static, $core); - - return $image; - } - - /** - * Reads given string into color object - * - * @param string $value - * @return AbstractColor - */ - public function parseColor($value) - { - return new Color($value); - } - - /** - * Checks if core module installation is available - * - * @return boolean - */ - protected function coreAvailable() - { - return (extension_loaded('imagick') && class_exists('Imagick')); - } -} diff --git a/src/Intervention/Image/Imagick/Encoder.php b/src/Intervention/Image/Imagick/Encoder.php deleted file mode 100644 index feb8a9d5..00000000 --- a/src/Intervention/Image/Imagick/Encoder.php +++ /dev/null @@ -1,239 +0,0 @@ -image->getCore(); - $imagick->setImageBackgroundColor('white'); - $imagick->setBackgroundColor('white'); - $imagick = $imagick->mergeImageLayers(\Imagick::LAYERMETHOD_MERGE); - $imagick->setFormat($format); - $imagick->setImageFormat($format); - $imagick->setCompression($compression); - $imagick->setImageCompression($compression); - $imagick->setCompressionQuality($this->quality); - $imagick->setImageCompressionQuality($this->quality); - - return $imagick->getImagesBlob(); - } - - /** - * Processes and returns encoded image as PNG string - * - * @return string - */ - protected function processPng() - { - $format = 'png'; - $compression = \Imagick::COMPRESSION_ZIP; - - $imagick = $this->image->getCore(); - $imagick->setFormat($format); - $imagick->setImageFormat($format); - $imagick->setCompression($compression); - $imagick->setImageCompression($compression); - - $this->image->mime = image_type_to_mime_type(IMAGETYPE_PNG); - - return $imagick->getImagesBlob(); - } - - /** - * Processes and returns encoded image as GIF string - * - * @return string - */ - protected function processGif() - { - $format = 'gif'; - $compression = \Imagick::COMPRESSION_LZW; - - $imagick = $this->image->getCore(); - $imagick->setFormat($format); - $imagick->setImageFormat($format); - $imagick->setCompression($compression); - $imagick->setImageCompression($compression); - - $this->image->mime = image_type_to_mime_type(IMAGETYPE_GIF); - - return $imagick->getImagesBlob(); - } - - protected function processWebp() - { - if ( ! \Imagick::queryFormats('WEBP')) { - throw new NotSupportedException( - "Webp format is not supported by Imagick installation." - ); - } - - $format = 'webp'; - $compression = \Imagick::COMPRESSION_JPEG; - - $imagick = $this->image->getCore(); - $imagick->setImageBackgroundColor(new \ImagickPixel('transparent')); - - $imagick = $imagick->mergeImageLayers(\Imagick::LAYERMETHOD_MERGE); - $imagick->setFormat($format); - $imagick->setImageFormat($format); - $imagick->setCompression($compression); - $imagick->setImageCompression($compression); - $imagick->setImageCompressionQuality($this->quality); - - return $imagick->getImagesBlob(); - } - - /** - * Processes and returns encoded image as TIFF string - * - * @return string - */ - protected function processTiff() - { - $format = 'tiff'; - $compression = \Imagick::COMPRESSION_UNDEFINED; - - $imagick = $this->image->getCore(); - $imagick->setFormat($format); - $imagick->setImageFormat($format); - $imagick->setCompression($compression); - $imagick->setImageCompression($compression); - $imagick->setCompressionQuality($this->quality); - $imagick->setImageCompressionQuality($this->quality); - - $this->image->mime = image_type_to_mime_type(IMAGETYPE_TIFF_II); - - return $imagick->getImagesBlob(); - } - - /** - * Processes and returns encoded image as BMP string - * - * @return string - */ - protected function processBmp() - { - $format = 'bmp'; - $compression = \Imagick::COMPRESSION_UNDEFINED; - - $imagick = $this->image->getCore(); - $imagick->setFormat($format); - $imagick->setImageFormat($format); - $imagick->setCompression($compression); - $imagick->setImageCompression($compression); - - $this->image->mime = image_type_to_mime_type(IMAGETYPE_BMP); - - return $imagick->getImagesBlob(); - } - - /** - * Processes and returns encoded image as ICO string - * - * @return string - */ - protected function processIco() - { - $format = 'ico'; - $compression = \Imagick::COMPRESSION_UNDEFINED; - - $imagick = $this->image->getCore(); - $imagick->setFormat($format); - $imagick->setImageFormat($format); - $imagick->setCompression($compression); - $imagick->setImageCompression($compression); - - $this->image->mime = image_type_to_mime_type(IMAGETYPE_ICO); - - return $imagick->getImagesBlob(); - } - - /** - * Processes and returns encoded image as PSD string - * - * @return string - */ - protected function processPsd() - { - $format = 'psd'; - $compression = \Imagick::COMPRESSION_UNDEFINED; - - $imagick = $this->image->getCore(); - $imagick->setFormat($format); - $imagick->setImageFormat($format); - $imagick->setCompression($compression); - $imagick->setImageCompression($compression); - - $this->image->mime = image_type_to_mime_type(IMAGETYPE_PSD); - - return $imagick->getImagesBlob(); - } - - /** - * Processes and returns encoded image as AVIF string - * - * @return string - */ - protected function processAvif() - { - if ( ! \Imagick::queryFormats('AVIF')) { - throw new NotSupportedException( - "AVIF format is not supported by Imagick installation." - ); - } - - $format = 'avif'; - $compression = \Imagick::COMPRESSION_UNDEFINED; - - $imagick = $this->image->getCore(); - $imagick->setFormat($format); - $imagick->setImageFormat($format); - $imagick->setCompression($compression); - $imagick->setImageCompression($compression); - $imagick->setCompressionQuality($this->quality); - $imagick->setImageCompressionQuality($this->quality); - - return $imagick->getImagesBlob(); - } - - /** - * Processes and returns encoded image as HEIC string - * - * @return string - */ - protected function processHeic() - { - if ( ! \Imagick::queryFormats('HEIC')) { - throw new NotSupportedException( - "HEIC format is not supported by Imagick installation." - ); - } - - $format = 'heic'; - $compression = \Imagick::COMPRESSION_UNDEFINED; - - $imagick = $this->image->getCore(); - $imagick->setFormat($format); - $imagick->setImageFormat($format); - $imagick->setCompression($compression); - $imagick->setImageCompression($compression); - $imagick->setCompressionQuality($this->quality); - $imagick->setImageCompressionQuality($this->quality); - - return $imagick->getImagesBlob(); - } -} diff --git a/src/Intervention/Image/Imagick/Font.php b/src/Intervention/Image/Imagick/Font.php deleted file mode 100644 index 9869d067..00000000 --- a/src/Intervention/Image/Imagick/Font.php +++ /dev/null @@ -1,122 +0,0 @@ -setStrokeAntialias(true); - $draw->setTextAntialias(true); - - // set font file - if ($this->hasApplicableFontFile()) { - $draw->setFont($this->file); - } else { - throw new RuntimeException( - "Font file must be provided to apply text to image." - ); - } - - // parse text color - $color = new Color($this->color); - - $draw->setFontSize($this->size); - $draw->setFillColor($color->getPixel()); - $draw->setTextKerning($this->kerning); - - // align horizontal - switch (strtolower($this->align)) { - case 'center': - $align = \Imagick::ALIGN_CENTER; - break; - - case 'right': - $align = \Imagick::ALIGN_RIGHT; - break; - - default: - $align = \Imagick::ALIGN_LEFT; - break; - } - - $draw->setTextAlignment($align); - - // align vertical - if (strtolower($this->valign) != 'bottom') { - - // corrections on y-position - switch (strtolower($this->valign)) { - case 'center': - case 'middle': - // calculate box size - $dimensions = $image->getCore()->queryFontMetrics($draw, $this->text); - $posy = $posy + $dimensions['textHeight'] * 0.65 / 2; - break; - - case 'top': - // calculate box size - $dimensions = $image->getCore()->queryFontMetrics($draw, $this->text, false); - $posy = $posy + $dimensions['characterHeight']; - break; - } - } - - // apply to image - $image->getCore()->annotateImage($draw, $posx, $posy, $this->angle * (-1), $this->text); - } - - /** - * Calculates bounding box of current font setting - * - * @return array - */ - public function getBoxSize() - { - $box = []; - - // build draw object - $draw = new \ImagickDraw(); - $draw->setStrokeAntialias(true); - $draw->setTextAntialias(true); - - // set font file - if ($this->hasApplicableFontFile()) { - $draw->setFont($this->file); - } else { - throw new RuntimeException( - "Font file must be provided to apply text to image." - ); - } - - $draw->setFontSize($this->size); - - $dimensions = (new \Imagick())->queryFontMetrics($draw, $this->text); - - if (strlen($this->text) == 0) { - // no text -> no boxsize - $box['width'] = 0; - $box['height'] = 0; - } else { - // get boxsize - $box['width'] = intval(abs($dimensions['textWidth'])); - $box['height'] = intval(abs($dimensions['textHeight'])); - } - - return $box; - } -} diff --git a/src/Intervention/Image/Imagick/Shapes/CircleShape.php b/src/Intervention/Image/Imagick/Shapes/CircleShape.php deleted file mode 100644 index 24172ea1..00000000 --- a/src/Intervention/Image/Imagick/Shapes/CircleShape.php +++ /dev/null @@ -1,40 +0,0 @@ -width = is_numeric($diameter) ? intval($diameter) : $this->diameter; - $this->height = is_numeric($diameter) ? intval($diameter) : $this->diameter; - $this->diameter = is_numeric($diameter) ? intval($diameter) : $this->diameter; - } - - /** - * Draw current circle on given image - * - * @param Image $image - * @param int $x - * @param int $y - * @return boolean - */ - public function applyToImage(Image $image, $x = 0, $y = 0) - { - return parent::applyToImage($image, $x, $y); - } -} diff --git a/src/Intervention/Image/Imagick/Shapes/EllipseShape.php b/src/Intervention/Image/Imagick/Shapes/EllipseShape.php deleted file mode 100644 index 99694b97..00000000 --- a/src/Intervention/Image/Imagick/Shapes/EllipseShape.php +++ /dev/null @@ -1,66 +0,0 @@ -width = is_numeric($width) ? intval($width) : $this->width; - $this->height = is_numeric($height) ? intval($height) : $this->height; - } - - /** - * Draw ellipse instance on given image - * - * @param Image $image - * @param int $x - * @param int $y - * @return boolean - */ - public function applyToImage(Image $image, $x = 0, $y = 0) - { - $circle = new \ImagickDraw; - - // set background - $bgcolor = new Color($this->background); - $circle->setFillColor($bgcolor->getPixel()); - - // set border - if ($this->hasBorder()) { - $border_color = new Color($this->border_color); - $circle->setStrokeWidth($this->border_width); - $circle->setStrokeColor($border_color->getPixel()); - } - - $circle->ellipse($x, $y, $this->width / 2, $this->height / 2, 0, 360); - - $image->getCore()->drawImage($circle); - - return true; - } -} diff --git a/src/Intervention/Image/Imagick/Shapes/LineShape.php b/src/Intervention/Image/Imagick/Shapes/LineShape.php deleted file mode 100644 index 0d6b3297..00000000 --- a/src/Intervention/Image/Imagick/Shapes/LineShape.php +++ /dev/null @@ -1,94 +0,0 @@ -x = is_numeric($x) ? intval($x) : $this->x; - $this->y = is_numeric($y) ? intval($y) : $this->y; - } - - /** - * Set current line color - * - * @param string $color - * @return void - */ - public function color($color) - { - $this->color = $color; - } - - /** - * Set current line width in pixels - * - * @param int $width - * @return void - */ - public function width($width) - { - $this->width = $width; - } - - /** - * Draw current instance of line to given endpoint on given image - * - * @param Image $image - * @param int $x - * @param int $y - * @return boolean - */ - public function applyToImage(Image $image, $x = 0, $y = 0) - { - $line = new \ImagickDraw; - - $color = new Color($this->color); - $line->setStrokeColor($color->getPixel()); - $line->setStrokeWidth($this->width); - - $line->line($this->x, $this->y, $x, $y); - $image->getCore()->drawImage($line); - - return true; - } -} diff --git a/src/Intervention/Image/Imagick/Shapes/PolygonShape.php b/src/Intervention/Image/Imagick/Shapes/PolygonShape.php deleted file mode 100644 index 45f44ad8..00000000 --- a/src/Intervention/Image/Imagick/Shapes/PolygonShape.php +++ /dev/null @@ -1,81 +0,0 @@ -points = $this->formatPoints($points); - } - - /** - * Draw polygon on given image - * - * @param Image $image - * @param int $x - * @param int $y - * @return boolean - */ - public function applyToImage(Image $image, $x = 0, $y = 0) - { - $polygon = new \ImagickDraw; - - // set background - $bgcolor = new Color($this->background); - $polygon->setFillColor($bgcolor->getPixel()); - - // set border - if ($this->hasBorder()) { - $border_color = new Color($this->border_color); - $polygon->setStrokeWidth($this->border_width); - $polygon->setStrokeColor($border_color->getPixel()); - } - - $polygon->polygon($this->points); - - $image->getCore()->drawImage($polygon); - - return true; - } - - /** - * Format polygon points to Imagick format - * - * @param Array $points - * @return Array - */ - private function formatPoints($points) - { - $ipoints = []; - $count = 1; - - foreach ($points as $key => $value) { - if ($count%2 === 0) { - $y = $value; - $ipoints[] = ['x' => $x, 'y' => $y]; - } else { - $x = $value; - } - $count++; - } - - return $ipoints; - } -} diff --git a/src/Intervention/Image/Imagick/Shapes/RectangleShape.php b/src/Intervention/Image/Imagick/Shapes/RectangleShape.php deleted file mode 100644 index 1166d77b..00000000 --- a/src/Intervention/Image/Imagick/Shapes/RectangleShape.php +++ /dev/null @@ -1,84 +0,0 @@ -x1 = is_numeric($x1) ? intval($x1) : $this->x1; - $this->y1 = is_numeric($y1) ? intval($y1) : $this->y1; - $this->x2 = is_numeric($x2) ? intval($x2) : $this->x2; - $this->y2 = is_numeric($y2) ? intval($y2) : $this->y2; - } - - /** - * Draw rectangle to given image at certain position - * - * @param Image $image - * @param int $x - * @param int $y - * @return boolean - */ - public function applyToImage(Image $image, $x = 0, $y = 0) - { - $rectangle = new \ImagickDraw; - - // set background - $bgcolor = new Color($this->background); - $rectangle->setFillColor($bgcolor->getPixel()); - - // set border - if ($this->hasBorder()) { - $border_color = new Color($this->border_color); - $rectangle->setStrokeWidth($this->border_width); - $rectangle->setStrokeColor($border_color->getPixel()); - } - - $rectangle->rectangle($this->x1, $this->y1, $this->x2, $this->y2); - - $image->getCore()->drawImage($rectangle); - - return true; - } -} diff --git a/src/Intervention/Image/Point.php b/src/Intervention/Image/Point.php deleted file mode 100644 index d51452e0..00000000 --- a/src/Intervention/Image/Point.php +++ /dev/null @@ -1,64 +0,0 @@ -x = is_numeric($x) ? intval($x) : 0; - $this->y = is_numeric($y) ? intval($y) : 0; - } - - /** - * Sets X coordinate - * - * @param int $x - */ - public function setX($x) - { - $this->x = intval($x); - } - - /** - * Sets Y coordinate - * - * @param int $y - */ - public function setY($y) - { - $this->y = intval($y); - } - - /** - * Sets both X and Y coordinate - * - * @param int $x - * @param int $y - */ - public function setPosition($x, $y) - { - $this->setX($x); - $this->setY($y); - } -} diff --git a/src/Intervention/Image/Response.php b/src/Intervention/Image/Response.php deleted file mode 100644 index 59a51e99..00000000 --- a/src/Intervention/Image/Response.php +++ /dev/null @@ -1,78 +0,0 @@ -image = $image; - $this->format = $format ? $format : $image->mime; - $this->quality = $quality ? $quality : 90; - } - - /** - * Builds response according to settings - * - * @return mixed - */ - public function make() - { - $this->image->encode($this->format, $this->quality); - $data = $this->image->getEncoded(); - $mime = finfo_buffer(finfo_open(FILEINFO_MIME_TYPE), $data); - $length = strlen($data); - - if (function_exists('app') && is_a($app = app(), 'Illuminate\Foundation\Application')) { - - $response = IlluminateResponse::make($data); - $response->header('Content-Type', $mime); - $response->header('Content-Length', $length); - - } elseif (class_exists('\Symfony\Component\HttpFoundation\Response')) { - - $response = new SymfonyResponse($data); - $response->headers->set('Content-Type', $mime); - $response->headers->set('Content-Length', $length); - - } else { - - header('Content-Type: ' . $mime); - header('Content-Length: ' . $length); - $response = $data; - } - - return $response; - } -} diff --git a/src/Intervention/Image/Size.php b/src/Intervention/Image/Size.php deleted file mode 100644 index b1f26e40..00000000 --- a/src/Intervention/Image/Size.php +++ /dev/null @@ -1,374 +0,0 @@ -width = is_numeric($width) ? intval($width) : 1; - $this->height = is_numeric($height) ? intval($height) : 1; - $this->pivot = $pivot ? $pivot : new Point; - } - - /** - * Set the width and height absolutely - * - * @param int $width - * @param int $height - */ - public function set($width, $height) - { - $this->width = $width; - $this->height = $height; - } - - /** - * Set current pivot point - * - * @param Point $point - */ - public function setPivot(Point $point) - { - $this->pivot = $point; - } - - /** - * Get the current width - * - * @return int - */ - public function getWidth() - { - return intval($this->width); - } - - /** - * Get the current height - * - * @return int - */ - public function getHeight() - { - return intval($this->height); - } - - /** - * Calculate the current aspect ratio - * - * @return float - */ - public function getRatio() - { - return $this->width / $this->height; - } - - /** - * Resize to desired width and/or height - * - * @param int $width - * @param int $height - * @param Closure $callback - * @return Size - */ - public function resize($width, $height, Closure $callback = null) - { - if (is_null($width) && is_null($height)) { - throw new InvalidArgumentException( - "Width or height needs to be defined." - ); - } - - // new size with dominant width - $dominant_w_size = clone $this; - $dominant_w_size->resizeHeight($height, $callback); - $dominant_w_size->resizeWidth($width, $callback); - - // new size with dominant height - $dominant_h_size = clone $this; - $dominant_h_size->resizeWidth($width, $callback); - $dominant_h_size->resizeHeight($height, $callback); - - // decide which size to use - if ($dominant_h_size->fitsInto(new self($width, $height))) { - $this->set($dominant_h_size->width, $dominant_h_size->height); - } else { - $this->set($dominant_w_size->width, $dominant_w_size->height); - } - - return $this; - } - - /** - * Scale size according to given constraints - * - * @param int $width - * @param Closure $callback - * @return Size - */ - private function resizeWidth($width, Closure $callback = null) - { - $constraint = $this->getConstraint($callback); - - if ($constraint->isFixed(Constraint::UPSIZE)) { - $max_width = $constraint->getSize()->getWidth(); - $max_height = $constraint->getSize()->getHeight(); - } - - if (is_numeric($width)) { - - if ($constraint->isFixed(Constraint::UPSIZE)) { - $this->width = ($width > $max_width) ? $max_width : $width; - } else { - $this->width = $width; - } - - if ($constraint->isFixed(Constraint::ASPECTRATIO)) { - $h = max(1, intval(round($this->width / $constraint->getSize()->getRatio()))); - - if ($constraint->isFixed(Constraint::UPSIZE)) { - $this->height = ($h > $max_height) ? $max_height : $h; - } else { - $this->height = $h; - } - } - } - } - - /** - * Scale size according to given constraints - * - * @param int $height - * @param Closure $callback - * @return Size - */ - private function resizeHeight($height, Closure $callback = null) - { - $constraint = $this->getConstraint($callback); - - if ($constraint->isFixed(Constraint::UPSIZE)) { - $max_width = $constraint->getSize()->getWidth(); - $max_height = $constraint->getSize()->getHeight(); - } - - if (is_numeric($height)) { - - if ($constraint->isFixed(Constraint::UPSIZE)) { - $this->height = ($height > $max_height) ? $max_height : $height; - } else { - $this->height = $height; - } - - if ($constraint->isFixed(Constraint::ASPECTRATIO)) { - $w = max(1, intval(round($this->height * $constraint->getSize()->getRatio()))); - - if ($constraint->isFixed(Constraint::UPSIZE)) { - $this->width = ($w > $max_width) ? $max_width : $w; - } else { - $this->width = $w; - } - } - } - } - - /** - * Calculate the relative position to another Size - * based on the pivot point settings of both sizes. - * - * @param Size $size - * @return \Intervention\Image\Point - */ - public function relativePosition(Size $size) - { - $x = $this->pivot->x - $size->pivot->x; - $y = $this->pivot->y - $size->pivot->y; - - return new Point($x, $y); - } - - /** - * Resize given Size to best fitting size of current size. - * - * @param Size $size - * @return \Intervention\Image\Size - */ - public function fit(Size $size, $position = 'center') - { - // create size with auto height - $auto_height = clone $size; - - $auto_height->resize($this->width, null, function ($constraint) { - $constraint->aspectRatio(); - }); - - // decide which version to use - if ($auto_height->fitsInto($this)) { - - $size = $auto_height; - - } else { - - // create size with auto width - $auto_width = clone $size; - - $auto_width->resize(null, $this->height, function ($constraint) { - $constraint->aspectRatio(); - }); - - $size = $auto_width; - } - - $this->align($position); - $size->align($position); - $size->setPivot($this->relativePosition($size)); - - return $size; - } - - /** - * Checks if given size fits into current size - * - * @param Size $size - * @return boolean - */ - public function fitsInto(Size $size) - { - return ($this->width <= $size->width) && ($this->height <= $size->height); - } - - /** - * Aligns current size's pivot point to given position - * and moves point automatically by offset. - * - * @param string $position - * @param int $offset_x - * @param int $offset_y - * @return \Intervention\Image\Size - */ - public function align($position, $offset_x = 0, $offset_y = 0) - { - switch (strtolower($position)) { - - case 'top': - case 'top-center': - case 'top-middle': - case 'center-top': - case 'middle-top': - $x = intval($this->width / 2); - $y = 0 + $offset_y; - break; - - case 'top-right': - case 'right-top': - $x = $this->width - $offset_x; - $y = 0 + $offset_y; - break; - - case 'left': - case 'left-center': - case 'left-middle': - case 'center-left': - case 'middle-left': - $x = 0 + $offset_x; - $y = intval($this->height / 2); - break; - - case 'right': - case 'right-center': - case 'right-middle': - case 'center-right': - case 'middle-right': - $x = $this->width - $offset_x; - $y = intval($this->height / 2); - break; - - case 'bottom-left': - case 'left-bottom': - $x = 0 + $offset_x; - $y = $this->height - $offset_y; - break; - - case 'bottom': - case 'bottom-center': - case 'bottom-middle': - case 'center-bottom': - case 'middle-bottom': - $x = intval($this->width / 2); - $y = $this->height - $offset_y; - break; - - case 'bottom-right': - case 'right-bottom': - $x = $this->width - $offset_x; - $y = $this->height - $offset_y; - break; - - case 'center': - case 'middle': - case 'center-center': - case 'middle-middle': - $x = intval($this->width / 2) + $offset_x; - $y = intval($this->height / 2) + $offset_y; - break; - - default: - case 'top-left': - case 'left-top': - $x = 0 + $offset_x; - $y = 0 + $offset_y; - break; - } - - $this->pivot->setPosition($x, $y); - - return $this; - } - - /** - * Runs constraints on current size - * - * @param Closure $callback - * @return \Intervention\Image\Constraint - */ - private function getConstraint(Closure $callback = null) - { - $constraint = new Constraint(clone $this); - - if (is_callable($callback)) { - $callback($constraint); - } - - return $constraint; - } -} diff --git a/src/ModifierStack.php b/src/ModifierStack.php new file mode 100644 index 00000000..109fbfc9 --- /dev/null +++ b/src/ModifierStack.php @@ -0,0 +1,30 @@ +modifiers as $modifier) { + $modifier->apply($image); + } + + return $image; + } + + public function push(ModifierInterface $modifier): self + { + $this->modifiers[] = $modifier; + + return $this; + } +} diff --git a/src/Modifiers/AbstractModifier.php b/src/Modifiers/AbstractModifier.php new file mode 100644 index 00000000..80a1aa02 --- /dev/null +++ b/src/Modifiers/AbstractModifier.php @@ -0,0 +1,19 @@ +modify($this); + } +} diff --git a/src/Modifiers/BlurModifier.php b/src/Modifiers/BlurModifier.php new file mode 100644 index 00000000..9d61ab43 --- /dev/null +++ b/src/Modifiers/BlurModifier.php @@ -0,0 +1,10 @@ +target)) { + return $this->target; + } + + if (in_array($this->target, ['rgb', 'RGB', RgbColorspace::class])) { + return new RgbColorspace(); + } + + if (in_array($this->target, ['cmyk', 'CMYK', CmykColorspace::class])) { + return new CmykColorspace(); + } + + throw new NotSupportedException('Given colorspace is not supported.'); + } +} diff --git a/src/Modifiers/ContainModifier.php b/src/Modifiers/ContainModifier.php new file mode 100644 index 00000000..cd3bc203 --- /dev/null +++ b/src/Modifiers/ContainModifier.php @@ -0,0 +1,36 @@ +size() + ->contain( + $this->width, + $this->height + ) + ->alignPivotTo( + $this->getResizeSize($image), + $this->position + ); + } + + public function getResizeSize(ImageInterface $image): SizeInterface + { + return new Rectangle($this->width, $this->height); + } +} diff --git a/src/Modifiers/ContrastModifier.php b/src/Modifiers/ContrastModifier.php new file mode 100644 index 00000000..5260fa4b --- /dev/null +++ b/src/Modifiers/ContrastModifier.php @@ -0,0 +1,10 @@ +size(); + + $crop = new Rectangle($this->width, $this->height); + $crop = $crop->contain( + $imagesize->width(), + $imagesize->height() + )->alignPivotTo($imagesize, $this->position); + + return $crop; + } + + public function getResizeSize(SizeInterface $size): SizeInterface + { + return $size->scale($this->width, $this->height); + } +} diff --git a/src/Modifiers/CropModifier.php b/src/Modifiers/CropModifier.php new file mode 100644 index 00000000..d733513f --- /dev/null +++ b/src/Modifiers/CropModifier.php @@ -0,0 +1,30 @@ +width, $this->height); + $crop->align($this->position); + + return $crop->alignPivotTo( + $image->size(), + $this->position + ); + } +} diff --git a/src/Modifiers/DrawEllipseModifier.php b/src/Modifiers/DrawEllipseModifier.php new file mode 100644 index 00000000..5448d860 --- /dev/null +++ b/src/Modifiers/DrawEllipseModifier.php @@ -0,0 +1,12 @@ +position); + } +} diff --git a/src/Modifiers/FlipModifier.php b/src/Modifiers/FlipModifier.php new file mode 100644 index 00000000..8251d91b --- /dev/null +++ b/src/Modifiers/FlipModifier.php @@ -0,0 +1,7 @@ +size() + ->containMax( + $this->width, + $this->height + ) + ->alignPivotTo( + $this->getResizeSize($image), + $this->position + ); + } +} diff --git a/src/Modifiers/PixelateModifier.php b/src/Modifiers/PixelateModifier.php new file mode 100644 index 00000000..3d706fd4 --- /dev/null +++ b/src/Modifiers/PixelateModifier.php @@ -0,0 +1,10 @@ +size()->movePivot( + $this->position, + $this->offset_x, + $this->offset_y + ); + + $watermark_size = $watermark->size()->movePivot( + $this->position + ); + + return $image_size->relativePositionTo($watermark_size); + } +} diff --git a/src/Modifiers/ProfileModifier.php b/src/Modifiers/ProfileModifier.php new file mode 100644 index 00000000..de21a5d2 --- /dev/null +++ b/src/Modifiers/ProfileModifier.php @@ -0,0 +1,12 @@ +core()->frame($position); + } + + if (preg_match("/^(?P[0-9]{1,3})%$/", $position, $matches) != 1) { + throw new InputException( + 'Position must be either integer or a percent value as string.' + ); + } + + $total = count($image); + $position = intval(round($total / 100 * intval($matches['percent']))); + $position = $position == $total ? $position - 1 : $position; + + return $image->core()->frame($position); + } +} diff --git a/src/Modifiers/ResizeCanvasModifier.php b/src/Modifiers/ResizeCanvasModifier.php new file mode 100644 index 00000000..849640d3 --- /dev/null +++ b/src/Modifiers/ResizeCanvasModifier.php @@ -0,0 +1,30 @@ +width) ? $image->width() : $this->width; + $height = is_null($this->height) ? $image->height() : $this->height; + + return (new Rectangle($width, $height)) + ->alignPivotTo( + $image->size(), + $this->position + ); + } +} diff --git a/src/Modifiers/ResizeCanvasRelativeModifier.php b/src/Modifiers/ResizeCanvasRelativeModifier.php new file mode 100644 index 00000000..eb11746c --- /dev/null +++ b/src/Modifiers/ResizeCanvasRelativeModifier.php @@ -0,0 +1,22 @@ +width) ? $image->width() : $image->width() + $this->width; + $height = is_null($this->height) ? $image->height() : $image->height() + $this->height; + + return (new Rectangle($width, $height)) + ->alignPivotTo( + $image->size(), + $this->position + ); + } +} diff --git a/src/Modifiers/ResizeDownModifier.php b/src/Modifiers/ResizeDownModifier.php new file mode 100644 index 00000000..30ff067a --- /dev/null +++ b/src/Modifiers/ResizeDownModifier.php @@ -0,0 +1,7 @@ +angle, 360); + } +} diff --git a/src/Modifiers/ScaleDownModifier.php b/src/Modifiers/ScaleDownModifier.php new file mode 100644 index 00000000..34367f30 --- /dev/null +++ b/src/Modifiers/ScaleDownModifier.php @@ -0,0 +1,7 @@ +x; + } + + /** + * {@inheritdoc} + * + * @see ResolutionInterface::setX() + */ + public function setX(float $x): self + { + $this->x = $x; + + return $this; + } + + /** + * {@inheritdoc} + * + * @see ResolutionInterface::y() + */ + public function y(): float + { + return $this->y; + } + + /** + * {@inheritdoc} + * + * @see ResolutionInterface::setY() + */ + public function setY(float $y): self + { + $this->y = $y; + + return $this; + } + + /** + * {@inheritdoc} + * + * @see ResolutionInterface::setPerUnit() + */ + protected function setPerUnit(int $per_unit): self + { + $this->per_unit = $per_unit; + + return $this; + } + + /** + * {@inheritdoc} + * + * @see ResolutionInterface::unit() + */ + public function unit(): string + { + return match ($this->per_unit) { + self::PER_CM => 'dpcm', + default => 'dpi', + }; + } + + /** + * {@inheritdoc} + * + * @see ResolutionInterface::perInch() + */ + public function perInch(): self + { + return match ($this->per_unit) { + self::PER_CM => $this + ->setPerUnit(self::PER_INCH) + ->setX($this->x * (1 / 2.54)) + ->setY($this->y * (1 / 2.54)), + default => $this + }; + } + + /** + * {@inheritdoc} + * + * @see ResolutionInterface::perCm() + */ + public function perCm(): self + { + return match ($this->per_unit) { + self::PER_INCH => $this + ->setPerUnit(self::PER_CM) + ->setX($this->x / (1 / 2.54)) + ->setY($this->y / (1 / 2.54)), + default => $this, + }; + } + + /** + * {@inheritdoc} + * + * @see ResolutionInterface::toString() + */ + public function toString(): string + { + return sprintf("%1\$.2f x %2\$.2f %3\$s", $this->x, $this->y, $this->unit()); + } + + /** + * {@inheritdoc} + * + * @see ResolutionInterface::__toString() + */ + public function __toString(): string + { + return $this->toString(); + } +} diff --git a/src/Traits/CanBuildFilePointer.php b/src/Traits/CanBuildFilePointer.php new file mode 100644 index 00000000..912f72a5 --- /dev/null +++ b/src/Traits/CanBuildFilePointer.php @@ -0,0 +1,15 @@ +filename = $filename; + } + + /** + * {@inheritdoc} + * + * @see FontInterface::setSize() + */ + public function setSize(float $size): FontInterface + { + $this->size = $size; + + return $this; + } + + /** + * {@inheritdoc} + * + * @see FontInterface::size() + */ + public function size(): float + { + return $this->size; + } + + /** + * {@inheritdoc} + * + * @see FontInterface::setAngle() + */ + public function setAngle(float $angle): FontInterface + { + $this->angle = $angle; + + return $this; + } + + /** + * {@inheritdoc} + * + * @see FontInterface::angle() + */ + public function angle(): float + { + return $this->angle; + } + + /** + * {@inheritdoc} + * + * @see FontInterface::setFilename() + */ + public function setFilename(string $filename): FontInterface + { + $this->filename = $filename; + + return $this; + } + + /** + * {@inheritdoc} + * + * @see FontInterface::filename() + */ + public function filename(): ?string + { + return $this->filename; + } + + /** + * {@inheritdoc} + * + * @see FontInterface::hasFilename() + */ + public function hasFilename(): bool + { + return !is_null($this->filename) && is_file($this->filename); + } + + /** + * {@inheritdoc} + * + * @see FontInterface::setColor() + */ + public function setColor(mixed $color): FontInterface + { + $this->color = $color; + + return $this; + } + + /** + * {@inheritdoc} + * + * @see FontInterface::color() + */ + public function color(): mixed + { + return $this->color; + } + + /** + * {@inheritdoc} + * + * @see FontInterface::alignment() + */ + public function alignment(): string + { + return $this->alignment; + } + + /** + * {@inheritdoc} + * + * @see FontInterface::setAlignment() + */ + public function setAlignment(string $value): FontInterface + { + $this->alignment = $value; + + return $this; + } + + /** + * {@inheritdoc} + * + * @see FontInterface::valignment() + */ + public function valignment(): string + { + return $this->valignment; + } + + /** + * {@inheritdoc} + * + * @see FontInterface::setValignment() + */ + public function setValignment(string $value): FontInterface + { + $this->valignment = $value; + + return $this; + } + + /** + * {@inheritdoc} + * + * @see FontInterface::setLineHeight() + */ + public function setLineHeight(float $height): FontInterface + { + $this->lineHeight = $height; + + return $this; + } + + /** + * {@inheritdoc} + * + * @see FontInterface::lineHeight() + */ + public function lineHeight(): float + { + return $this->lineHeight; + } +} diff --git a/src/Typography/FontFactory.php b/src/Typography/FontFactory.php new file mode 100644 index 00000000..8e942713 --- /dev/null +++ b/src/Typography/FontFactory.php @@ -0,0 +1,73 @@ +font = is_a($init, FontInterface::class) ? $init : new Font(); + + if (is_callable($init)) { + $init($this); + } + } + + public function __invoke(): FontInterface + { + return $this->font; + } + + public function filename(string $value): self + { + $this->font->setFilename($value); + + return $this; + } + + public function color(mixed $value): self + { + $this->font->setColor($value); + + return $this; + } + + public function size(float $value): self + { + $this->font->setSize($value); + + return $this; + } + + public function align(string $value): self + { + $this->font->setAlignment($value); + + return $this; + } + + public function valign(string $value): self + { + $this->font->setValignment($value); + + return $this; + } + + public function lineHeight(float $value): self + { + $this->font->setLineHeight($value); + + return $this; + } + + public function angle(float $value): self + { + $this->font->setAngle($value); + + return $this; + } +} diff --git a/src/Typography/Line.php b/src/Typography/Line.php new file mode 100644 index 00000000..88d84c58 --- /dev/null +++ b/src/Typography/Line.php @@ -0,0 +1,32 @@ +position; + } + + public function setPosition(Point $point): self + { + $this->position = $point; + + return $this; + } + + public function __toString(): string + { + return $this->text; + } +} diff --git a/src/Typography/TextBlock.php b/src/Typography/TextBlock.php new file mode 100644 index 00000000..f83a7dc4 --- /dev/null +++ b/src/Typography/TextBlock.php @@ -0,0 +1,52 @@ +push(new Line($line)); + } + } + + /** + * Return array of lines in text block + * + * @return array + */ + public function lines(): array + { + return $this->items; + } + + public function line($key): ?Line + { + if (!array_key_exists($key, $this->lines())) { + return null; + } + + return $this->lines()[$key]; + } + + /** + * Return line with most characters of text block + * + * @return Line + */ + public function longestLine(): Line + { + $lines = $this->lines(); + usort($lines, function ($a, $b) { + if (mb_strlen($a) === mb_strlen($b)) { + return 0; + } + return (mb_strlen($a) > mb_strlen($b)) ? -1 : 1; + }); + + return $lines[0]; + } +} diff --git a/src/config/config.php b/src/config/config.php deleted file mode 100644 index 2b1d2c3e..00000000 --- a/src/config/config.php +++ /dev/null @@ -1,20 +0,0 @@ - 'gd' - -]; diff --git a/tests/AbstractColorTest.php b/tests/AbstractColorTest.php deleted file mode 100644 index 0baeaa3b..00000000 --- a/tests/AbstractColorTest.php +++ /dev/null @@ -1,20 +0,0 @@ -getMockForAbstractClass('\Intervention\Image\AbstractColor'); - $color->format('xxxxxxxxxxxxxxxxxxxxxxx'); - } -} diff --git a/tests/AbstractCommandTest.php b/tests/AbstractCommandTest.php deleted file mode 100644 index a89bee49..00000000 --- a/tests/AbstractCommandTest.php +++ /dev/null @@ -1,48 +0,0 @@ -getTestCommand(); - $this->assertEquals('foo', $command->argument(0)->value()); - $this->assertEquals('bar', $command->argument(1)->value()); - } - - public function testGetOutput() - { - $command = $this->getTestCommand(); - $command->setOutput('foo'); - $this->assertEquals('foo', $command->getOutput()); - } - - public function testHasOutput() - { - $command = $this->getTestCommand(); - $this->assertEquals(false, $command->hasOutput()); - $command->setOutput('foo'); - $this->assertEquals(true, $command->hasOutput()); - } - - public function testSetOutput() - { - $command = $this->getTestCommand(); - $command->setOutput('foo'); - $this->assertEquals(true, $command->hasOutput()); - } - - public function getTestCommand() - { - $arguments = ['foo', 'bar']; - $command = $this->getMockForAbstractClass('\Intervention\Image\Commands\AbstractCommand', [$arguments]); - - return $command; - } -} diff --git a/tests/AbstractDecoderTest.php b/tests/AbstractDecoderTest.php deleted file mode 100644 index a06fc8a1..00000000 --- a/tests/AbstractDecoderTest.php +++ /dev/null @@ -1,160 +0,0 @@ -getTestDecoder(new \Imagick); - $this->assertTrue($source->isImagick()); - - $source = $this->getTestDecoder(new stdClass); - $this->assertFalse($source->isImagick()); - - $source = $this->getTestDecoder(null); - $this->assertFalse($source->isImagick()); - } - - public function testIsGdResource() - { - $resource = imagecreatefromjpeg(__DIR__.'/images/test.jpg'); - $source = $this->getTestDecoder($resource); - $this->assertTrue($source->isGdResource()); - - $source = $this->getTestDecoder(tmpfile()); - $this->assertFalse($source->isGdResource()); - - $source = $this->getTestDecoder(null); - $this->assertFalse($source->isGdResource()); - } - - public function testIsFilepath() - { - $source = $this->getTestDecoder(__DIR__.'/AbstractDecoderTest.php'); - $this->assertTrue($source->isFilepath()); - - $source = $this->getTestDecoder(null); - $this->assertFalse($source->isFilepath()); - - $source = $this->getTestDecoder([]); - $this->assertFalse($source->isFilepath()); - - $source = $this->getTestDecoder(new stdClass); - $this->assertFalse($source->isFilepath()); - } - - public function testIsUrl() - { - $source = $this->getTestDecoder('http://foo.bar'); - $this->assertTrue($source->isUrl()); - - $source = $this->getTestDecoder(null); - $this->assertFalse($source->isUrl()); - } - - public function testIsStream() - { - $source = $this->getTestDecoder(fopen(__DIR__ . '/images/test.jpg', 'r')); - $this->assertTrue($source->isStream()); - - $source = $this->getTestDecoder(new \GuzzleHttp\Psr7\Stream(fopen(__DIR__ . '/images/test.jpg', 'r'))); - $this->assertTrue($source->isStream()); - - $source = $this->getTestDecoder(null); - $this->assertFalse($source->isStream()); - } - - public function testIsBinary() - { - $source = $this->getTestDecoder(file_get_contents(__DIR__.'/images/test.jpg')); - $this->assertTrue($source->isBinary()); - - $source = $this->getTestDecoder(null); - $this->assertFalse($source->isBinary()); - - $source = $this->getTestDecoder(1); - $this->assertFalse($source->isBinary()); - - $source = $this->getTestDecoder(0); - $this->assertFalse($source->isBinary()); - - $source = $this->getTestDecoder([1,2,3]); - $this->assertFalse($source->isBinary()); - - $source = $this->getTestDecoder(new stdClass); - $this->assertFalse($source->isBinary()); - } - - public function testIsInterventionImage() - { - $source = $this->getTestDecoder(1); - $this->assertFalse($source->isInterventionImage()); - - $img = Mockery::mock('Intervention\Image\Image'); - $source = $this->getTestDecoder($img); - $this->assertTrue($source->isInterventionImage()); - } - - public function testIsSplFileInfo() - { - $source = $this->getTestDecoder(1); - $this->assertFalse($source->isSplFileInfo()); - - $img = Mockery::mock('SplFileInfo'); - $source = $this->getTestDecoder($img); - $this->assertTrue($source->isSplFileInfo()); - - $img = Mockery::mock('Symfony\Component\HttpFoundation\File\UploadedFile', 'SplFileInfo'); - $this->assertTrue($source->isSplFileInfo()); - } - - public function testIsSymfonyUpload() - { - $source = $this->getTestDecoder(1); - $this->assertFalse($source->isSymfonyUpload()); - - $img = Mockery::mock('Symfony\Component\HttpFoundation\File\UploadedFile'); - $source = $this->getTestDecoder($img); - $this->assertTrue($source->isSymfonyUpload()); - } - - public function testIsDataUrl() - { - $source = $this->getTestDecoder('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAGElEQVQYlWM8c+bMfwYiABMxikYVUk8hAHWzA3cRvs4UAAAAAElFTkSuQmCC'); - $this->assertTrue($source->isDataUrl()); - - $source = $this->getTestDecoder(null); - $this->assertFalse($source->isDataUrl()); - } - - public function testIsBase64() - { - $decoder = $this->getTestDecoder(null); - $this->assertFalse($decoder->isBase64()); - - $decoder = $this->getTestDecoder('random'); - $this->assertFalse($decoder->isBase64()); - - $base64 = "iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAGElEQVQYlWM8c+bMfwYiABMxikYVUk8hAHWzA3cRvs4UAAAAAElFTkSuQmCC"; - $decoder = $this->getTestDecoder($base64); - $this->assertTrue($decoder->isBase64()); - - $base64WithNewlines = 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+' . "\n" . - '9AAAAGElEQVQYlWM8c+bMfwYiABMxikYVUk8hAHWzA3' . "\n" . - 'cRvs4UAAAAAElFTkSuQmCC'; - - $decoder = $this->getTestDecoder($base64WithNewlines); - $this->assertTrue($decoder->isBase64()); - } - - public function getTestDecoder($data) - { - return $this->getMockForAbstractClass('\Intervention\Image\AbstractDecoder', [$data]); - } -} diff --git a/tests/AbstractDriverTest.php b/tests/AbstractDriverTest.php deleted file mode 100644 index 704c0992..00000000 --- a/tests/AbstractDriverTest.php +++ /dev/null @@ -1,21 +0,0 @@ -getMockForAbstractClass('\Intervention\Image\AbstractDriver'); - $command = $driver->executeCommand($image, 'xxxxxxxxxxxxxxxxxxxxxxx', []); - } -} diff --git a/tests/AbstractFontTest.php b/tests/AbstractFontTest.php deleted file mode 100644 index 37dfe56d..00000000 --- a/tests/AbstractFontTest.php +++ /dev/null @@ -1,86 +0,0 @@ -getMockForAbstractClass('\Intervention\Image\AbstractFont', ['test']); - $this->assertEquals('test', $font->text); - } - - public function testText() - { - $font = $this->getMockForAbstractClass('\Intervention\Image\AbstractFont'); - $font->text('test'); - $this->assertEquals('test', $font->text); - } - - public function testSize() - { - $font = $this->getMockForAbstractClass('\Intervention\Image\AbstractFont'); - $font->size(16); - $this->assertEquals(16, $font->size); - } - - public function testColor() - { - $font = $this->getMockForAbstractClass('\Intervention\Image\AbstractFont'); - $font->color('#ffffff'); - $this->assertEquals('#ffffff', $font->color); - } - - public function testAngle() - { - $font = $this->getMockForAbstractClass('\Intervention\Image\AbstractFont'); - $font->angle(30); - $this->assertEquals(30, $font->angle); - } - - public function testAlign() - { - $font = $this->getMockForAbstractClass('\Intervention\Image\AbstractFont'); - $font->align('right'); - $this->assertEquals('right', $font->align); - } - - public function testValign() - { - $font = $this->getMockForAbstractClass('\Intervention\Image\AbstractFont'); - $font->valign('top'); - $this->assertEquals('top', $font->valign); - } - - public function testKerning() - { - $font = $this->getMockForAbstractClass('\Intervention\Image\AbstractFont'); - $font->kerning(10.5); - $this->assertEquals(10.5, $font->kerning); - } - - public function testFile() - { - $font = $this->getMockForAbstractClass('\Intervention\Image\AbstractFont'); - $font->file('test.ttf'); - $this->assertEquals('test.ttf', $font->file); - } - - public function testCountLines() - { - $font = $this->getMockForAbstractClass('\Intervention\Image\AbstractFont'); - $font->text('foo'.PHP_EOL.'bar'.PHP_EOL.'baz'); - $this->assertEquals(3, $font->countLines()); - $font->text("foo\nbar\nbaz"); - $this->assertEquals(3, $font->countLines()); - $font->text('foo - bar - baz'); - $this->assertEquals(3, $font->countLines()); - } -} diff --git a/tests/AbstractShapeTest.php b/tests/AbstractShapeTest.php deleted file mode 100644 index 64f88adc..00000000 --- a/tests/AbstractShapeTest.php +++ /dev/null @@ -1,43 +0,0 @@ -getMockForAbstractClass('\Intervention\Image\AbstractShape'); - $shape->background('foo'); - $this->assertEquals('foo', $shape->background); - $this->assertEquals(0, $shape->border_width); - } - - public function testBorder() - { - $shape = $this->getMockForAbstractClass('\Intervention\Image\AbstractShape'); - $shape->border(4); - $this->assertEquals(4, $shape->border_width); - $this->assertEquals('#000000', $shape->border_color); - } - - public function testBorderWithColor() - { - $shape = $this->getMockForAbstractClass('\Intervention\Image\AbstractShape'); - $shape->border(3, '#ff00ff'); - $this->assertEquals(3, $shape->border_width); - $this->assertEquals('#ff00ff', $shape->border_color); - } - - public function testHasBorder() - { - $shape = $this->getMockForAbstractClass('\Intervention\Image\AbstractShape'); - $this->assertFalse($shape->hasBorder()); - $shape->border(1); - $this->assertTrue($shape->hasBorder()); - } -} diff --git a/tests/ArgumentTest.php b/tests/ArgumentTest.php deleted file mode 100644 index a40a1080..00000000 --- a/tests/ArgumentTest.php +++ /dev/null @@ -1,422 +0,0 @@ -getMockedCommand(['foo'])); - $this->validateArgument($arg, 'foo'); - - $arg = new Argument($this->getMockedCommand(['foo', 'bar']), 1); - $this->validateArgument($arg, 'bar'); - - $arg = new Argument($this->getMockedCommand(), 0); - $this->validateArgument($arg, null); - } - - public function testRequiredPass() - { - $arg = new Argument($this->getMockedCommand(['foo'])); - $arg->required(); - $this->validateArgument($arg, 'foo'); - - $arg = new Argument($this->getMockedCommand([null])); - $arg->required(); - $this->validateArgument($arg, null); - - $arg = new Argument($this->getMockedCommand([0])); - $arg->required(); - $this->validateArgument($arg, 0); - } - - /** - * @expectedException \Intervention\Image\Exception\InvalidArgumentException - */ - public function testRequiredFail() - { - $arg = new Argument($this->getMockedCommand([])); - $arg->required(); - } - - /** - * @expectedException \Intervention\Image\Exception\InvalidArgumentException - */ - public function testRequiredFailSecondParameter() - { - $arg = new Argument($this->getMockedCommand(['foo']), 1); - $arg->required(); - } - - public function testTypeIntegerPass() - { - $arg = new Argument($this->getMockedCommand([])); - $arg->type('integer'); - $this->validateArgument($arg, null); - - $arg = new Argument($this->getMockedCommand([123])); - $arg->type('integer'); - $this->validateArgument($arg, 123); - } - - /** - * @expectedException \Intervention\Image\Exception\InvalidArgumentException - */ - public function testTypeIntegerFail() - { - $arg = new Argument($this->getMockedCommand(['foo'])); - $arg->type('integer'); - } - - public function testTypeArrayPass() - { - $arg = new Argument($this->getMockedCommand([])); - $arg->type('array'); - $this->validateArgument($arg, null); - - $arg = new Argument($this->getMockedCommand([[1,2,3]])); - $arg->type('array'); - $this->validateArgument($arg, [1,2,3]); - } - - /** - * @expectedException \Intervention\Image\Exception\InvalidArgumentException - */ - public function testTypeArrayFail() - { - $arg = new Argument($this->getMockedCommand(['foo'])); - $arg->type('array'); - } - - public function testTypeDigitPass() - { - $arg = new Argument($this->getMockedCommand([])); - $arg->type('digit'); - $this->validateArgument($arg, null); - - $arg = new Argument($this->getMockedCommand([0])); - $arg->type('digit'); - $this->validateArgument($arg, 0); - - $arg = new Argument($this->getMockedCommand([123])); - $arg->type('digit'); - $this->validateArgument($arg, 123); - - $arg = new Argument($this->getMockedCommand([5.0])); - $arg->type('digit'); - $this->validateArgument($arg, 5.0); - - $arg = new Argument($this->getMockedCommand([-10])); - $arg->type('digit'); - $this->validateArgument($arg, -10); - - $arg = new Argument($this->getMockedCommand([-10.0])); - $arg->type('digit'); - $this->validateArgument($arg, -10.0); - - $arg = new Argument($this->getMockedCommand(['12'])); - $arg->type('digit'); - $this->validateArgument($arg, '12'); - - $arg = new Argument($this->getMockedCommand(['12.0'])); - $arg->type('digit'); - $this->validateArgument($arg, '12.0'); - } - - /** - * @expectedException \Intervention\Image\Exception\InvalidArgumentException - */ - public function testTypeDigitFailString() - { - $arg = new Argument($this->getMockedCommand(['foo'])); - $arg->type('digit'); - } - - /** - * @expectedException \Intervention\Image\Exception\InvalidArgumentException - */ - public function testTypeDigitFailFloat() - { - $arg = new Argument($this->getMockedCommand([12.5])); - $arg->type('digit'); - } - - /** - * @expectedException \Intervention\Image\Exception\InvalidArgumentException - */ - public function testTypeDigitFailBool() - { - $arg = new Argument($this->getMockedCommand([true])); - $arg->type('digit'); - } - - public function testTypeNumericPass() - { - $arg = new Argument($this->getMockedCommand([])); - $arg->type('numeric'); - $this->validateArgument($arg, null); - - $arg = new Argument($this->getMockedCommand([12.3])); - $arg->type('numeric'); - $this->validateArgument($arg, 12.3); - } - - /** - * @expectedException \Intervention\Image\Exception\InvalidArgumentException - */ - public function testTypeNumericFail() - { - $arg = new Argument($this->getMockedCommand(['foo'])); - $arg->type('numeric'); - } - - public function testTypeBooleanPass() - { - $arg = new Argument($this->getMockedCommand([])); - $arg->type('boolean'); - $this->validateArgument($arg, null); - - $arg = new Argument($this->getMockedCommand([true])); - $arg->type('boolean'); - $this->validateArgument($arg, true); - - $arg = new Argument($this->getMockedCommand([false])); - $arg->type('boolean'); - $this->validateArgument($arg, false); - } - - /** - * @expectedException \Intervention\Image\Exception\InvalidArgumentException - */ - public function testTypeBooleanFail() - { - $arg = new Argument($this->getMockedCommand(['foo'])); - $arg->type('boolean'); - } - - public function testTypeStringPass() - { - $arg = new Argument($this->getMockedCommand([])); - $arg->type('string'); - $this->validateArgument($arg, null); - - $arg = new Argument($this->getMockedCommand(['foo'])); - $arg->type('string'); - $this->validateArgument($arg, 'foo'); - } - - /** - * @expectedException \Intervention\Image\Exception\InvalidArgumentException - */ - public function testTypeStringFail() - { - $arg = new Argument($this->getMockedCommand([12])); - $arg->type('string'); - } - - public function testTypeClosurePass() - { - $arg = new Argument($this->getMockedCommand([])); - $arg->type('closure'); - $this->validateArgument($arg, null); - - $c = function ($foo) {}; - $arg = new Argument($this->getMockedCommand([$c])); - $arg->type('closure'); - $this->validateArgument($arg, $c); - } - - /** - * @expectedException \Intervention\Image\Exception\InvalidArgumentException - */ - public function testTypeClosureFail() - { - $arg = new Argument($this->getMockedCommand(['foo'])); - $arg->type('closure'); - } - - public function testBetweenPass() - { - $arg = new Argument($this->getMockedCommand([])); - $arg->between(0, 10); - $this->validateArgument($arg, null); - - $arg = new Argument($this->getMockedCommand([null])); - $arg->between(0, 10); - $this->validateArgument($arg, null); - - $arg = new Argument($this->getMockedCommand([4.5])); - $arg->between(0, 10); - $this->validateArgument($arg, 4.5); - - $arg = new Argument($this->getMockedCommand([4.5])); - $arg->between(10, 1); - $this->validateArgument($arg, 4.5); - - $arg = new Argument($this->getMockedCommand([0])); - $arg->between(0, 10); - $this->validateArgument($arg, 0); - - $arg = new Argument($this->getMockedCommand([10])); - $arg->between(0, 10); - $this->validateArgument($arg, 10); - - $arg = new Argument($this->getMockedCommand([0])); - $arg->between(-100, 100); - $this->validateArgument($arg, 0); - - $arg = new Argument($this->getMockedCommand([-100])); - $arg->between(-100, 100); - $this->validateArgument($arg, -100); - } - - /** - * @expectedException \Intervention\Image\Exception\InvalidArgumentException - */ - public function testBetweenFailString() - { - $arg = new Argument($this->getMockedCommand(['foo'])); - $arg->between(1, 10); - } - - /** - * @expectedException \Intervention\Image\Exception\InvalidArgumentException - */ - public function testBetweenFailAbove() - { - $arg = new Argument($this->getMockedCommand([10.9])); - $arg->between(0, 10); - } - - /** - * @expectedException \Intervention\Image\Exception\InvalidArgumentException - */ - public function testBetweenFailBelow() - { - $arg = new Argument($this->getMockedCommand([-1])); - $arg->between(0, 10); - } - - /** - * @expectedException \Intervention\Image\Exception\InvalidArgumentException - */ - public function testBetweenFail() - { - $arg = new Argument($this->getMockedCommand([-1000])); - $arg->between(-100, 100); - } - - public function testMinPass() - { - $arg = new Argument($this->getMockedCommand([])); - $arg->min(10); - $this->validateArgument($arg, null); - - $arg = new Argument($this->getMockedCommand([null])); - $arg->min(10); - $this->validateArgument($arg, null); - - $arg = new Argument($this->getMockedCommand([50])); - $arg->min(10); - $this->validateArgument($arg, 50); - - $arg = new Argument($this->getMockedCommand([50])); - $arg->min(50); - $this->validateArgument($arg, 50); - - $arg = new Argument($this->getMockedCommand([50])); - $arg->min(-10); - $this->validateArgument($arg, 50); - - $arg = new Argument($this->getMockedCommand([-10])); - $arg->min(-10); - $this->validateArgument($arg, -10); - } - - /** - * @expectedException \Intervention\Image\Exception\InvalidArgumentException - */ - public function testMinFailString() - { - $arg = new Argument($this->getMockedCommand(['foo'])); - $arg->min(10); - } - - /** - * @expectedException \Intervention\Image\Exception\InvalidArgumentException - */ - public function testMinFail() - { - $arg = new Argument($this->getMockedCommand([10.9])); - $arg->min(11); - } - - public function testMaxPass() - { - $arg = new Argument($this->getMockedCommand([])); - $arg->max(100); - $this->validateArgument($arg, null); - - $arg = new Argument($this->getMockedCommand([null])); - $arg->max(100); - $this->validateArgument($arg, null); - - $arg = new Argument($this->getMockedCommand([50])); - $arg->max(100); - $this->validateArgument($arg, 50); - - $arg = new Argument($this->getMockedCommand([100])); - $arg->max(100); - $this->validateArgument($arg, 100); - - $arg = new Argument($this->getMockedCommand([-100])); - $arg->max(-10); - $this->validateArgument($arg, -100); - - $arg = new Argument($this->getMockedCommand([-10])); - $arg->max(-10); - $this->validateArgument($arg, -10); - } - - /** - * @expectedException \Intervention\Image\Exception\InvalidArgumentException - */ - public function testMaxFailString() - { - $arg = new Argument($this->getMockedCommand(['foo'])); - $arg->max(10); - } - - /** - * @expectedException \Intervention\Image\Exception\InvalidArgumentException - */ - public function testMaxFail() - { - $arg = new Argument($this->getMockedCommand([25])); - $arg->max(10); - } - - public function testValueDefault() - { - $arg = new Argument($this->getMockedCommand()); - $value = $arg->value('foo'); - $this->assertEquals('foo', $value); - - $arg = new Argument($this->getMockedCommand([null])); - $value = $arg->value('foo'); - $this->assertEquals('foo', $value); - } - - private function validateArgument($argument, $value) - { - $this->assertInstanceOf('\Intervention\Image\Commands\Argument', $argument); - $this->assertEquals($value, $argument->value()); - } - - private function getMockedCommand($arguments = []) - { - return $this->getMockForAbstractClass('\Intervention\Image\Commands\AbstractCommand', [$arguments]); - } -} diff --git a/tests/BackupCommandTest.php b/tests/BackupCommandTest.php deleted file mode 100644 index f7d6960f..00000000 --- a/tests/BackupCommandTest.php +++ /dev/null @@ -1,65 +0,0 @@ -shouldReceive('cloneCore')->once(); - $resource = imagecreatefromjpeg(__DIR__.'/images/test.jpg'); - $image = Mockery::mock('Intervention\Image\Image', [$driver]); - $image->shouldReceive('getCore')->once()->andReturn($resource); - $image->shouldReceive('setBackup')->once(); - $command = new BackupGd([]); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testGdWithName() - { - $driver = Mockery::mock('Intervention\Image\Gd\Driver'); - $driver->shouldReceive('cloneCore')->once(); - $resource = imagecreatefromjpeg(__DIR__.'/images/test.jpg'); - $image = Mockery::mock('Intervention\Image\Image', [$driver]); - $image->shouldReceive('getCore')->once()->andReturn($resource); - $image->shouldReceive('setBackup')->once(); - $command = new BackupGd(['name' => 'fooBackup']); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagickWithoutName() - { - $driver = Mockery::mock('Intervention\Image\Imagick\Driver'); - $driver->shouldReceive('cloneCore')->once(); - $imagick = Mockery::mock('Imagick'); - $image = Mockery::mock('Intervention\Image\Image', [$driver]); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - $image->shouldReceive('setBackup')->once(); - $command = new BackupImagick([]); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagickWithName() - { - $driver = Mockery::mock('Intervention\Image\Imagick\Driver'); - $driver->shouldReceive('cloneCore')->once(); - $imagick = Mockery::mock('Imagick'); - $image = Mockery::mock('Intervention\Image\Image', [$driver]); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - $image->shouldReceive('setBackup')->once(); - $command = new BackupImagick(['name' => 'fooBackup']); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/BlurCommandTest.php b/tests/BlurCommandTest.php deleted file mode 100644 index 6267d48e..00000000 --- a/tests/BlurCommandTest.php +++ /dev/null @@ -1,34 +0,0 @@ -shouldReceive('getCore')->times(2)->andReturn($resource); - $command = new BlurGd([2]); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagick() - { - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('blurimage')->with(2, 1)->andReturn(true); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - $command = new BlurImagick([2]); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/BrightnessCommandTest.php b/tests/BrightnessCommandTest.php deleted file mode 100644 index 2c225d0b..00000000 --- a/tests/BrightnessCommandTest.php +++ /dev/null @@ -1,34 +0,0 @@ -shouldReceive('getCore')->once()->andReturn($resource); - $command = new BrightnessGd([12]); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagick() - { - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('modulateimage')->with(112, 100, 100)->andReturn(true); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - $command = new BrightnessImagick([12]); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/ChecksumCommandTest.php b/tests/ChecksumCommandTest.php deleted file mode 100644 index 5be7ca68..00000000 --- a/tests/ChecksumCommandTest.php +++ /dev/null @@ -1,27 +0,0 @@ -shouldReceive('getSize')->once()->andReturn($size); - $image->shouldReceive('pickColor')->times(9)->andReturn($color); - $command = new ChecksumCommand([]); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertTrue($command->hasOutput()); - $this->assertEquals('ec9cbdb71be04e26b4a89333f20c273b', $command->getOutput()); - } -} diff --git a/tests/CircleCommandTest.php b/tests/CircleCommandTest.php deleted file mode 100644 index 9c916a14..00000000 --- a/tests/CircleCommandTest.php +++ /dev/null @@ -1,43 +0,0 @@ -shouldReceive('getDriverName')->once()->andReturn('Gd'); - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getDriver')->once()->andReturn($driver); - $image->shouldReceive('getCore')->once()->andReturn($resource); - $command = new CircleCommand([250, 10, 20]); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertFalse($command->hasOutput()); - } - - public function testImagick() - { - $imagick = Mockery::mock('\Imagick'); - $imagick->shouldReceive('drawimage'); - $driver = Mockery::mock('\Intervention\Image\Imagick\Driver'); - $driver->shouldReceive('getDriverName')->once()->andReturn('Imagick'); - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getDriver')->once()->andReturn($driver); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - - $command = new CircleCommand([25, 10, 20]); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertFalse($command->hasOutput()); - } - -} diff --git a/tests/CircleShapeTest.php b/tests/CircleShapeTest.php deleted file mode 100644 index 18a51482..00000000 --- a/tests/CircleShapeTest.php +++ /dev/null @@ -1,52 +0,0 @@ -assertInstanceOf('Intervention\Image\Gd\Shapes\CircleShape', $circle); - $this->assertEquals(250, $circle->diameter); - - } - - public function testGdApplyToImage() - { - $core = imagecreatetruecolor(300, 200); - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($core); - $circle = new CircleGd(250); - $result = $circle->applyToImage($image, 10, 20); - $this->assertInstanceOf('Intervention\Image\Gd\Shapes\CircleShape', $circle); - $this->assertTrue($result); - } - - public function testImagickConstructor() - { - $circle = new CircleImagick(250); - $this->assertInstanceOf('Intervention\Image\Imagick\Shapes\CircleShape', $circle); - $this->assertEquals(250, $circle->width); - } - - public function testImagickApplyToImage() - { - $core = Mockery::mock('\Imagick'); - $core->shouldReceive('drawimage')->once(); - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($core); - $circle = new CircleImagick(250); - $result = $circle->applyToImage($image, 10, 20); - $this->assertInstanceOf('Intervention\Image\Imagick\Shapes\CircleShape', $circle); - $this->assertTrue($result); - } - -} diff --git a/tests/CollectionTest.php b/tests/CollectionTest.php new file mode 100644 index 00000000..a52b702f --- /dev/null +++ b/tests/CollectionTest.php @@ -0,0 +1,147 @@ +assertInstanceOf(Collection::class, $collection); + + $collection = Collection::create(['foo', 'bar', 'baz']); + $this->assertInstanceOf(Collection::class, $collection); + } + + public function testIterator() + { + $collection = new Collection(['foo', 'bar', 'baz']); + foreach ($collection as $key => $item) { + switch ($key) { + case 0: + $this->assertEquals('foo', $item); + break; + + case 1: + $this->assertEquals('bar', $item); + break; + + case 2: + $this->assertEquals('baz', $item); + break; + } + } + } + + public function testCount() + { + $collection = new Collection(['foo', 'bar', 'baz']); + $this->assertEquals(3, $collection->count()); + $this->assertEquals(3, count($collection)); + } + + public function testFilter() + { + $collection = new Collection(['foo', 'bar', 'baz']); + $this->assertEquals(3, $collection->count()); + $collection = $collection->filter(function ($text) { + return substr($text, 0, 1) == 'b'; + }); + $this->assertEquals(2, $collection->count()); + } + + public function testFirstLast() + { + $collection = new Collection(['foo', 'bar', 'baz']); + $this->assertEquals('foo', $collection->first()); + $this->assertEquals('baz', $collection->last()); + + $collection = new Collection(); + $this->assertNull($collection->first()); + $this->assertNull($collection->last()); + } + + public function testPush() + { + $collection = new Collection(['foo', 'bar', 'baz']); + $this->assertEquals(3, $collection->count()); + $result = $collection->push('test'); + $this->assertEquals(4, $collection->count()); + $this->assertInstanceOf(Collection::class, $result); + } + + public function testPushEach() + { + $collection = Collection::create()->pushEach(['foo', 'bar', 'baz'], function ($item) { + return strtoupper($item); + }); + $this->assertEquals(3, $collection->count()); + $this->assertEquals('FOO', $collection->get(0)); + $this->assertEquals('BAR', $collection->get(1)); + $this->assertEquals('BAZ', $collection->get(2)); + } + + public function testToArray() + { + $collection = new Collection(['foo', 'bar', 'baz']); + $this->assertEquals(['foo', 'bar', 'baz'], $collection->toArray()); + } + + public function testMap(): void + { + $collection = new Collection(['FOO', 'BAR', 'BAZ']); + $mapped = $collection->map(function ($item) { + return strtolower($item); + }); + $this->assertInstanceOf(Collection::class, $collection); + $this->assertInstanceOf(Collection::class, $mapped); + $this->assertEquals(['FOO', 'BAR', 'BAZ'], $collection->toArray()); + $this->assertEquals(['foo', 'bar', 'baz'], $mapped->toArray()); + } + + public function testGet(): void + { + $collection = new Collection([ + 'first', + 'second', + ['testx' => 'x'], + 'foo' => 'foo_value', + 'bar' => 'bar_value', + 'baz' => [ + 'test1' => '1', + 'test2' => '2', + 'test3' => [ + 'example' => 'value' + ] + ] + ]); + + $this->assertEquals('first', $collection->get(0)); + $this->assertEquals('second', $collection->get(1)); + $this->assertEquals('first', $collection->get('0')); + $this->assertEquals('second', $collection->get('1')); + $this->assertEquals('x', $collection->get('2.testx')); + $this->assertEquals('foo_value', $collection->get('foo')); + $this->assertEquals('bar_value', $collection->get('bar')); + $this->assertEquals('1', $collection->get('baz.test1')); + $this->assertEquals('2', $collection->get('baz.test2')); + $this->assertEquals('value', $collection->get('baz.test3.example')); + $this->assertEquals('value', $collection->get('baz.test3.example', 'default')); + $this->assertEquals('default', $collection->get('baz.test3.no', 'default')); + $this->assertEquals(['example' => 'value'], $collection->get('baz.test3')); + } + + public function testEmpty(): void + { + $collection = new Collection([1, 2, 3]); + $this->assertEquals(3, $collection->count()); + $result = $collection->empty(); + $this->assertEquals(0, $collection->count()); + $this->assertEquals(0, $result->count()); + } +} diff --git a/tests/ColorizeCommandTest.php b/tests/ColorizeCommandTest.php deleted file mode 100644 index 0b3f9ece..00000000 --- a/tests/ColorizeCommandTest.php +++ /dev/null @@ -1,37 +0,0 @@ -shouldReceive('getCore')->once()->andReturn($resource); - $command = new ColorizeGd([20, 0, -40]); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagick() - { - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('getquantumrange')->with()->once()->andReturn(['quantumRangeLong' => 42]); - $imagick->shouldReceive('levelimage')->with(0, 4, 42, \Imagick::CHANNEL_RED)->once()->andReturn(true); - $imagick->shouldReceive('levelimage')->with(0, 1, 42, \Imagick::CHANNEL_GREEN)->once()->andReturn(true); - $imagick->shouldReceive('levelimage')->with(0, 0.6, 42, \Imagick::CHANNEL_BLUE)->once()->andReturn(true); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->times(4)->andReturn($imagick); - $command = new ColorizeImagick([20, 0, -40]); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/Colors/Cmyk/ChannelTest.php b/tests/Colors/Cmyk/ChannelTest.php new file mode 100644 index 00000000..64f03f33 --- /dev/null +++ b/tests/Colors/Cmyk/ChannelTest.php @@ -0,0 +1,60 @@ +assertInstanceOf(Channel::class, $channel); + + $channel = new Channel(value: 0); + $this->assertInstanceOf(Channel::class, $channel); + + $channel = new Channel(normalized: 0); + $this->assertInstanceOf(Channel::class, $channel); + + $this->expectException(ColorException::class); + $channel = new Channel(); + + $this->expectException(ColorException::class); + $channel = new Channel(normalized: 2); + } + + public function testValue(): void + { + $channel = new Channel(10); + $this->assertEquals(10, $channel->value()); + } + + public function testNormalize(): void + { + $channel = new Channel(100); + $this->assertEquals(1, $channel->normalize()); + $channel = new Channel(0); + $this->assertEquals(0, $channel->normalize()); + $channel = new Channel(20); + $this->assertEquals(.2, $channel->normalize()); + } + + public function testValidate(): void + { + $this->expectException(ColorException::class); + new Channel(101); + + $this->expectException(ColorException::class); + new Channel(-1); + } +} diff --git a/tests/Colors/Cmyk/ColorTest.php b/tests/Colors/Cmyk/ColorTest.php new file mode 100644 index 00000000..6a06634c --- /dev/null +++ b/tests/Colors/Cmyk/ColorTest.php @@ -0,0 +1,76 @@ +assertInstanceOf(Color::class, $color); + } + + public function testColorspace(): void + { + $color = new Color(0, 0, 0, 0); + $this->assertInstanceOf(Colorspace::class, $color->colorspace()); + } + + public function testChannels(): void + { + $color = new Color(10, 20, 30, 40); + $this->assertIsArray($color->channels()); + $this->assertCount(4, $color->channels()); + } + + public function testChannel(): void + { + $color = new Color(10, 20, 30, 40); + $channel = $color->channel(Cyan::class); + $this->assertInstanceOf(Cyan::class, $channel); + $this->assertEquals(10, $channel->value()); + } + + public function testCyanMagentaYellowKey(): void + { + $color = new Color(10, 20, 30, 40); + $this->assertInstanceOf(Cyan::class, $color->cyan()); + $this->assertInstanceOf(Magenta::class, $color->magenta()); + $this->assertInstanceOf(Yellow::class, $color->yellow()); + $this->assertInstanceOf(Key::class, $color->key()); + $this->assertEquals(10, $color->cyan()->value()); + $this->assertEquals(20, $color->magenta()->value()); + $this->assertEquals(30, $color->yellow()->value()); + $this->assertEquals(40, $color->key()->value()); + } + + public function testToArray(): void + { + $color = new Color(10, 20, 30, 40); + $this->assertEquals([10, 20, 30, 40], $color->toArray()); + } + + public function testNormalize(): void + { + $color = new Color(100, 50, 20, 0); + $this->assertEquals([1.0, 0.5, 0.2, 0.0], $color->normalize()); + } + + public function testToString(): void + { + $color = new Color(100, 50, 20, 0); + $this->assertEquals('cmyk(100%, 50%, 20%, 0%)', (string) $color); + } +} diff --git a/tests/Colors/Cmyk/ColorspaceTest.php b/tests/Colors/Cmyk/ColorspaceTest.php new file mode 100644 index 00000000..dacd8fed --- /dev/null +++ b/tests/Colors/Cmyk/ColorspaceTest.php @@ -0,0 +1,80 @@ +colorFromNormalized([0, 1, 0, 1]); + $this->assertInstanceOf(CmykColor::class, $result); + $this->assertEquals(0, $result->channel(Cyan::class)->value()); + $this->assertEquals(100, $result->channel(Magenta::class)->value()); + $this->assertEquals(0, $result->channel(Yellow::class)->value()); + $this->assertEquals(100, $result->channel(Key::class)->value()); + } + + public function testImportRgbColor(): void + { + $colorspace = new Colorspace(); + + $result = $colorspace->importColor(new RgbColor(255, 0, 255)); + $this->assertInstanceOf(CmykColor::class, $result); + $this->assertEquals(0, $result->channel(Cyan::class)->value()); + $this->assertEquals(100, $result->channel(Magenta::class)->value()); + $this->assertEquals(0, $result->channel(Yellow::class)->value()); + $this->assertEquals(0, $result->channel(Key::class)->value()); + + $result = $colorspace->importColor(new RgbColor(127, 127, 127)); + $this->assertInstanceOf(CmykColor::class, $result); + $this->assertEquals(0, $result->channel(Cyan::class)->value()); + $this->assertEquals(0, $result->channel(Magenta::class)->value()); + $this->assertEquals(0, $result->channel(Yellow::class)->value()); + $this->assertEquals(50, $result->channel(Key::class)->value()); + } + + public function testImportHsvColor(): void + { + $colorspace = new Colorspace(); + $result = $colorspace->importColor(new HsvColor(0, 0, 50)); + $this->assertInstanceOf(CmykColor::class, $result); + $this->assertEquals(0, $result->channel(Cyan::class)->value()); + $this->assertEquals(0, $result->channel(Magenta::class)->value()); + $this->assertEquals(0, $result->channel(Yellow::class)->value()); + $this->assertEquals(50, $result->channel(Key::class)->value()); + } + + public function testImportHslColor(): void + { + $colorspace = new Colorspace(); + + $result = $colorspace->importColor(new HslColor(300, 100, 50)); + $this->assertInstanceOf(CmykColor::class, $result); + $this->assertEquals(0, $result->channel(Cyan::class)->value()); + $this->assertEquals(100, $result->channel(Magenta::class)->value()); + $this->assertEquals(0, $result->channel(Yellow::class)->value()); + $this->assertEquals(0, $result->channel(Key::class)->value()); + + $result = $colorspace->importColor(new HslColor(0, 0, 50)); + $this->assertInstanceOf(CmykColor::class, $result); + $this->assertEquals(0, $result->channel(Cyan::class)->value()); + $this->assertEquals(0, $result->channel(Magenta::class)->value()); + $this->assertEquals(0, $result->channel(Yellow::class)->value()); + $this->assertEquals(50, $result->channel(Key::class)->value()); + } +} diff --git a/tests/Colors/Cmyk/Decoders/StringColorDecoderTest.php b/tests/Colors/Cmyk/Decoders/StringColorDecoderTest.php new file mode 100644 index 00000000..f6af4237 --- /dev/null +++ b/tests/Colors/Cmyk/Decoders/StringColorDecoderTest.php @@ -0,0 +1,35 @@ +decode('cmyk(0,0,0,0)'); + $this->assertInstanceOf(Color::class, $result); + $this->assertEquals([0, 0, 0, 0], $result->toArray()); + + $result = $decoder->decode('cmyk(0, 100, 100, 0)'); + $this->assertInstanceOf(Color::class, $result); + $this->assertEquals([0, 100, 100, 0], $result->toArray()); + + $result = $decoder->decode('cmyk(0, 100, 100, 0)'); + $this->assertInstanceOf(Color::class, $result); + $this->assertEquals([0, 100, 100, 0], $result->toArray()); + + + $result = $decoder->decode('cmyk(0%, 100%, 100%, 0%)'); + $this->assertInstanceOf(Color::class, $result); + $this->assertEquals([0, 100, 100, 0], $result->toArray()); + } +} diff --git a/tests/Colors/Hsl/ChannelTest.php b/tests/Colors/Hsl/ChannelTest.php new file mode 100644 index 00000000..2c7f9c27 --- /dev/null +++ b/tests/Colors/Hsl/ChannelTest.php @@ -0,0 +1,74 @@ +assertInstanceOf(Hue::class, $channel); + + $channel = new Hue(value: 0); + $this->assertInstanceOf(Hue::class, $channel); + + $channel = new Hue(normalized: 0); + $this->assertInstanceOf(Hue::class, $channel); + + $this->expectException(ColorException::class); + $channel = new Hue(); + + $this->expectException(ColorException::class); + $channel = new Hue(normalized: 2); + } + + public function testValue(): void + { + $channel = new Hue(10); + $this->assertEquals(10, $channel->value()); + } + + public function testNormalize(): void + { + $channel = new Hue(360); + $this->assertEquals(1, $channel->normalize()); + $channel = new Hue(180); + $this->assertEquals(0.5, $channel->normalize()); + $channel = new Hue(0); + $this->assertEquals(0, $channel->normalize()); + $channel = new Luminance(90); + $this->assertEquals(.9, $channel->normalize()); + } + + public function testValidate(): void + { + $this->expectException(ColorException::class); + new Hue(361); + + $this->expectException(ColorException::class); + new Hue(-1); + + $this->expectException(ColorException::class); + new Saturation(101); + + $this->expectException(ColorException::class); + new Saturation(-1); + + $this->expectException(ColorException::class); + new Luminance(101); + + $this->expectException(ColorException::class); + new Luminance(-1); + } +} diff --git a/tests/Colors/Hsl/ColorTest.php b/tests/Colors/Hsl/ColorTest.php new file mode 100644 index 00000000..9039309c --- /dev/null +++ b/tests/Colors/Hsl/ColorTest.php @@ -0,0 +1,84 @@ +assertInstanceOf(Color::class, $color); + } + + public function testColorspace(): void + { + $color = new Color(0, 0, 0); + $this->assertInstanceOf(Colorspace::class, $color->colorspace()); + } + + public function testChannels(): void + { + $color = new Color(10, 20, 30); + $this->assertIsArray($color->channels()); + $this->assertCount(3, $color->channels()); + } + + public function testChannel(): void + { + $color = new Color(10, 20, 30); + $channel = $color->channel(Hue::class); + $this->assertInstanceOf(Hue::class, $channel); + $this->assertEquals(10, $channel->value()); + } + + public function testHueSaturationLuminanceKey(): void + { + $color = new Color(10, 20, 30); + $this->assertInstanceOf(Hue::class, $color->hue()); + $this->assertInstanceOf(Saturation::class, $color->saturation()); + $this->assertInstanceOf(Luminance::class, $color->luminance()); + $this->assertEquals(10, $color->hue()->value()); + $this->assertEquals(20, $color->saturation()->value()); + $this->assertEquals(30, $color->luminance()->value()); + } + + public function testToArray(): void + { + $color = new Color(10, 20, 30); + $this->assertEquals([10, 20, 30], $color->toArray()); + } + + public function testNormalize(): void + { + $color = new Color(180, 50, 25); + $this->assertEquals([.5, 0.5, 0.25], $color->normalize()); + } + + public function testToString(): void + { + $color = new Color(100, 50, 20, 0); + $this->assertEquals('hsl(100, 50%, 20%)', (string) $color); + } + + public function testIsGreyscale(): void + { + $color = new Color(0, 1, 0); + $this->assertFalse($color->isGreyscale()); + + $color = new Color(1, 0, 0); + $this->assertTrue($color->isGreyscale()); + + $color = new Color(0, 0, 1); + $this->assertTrue($color->isGreyscale()); + } +} diff --git a/tests/Colors/Hsl/ColorspaceTest.php b/tests/Colors/Hsl/ColorspaceTest.php new file mode 100644 index 00000000..365a8e7b --- /dev/null +++ b/tests/Colors/Hsl/ColorspaceTest.php @@ -0,0 +1,80 @@ +colorFromNormalized([1, 0, 1]); + $this->assertInstanceOf(HslColor::class, $result); + $this->assertEquals(360, $result->channel(Hue::class)->value()); + $this->assertEquals(0, $result->channel(Saturation::class)->value()); + $this->assertEquals(100, $result->channel(Luminance::class)->value()); + } + + public function testImportRgbColor(): void + { + $colorspace = new Colorspace(); + + $result = $colorspace->importColor(new RgbColor(255, 0, 255)); + $this->assertInstanceOf(HslColor::class, $result); + $this->assertEquals(300, $result->channel(Hue::class)->value()); + $this->assertEquals(100, $result->channel(Saturation::class)->value()); + $this->assertEquals(50, $result->channel(Luminance::class)->value()); + + $result = $colorspace->importColor(new RgbColor(127, 127, 127)); + $this->assertInstanceOf(HslColor::class, $result); + $this->assertEquals(0, $result->channel(Hue::class)->value()); + $this->assertEquals(0, $result->channel(Saturation::class)->value()); + $this->assertEquals(50, $result->channel(Luminance::class)->value()); + } + + public function testImportCmykColor(): void + { + $colorspace = new Colorspace(); + + $result = $colorspace->importColor(new CmykColor(0, 100, 0, 0)); + $this->assertInstanceOf(HslColor::class, $result); + $this->assertEquals(300, $result->channel(Hue::class)->value()); + $this->assertEquals(100, $result->channel(Saturation::class)->value()); + $this->assertEquals(50, $result->channel(Luminance::class)->value()); + + $result = $colorspace->importColor(new CmykColor(0, 0, 0, 50)); + $this->assertInstanceOf(HslColor::class, $result); + $this->assertEquals(0, $result->channel(Hue::class)->value()); + $this->assertEquals(0, $result->channel(Saturation::class)->value()); + $this->assertEquals(50, $result->channel(Luminance::class)->value()); + } + + public function testImportHsvColor(): void + { + $colorspace = new Colorspace(); + + $result = $colorspace->importColor(new HsvColor(300, 100, 100)); + $this->assertInstanceOf(HslColor::class, $result); + $this->assertEquals(300, $result->channel(Hue::class)->value()); + $this->assertEquals(100, $result->channel(Saturation::class)->value()); + $this->assertEquals(50, $result->channel(Luminance::class)->value()); + + $result = $colorspace->importColor(new HsvColor(0, 0, 50)); + $this->assertInstanceOf(HslColor::class, $result); + $this->assertEquals(0, $result->channel(Hue::class)->value()); + $this->assertEquals(0, $result->channel(Saturation::class)->value()); + $this->assertEquals(50, $result->channel(Luminance::class)->value()); + } +} diff --git a/tests/Colors/Hsl/Decoders/StringColorDecoderTest.php b/tests/Colors/Hsl/Decoders/StringColorDecoderTest.php new file mode 100644 index 00000000..351ba02d --- /dev/null +++ b/tests/Colors/Hsl/Decoders/StringColorDecoderTest.php @@ -0,0 +1,35 @@ +decode('hsl(0,0,0)'); + $this->assertInstanceOf(Color::class, $result); + $this->assertEquals([0, 0, 0], $result->toArray()); + + $result = $decoder->decode('hsl(0, 100, 50)'); + $this->assertInstanceOf(Color::class, $result); + $this->assertEquals([0, 100, 50], $result->toArray()); + + $result = $decoder->decode('hsl(360, 100, 50)'); + $this->assertInstanceOf(Color::class, $result); + $this->assertEquals([360, 100, 50], $result->toArray()); + + $result = $decoder->decode('hsl(180, 100%, 50%)'); + $this->assertInstanceOf(Color::class, $result); + $this->assertEquals([180, 100, 50], $result->toArray()); + } +} diff --git a/tests/Colors/Hsv/ChannelTest.php b/tests/Colors/Hsv/ChannelTest.php new file mode 100644 index 00000000..2e463c53 --- /dev/null +++ b/tests/Colors/Hsv/ChannelTest.php @@ -0,0 +1,75 @@ +assertInstanceOf(Hue::class, $channel); + + $channel = new Hue(value: 0); + $this->assertInstanceOf(Hue::class, $channel); + + $channel = new Hue(normalized: 0); + $this->assertInstanceOf(Hue::class, $channel); + + $this->expectException(ColorException::class); + $channel = new Hue(); + + $this->expectException(ColorException::class); + $channel = new Hue(normalized: 2); + } + + public function testValue(): void + { + $channel = new Hue(10); + $this->assertEquals(10, $channel->value()); + } + + public function testNormalize(): void + { + $channel = new Hue(360); + $this->assertEquals(1, $channel->normalize()); + $channel = new Hue(180); + $this->assertEquals(0.5, $channel->normalize()); + $channel = new Hue(0); + $this->assertEquals(0, $channel->normalize()); + $channel = new Hue(90); + $this->assertEquals(.25, $channel->normalize()); + } + + public function testValidate(): void + { + $this->expectException(ColorException::class); + new Hue(361); + + $this->expectException(ColorException::class); + new Hue(-1); + + $this->expectException(ColorException::class); + new Saturation(101); + + $this->expectException(ColorException::class); + new Saturation(-1); + + $this->expectException(ColorException::class); + new Value(101); + + $this->expectException(ColorException::class); + new Value(-1); + } +} diff --git a/tests/Colors/Hsv/ColorTest.php b/tests/Colors/Hsv/ColorTest.php new file mode 100644 index 00000000..3fc70b09 --- /dev/null +++ b/tests/Colors/Hsv/ColorTest.php @@ -0,0 +1,84 @@ +assertInstanceOf(Color::class, $color); + } + + public function testColorspace(): void + { + $color = new Color(0, 0, 0); + $this->assertInstanceOf(Colorspace::class, $color->colorspace()); + } + + public function testChannels(): void + { + $color = new Color(10, 20, 30); + $this->assertIsArray($color->channels()); + $this->assertCount(3, $color->channels()); + } + + public function testChannel(): void + { + $color = new Color(10, 20, 30); + $channel = $color->channel(Hue::class); + $this->assertInstanceOf(Hue::class, $channel); + $this->assertEquals(10, $channel->value()); + } + + public function testHueSaturationValueKey(): void + { + $color = new Color(10, 20, 30); + $this->assertInstanceOf(Hue::class, $color->hue()); + $this->assertInstanceOf(Saturation::class, $color->saturation()); + $this->assertInstanceOf(Value::class, $color->value()); + $this->assertEquals(10, $color->hue()->value()); + $this->assertEquals(20, $color->saturation()->value()); + $this->assertEquals(30, $color->value()->value()); + } + + public function testToArray(): void + { + $color = new Color(10, 20, 30); + $this->assertEquals([10, 20, 30], $color->toArray()); + } + + public function testNormalize(): void + { + $color = new Color(180, 50, 25); + $this->assertEquals([.5, 0.5, 0.25], $color->normalize()); + } + + public function testToString(): void + { + $color = new Color(100, 50, 20, 0); + $this->assertEquals('hsv(100, 50%, 20%)', (string) $color); + } + + public function testIsGreyscale(): void + { + $color = new Color(0, 1, 0); + $this->assertFalse($color->isGreyscale()); + + $color = new Color(1, 0, 0); + $this->assertTrue($color->isGreyscale()); + + $color = new Color(0, 0, 1); + $this->assertTrue($color->isGreyscale()); + } +} diff --git a/tests/Colors/Hsv/ColorspaceTest.php b/tests/Colors/Hsv/ColorspaceTest.php new file mode 100644 index 00000000..00def55a --- /dev/null +++ b/tests/Colors/Hsv/ColorspaceTest.php @@ -0,0 +1,80 @@ +colorFromNormalized([1, 0, 1]); + $this->assertInstanceOf(HsvColor::class, $result); + $this->assertEquals(360, $result->channel(Hue::class)->value()); + $this->assertEquals(0, $result->channel(Saturation::class)->value()); + $this->assertEquals(100, $result->channel(Value::class)->value()); + } + + public function testImportRgbColor(): void + { + $colorspace = new Colorspace(); + + $result = $colorspace->importColor(new RgbColor(255, 0, 255)); + $this->assertInstanceOf(HsvColor::class, $result); + $this->assertEquals(300, $result->channel(Hue::class)->value()); + $this->assertEquals(100, $result->channel(Saturation::class)->value()); + $this->assertEquals(100, $result->channel(Value::class)->value()); + + $result = $colorspace->importColor(new RgbColor(127, 127, 127)); + $this->assertInstanceOf(HsvColor::class, $result); + $this->assertEquals(0, $result->channel(Hue::class)->value()); + $this->assertEquals(0, $result->channel(Saturation::class)->value()); + $this->assertEquals(50, $result->channel(Value::class)->value()); + } + + public function testImportCmykColor(): void + { + $colorspace = new Colorspace(); + + $result = $colorspace->importColor(new CmykColor(0, 100, 0, 0)); + $this->assertInstanceOf(HsvColor::class, $result); + $this->assertEquals(300, $result->channel(Hue::class)->value()); + $this->assertEquals(100, $result->channel(Saturation::class)->value()); + $this->assertEquals(100, $result->channel(Value::class)->value()); + + $result = $colorspace->importColor(new CmykColor(0, 0, 0, 50)); + $this->assertInstanceOf(HsvColor::class, $result); + $this->assertEquals(0, $result->channel(Hue::class)->value()); + $this->assertEquals(0, $result->channel(Saturation::class)->value()); + $this->assertEquals(50, $result->channel(Value::class)->value()); + } + + public function testImportHslColor(): void + { + $colorspace = new Colorspace(); + + $result = $colorspace->importColor(new HslColor(300, 100, 50)); + $this->assertInstanceOf(HsvColor::class, $result); + $this->assertEquals(300, $result->channel(Hue::class)->value()); + $this->assertEquals(100, $result->channel(Saturation::class)->value()); + $this->assertEquals(100, $result->channel(Value::class)->value()); + + $result = $colorspace->importColor(new HslColor(0, 0, 50)); + $this->assertInstanceOf(HsvColor::class, $result); + $this->assertEquals(0, $result->channel(Hue::class)->value()); + $this->assertEquals(0, $result->channel(Saturation::class)->value()); + $this->assertEquals(50, $result->channel(Value::class)->value()); + } +} diff --git a/tests/Colors/Hsv/Decoders/StringColorDecoderTest.php b/tests/Colors/Hsv/Decoders/StringColorDecoderTest.php new file mode 100644 index 00000000..6aa95c89 --- /dev/null +++ b/tests/Colors/Hsv/Decoders/StringColorDecoderTest.php @@ -0,0 +1,56 @@ +decode('hsv(0,0,0)'); + $this->assertInstanceOf(Color::class, $result); + $this->assertEquals([0, 0, 0], $result->toArray()); + + $result = $decoder->decode('hsv(0, 100, 100)'); + $this->assertInstanceOf(Color::class, $result); + $this->assertEquals([0, 100, 100], $result->toArray()); + + $result = $decoder->decode('hsv(360, 100, 100)'); + $this->assertInstanceOf(Color::class, $result); + $this->assertEquals([360, 100, 100], $result->toArray()); + + + $result = $decoder->decode('hsv(180, 100%, 100%)'); + $this->assertInstanceOf(Color::class, $result); + $this->assertEquals([180, 100, 100], $result->toArray()); + } + + public function testDecodeHsb(): void + { + $decoder = new StringColorDecoder(); + $result = $decoder->decode('hsb(0,0,0)'); + $this->assertInstanceOf(Color::class, $result); + $this->assertEquals([0, 0, 0], $result->toArray()); + + $result = $decoder->decode('hsb(0, 100, 100)'); + $this->assertInstanceOf(Color::class, $result); + $this->assertEquals([0, 100, 100], $result->toArray()); + + $result = $decoder->decode('hsb(360, 100, 100)'); + $this->assertInstanceOf(Color::class, $result); + $this->assertEquals([360, 100, 100], $result->toArray()); + + + $result = $decoder->decode('hsb(180, 100%, 100%)'); + $this->assertInstanceOf(Color::class, $result); + $this->assertEquals([180, 100, 100], $result->toArray()); + } +} diff --git a/tests/Colors/Rgb/ChannelTest.php b/tests/Colors/Rgb/ChannelTest.php new file mode 100644 index 00000000..5f2c45d6 --- /dev/null +++ b/tests/Colors/Rgb/ChannelTest.php @@ -0,0 +1,59 @@ +assertInstanceOf(Channel::class, $channel); + + $channel = new Channel(value: 0); + $this->assertInstanceOf(Channel::class, $channel); + + $channel = new Channel(normalized: 0); + $this->assertInstanceOf(Channel::class, $channel); + + $this->expectException(ColorException::class); + $channel = new Channel(); + + $this->expectException(ColorException::class); + $channel = new Channel(normalized: 2); + } + + public function testValue(): void + { + $channel = new Channel(10); + $this->assertEquals(10, $channel->value()); + } + + public function testNormalize(): void + { + $channel = new Channel(255); + $this->assertEquals(1, $channel->normalize()); + $channel = new Channel(0); + $this->assertEquals(0, $channel->normalize()); + $channel = new Channel(51); + $this->assertEquals(.2, $channel->normalize()); + } + + public function testValidate(): void + { + $this->expectException(ColorException::class); + new Channel(256); + + $this->expectException(ColorException::class); + new Channel(-1); + } +} diff --git a/tests/Colors/Rgb/ColorTest.php b/tests/Colors/Rgb/ColorTest.php new file mode 100644 index 00000000..8f0d5890 --- /dev/null +++ b/tests/Colors/Rgb/ColorTest.php @@ -0,0 +1,129 @@ +assertInstanceOf(Color::class, $color); + + $color = new Color(0, 0, 0, 0); + $this->assertInstanceOf(Color::class, $color); + } + + public function testCreate(): void + { + $color = Color::create('ccc'); + $this->assertInstanceOf(Color::class, $color); + $this->assertEquals([204, 204, 204, 255], $color->toArray()); + + $color = Color::create('rgba(10, 20, 30, .2)'); + $this->assertInstanceOf(Color::class, $color); + $this->assertEquals([10, 20, 30, 51], $color->toArray()); + } + + public function testColorspace(): void + { + $color = new Color(0, 0, 0); + $this->assertInstanceOf(RgbColorspace::class, $color->colorspace()); + } + + public function testChannels(): void + { + $color = new Color(10, 20, 30); + $this->assertIsArray($color->channels()); + $this->assertCount(4, $color->channels()); + } + + public function testChannel(): void + { + $color = new Color(10, 20, 30); + $channel = $color->channel(Red::class); + $this->assertInstanceOf(Red::class, $channel); + $this->assertEquals(10, $channel->value()); + } + + public function testRedGreenBlue(): void + { + $color = new Color(10, 20, 30); + $this->assertInstanceOf(Red::class, $color->red()); + $this->assertInstanceOf(Green::class, $color->green()); + $this->assertInstanceOf(Blue::class, $color->blue()); + $this->assertEquals(10, $color->red()->value()); + $this->assertEquals(20, $color->green()->value()); + $this->assertEquals(30, $color->blue()->value()); + } + + public function testToArray(): void + { + $color = new Color(10, 20, 30); + $this->assertEquals([10, 20, 30, 255], $color->toArray()); + } + + public function testToHex(): void + { + $color = new Color(181, 55, 23); + $this->assertEquals('b53717', $color->toHex()); + $this->assertEquals('#b53717', $color->toHex('#')); + } + + public function testNormalize(): void + { + $color = new Color(255, 0, 51); + $this->assertEquals([1.0, 0.0, 0.2, 1.0], $color->normalize()); + } + + public function testToString(): void + { + $color = new Color(181, 55, 23); + $this->assertEquals('rgb(181, 55, 23)', (string) $color); + } + + public function testConvertTo(): void + { + $color = new Color(0, 0, 0); + $converted = $color->convertTo(CmykColorspace::class); + $this->assertInstanceOf(CmykColor::class, $converted); + $this->assertEquals([0, 0, 0, 100], $converted->toArray()); + + $color = new Color(255, 255, 255); + $converted = $color->convertTo(CmykColorspace::class); + $this->assertInstanceOf(CmykColor::class, $converted); + $this->assertEquals([0, 0, 0, 0], $converted->toArray()); + + $color = new Color(255, 0, 0); + $converted = $color->convertTo(CmykColorspace::class); + $this->assertInstanceOf(CmykColor::class, $converted); + $this->assertEquals([0, 100, 100, 0], $converted->toArray()); + + $color = new Color(255, 0, 255); + $converted = $color->convertTo(CmykColorspace::class); + $this->assertInstanceOf(CmykColor::class, $converted); + $this->assertEquals([0, 100, 0, 0], $converted->toArray()); + + $color = new Color(255, 255, 0); + $converted = $color->convertTo(CmykColorspace::class); + $this->assertInstanceOf(CmykColor::class, $converted); + $this->assertEquals([0, 0, 100, 0], $converted->toArray()); + + $color = new Color(255, 204, 204); + $converted = $color->convertTo(CmykColorspace::class); + $this->assertInstanceOf(CmykColor::class, $converted); + $this->assertEquals([0, 20, 20, 0], $converted->toArray()); + } +} diff --git a/tests/Colors/Rgb/ColorspaceTest.php b/tests/Colors/Rgb/ColorspaceTest.php new file mode 100644 index 00000000..a79727d4 --- /dev/null +++ b/tests/Colors/Rgb/ColorspaceTest.php @@ -0,0 +1,82 @@ +colorFromNormalized([1, 0, 1, 1]); + $this->assertInstanceOf(RgbColor::class, $result); + $this->assertEquals(255, $result->channel(Red::class)->value()); + $this->assertEquals(0, $result->channel(Green::class)->value()); + $this->assertEquals(255, $result->channel(Blue::class)->value()); + $this->assertEquals(255, $result->channel(Alpha::class)->value()); + } + + public function testImportCmykColor(): void + { + $colorspace = new Colorspace(); + $result = $colorspace->importColor(new CmykColor(0, 100, 0, 0)); + $this->assertInstanceOf(RgbColor::class, $result); + $this->assertEquals(255, $result->channel(Red::class)->value()); + $this->assertEquals(0, $result->channel(Green::class)->value()); + $this->assertEquals(255, $result->channel(Blue::class)->value()); + + $result = $colorspace->importColor(new CmykColor(0, 0, 0, 50)); + $this->assertInstanceOf(RgbColor::class, $result); + $this->assertEquals(127, $result->channel(Red::class)->value()); + $this->assertEquals(127, $result->channel(Green::class)->value()); + $this->assertEquals(127, $result->channel(Blue::class)->value()); + } + + public function testImportHsvColor(): void + { + $colorspace = new Colorspace(); + + $result = $colorspace->importColor(new HsvColor(300, 100, 100)); + $this->assertInstanceOf(RgbColor::class, $result); + $this->assertEquals(255, $result->channel(Red::class)->value()); + $this->assertEquals(0, $result->channel(Green::class)->value()); + $this->assertEquals(255, $result->channel(Blue::class)->value()); + + $result = $colorspace->importColor(new HsvColor(0, 0, 50)); + $this->assertInstanceOf(RgbColor::class, $result); + $this->assertEquals(128, $result->channel(Red::class)->value()); + $this->assertEquals(128, $result->channel(Green::class)->value()); + $this->assertEquals(128, $result->channel(Blue::class)->value()); + } + + public function testImportHslColor(): void + { + $colorspace = new Colorspace(); + + $result = $colorspace->importColor(new HslColor(300, 100, 50)); + $this->assertInstanceOf(RgbColor::class, $result); + $this->assertEquals(255, $result->channel(Red::class)->value()); + $this->assertEquals(0, $result->channel(Green::class)->value()); + $this->assertEquals(255, $result->channel(Blue::class)->value()); + + $result = $colorspace->importColor(new HslColor(0, 0, 50)); + $this->assertInstanceOf(RgbColor::class, $result); + $this->assertEquals(128, $result->channel(Red::class)->value()); + $this->assertEquals(128, $result->channel(Green::class)->value()); + $this->assertEquals(128, $result->channel(Blue::class)->value()); + } +} diff --git a/tests/Colors/Rgb/Decoders/HexColorDecoderTest.php b/tests/Colors/Rgb/Decoders/HexColorDecoderTest.php new file mode 100644 index 00000000..439b533f --- /dev/null +++ b/tests/Colors/Rgb/Decoders/HexColorDecoderTest.php @@ -0,0 +1,58 @@ +decode('ccc'); + $this->assertInstanceOf(Color::class, $result); + $this->assertEquals([204, 204, 204, 255], $result->toArray()); + + $result = $decoder->decode('ccff33'); + $this->assertInstanceOf(Color::class, $result); + $this->assertEquals([204, 255, 51, 255], $result->toArray()); + + $result = $decoder->decode('#ccc'); + $this->assertInstanceOf(Color::class, $result); + $this->assertEquals([204, 204, 204, 255], $result->toArray()); + + $result = $decoder->decode('cccccc'); + $this->assertInstanceOf(Color::class, $result); + $this->assertEquals([204, 204, 204, 255], $result->toArray()); + + $result = $decoder->decode('#cccccc'); + $this->assertInstanceOf(Color::class, $result); + $this->assertEquals([204, 204, 204, 255], $result->toArray()); + + $result = $decoder->decode('#ccccccff'); + $this->assertInstanceOf(Color::class, $result); + $this->assertEquals([204, 204, 204, 255], $result->toArray()); + + $result = $decoder->decode('#cccf'); + $this->assertInstanceOf(Color::class, $result); + $this->assertEquals([204, 204, 204, 255], $result->toArray()); + + $result = $decoder->decode('ccccccff'); + $this->assertInstanceOf(Color::class, $result); + $this->assertEquals([204, 204, 204, 255], $result->toArray()); + + $result = $decoder->decode('cccf'); + $this->assertInstanceOf(Color::class, $result); + $this->assertEquals([204, 204, 204, 255], $result->toArray()); + + $result = $decoder->decode('#b53717aa'); + $this->assertInstanceOf(Color::class, $result); + $this->assertEquals([181, 55, 23, 170], $result->toArray()); + } +} diff --git a/tests/Colors/Rgb/Decoders/HtmlColornameDecoderTest.php b/tests/Colors/Rgb/Decoders/HtmlColornameDecoderTest.php new file mode 100644 index 00000000..843d7a15 --- /dev/null +++ b/tests/Colors/Rgb/Decoders/HtmlColornameDecoderTest.php @@ -0,0 +1,30 @@ +decode('salmon'); + $this->assertInstanceOf(Color::class, $result); + $this->assertEquals([250, 128, 114, 255], $result->toArray()); + + $result = $decoder->decode('khaki'); + $this->assertInstanceOf(Color::class, $result); + $this->assertEquals([240, 230, 140, 255], $result->toArray()); + + $result = $decoder->decode('peachpuff'); + $this->assertInstanceOf(Color::class, $result); + $this->assertEquals([255, 218, 185, 255], $result->toArray()); + } +} diff --git a/tests/Colors/Rgb/Decoders/StringColorDecoderTest.php b/tests/Colors/Rgb/Decoders/StringColorDecoderTest.php new file mode 100644 index 00000000..956fe100 --- /dev/null +++ b/tests/Colors/Rgb/Decoders/StringColorDecoderTest.php @@ -0,0 +1,50 @@ +decode('rgb(204, 204, 204)'); + $this->assertInstanceOf(Color::class, $result); + $this->assertEquals([204, 204, 204, 255], $result->toArray()); + + $result = $decoder->decode('rgb(204,204,204)'); + $this->assertInstanceOf(Color::class, $result); + $this->assertEquals([204, 204, 204, 255], $result->toArray()); + + $result = $decoder->decode('rgb(100%,20%,0%)'); + $this->assertInstanceOf(Color::class, $result); + $this->assertEquals([255, 51, 0, 255], $result->toArray()); + + $result = $decoder->decode('rgb(100%,19.8064%,0.1239483%)'); + $this->assertInstanceOf(Color::class, $result); + $this->assertEquals([255, 51, 0, 255], $result->toArray()); + + $result = $decoder->decode('rgba(204, 204, 204, 1)'); + $this->assertInstanceOf(Color::class, $result); + $this->assertEquals([204, 204, 204, 255], $result->toArray()); + + $result = $decoder->decode('rgba(204,204,204,.2)'); + $this->assertInstanceOf(Color::class, $result); + $this->assertEquals([204, 204, 204, 51], $result->toArray()); + + $result = $decoder->decode('rgba(204,204,204,0.2)'); + $this->assertInstanceOf(Color::class, $result); + $this->assertEquals([204, 204, 204, 51], $result->toArray()); + + $result = $decoder->decode('srgb(255, 0, 0)'); + $this->assertInstanceOf(Color::class, $result); + $this->assertEquals([255, 0, 0, 255], $result->toArray()); + } +} diff --git a/tests/ConstraintTest.php b/tests/ConstraintTest.php deleted file mode 100644 index 0ac3375d..00000000 --- a/tests/ConstraintTest.php +++ /dev/null @@ -1,58 +0,0 @@ -getMockedSize(800, 600); - $constraint = new Constraint($size); - $this->assertInstanceOf('Intervention\Image\Constraint', $constraint); - $this->assertFalse($constraint->isFixed(Constraint::ASPECTRATIO)); - $this->assertFalse($constraint->isFixed(Constraint::UPSIZE)); - } - - public function testSetOnlyAspectRatio() - { - $size = $this->getMockedSize(800, 600); - $constraint = new Constraint($size); - $constraint->aspectRatio(); - $this->assertTrue($constraint->isFixed(Constraint::ASPECTRATIO)); - $this->assertFalse($constraint->isFixed(Constraint::UPSIZE)); - } - - public function testSetOnlyUpsize() - { - $size = $this->getMockedSize(800, 600); - $constraint = new Constraint($size); - $constraint->upsize(); - $this->assertFalse($constraint->isFixed(Constraint::ASPECTRATIO)); - $this->assertTrue($constraint->isFixed(Constraint::UPSIZE)); - } - - public function testSetAspectratioAndUpsize() - { - $size = $this->getMockedSize(800, 600); - $constraint = new Constraint($size); - $constraint->aspectRatio(); - $constraint->upsize(); - $this->assertTrue($constraint->isFixed(Constraint::ASPECTRATIO)); - $this->assertTrue($constraint->isFixed(Constraint::UPSIZE)); - } - - private function getMockedSize($width, $height) - { - $size = Mockery::mock('\Intervention\Image\Size', [$width, $height]); - $size->shouldReceive('getWidth')->andReturn($width); - $size->shouldReceive('getHeight')->andReturn($height); - $size->shouldReceive('getRatio')->andReturn($width/$height); - return $size; - } -} diff --git a/tests/ContrastCommandTest.php b/tests/ContrastCommandTest.php deleted file mode 100644 index 9b81917a..00000000 --- a/tests/ContrastCommandTest.php +++ /dev/null @@ -1,34 +0,0 @@ -shouldReceive('getCore')->once()->andReturn($resource); - $command = new ContrastGd([20]); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagick() - { - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('sigmoidalcontrastimage')->with(true, 5, 0)->andReturn(true); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - $command = new ContrastImagick([20]); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/CropCommandTest.php b/tests/CropCommandTest.php deleted file mode 100644 index 23ac95ba..00000000 --- a/tests/CropCommandTest.php +++ /dev/null @@ -1,36 +0,0 @@ -shouldReceive('getCore')->once()->andReturn($resource); - $image->shouldReceive('setCore')->once(); - $command = new CropGd([100, 150, 10, 20]); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagick() - { - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('cropimage')->with(100, 150, 10, 20)->andReturn(true); - $imagick->shouldReceive('setimagepage')->with(0, 0, 0, 0)->once(); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->times(2)->andReturn($imagick); - $command = new CropImagick([100, 150, 10, 20]); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/DestroyCommandTest.php b/tests/DestroyCommandTest.php deleted file mode 100644 index cc788463..00000000 --- a/tests/DestroyCommandTest.php +++ /dev/null @@ -1,46 +0,0 @@ -shouldReceive('getCore')->once()->andReturn($resource); - $image->shouldReceive('getBackups')->once()->andReturn($backups); - $command = new DestroyGd([]); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagick() - { - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('clear')->with()->andReturn(true); - - $backup = Mockery::mock('Imagick'); - $backup->shouldReceive('clear')->with()->andReturn(true); - $backups = [$backup]; - - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - $image->shouldReceive('getBackups')->once()->andReturn($backups); - $command = new DestroyImagick([]); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/DriverTest.php b/tests/DriverTest.php deleted file mode 100644 index 5cd8a36e..00000000 --- a/tests/DriverTest.php +++ /dev/null @@ -1,61 +0,0 @@ -newImage(300, 200, '00ff00'); - $this->assertInstanceOf('\Intervention\Image\Image', $image); - $this->assertInstanceOf('\Intervention\Image\Gd\Driver', $image->getDriver()); - $this->assertInternalType('resource', $image->getCore()); - } - - public function testNewImageImagick() - { - $driver = new ImagickDriver( - Mockery::mock('\Intervention\Image\Imagick\Decoder'), - Mockery::mock('\Intervention\Image\Imagick\Encoder') - ); - - $image = $driver->newImage(300, 200, '00ff00'); - $this->assertInstanceOf('\Intervention\Image\Image', $image); - $this->assertInstanceOf('\Intervention\Image\Imagick\Driver', $image->getDriver()); - $this->assertInstanceOf('\Imagick', $image->getCore()); - } - - public function testParseColorGd() - { - $driver = new GdDriver( - Mockery::mock('\Intervention\Image\Gd\Decoder'), - Mockery::mock('\Intervention\Image\Gd\Encoder') - ); - - $color = $driver->parseColor('00ff00'); - $this->assertInstanceOf('\Intervention\Image\Gd\Color', $color); - } - - public function testParseColorImagick() - { - $driver = new ImagickDriver( - Mockery::mock('\Intervention\Image\Imagick\Decoder'), - Mockery::mock('\Intervention\Image\Imagick\Encoder') - ); - - $color = $driver->parseColor('00ff00'); - $this->assertInstanceOf('\Intervention\Image\Imagick\Color', $color); - } -} diff --git a/tests/Drivers/AbstractDecoderTest.php b/tests/Drivers/AbstractDecoderTest.php new file mode 100644 index 00000000..6ad61e87 --- /dev/null +++ b/tests/Drivers/AbstractDecoderTest.php @@ -0,0 +1,51 @@ +makePartial(); + $decoder->shouldReceive('decode')->with('test input')->andReturn($result); + + $decoder->handle('test input'); + } + + public function testHandleFail(): void + { + $decoder = Mockery::mock(AbstractDecoder::class, [])->makePartial()->shouldAllowMockingProtectedMethods(); + $decoder->shouldReceive('decode')->with('test input')->andThrow(DecoderException::class); + + $this->expectException(DecoderException::class); + + $decoder->handle('test input'); + } + + public function testHandleFailWithSuccessor(): void + { + $result = Mockery::mock(ColorInterface::class); + $successor = Mockery::mock(AbstractDecoder::class)->makePartial(); + $successor->shouldReceive('decode')->with('test input')->andReturn($result); + + $decoder = Mockery::mock( + AbstractDecoder::class, + [$successor] + )->makePartial()->shouldAllowMockingProtectedMethods(); + $decoder->shouldReceive('decode')->with('test input')->andThrow(DecoderException::class); + + $decoder->handle('test input'); + } +} diff --git a/tests/Drivers/AbstractInputHandlerTest.php b/tests/Drivers/AbstractInputHandlerTest.php new file mode 100644 index 00000000..86b4496c --- /dev/null +++ b/tests/Drivers/AbstractInputHandlerTest.php @@ -0,0 +1,45 @@ +shouldReceive('handle')->with('test image')->andReturn($image); + $chain->shouldReceive('decode')->with('test image')->andReturn(Mockery::mock(ImageInterface::class)); + + $modifier = $this->getModifier($chain); + $modifier->handle('test image'); + } + + private function getModifier(AbstractDecoder $chain): AbstractInputHandler + { + return new class ([$chain]) extends AbstractInputHandler + { + public function __construct(protected array $decoders = []) + { + // + } + + protected function chain(): AbstractDecoder + { + return $this->decoders[0]; + } + }; + } +} diff --git a/tests/Drivers/DriverSpecializedAnalyzerTest.php b/tests/Drivers/DriverSpecializedAnalyzerTest.php new file mode 100644 index 00000000..b36473b4 --- /dev/null +++ b/tests/Drivers/DriverSpecializedAnalyzerTest.php @@ -0,0 +1,29 @@ +makePartial(); + + $this->assertInstanceOf(DriverInterface::class, $analyzer->driver()); + } +} diff --git a/tests/Drivers/DriverSpecializedEncoderTest.php b/tests/Drivers/DriverSpecializedEncoderTest.php new file mode 100644 index 00000000..c6f4b2e4 --- /dev/null +++ b/tests/Drivers/DriverSpecializedEncoderTest.php @@ -0,0 +1,38 @@ +makePartial(); + $result = $encoder->getBuffered(function () { + echo 'result'; + }); + $this->assertEquals('result', $result); + } + + public function testGetAttributes(): void + { + $encoder = Mockery::mock(DriverSpecializedEncoder::class, [ + new PngEncoder(color_limit: 123), + Mockery::mock(DriverInterface::class), + ])->makePartial(); + + $this->assertEquals(123, $encoder->color_limit); + } +} diff --git a/tests/Drivers/Gd/Analyzers/ColorspaceAnalyzerTest.php b/tests/Drivers/Gd/Analyzers/ColorspaceAnalyzerTest.php new file mode 100644 index 00000000..2dd2cb92 --- /dev/null +++ b/tests/Drivers/Gd/Analyzers/ColorspaceAnalyzerTest.php @@ -0,0 +1,21 @@ +readTestImage('tile.png'); + $analyzer = new ColorspaceAnalyzer(); + $result = $analyzer->analyze($image); + $this->assertInstanceOf(ColorspaceInterface::class, $result); + } +} diff --git a/tests/Drivers/Gd/Analyzers/HeightAnalyzerTest.php b/tests/Drivers/Gd/Analyzers/HeightAnalyzerTest.php new file mode 100644 index 00000000..eb7873b0 --- /dev/null +++ b/tests/Drivers/Gd/Analyzers/HeightAnalyzerTest.php @@ -0,0 +1,20 @@ +readTestImage('tile.png'); + $analyzer = new HeightAnalyzer(); + $result = $analyzer->analyze($image); + $this->assertEquals(16, $result); + } +} diff --git a/tests/Drivers/Gd/Analyzers/PixelColorAnalyzer.php b/tests/Drivers/Gd/Analyzers/PixelColorAnalyzer.php new file mode 100644 index 00000000..12a31530 --- /dev/null +++ b/tests/Drivers/Gd/Analyzers/PixelColorAnalyzer.php @@ -0,0 +1,22 @@ +readTestImage('tile.png'); + $analyzer = new PixelColorAnalyzer(0, 0); + $result = $analyzer->analyze($image); + $this->assertInstanceOf(ColorInterface::class, $result); + $this->assertEquals('b4e000', $result->toHex()); + } +} diff --git a/tests/Drivers/Gd/Analyzers/PixelColorAnalyzerTest.php b/tests/Drivers/Gd/Analyzers/PixelColorAnalyzerTest.php new file mode 100644 index 00000000..497756d1 --- /dev/null +++ b/tests/Drivers/Gd/Analyzers/PixelColorAnalyzerTest.php @@ -0,0 +1,24 @@ +readTestImage('tile.png'); + $analyzer = new PixelColorsAnalyzer(0, 0); + $result = $analyzer->analyze($image); + $this->assertInstanceOf(Collection::class, $result); + $this->assertInstanceOf(ColorInterface::class, $result->first()); + $this->assertEquals('b4e000', $result->first()->toHex()); + } +} diff --git a/tests/Drivers/Gd/Analyzers/ResolutionAnalyzerTest.php b/tests/Drivers/Gd/Analyzers/ResolutionAnalyzerTest.php new file mode 100644 index 00000000..21263f16 --- /dev/null +++ b/tests/Drivers/Gd/Analyzers/ResolutionAnalyzerTest.php @@ -0,0 +1,21 @@ +readTestImage('tile.png'); + $analyzer = new ResolutionAnalyzer(); + $result = $analyzer->analyze($image); + $this->assertInstanceOf(Resolution::class, $result); + } +} diff --git a/tests/Drivers/Gd/Analyzers/WidthAnalyzerTest.php b/tests/Drivers/Gd/Analyzers/WidthAnalyzerTest.php new file mode 100644 index 00000000..1123a139 --- /dev/null +++ b/tests/Drivers/Gd/Analyzers/WidthAnalyzerTest.php @@ -0,0 +1,20 @@ +readTestImage('tile.png'); + $analyzer = new WidthAnalyzer(); + $result = $analyzer->analyze($image); + $this->assertEquals(16, $result); + } +} diff --git a/tests/Drivers/Gd/CoreTest.php b/tests/Drivers/Gd/CoreTest.php new file mode 100644 index 00000000..8afc5e5f --- /dev/null +++ b/tests/Drivers/Gd/CoreTest.php @@ -0,0 +1,62 @@ +assertInstanceOf(GdImage::class, $core->native()); + } + + public function testAdd(): void + { + $gd1 = imagecreatetruecolor(3, 2); + $gd2 = imagecreatetruecolor(3, 2); + $core = new Core([new Frame($gd1)]); + $this->assertEquals(1, $core->count()); + $result = $core->add(new Frame($gd2)); + $this->assertEquals(2, $core->count()); + $this->assertInstanceOf(Core::class, $result); + } + + public function testSetNative(): void + { + $gd1 = imagecreatetruecolor(3, 2); + $gd2 = imagecreatetruecolor(3, 2); + $core = new Core([new Frame($gd1)]); + $this->assertEquals($gd1, $core->native()); + $core->setNative($gd2); + $this->assertEquals($gd2, $core->native()); + } + + public function testFrame(): void + { + $core = new Core([ + new Frame(imagecreatetruecolor(3, 2)), + new Frame(imagecreatetruecolor(3, 2)), + ]); + $this->assertInstanceOf(Frame::class, $core->frame(0)); + $this->assertInstanceOf(Frame::class, $core->frame(1)); + } + + public function testSetGetLoops(): void + { + $core = new Core([ + new Frame(imagecreatetruecolor(3, 2)) + ]); + + $this->assertEquals(0, $core->loops()); + $result = $core->setLoops(12); + $this->assertInstanceOf(Core::class, $result); + $this->assertEquals(12, $core->loops()); + } +} diff --git a/tests/Drivers/Gd/Decoders/Base64ImageDecoderTest.php b/tests/Drivers/Gd/Decoders/Base64ImageDecoderTest.php new file mode 100644 index 00000000..733ec18b --- /dev/null +++ b/tests/Drivers/Gd/Decoders/Base64ImageDecoderTest.php @@ -0,0 +1,26 @@ +decode( + base64_encode($this->getTestImageData('blue.gif')) + ); + $this->assertInstanceOf(Image::class, $result); + } +} diff --git a/tests/Drivers/Gd/Decoders/BinaryImageDecoderTest.php b/tests/Drivers/Gd/Decoders/BinaryImageDecoderTest.php new file mode 100644 index 00000000..609bc30f --- /dev/null +++ b/tests/Drivers/Gd/Decoders/BinaryImageDecoderTest.php @@ -0,0 +1,55 @@ +decode(file_get_contents($this->getTestImagePath('tile.png'))); + $this->assertInstanceOf(Image::class, $image); + $this->assertEquals(16, $image->width()); + $this->assertEquals(16, $image->height()); + $this->assertCount(1, $image); + } + + public function testDecodeGif(): void + { + $decoder = new BinaryImageDecoder(); + $image = $decoder->decode(file_get_contents($this->getTestImagePath('red.gif'))); + $this->assertInstanceOf(Image::class, $image); + $this->assertEquals(16, $image->width()); + $this->assertEquals(16, $image->height()); + $this->assertCount(1, $image); + } + + public function testDecodeAnimatedGif(): void + { + $decoder = new BinaryImageDecoder(); + $image = $decoder->decode(file_get_contents($this->getTestImagePath('cats.gif'))); + $this->assertInstanceOf(Image::class, $image); + $this->assertEquals(75, $image->width()); + $this->assertEquals(50, $image->height()); + $this->assertCount(4, $image); + } + + public function testDecodeJpegWithExif(): void + { + $decoder = new BinaryImageDecoder(); + $image = $decoder->decode(file_get_contents($this->getTestImagePath('exif.jpg'))); + $this->assertInstanceOf(Image::class, $image); + $this->assertEquals(16, $image->width()); + $this->assertEquals(16, $image->height()); + $this->assertCount(1, $image); + $this->assertEquals('Oliver Vogel', $image->exif('IFD0.Artist')); + } +} diff --git a/tests/Drivers/Gd/Decoders/DataUriImageDecoderTest.php b/tests/Drivers/Gd/Decoders/DataUriImageDecoderTest.php new file mode 100644 index 00000000..4a807d78 --- /dev/null +++ b/tests/Drivers/Gd/Decoders/DataUriImageDecoderTest.php @@ -0,0 +1,26 @@ +decode( + sprintf('data:image/jpeg;base64,%s', base64_encode($this->getTestImageData('blue.gif'))) + ); + $this->assertInstanceOf(Image::class, $result); + } +} diff --git a/tests/Drivers/Gd/Decoders/FilePathImageDecoderTest.php b/tests/Drivers/Gd/Decoders/FilePathImageDecoderTest.php new file mode 100644 index 00000000..16fa6b2a --- /dev/null +++ b/tests/Drivers/Gd/Decoders/FilePathImageDecoderTest.php @@ -0,0 +1,26 @@ +decode( + $this->getTestImagePath() + ); + $this->assertInstanceOf(Image::class, $result); + } +} diff --git a/tests/Drivers/Gd/Decoders/FilePointerImageDecoderTest.php b/tests/Drivers/Gd/Decoders/FilePointerImageDecoderTest.php new file mode 100644 index 00000000..566b8f77 --- /dev/null +++ b/tests/Drivers/Gd/Decoders/FilePointerImageDecoderTest.php @@ -0,0 +1,25 @@ +getTestImagePath('test.jpg'), 'r'); + $result = $decoder->decode($fp); + $this->assertInstanceOf(Image::class, $result); + } +} diff --git a/tests/Drivers/Gd/Decoders/ImageObjectDecoderTest.php b/tests/Drivers/Gd/Decoders/ImageObjectDecoderTest.php new file mode 100644 index 00000000..5cd03ff2 --- /dev/null +++ b/tests/Drivers/Gd/Decoders/ImageObjectDecoderTest.php @@ -0,0 +1,24 @@ +decode($this->readTestImage('blue.gif')); + $this->assertInstanceOf(Image::class, $result); + } +} diff --git a/tests/Drivers/Gd/Encoders/AvifEncoderTest.php b/tests/Drivers/Gd/Encoders/AvifEncoderTest.php new file mode 100644 index 00000000..78021a12 --- /dev/null +++ b/tests/Drivers/Gd/Encoders/AvifEncoderTest.php @@ -0,0 +1,35 @@ +getTestImage(); + $encoder = new AvifEncoder(10); + $result = $encoder->encode($image); + $this->assertMimeType('image/avif', (string) $result); + } +} diff --git a/tests/Drivers/Gd/Encoders/BmpEncoderTest.php b/tests/Drivers/Gd/Encoders/BmpEncoderTest.php new file mode 100644 index 00000000..a1a70990 --- /dev/null +++ b/tests/Drivers/Gd/Encoders/BmpEncoderTest.php @@ -0,0 +1,35 @@ +getTestImage(); + $encoder = new BmpEncoder(); + $result = $encoder->encode($image); + $this->assertMimeType(['image/bmp', 'image/x-ms-bmp'], (string) $result); + } +} diff --git a/tests/Drivers/Gd/Encoders/GifEncoderTest.php b/tests/Drivers/Gd/Encoders/GifEncoderTest.php new file mode 100644 index 00000000..bc33ec7c --- /dev/null +++ b/tests/Drivers/Gd/Encoders/GifEncoderTest.php @@ -0,0 +1,60 @@ +setDelay(1); + $frame2 = new Frame($gd2); + $frame2->setDelay(.2); + $frame3 = new Frame($gd3); + $frame3->setDelay(1); + + return new Image( + new Driver(), + new Core([$frame1, $frame2, $frame3]) + ); + } + + public function testEncode(): void + { + $image = $this->getTestImage(); + $encoder = new GifEncoder(); + $result = $encoder->encode($image); + $this->assertMimeType('image/gif', (string) $result); + } + + public function testEncodeReduced(): void + { + $image = $this->readTestImage('gradient.gif'); + $gd = $image->core()->native(); + $this->assertEquals(15, imagecolorstotal($gd)); + $encoder = new GifEncoder(2); + $result = $encoder->encode($image); + $gd = imagecreatefromstring((string) $result); + $this->assertEquals(2, imagecolorstotal($gd)); + } +} diff --git a/tests/Drivers/Gd/Encoders/JpegEncoderTest.php b/tests/Drivers/Gd/Encoders/JpegEncoderTest.php new file mode 100644 index 00000000..7befa558 --- /dev/null +++ b/tests/Drivers/Gd/Encoders/JpegEncoderTest.php @@ -0,0 +1,35 @@ +getTestImage(); + $encoder = new JpegEncoder(75); + $result = $encoder->encode($image); + $this->assertMimeType('image/jpeg', (string) $result); + } +} diff --git a/tests/Drivers/Gd/Encoders/PngEncoderTest.php b/tests/Drivers/Gd/Encoders/PngEncoderTest.php new file mode 100644 index 00000000..738f0da8 --- /dev/null +++ b/tests/Drivers/Gd/Encoders/PngEncoderTest.php @@ -0,0 +1,49 @@ +getTestImage(); + $encoder = new PngEncoder(); + $result = $encoder->encode($image); + $this->assertMimeType('image/png', (string) $result); + } + + public function testEncodeReduced(): void + { + $image = $this->readTestImage('tile.png'); + $gd = $image->core()->native(); + $this->assertEquals(3, imagecolorstotal($gd)); + $encoder = new PngEncoder(2); + $result = $encoder->encode($image); + $gd = imagecreatefromstring((string) $result); + $this->assertEquals(2, imagecolorstotal($gd)); + } +} diff --git a/tests/Drivers/Gd/Encoders/WebpEncoderTest.php b/tests/Drivers/Gd/Encoders/WebpEncoderTest.php new file mode 100644 index 00000000..3f1ba724 --- /dev/null +++ b/tests/Drivers/Gd/Encoders/WebpEncoderTest.php @@ -0,0 +1,36 @@ +getTestImage(); + $encoder = new WebpEncoder(75); + $result = $encoder->encode($image); + $this->assertMimeType('image/webp', (string) $result); + } +} diff --git a/tests/Drivers/Gd/FrameTest.php b/tests/Drivers/Gd/FrameTest.php new file mode 100644 index 00000000..e95d45ea --- /dev/null +++ b/tests/Drivers/Gd/FrameTest.php @@ -0,0 +1,109 @@ +getTestFrame(); + $this->assertInstanceOf(Frame::class, $frame); + } + + public function testGetNative(): void + { + $frame = $this->getTestFrame(); + $this->assertInstanceOf(GdImage::class, $frame->native()); + } + + public function testSetCore(): void + { + $core1 = imagecreatetruecolor(3, 2); + $core2 = imagecreatetruecolor(3, 3); + $frame = new Frame($core1); + $this->assertEquals(2, $frame->size()->height()); + $result = $frame->setNative($core2); + $this->assertInstanceOf(Frame::class, $result); + $this->assertEquals(3, $frame->size()->height()); + } + + public function testGetSize(): void + { + $frame = $this->getTestFrame(); + $this->assertInstanceOf(Rectangle::class, $frame->size()); + } + + public function testSetGetDelay() + { + $frame = $this->getTestFrame(); + $this->assertEquals(0, $frame->delay()); + + $result = $frame->setDelay(1.5); + $this->assertInstanceOf(Frame::class, $result); + $this->assertEquals(1.5, $frame->delay()); + } + + public function testSetGetDispose() + { + $frame = $this->getTestFrame(); + $this->assertEquals(1, $frame->dispose()); + + $result = $frame->setDispose(100); + $this->assertInstanceOf(Frame::class, $result); + $this->assertEquals(100, $frame->dispose()); + } + + public function testSetGetOffsetLeft() + { + $frame = $this->getTestFrame(); + $this->assertEquals(0, $frame->offsetLeft()); + + $result = $frame->setOffsetLeft(100); + $this->assertInstanceOf(Frame::class, $result); + $this->assertEquals(100, $frame->offsetLeft()); + } + + public function testSetGetOffsetTop() + { + $frame = $this->getTestFrame(); + $this->assertEquals(0, $frame->offsetTop()); + + $result = $frame->setOffsetTop(100); + $this->assertInstanceOf(Frame::class, $result); + $this->assertEquals(100, $frame->offsetTop()); + } + + public function testSetGetOffset() + { + $frame = $this->getTestFrame(); + $this->assertEquals(0, $frame->offsetTop()); + $this->assertEquals(0, $frame->offsetLeft()); + + $result = $frame->setOffset(100, 200); + $this->assertInstanceOf(Frame::class, $result); + $this->assertEquals(100, $frame->offsetLeft()); + $this->assertEquals(200, $frame->offsetTop()); + } + + public function testToImage(): void + { + $frame = $this->getTestFrame(); + $this->assertInstanceOf(Image::class, $frame->toImage(new Driver())); + } +} diff --git a/tests/Drivers/Gd/ImageTest.php b/tests/Drivers/Gd/ImageTest.php new file mode 100644 index 00000000..8d8cfb9c --- /dev/null +++ b/tests/Drivers/Gd/ImageTest.php @@ -0,0 +1,141 @@ +image = new Image( + new Driver(), + new Core([ + new Frame(imagecreatetruecolor(3, 2)), + new Frame(imagecreatetruecolor(3, 2)), + ]), + new Collection([ + 'test' => 'foo' + ]), + ); + } + + public function testDriver(): void + { + $this->assertInstanceOf(Driver::class, $this->image->driver()); + } + + public function testCore(): void + { + $this->assertInstanceOf(Core::class, $this->image->core()); + } + + public function testCount(): void + { + $this->assertEquals(2, $this->image->count()); + } + + public function testIteration(): void + { + foreach ($this->image as $frame) { + $this->assertInstanceOf(Frame::class, $frame); + } + } + + public function testIsAnimated(): void + { + $this->assertTrue($this->image->isAnimated()); + } + + public function testLoops(): void + { + $this->assertEquals(0, $this->image->loops()); + } + + public function testExif(): void + { + $this->assertInstanceOf(Collection::class, $this->image->exif()); + $this->assertEquals('foo', $this->image->exif('test')); + } + + public function testModify(): void + { + $result = $this->image->modify(new GreyscaleModifier()); + $this->assertInstanceOf(Image::class, $result); + } + + public function testAnalyze(): void + { + $result = $this->image->analyze(new WidthAnalyzer()); + $this->assertEquals(3, $result); + } + + public function testEncode(): void + { + $result = $this->image->encode(new PngEncoder()); + $this->assertInstanceOf(EncodedImage::class, $result); + } + + public function testWidthHeightSize(): void + { + $this->assertEquals(3, $this->image->width()); + $this->assertEquals(2, $this->image->height()); + $this->assertInstanceOf(SizeInterface::class, $this->image->size()); + } + + public function testColorspace(): void + { + $this->assertInstanceOf(ColorspaceInterface::class, $this->image->colorspace()); + } + + public function testResolution(): void + { + $this->assertInstanceOf(ResolutionInterface::class, $this->image->resolution()); + } + + public function testPickColor(): void + { + $this->assertInstanceOf(ColorInterface::class, $this->image->pickColor(0, 0)); + $this->assertInstanceOf(ColorInterface::class, $this->image->pickColor(0, 0, 1)); + } + + public function testPickColors(): void + { + $result = $this->image->pickColors(0, 0); + $this->assertInstanceOf(Collection::class, $result); + $this->assertEquals(2, $result->count()); + } + + public function testProfile(): void + { + $this->expectException(NotSupportedException::class); + $this->image->profile(); + } + + public function testSharpen(): void + { + $this->assertInstanceOf(Image::class, $this->image->sharpen(12)); + } + + public function testText(): void + { + $this->assertInstanceOf(Image::class, $this->image->text('test', 0, 0, new Font())); + } +} diff --git a/tests/Drivers/Gd/InputHandlerTest.php b/tests/Drivers/Gd/InputHandlerTest.php new file mode 100644 index 00000000..1857b20e --- /dev/null +++ b/tests/Drivers/Gd/InputHandlerTest.php @@ -0,0 +1,143 @@ +expectException(DecoderException::class); + $handler->handle(''); + } + + public function testHandleBinaryImage(): void + { + $handler = new InputHandler(); + $input = file_get_contents(__DIR__ . '/../../images/animation.gif'); + $result = $handler->handle($input); + $this->assertInstanceOf(Image::class, $result); + } + + public function testHandleSplFileInfo(): void + { + $handler = new InputHandler(); + $input = new SplFileInfo(__DIR__ . '/../../images/test.jpg'); + $result = $handler->handle($input); + $this->assertInstanceOf(Image::class, $result); + } + + public function testHandleFilePathImage(): void + { + $handler = new InputHandler(); + $input = __DIR__ . '/../../images/animation.gif'; + $result = $handler->handle($input); + $this->assertInstanceOf(Image::class, $result); + } + + public function testHandleBase64Image(): void + { + $handler = new InputHandler(); + $input = base64_encode(file_get_contents(__DIR__ . '/../../images/animation.gif')); + $result = $handler->handle($input); + $this->assertInstanceOf(Image::class, $result); + } + + public function testHandleDataUriImage(): void + { + $handler = new InputHandler(); + $input = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=='; + $result = $handler->handle($input); + $this->assertInstanceOf(Image::class, $result); + } + + public function testHandleHexColor(): void + { + $handler = new InputHandler(); + $input = 'ccff33'; + $result = $handler->handle($input); + $this->assertInstanceOf(RgbColor::class, $result); + $this->assertEquals([204, 255, 51, 255], $result->toArray()); + + $handler = new InputHandler(); + $input = 'cf3'; + $result = $handler->handle($input); + $this->assertInstanceOf(RgbColor::class, $result); + $this->assertEquals([204, 255, 51, 255], $result->toArray()); + + $handler = new InputHandler(); + $input = '#123456'; + $result = $handler->handle($input); + $this->assertInstanceOf(RgbColor::class, $result); + $this->assertEquals([18, 52, 86, 255], $result->toArray()); + + $handler = new InputHandler(); + $input = '#333'; + $result = $handler->handle($input); + $this->assertInstanceOf(RgbColor::class, $result); + $this->assertEquals([51, 51, 51, 255], $result->toArray()); + + $handler = new InputHandler(); + $input = '#3333'; + $result = $handler->handle($input); + $this->assertInstanceOf(RgbColor::class, $result); + $this->assertEquals([51, 51, 51, 51], $result->toArray()); + + $handler = new InputHandler(); + $input = '#33333333'; + $result = $handler->handle($input); + $this->assertInstanceOf(RgbColor::class, $result); + $this->assertEquals([51, 51, 51, 51], $result->toArray()); + } + + public function testHandleRgbString(): void + { + $handler = new InputHandler(); + $result = $handler->handle('rgb(10, 20, 30)'); + $this->assertInstanceOf(RgbColor::class, $result); + $this->assertEquals([10, 20, 30, 255], $result->toArray()); + + $handler = new InputHandler(); + $result = $handler->handle('rgba(10, 20, 30, 1.0)'); + $this->assertInstanceOf(RgbColor::class, $result); + $this->assertEquals([10, 20, 30, 255], $result->toArray()); + } + + public function testHandleHsvString(): void + { + $handler = new InputHandler(); + $result = $handler->handle('hsv(10, 20, 30)'); + $this->assertInstanceOf(HsvColor::class, $result); + $this->assertEquals([10, 20, 30], $result->toArray()); + } + + public function testHandleCmykString(): void + { + $handler = new InputHandler(); + $result = $handler->handle('cmyk(10, 20, 30, 40)'); + $this->assertInstanceOf(CmykColor::class, $result); + $this->assertEquals([10, 20, 30, 40], $result->toArray()); + } + + public function testHandleTransparent(): void + { + $handler = new InputHandler(); + $input = 'transparent'; + $result = $handler->handle($input); + $this->assertInstanceOf(RgbColor::class, $result); + $this->assertEquals([255, 0, 255, 0], $result->toArray()); + } +} diff --git a/tests/Drivers/Gd/Modifiers/BlurModifierTest.php b/tests/Drivers/Gd/Modifiers/BlurModifierTest.php new file mode 100644 index 00000000..c507fae2 --- /dev/null +++ b/tests/Drivers/Gd/Modifiers/BlurModifierTest.php @@ -0,0 +1,24 @@ +readTestImage('trim.png'); + $this->assertEquals('00aef0', $image->pickColor(14, 14)->toHex()); + $image->modify(new BlurModifier(30)); + $this->assertEquals('4fa68d', $image->pickColor(14, 14)->toHex()); + } +} diff --git a/tests/Drivers/Gd/Modifiers/BrightnessModifierTest.php b/tests/Drivers/Gd/Modifiers/BrightnessModifierTest.php new file mode 100644 index 00000000..6133a9ae --- /dev/null +++ b/tests/Drivers/Gd/Modifiers/BrightnessModifierTest.php @@ -0,0 +1,24 @@ +readTestImage('trim.png'); + $this->assertEquals('00aef0', $image->pickColor(14, 14)->toHex()); + $image->modify(new BrightnessModifier(30)); + $this->assertEquals('4cfaff', $image->pickColor(14, 14)->toHex()); + } +} diff --git a/tests/Drivers/Gd/Modifiers/ColorizeModifierTest.php b/tests/Drivers/Gd/Modifiers/ColorizeModifierTest.php new file mode 100644 index 00000000..a4c0a019 --- /dev/null +++ b/tests/Drivers/Gd/Modifiers/ColorizeModifierTest.php @@ -0,0 +1,24 @@ +readTestImage('tile.png'); + $image = $image->modify(new ColorizeModifier(100, -100, -100)); + $this->assertColor(255, 0, 0, 255, $image->pickColor(5, 5)); + $this->assertColor(255, 0, 0, 255, $image->pickColor(15, 15)); + } +} diff --git a/tests/Drivers/Gd/Modifiers/ContainModifierTest.php b/tests/Drivers/Gd/Modifiers/ContainModifierTest.php new file mode 100644 index 00000000..e648b5ed --- /dev/null +++ b/tests/Drivers/Gd/Modifiers/ContainModifierTest.php @@ -0,0 +1,29 @@ +readTestImage('blocks.png'); + $this->assertEquals(640, $image->width()); + $this->assertEquals(480, $image->height()); + $image->modify(new ContainModifier(200, 100, 'ff0')); + $this->assertEquals(200, $image->width()); + $this->assertEquals(100, $image->height()); + $this->assertColor(255, 255, 0, 255, $image->pickColor(0, 0)); + $this->assertColor(255, 255, 0, 0, $image->pickColor(140, 10)); // transparent + $this->assertColor(255, 255, 0, 255, $image->pickColor(175, 10)); + } +} diff --git a/tests/Drivers/Gd/Modifiers/ContrastModifierTest.php b/tests/Drivers/Gd/Modifiers/ContrastModifierTest.php new file mode 100644 index 00000000..5a2e5a0c --- /dev/null +++ b/tests/Drivers/Gd/Modifiers/ContrastModifierTest.php @@ -0,0 +1,24 @@ +readTestImage('trim.png'); + $this->assertEquals('00aef0', $image->pickColor(14, 14)->toHex()); + $image->modify(new ContrastModifier(30)); + $this->assertEquals('00ceff', $image->pickColor(14, 14)->toHex()); + } +} diff --git a/tests/Drivers/Gd/Modifiers/CoverModifierTest.php b/tests/Drivers/Gd/Modifiers/CoverModifierTest.php new file mode 100644 index 00000000..0f88a9b9 --- /dev/null +++ b/tests/Drivers/Gd/Modifiers/CoverModifierTest.php @@ -0,0 +1,30 @@ +readTestImage('blocks.png'); + $this->assertEquals(640, $image->width()); + $this->assertEquals(480, $image->height()); + $image->modify(new CoverModifier(100, 100, 'center')); + $this->assertEquals(100, $image->width()); + $this->assertEquals(100, $image->height()); + $this->assertColor(255, 0, 0, 255, $image->pickColor(90, 90)); + $this->assertColor(0, 255, 0, 255, $image->pickColor(65, 70)); + $this->assertColor(0, 0, 255, 255, $image->pickColor(70, 52)); + $this->assertTransparency($image->pickColor(90, 30)); + } +} diff --git a/tests/Drivers/Gd/Modifiers/CropModifierTest.php b/tests/Drivers/Gd/Modifiers/CropModifierTest.php new file mode 100644 index 00000000..a51e7d6f --- /dev/null +++ b/tests/Drivers/Gd/Modifiers/CropModifierTest.php @@ -0,0 +1,27 @@ +readTestImage('blocks.png'); + $image = $image->modify(new CropModifier(200, 200, 0, 0, 'bottom-right')); + $this->assertEquals(200, $image->width()); + $this->assertEquals(200, $image->height()); + $this->assertColor(255, 0, 0, 255, $image->pickColor(5, 5)); + $this->assertColor(255, 0, 0, 255, $image->pickColor(100, 100)); + $this->assertColor(255, 0, 0, 255, $image->pickColor(190, 190)); + } +} diff --git a/tests/Drivers/Gd/Modifiers/DrawEllipseModiferTest.php b/tests/Drivers/Gd/Modifiers/DrawEllipseModiferTest.php new file mode 100644 index 00000000..78fc3c03 --- /dev/null +++ b/tests/Drivers/Gd/Modifiers/DrawEllipseModiferTest.php @@ -0,0 +1,28 @@ +readTestImage('trim.png'); + $this->assertEquals('00aef0', $image->pickColor(14, 14)->toHex()); + $drawable = new Ellipse(10, 10, new Point(14, 14)); + $drawable->setBackgroundColor('b53717'); + $image->modify(new DrawEllipseModifier($drawable)); + $this->assertEquals('b53717', $image->pickColor(14, 14)->toHex()); + } +} diff --git a/tests/Drivers/Gd/Modifiers/DrawLineModiferTest.php b/tests/Drivers/Gd/Modifiers/DrawLineModiferTest.php new file mode 100644 index 00000000..8a4df673 --- /dev/null +++ b/tests/Drivers/Gd/Modifiers/DrawLineModiferTest.php @@ -0,0 +1,28 @@ +readTestImage('trim.png'); + $this->assertEquals('00aef0', $image->pickColor(14, 14)->toHex()); + $line = new Line(new Point(0, 0), new Point(10, 0), 4); + $line->setBackgroundColor('b53517'); + $image->modify(new DrawLineModifier($line)); + $this->assertEquals('b53517', $image->pickColor(0, 0)->toHex()); + } +} diff --git a/tests/Drivers/Gd/Modifiers/DrawPixelModifierTest.php b/tests/Drivers/Gd/Modifiers/DrawPixelModifierTest.php new file mode 100644 index 00000000..c1c7bcfd --- /dev/null +++ b/tests/Drivers/Gd/Modifiers/DrawPixelModifierTest.php @@ -0,0 +1,25 @@ +readTestImage('trim.png'); + $this->assertEquals('00aef0', $image->pickColor(14, 14)->toHex()); + $image->modify(new DrawPixelModifier(new Point(14, 14), 'ffffff')); + $this->assertEquals('ffffff', $image->pickColor(14, 14)->toHex()); + } +} diff --git a/tests/Drivers/Gd/Modifiers/DrawPolygonModifierTest.php b/tests/Drivers/Gd/Modifiers/DrawPolygonModifierTest.php new file mode 100644 index 00000000..dc04a92e --- /dev/null +++ b/tests/Drivers/Gd/Modifiers/DrawPolygonModifierTest.php @@ -0,0 +1,28 @@ +readTestImage('trim.png'); + $this->assertEquals('00aef0', $image->pickColor(14, 14)->toHex()); + $drawable = new Polygon([new Point(0, 0), new Point(15, 15), new Point(20, 20)]); + $drawable->setBackgroundColor('b53717'); + $image->modify(new DrawPolygonModifier($drawable)); + $this->assertEquals('b53717', $image->pickColor(14, 14)->toHex()); + } +} diff --git a/tests/Drivers/Gd/Modifiers/DrawRectangleModifierTest.php b/tests/Drivers/Gd/Modifiers/DrawRectangleModifierTest.php new file mode 100644 index 00000000..d2ae150b --- /dev/null +++ b/tests/Drivers/Gd/Modifiers/DrawRectangleModifierTest.php @@ -0,0 +1,28 @@ +readTestImage('trim.png'); + $this->assertEquals('00aef0', $image->pickColor(14, 14)->toHex()); + $rectangle = new Rectangle(300, 200, new Point(14, 14)); + $rectangle->setBackgroundColor('ffffff'); + $image->modify(new DrawRectangleModifier($rectangle)); + $this->assertEquals('ffffff', $image->pickColor(14, 14)->toHex()); + } +} diff --git a/tests/Drivers/Gd/Modifiers/FillModifierTest.php b/tests/Drivers/Gd/Modifiers/FillModifierTest.php new file mode 100644 index 00000000..78d0177c --- /dev/null +++ b/tests/Drivers/Gd/Modifiers/FillModifierTest.php @@ -0,0 +1,38 @@ +readTestImage('blocks.png'); + $this->assertEquals('0000ff', $image->pickColor(420, 270)->toHex()); + $this->assertEquals('ff0000', $image->pickColor(540, 400)->toHex()); + $image->modify(new FillModifier(new Color(204, 204, 204), new Point(540, 400))); + $this->assertEquals('0000ff', $image->pickColor(420, 270)->toHex()); + $this->assertEquals('cccccc', $image->pickColor(540, 400)->toHex()); + } + + public function testFillAllColor(): void + { + $image = $this->readTestImage('blocks.png'); + $this->assertEquals('0000ff', $image->pickColor(420, 270)->toHex()); + $this->assertEquals('ff0000', $image->pickColor(540, 400)->toHex()); + $image->modify(new FillModifier(new Color(204, 204, 204))); + $this->assertEquals('cccccc', $image->pickColor(420, 270)->toHex()); + $this->assertEquals('cccccc', $image->pickColor(540, 400)->toHex()); + } +} diff --git a/tests/Drivers/Gd/Modifiers/FlipFlopModifierTest.php b/tests/Drivers/Gd/Modifiers/FlipFlopModifierTest.php new file mode 100644 index 00000000..93279eb5 --- /dev/null +++ b/tests/Drivers/Gd/Modifiers/FlipFlopModifierTest.php @@ -0,0 +1,34 @@ +readTestImage('tile.png'); + $this->assertEquals('b4e000', $image->pickColor(0, 0)->toHex()); + $image->modify(new FlipModifier()); + $this->assertEquals('00000000', $image->pickColor(0, 0)->toHex()); + } + + public function testFlopImage(): void + { + $image = $this->readTestImage('tile.png'); + $this->assertEquals('b4e000', $image->pickColor(0, 0)->toHex()); + $image->modify(new FlopModifier()); + $this->assertEquals('00000000', $image->pickColor(0, 0)->toHex()); + } +} diff --git a/tests/Drivers/Gd/Modifiers/GammaModifierTest.php b/tests/Drivers/Gd/Modifiers/GammaModifierTest.php new file mode 100644 index 00000000..0a2a9dea --- /dev/null +++ b/tests/Drivers/Gd/Modifiers/GammaModifierTest.php @@ -0,0 +1,24 @@ +readTestImage('trim.png'); + $this->assertEquals('00aef0', $image->pickColor(0, 0)->toHex()); + $image->modify(new GammaModifier(2.1)); + $this->assertEquals('00d5f8', $image->pickColor(0, 0)->toHex()); + } +} diff --git a/tests/Drivers/Gd/Modifiers/GreyscaleModifierTest.php b/tests/Drivers/Gd/Modifiers/GreyscaleModifierTest.php new file mode 100644 index 00000000..d825d568 --- /dev/null +++ b/tests/Drivers/Gd/Modifiers/GreyscaleModifierTest.php @@ -0,0 +1,24 @@ +readTestImage('trim.png'); + $this->assertFalse($image->pickColor(0, 0)->isGreyscale()); + $image->modify(new GreyscaleModifier()); + $this->assertTrue($image->pickColor(0, 0)->isGreyscale()); + } +} diff --git a/tests/Drivers/Gd/Modifiers/InvertModifierTest.php b/tests/Drivers/Gd/Modifiers/InvertModifierTest.php new file mode 100644 index 00000000..550fdb48 --- /dev/null +++ b/tests/Drivers/Gd/Modifiers/InvertModifierTest.php @@ -0,0 +1,26 @@ +readTestImage('trim.png'); + $this->assertEquals('00aef0', $image->pickColor(0, 0)->toHex()); + $this->assertEquals('ffa601', $image->pickColor(25, 25)->toHex()); + $image->modify(new InvertModifier()); + $this->assertEquals('ff510f', $image->pickColor(0, 0)->toHex()); + $this->assertEquals('0059fe', $image->pickColor(25, 25)->toHex()); + } +} diff --git a/tests/Drivers/Gd/Modifiers/PixelateModifierTest.php b/tests/Drivers/Gd/Modifiers/PixelateModifierTest.php new file mode 100644 index 00000000..7d46f6a8 --- /dev/null +++ b/tests/Drivers/Gd/Modifiers/PixelateModifierTest.php @@ -0,0 +1,26 @@ +readTestImage('trim.png'); + $this->assertEquals('00aef0', $image->pickColor(0, 0)->toHex()); + $this->assertEquals('00aef0', $image->pickColor(14, 14)->toHex()); + $image->modify(new PixelateModifier(10)); + $this->assertEquals('00aef0', $image->pickColor(0, 0)->toHex()); + $this->assertEquals('6aaa8b', $image->pickColor(14, 14)->toHex()); + } +} diff --git a/tests/Drivers/Gd/Modifiers/PlaceModifierTest.php b/tests/Drivers/Gd/Modifiers/PlaceModifierTest.php new file mode 100644 index 00000000..9354bf42 --- /dev/null +++ b/tests/Drivers/Gd/Modifiers/PlaceModifierTest.php @@ -0,0 +1,24 @@ +readTestImage('test.jpg'); + $this->assertEquals('febc44', $image->pickColor(300, 25)->toHex()); + $image->modify(new PlaceModifier(__DIR__ . '/../../../images/circle.png', 'top-right', 0, 0)); + $this->assertEquals('32250d', $image->pickColor(300, 25)->toHex()); + } +} diff --git a/tests/Drivers/Gd/Modifiers/RemoveAnimationModifierTest.php b/tests/Drivers/Gd/Modifiers/RemoveAnimationModifierTest.php new file mode 100644 index 00000000..0b577e6f --- /dev/null +++ b/tests/Drivers/Gd/Modifiers/RemoveAnimationModifierTest.php @@ -0,0 +1,34 @@ +readTestImage('animation.gif'); + $this->assertEquals(8, count($image)); + $result = $image->modify(new RemoveAnimationModifier(2)); + $this->assertEquals(1, count($image)); + $this->assertEquals(1, count($result)); + } + + public function testApplyPercent(): void + { + $image = $this->readTestImage('animation.gif'); + $this->assertEquals(8, count($image)); + $result = $image->modify(new RemoveAnimationModifier('20%')); + $this->assertEquals(1, count($image)); + $this->assertEquals(1, count($result)); + } +} diff --git a/tests/Drivers/Gd/Modifiers/ResizeCanvasModifierTest.php b/tests/Drivers/Gd/Modifiers/ResizeCanvasModifierTest.php new file mode 100644 index 00000000..000a8b66 --- /dev/null +++ b/tests/Drivers/Gd/Modifiers/ResizeCanvasModifierTest.php @@ -0,0 +1,55 @@ +createTestImage(1, 1); + $this->assertEquals(1, $image->width()); + $this->assertEquals(1, $image->height()); + $image->modify(new ResizeCanvasModifier(3, 3, 'ff0', 'center')); + $this->assertEquals(3, $image->width()); + $this->assertEquals(3, $image->height()); + $this->assertColor(255, 255, 0, 255, $image->pickColor(0, 0)); + $this->assertColor(255, 0, 0, 255, $image->pickColor(1, 1)); + $this->assertColor(255, 255, 0, 255, $image->pickColor(2, 2)); + } + + public function testModifyWithTransparency(): void + { + $image = $this->readTestImage('tile.png'); + $this->assertEquals(16, $image->width()); + $this->assertEquals(16, $image->height()); + $image->modify(new ResizeCanvasModifier(18, 18, 'ff0', 'center')); + $this->assertEquals(18, $image->width()); + $this->assertEquals(18, $image->height()); + $this->assertColor(255, 255, 0, 255, $image->pickColor(0, 0)); + $this->assertColor(180, 224, 0, 255, $image->pickColor(1, 1)); + $this->assertColor(180, 224, 0, 255, $image->pickColor(2, 2)); + $this->assertColor(255, 255, 0, 255, $image->pickColor(17, 17)); + $this->assertTransparency($image->pickColor(12, 1)); + } + + public function testModifyEdge(): void + { + $image = $this->createTestImage(1, 1); + $this->assertColor(255, 0, 0, 255, $image->pickColor(0, 0)); + $image->modify(new ResizeCanvasModifier(null, 2, 'ff0', 'bottom')); + $this->assertEquals(1, $image->width()); + $this->assertEquals(2, $image->height()); + $this->assertColor(255, 255, 0, 255, $image->pickColor(0, 0)); + $this->assertColor(255, 0, 0, 255, $image->pickColor(0, 1)); + } +} diff --git a/tests/Drivers/Gd/Modifiers/ResizeCanvasRelativeModifierTest.php b/tests/Drivers/Gd/Modifiers/ResizeCanvasRelativeModifierTest.php new file mode 100644 index 00000000..607b51cb --- /dev/null +++ b/tests/Drivers/Gd/Modifiers/ResizeCanvasRelativeModifierTest.php @@ -0,0 +1,44 @@ +createTestImage(1, 1); + $this->assertEquals(1, $image->width()); + $this->assertEquals(1, $image->height()); + $image->modify(new ResizeCanvasRelativeModifier(2, 2, 'ff0', 'center')); + $this->assertEquals(3, $image->width()); + $this->assertEquals(3, $image->height()); + $this->assertColor(255, 255, 0, 255, $image->pickColor(0, 0)); + $this->assertColor(255, 0, 0, 255, $image->pickColor(1, 1)); + $this->assertColor(255, 255, 0, 255, $image->pickColor(2, 2)); + } + + public function testModifyWithTransparency(): void + { + $image = $this->readTestImage('tile.png'); + $this->assertEquals(16, $image->width()); + $this->assertEquals(16, $image->height()); + $image->modify(new ResizeCanvasRelativeModifier(2, 2, 'ff0', 'center')); + $this->assertEquals(18, $image->width()); + $this->assertEquals(18, $image->height()); + $this->assertColor(255, 255, 0, 255, $image->pickColor(0, 0)); + $this->assertColor(180, 224, 0, 255, $image->pickColor(1, 1)); + $this->assertColor(180, 224, 0, 255, $image->pickColor(2, 2)); + $this->assertColor(255, 255, 0, 255, $image->pickColor(17, 17)); + $this->assertTransparency($image->pickColor(12, 1)); + } +} diff --git a/tests/Drivers/Gd/Modifiers/ResizeModifierTest.php b/tests/Drivers/Gd/Modifiers/ResizeModifierTest.php new file mode 100644 index 00000000..7ed1eeb6 --- /dev/null +++ b/tests/Drivers/Gd/Modifiers/ResizeModifierTest.php @@ -0,0 +1,30 @@ +readTestImage('blocks.png'); + $this->assertEquals(640, $image->width()); + $this->assertEquals(480, $image->height()); + $image->modify(new ResizeModifier(200, 100)); + $this->assertEquals(200, $image->width()); + $this->assertEquals(100, $image->height()); + $this->assertColor(255, 0, 0, 255, $image->pickColor(150, 70)); + $this->assertColor(0, 255, 0, 255, $image->pickColor(125, 70)); + $this->assertColor(0, 0, 255, 255, $image->pickColor(130, 54)); + $this->assertTransparency($image->pickColor(170, 30)); + } +} diff --git a/tests/Drivers/Gd/Modifiers/ResolutionModifierTest.php b/tests/Drivers/Gd/Modifiers/ResolutionModifierTest.php new file mode 100644 index 00000000..39407bbb --- /dev/null +++ b/tests/Drivers/Gd/Modifiers/ResolutionModifierTest.php @@ -0,0 +1,26 @@ +readTestImage('test.jpg'); + $this->assertEquals(72.0, $image->resolution()->x()); + $this->assertEquals(72.0, $image->resolution()->y()); + $image->modify(new ResolutionModifier(1, 2)); + $this->assertEquals(1.0, $image->resolution()->x()); + $this->assertEquals(2.0, $image->resolution()->y()); + } +} diff --git a/tests/Drivers/Gd/Modifiers/RotateModifierTest.php b/tests/Drivers/Gd/Modifiers/RotateModifierTest.php new file mode 100644 index 00000000..56e9c2a9 --- /dev/null +++ b/tests/Drivers/Gd/Modifiers/RotateModifierTest.php @@ -0,0 +1,26 @@ +readTestImage('test.jpg'); + $this->assertEquals(320, $image->width()); + $this->assertEquals(240, $image->height()); + $image->modify(new RotateModifier(90, 'fff')); + $this->assertEquals(240, $image->width()); + $this->assertEquals(320, $image->height()); + } +} diff --git a/tests/Drivers/Gd/Modifiers/SharpenModifierTest.php b/tests/Drivers/Gd/Modifiers/SharpenModifierTest.php new file mode 100644 index 00000000..4df2858c --- /dev/null +++ b/tests/Drivers/Gd/Modifiers/SharpenModifierTest.php @@ -0,0 +1,24 @@ +readTestImage('trim.png'); + $this->assertEquals('60ab96', $image->pickColor(15, 14)->toHex()); + $image->modify(new SharpenModifier(10)); + $this->assertEquals('4daba7', $image->pickColor(15, 14)->toHex()); + } +} diff --git a/tests/Drivers/Imagick/Analyzers/ColorspaceAnalyzerTest.php b/tests/Drivers/Imagick/Analyzers/ColorspaceAnalyzerTest.php new file mode 100644 index 00000000..9aa7a6eb --- /dev/null +++ b/tests/Drivers/Imagick/Analyzers/ColorspaceAnalyzerTest.php @@ -0,0 +1,21 @@ +readTestImage('tile.png'); + $analyzer = new ColorspaceAnalyzer(); + $result = $analyzer->analyze($image); + $this->assertInstanceOf(ColorspaceInterface::class, $result); + } +} diff --git a/tests/Drivers/Imagick/Analyzers/HeightAnalyzerTest.php b/tests/Drivers/Imagick/Analyzers/HeightAnalyzerTest.php new file mode 100644 index 00000000..ee739792 --- /dev/null +++ b/tests/Drivers/Imagick/Analyzers/HeightAnalyzerTest.php @@ -0,0 +1,20 @@ +readTestImage('tile.png'); + $analyzer = new HeightAnalyzer(); + $result = $analyzer->analyze($image); + $this->assertEquals(16, $result); + } +} diff --git a/tests/Drivers/Imagick/Analyzers/PixelColorAnalyzer.php b/tests/Drivers/Imagick/Analyzers/PixelColorAnalyzer.php new file mode 100644 index 00000000..a229fbe4 --- /dev/null +++ b/tests/Drivers/Imagick/Analyzers/PixelColorAnalyzer.php @@ -0,0 +1,22 @@ +readTestImage('tile.png'); + $analyzer = new PixelColorAnalyzer(0, 0); + $result = $analyzer->analyze($image); + $this->assertInstanceOf(ColorInterface::class, $result); + $this->assertEquals('b4e000', $result->toHex()); + } +} diff --git a/tests/Drivers/Imagick/Analyzers/PixelColorAnalyzerTest.php b/tests/Drivers/Imagick/Analyzers/PixelColorAnalyzerTest.php new file mode 100644 index 00000000..d0367757 --- /dev/null +++ b/tests/Drivers/Imagick/Analyzers/PixelColorAnalyzerTest.php @@ -0,0 +1,24 @@ +readTestImage('tile.png'); + $analyzer = new PixelColorsAnalyzer(0, 0); + $result = $analyzer->analyze($image); + $this->assertInstanceOf(Collection::class, $result); + $this->assertInstanceOf(ColorInterface::class, $result->first()); + $this->assertEquals('b4e000', $result->first()->toHex()); + } +} diff --git a/tests/Drivers/Imagick/Analyzers/ProfileAnalyzerTest.php b/tests/Drivers/Imagick/Analyzers/ProfileAnalyzerTest.php new file mode 100644 index 00000000..bb3b6238 --- /dev/null +++ b/tests/Drivers/Imagick/Analyzers/ProfileAnalyzerTest.php @@ -0,0 +1,21 @@ +readTestImage('tile.png'); + $analyzer = new ProfileAnalyzer(); + $this->expectException(ColorException::class); + $analyzer->analyze($image); + } +} diff --git a/tests/Drivers/Imagick/Analyzers/ResolutionAnalyzerTest.php b/tests/Drivers/Imagick/Analyzers/ResolutionAnalyzerTest.php new file mode 100644 index 00000000..1ad3d77d --- /dev/null +++ b/tests/Drivers/Imagick/Analyzers/ResolutionAnalyzerTest.php @@ -0,0 +1,21 @@ +readTestImage('tile.png'); + $analyzer = new ResolutionAnalyzer(); + $result = $analyzer->analyze($image); + $this->assertInstanceOf(Resolution::class, $result); + } +} diff --git a/tests/Drivers/Imagick/Analyzers/WidthAnalyzerTest.php b/tests/Drivers/Imagick/Analyzers/WidthAnalyzerTest.php new file mode 100644 index 00000000..601263c9 --- /dev/null +++ b/tests/Drivers/Imagick/Analyzers/WidthAnalyzerTest.php @@ -0,0 +1,20 @@ +readTestImage('tile.png'); + $analyzer = new WidthAnalyzer(); + $result = $analyzer->analyze($image); + $this->assertEquals(16, $result); + } +} diff --git a/tests/Drivers/Imagick/CoreTest.php b/tests/Drivers/Imagick/CoreTest.php new file mode 100644 index 00000000..71859280 --- /dev/null +++ b/tests/Drivers/Imagick/CoreTest.php @@ -0,0 +1,69 @@ +assertInstanceOf(Core::class, $core); + } + + public function testAdd(): void + { + $imagick = new Imagick(); + $imagick->newImage(100, 100, new ImagickPixel('red')); + $core = new Core($imagick); + $this->assertEquals(1, $core->count()); + $result = $core->add(new Frame(clone $imagick)); + $this->assertEquals(2, $core->count()); + $this->assertInstanceOf(Core::class, $result); + } + + public function testCount(): void + { + $imagick = new Imagick(); + $imagick->newImage(100, 100, new ImagickPixel('red')); + $imagick->addImage(clone $imagick); + $core = new Core($imagick); + $this->assertEquals(2, $core->count()); + } + + public function testIterator(): void + { + $imagick = new Imagick(); + $imagick->newImage(100, 100, new ImagickPixel('red')); + $imagick->addImage(clone $imagick); + $core = new Core($imagick); + foreach ($core as $frame) { + $this->assertInstanceOf(Frame::class, $frame); + } + } + + public function testNative(): void + { + $imagick = new Imagick(); + $imagick->newImage(100, 100, new ImagickPixel('red')); + $core = new Core($imagick); + $this->assertInstanceOf(Imagick::class, $core->native()); + } + + public function testSetGetLoops(): void + { + $imagick = new Imagick(); + $imagick->newImage(100, 100, new ImagickPixel('red')); + $core = new Core($imagick); + $this->assertEquals(0, $core->loops()); + $result = $core->setLoops(12); + $this->assertEquals(12, $core->loops()); + $this->assertInstanceOf(Core::class, $result); + } +} diff --git a/tests/Drivers/Imagick/Decoders/BinaryImageDecoderTest.php b/tests/Drivers/Imagick/Decoders/BinaryImageDecoderTest.php new file mode 100644 index 00000000..a109ce86 --- /dev/null +++ b/tests/Drivers/Imagick/Decoders/BinaryImageDecoderTest.php @@ -0,0 +1,62 @@ +decode(file_get_contents($this->getTestImagePath('tile.png'))); + $this->assertInstanceOf(Image::class, $image); + $this->assertInstanceOf(RgbColorspace::class, $image->colorspace()); + $this->assertEquals(16, $image->width()); + $this->assertEquals(16, $image->height()); + $this->assertCount(1, $image); + } + + public function testDecodeGif(): void + { + $decoder = new BinaryImageDecoder(); + $image = $decoder->decode(file_get_contents($this->getTestImagePath('red.gif'))); + $this->assertInstanceOf(Image::class, $image); + $this->assertEquals(16, $image->width()); + $this->assertEquals(16, $image->height()); + $this->assertCount(1, $image); + } + + public function testDecodeAnimatedGif(): void + { + $decoder = new BinaryImageDecoder(); + $image = $decoder->decode(file_get_contents($this->getTestImagePath('cats.gif'))); + $this->assertInstanceOf(Image::class, $image); + $this->assertEquals(75, $image->width()); + $this->assertEquals(50, $image->height()); + $this->assertCount(4, $image); + } + + public function testDecodeJpegWithExif(): void + { + $decoder = new BinaryImageDecoder(); + $image = $decoder->decode(file_get_contents($this->getTestImagePath('exif.jpg'))); + $this->assertInstanceOf(Image::class, $image); + $this->assertEquals(16, $image->width()); + $this->assertEquals(16, $image->height()); + $this->assertCount(1, $image); + $this->assertEquals('Oliver Vogel', $image->exif('IFD0.Artist')); + } + + public function testDecodeCmykImage(): void + { + $decoder = new BinaryImageDecoder(); + $image = $decoder->decode(file_get_contents($this->getTestImagePath('cmyk.jpg'))); + $this->assertInstanceOf(Image::class, $image); + $this->assertInstanceOf(CmykColorspace::class, $image->colorspace()); + } +} diff --git a/tests/Drivers/Imagick/Decoders/FilePointerImageDecoderTest.php b/tests/Drivers/Imagick/Decoders/FilePointerImageDecoderTest.php new file mode 100644 index 00000000..e88e73b8 --- /dev/null +++ b/tests/Drivers/Imagick/Decoders/FilePointerImageDecoderTest.php @@ -0,0 +1,25 @@ +getTestImagePath('test.jpg'), 'r'); + $result = $decoder->decode($fp); + $this->assertInstanceOf(Image::class, $result); + } +} diff --git a/tests/Drivers/Imagick/Decoders/ImageObjectDecoderTest.php b/tests/Drivers/Imagick/Decoders/ImageObjectDecoderTest.php new file mode 100644 index 00000000..55fbae11 --- /dev/null +++ b/tests/Drivers/Imagick/Decoders/ImageObjectDecoderTest.php @@ -0,0 +1,24 @@ +decode($this->readTestImage('blue.gif')); + $this->assertInstanceOf(Image::class, $result); + } +} diff --git a/tests/Drivers/Imagick/Encoders/AvifEncoderTest.php b/tests/Drivers/Imagick/Encoders/AvifEncoderTest.php new file mode 100644 index 00000000..c8e640cf --- /dev/null +++ b/tests/Drivers/Imagick/Encoders/AvifEncoderTest.php @@ -0,0 +1,37 @@ +newImage(3, 2, new ImagickPixel('red'), 'png'); + + return new Image( + new Driver(), + new Core($imagick) + ); + } + + public function testEncode(): void + { + $image = $this->getTestImage(); + $encoder = new AvifEncoder(10); + $result = $encoder->encode($image); + $this->assertMimeType('image/avif', (string) $result); + } +} diff --git a/tests/Drivers/Imagick/Encoders/BmpEncoderTest.php b/tests/Drivers/Imagick/Encoders/BmpEncoderTest.php new file mode 100644 index 00000000..fdc85390 --- /dev/null +++ b/tests/Drivers/Imagick/Encoders/BmpEncoderTest.php @@ -0,0 +1,52 @@ +newImage(3, 2, new ImagickPixel('red'), 'png'); + + return new Image( + new Driver(), + new Core($imagick) + ); + } + + public function testEncode(): void + { + $image = $this->getTestImage(); + $encoder = new BmpEncoder(); + $result = $encoder->encode($image); + $this->assertMimeType(['image/bmp', 'image/x-ms-bmp'], (string) $result); + } + + public function testEncodeReduced(): void + { + $image = $this->readTestImage('gradient.bmp'); + $imagick = $image->core()->native(); + $this->assertEquals(15, $imagick->getImageColors()); + $encoder = new BmpEncoder(2); + $result = $encoder->encode($image); + $imagick = new Imagick(); + $imagick->readImageBlob((string) $result); + $this->assertEquals(2, $imagick->getImageColors()); + } +} diff --git a/tests/Drivers/Imagick/Encoders/GifEncoderTest.php b/tests/Drivers/Imagick/Encoders/GifEncoderTest.php new file mode 100644 index 00000000..f0a9e8a8 --- /dev/null +++ b/tests/Drivers/Imagick/Encoders/GifEncoderTest.php @@ -0,0 +1,66 @@ +newImage(30, 20, new ImagickPixel('red'), 'png'); + $frame->setImageDelay(50); + $imagick->addImage($frame); + + $frame = new Imagick(); + $frame->newImage(30, 20, new ImagickPixel('green'), 'png'); + $frame->setImageDelay(50); + $imagick->addImage($frame); + + $frame = new Imagick(); + $frame->newImage(30, 20, new ImagickPixel('blue'), 'png'); + $frame->setImageDelay(50); + $imagick->addImage($frame); + + return new Image( + new Driver(), + new Core($imagick) + ); + } + + public function testEncode(): void + { + $image = $this->getTestImage(); + $encoder = new GifEncoder(); + $result = $encoder->encode($image); + $this->assertMimeType('image/gif', (string) $result); + } + + public function testEncodeReduced(): void + { + $image = $this->readTestImage('gradient.gif'); + $imagick = $image->core()->native(); + $this->assertEquals(15, $imagick->getImageColors()); + $encoder = new GifEncoder(2); + $result = $encoder->encode($image); + $imagick = new Imagick(); + $imagick->readImageBlob((string) $result); + $this->assertEquals(2, $imagick->getImageColors()); + } +} diff --git a/tests/Drivers/Imagick/Encoders/JpegEncoderTest.php b/tests/Drivers/Imagick/Encoders/JpegEncoderTest.php new file mode 100644 index 00000000..dfc2b680 --- /dev/null +++ b/tests/Drivers/Imagick/Encoders/JpegEncoderTest.php @@ -0,0 +1,37 @@ +newImage(3, 2, new ImagickPixel('red'), 'png'); + + return new Image( + new Driver(), + new Core($imagick) + ); + } + + public function testEncode(): void + { + $image = $this->getTestImage(); + $encoder = new JpegEncoder(75); + $result = $encoder->encode($image); + $this->assertMimeType('image/jpeg', (string) $result); + } +} diff --git a/tests/Drivers/Imagick/Encoders/PngEncoderTest.php b/tests/Drivers/Imagick/Encoders/PngEncoderTest.php new file mode 100644 index 00000000..5d8b2e6e --- /dev/null +++ b/tests/Drivers/Imagick/Encoders/PngEncoderTest.php @@ -0,0 +1,53 @@ +newImage(3, 2, new ImagickPixel('red'), 'jpg'); + + return new Image( + new Driver(), + new Core($imagick) + ); + } + + public function testEncode(): void + { + $image = $this->getTestImage(); + $encoder = new PngEncoder(75); + $result = $encoder->encode($image); + $this->assertMimeType('image/png', (string) $result); + } + + public function testEncodeReduced(): void + { + $image = $this->readTestImage('tile.png'); + $imagick = $image->core()->native(); + $this->assertEquals(3, $imagick->getImageColors()); + $encoder = new PngEncoder(2); + $result = $encoder->encode($image); + $imagick = new Imagick(); + $imagick->readImageBlob((string) $result); + $this->assertEquals(2, $imagick->getImageColors()); + } +} diff --git a/tests/Drivers/Imagick/Encoders/WebpEncoderTest.php b/tests/Drivers/Imagick/Encoders/WebpEncoderTest.php new file mode 100644 index 00000000..fb96d957 --- /dev/null +++ b/tests/Drivers/Imagick/Encoders/WebpEncoderTest.php @@ -0,0 +1,38 @@ +newImage(3, 2, new ImagickPixel('red'), 'png'); + + return new Image( + new Driver(), + new Core($imagick) + ); + } + + public function testEncode(): void + { + $image = $this->getTestImage(); + $encoder = new WebpEncoder(75); + $result = $encoder->encode($image); + $this->assertMimeType('image/webp', (string) $result); + } +} diff --git a/tests/Drivers/Imagick/FrameTest.php b/tests/Drivers/Imagick/FrameTest.php new file mode 100644 index 00000000..8e04ddaf --- /dev/null +++ b/tests/Drivers/Imagick/FrameTest.php @@ -0,0 +1,100 @@ +newImage(3, 2, new ImagickPixel('red'), 'png'); + $imagick->setImageDelay(125); // 1.25 seconds + $imagick->setImageDispose(5); + $imagick->setImagePage(3, 2, 8, 9); + + return new Frame($imagick); + } + + public function testConstructor(): void + { + $frame = $this->getTestFrame(); + $this->assertInstanceOf(Frame::class, $frame); + } + + public function testGetSize(): void + { + $frame = $this->getTestFrame(); + $this->assertInstanceOf(Rectangle::class, $frame->size()); + } + + public function testSetGetDelay() + { + $frame = $this->getTestFrame(); + $this->assertEquals(1.25, $frame->delay()); + + $result = $frame->setDelay(2.5); + $this->assertInstanceOf(Frame::class, $result); + $this->assertEquals(2.5, $frame->delay()); + $this->assertEquals(250, $frame->native()->getImageDelay()); + } + + public function testSetGetDispose() + { + $frame = $this->getTestFrame(); + $this->assertEquals(5, $frame->dispose()); + + $result = $frame->setDispose(100); + $this->assertInstanceOf(Frame::class, $result); + $this->assertEquals(100, $frame->dispose()); + } + + public function testSetGetOffsetLeft() + { + $frame = $this->getTestFrame(); + $this->assertEquals(8, $frame->offsetLeft()); + + $result = $frame->setOffsetLeft(100); + $this->assertInstanceOf(Frame::class, $result); + $this->assertEquals(100, $frame->offsetLeft()); + } + + public function testSetGetOffsetTop() + { + $frame = $this->getTestFrame(); + $this->assertEquals(9, $frame->offsetTop()); + + $result = $frame->setOffsetTop(100); + $this->assertInstanceOf(Frame::class, $result); + $this->assertEquals(100, $frame->offsetTop()); + } + + public function testSetGetOffset() + { + $frame = $this->getTestFrame(); + $this->assertEquals(8, $frame->offsetLeft()); + $this->assertEquals(9, $frame->offsetTop()); + + $result = $frame->setOffset(100, 200); + $this->assertInstanceOf(Frame::class, $result); + $this->assertEquals(100, $frame->offsetLeft()); + $this->assertEquals(200, $frame->offsetTop()); + } + + public function testToImage(): void + { + $frame = $this->getTestFrame(); + $this->assertInstanceOf(Image::class, $frame->toImage(new Driver())); + } +} diff --git a/tests/Drivers/Imagick/ImageTest.php b/tests/Drivers/Imagick/ImageTest.php new file mode 100644 index 00000000..57f55bf1 --- /dev/null +++ b/tests/Drivers/Imagick/ImageTest.php @@ -0,0 +1,135 @@ +readImage(__DIR__ . '/../../images/animation.gif'); + $this->image = new Image( + new Driver(), + new Core($imagick), + new Collection([ + 'test' => 'foo' + ]), + ); + } + + public function testDriver(): void + { + $this->assertInstanceOf(Driver::class, $this->image->driver()); + } + + public function testCore(): void + { + $this->assertInstanceOf(Core::class, $this->image->core()); + } + + public function testCount(): void + { + $this->assertEquals(8, $this->image->count()); + } + + public function testIteration(): void + { + foreach ($this->image as $frame) { + $this->assertInstanceOf(Frame::class, $frame); + } + } + + public function testIsAnimated(): void + { + $this->assertTrue($this->image->isAnimated()); + } + + public function testLoops(): void + { + $this->assertEquals(3, $this->image->loops()); + } + + public function testExif(): void + { + $this->assertInstanceOf(Collection::class, $this->image->exif()); + $this->assertEquals('foo', $this->image->exif('test')); + } + + public function testModify(): void + { + $result = $this->image->modify(new GreyscaleModifier()); + $this->assertInstanceOf(Image::class, $result); + } + + public function testAnalyze(): void + { + $result = $this->image->analyze(new WidthAnalyzer()); + $this->assertEquals(20, $result); + } + + public function testEncode(): void + { + $result = $this->image->encode(new PngEncoder()); + $this->assertInstanceOf(EncodedImage::class, $result); + } + + public function testWidthHeightSize(): void + { + $this->assertEquals(20, $this->image->width()); + $this->assertEquals(15, $this->image->height()); + $this->assertInstanceOf(SizeInterface::class, $this->image->size()); + } + + public function testColorspace(): void + { + $this->assertInstanceOf(ColorspaceInterface::class, $this->image->colorspace()); + } + + public function testResolution(): void + { + $this->assertInstanceOf(ResolutionInterface::class, $this->image->resolution()); + } + + public function testPickColor(): void + { + $this->assertInstanceOf(ColorInterface::class, $this->image->pickColor(0, 0)); + $this->assertInstanceOf(ColorInterface::class, $this->image->pickColor(0, 0, 1)); + } + + public function testPickColors(): void + { + $result = $this->image->pickColors(0, 0); + $this->assertInstanceOf(Collection::class, $result); + $this->assertEquals(8, $result->count()); + } + + public function testProfile(): void + { + $this->expectException(ColorException::class); + $this->image->profile(); + } + + public function testSharpen(): void + { + $this->assertInstanceOf(Image::class, $this->image->sharpen(12)); + } +} diff --git a/tests/Drivers/Imagick/InputHandlerTest.php b/tests/Drivers/Imagick/InputHandlerTest.php new file mode 100644 index 00000000..1175858a --- /dev/null +++ b/tests/Drivers/Imagick/InputHandlerTest.php @@ -0,0 +1,143 @@ +expectException(DecoderException::class); + $handler->handle(''); + } + + public function testHandleBinaryImage(): void + { + $handler = new InputHandler(); + $input = file_get_contents(__DIR__ . '/../../images/animation.gif'); + $result = $handler->handle($input); + $this->assertInstanceOf(Image::class, $result); + } + + public function testHandleSplFileInfo(): void + { + $handler = new InputHandler(); + $input = new SplFileInfo(__DIR__ . '/../../images/test.jpg'); + $result = $handler->handle($input); + $this->assertInstanceOf(Image::class, $result); + } + + public function testHandleFilePathImage(): void + { + $handler = new InputHandler(); + $input = __DIR__ . '/../../images/animation.gif'; + $result = $handler->handle($input); + $this->assertInstanceOf(Image::class, $result); + } + + public function testHandleBase64Image(): void + { + $handler = new InputHandler(); + $input = base64_encode(file_get_contents(__DIR__ . '/../../images/animation.gif')); + $result = $handler->handle($input); + $this->assertInstanceOf(Image::class, $result); + } + + public function testHandleDataUriImage(): void + { + $handler = new InputHandler(); + $input = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=='; + $result = $handler->handle($input); + $this->assertInstanceOf(Image::class, $result); + } + + public function testHandleHexColor(): void + { + $handler = new InputHandler(); + $input = 'ccff33'; + $result = $handler->handle($input); + $this->assertInstanceOf(RgbColor::class, $result); + $this->assertEquals([204, 255, 51, 255], $result->toArray()); + + $handler = new InputHandler(); + $input = 'cf3'; + $result = $handler->handle($input); + $this->assertInstanceOf(RgbColor::class, $result); + $this->assertEquals([204, 255, 51, 255], $result->toArray()); + + $handler = new InputHandler(); + $input = '#123456'; + $result = $handler->handle($input); + $this->assertInstanceOf(RgbColor::class, $result); + $this->assertEquals([18, 52, 86, 255], $result->toArray()); + + $handler = new InputHandler(); + $input = '#333'; + $result = $handler->handle($input); + $this->assertInstanceOf(RgbColor::class, $result); + $this->assertEquals([51, 51, 51, 255], $result->toArray()); + + $handler = new InputHandler(); + $input = '#3333'; + $result = $handler->handle($input); + $this->assertInstanceOf(RgbColor::class, $result); + $this->assertEquals([51, 51, 51, 51], $result->toArray()); + + $handler = new InputHandler(); + $input = '#33333333'; + $result = $handler->handle($input); + $this->assertInstanceOf(RgbColor::class, $result); + $this->assertEquals([51, 51, 51, 51], $result->toArray()); + } + + public function testHandleRgbString(): void + { + $handler = new InputHandler(); + $result = $handler->handle('rgb(10, 20, 30)'); + $this->assertInstanceOf(RgbColor::class, $result); + $this->assertEquals([10, 20, 30, 255], $result->toArray()); + + $handler = new InputHandler(); + $result = $handler->handle('rgba(10, 20, 30, 1.0)'); + $this->assertInstanceOf(RgbColor::class, $result); + $this->assertEquals([10, 20, 30, 255], $result->toArray()); + } + + public function testHandleCmykString(): void + { + $handler = new InputHandler(); + $result = $handler->handle('cmyk(10, 20, 30, 40)'); + $this->assertInstanceOf(CmykColor::class, $result); + $this->assertEquals([10, 20, 30, 40], $result->toArray()); + } + + public function testHandleHsvString(): void + { + $handler = new InputHandler(); + $result = $handler->handle('hsv(10, 20, 30)'); + $this->assertInstanceOf(HsvColor::class, $result); + $this->assertEquals([10, 20, 30], $result->toArray()); + } + + public function testHandleTransparent(): void + { + $handler = new InputHandler(); + $input = 'transparent'; + $result = $handler->handle($input); + $this->assertInstanceOf(RgbColor::class, $result); + $this->assertEquals([255, 0, 255, 0], $result->toArray()); + } +} diff --git a/tests/Drivers/Imagick/Modifiers/BlurModifierTest.php b/tests/Drivers/Imagick/Modifiers/BlurModifierTest.php new file mode 100644 index 00000000..2396684c --- /dev/null +++ b/tests/Drivers/Imagick/Modifiers/BlurModifierTest.php @@ -0,0 +1,24 @@ +readTestImage('trim.png'); + $this->assertEquals('00aef0', $image->pickColor(14, 14)->toHex()); + $image->modify(new BlurModifier(30)); + $this->assertEquals('42acb2', $image->pickColor(14, 14)->toHex()); + } +} diff --git a/tests/Drivers/Imagick/Modifiers/BrightnessModifierTest.php b/tests/Drivers/Imagick/Modifiers/BrightnessModifierTest.php new file mode 100644 index 00000000..5192075d --- /dev/null +++ b/tests/Drivers/Imagick/Modifiers/BrightnessModifierTest.php @@ -0,0 +1,24 @@ +readTestImage('trim.png'); + $this->assertEquals('00aef0', $image->pickColor(14, 14)->toHex()); + $image->modify(new BrightnessModifier(30)); + $this->assertEquals('39c9ff', $image->pickColor(14, 14)->toHex()); + } +} diff --git a/tests/Drivers/Imagick/Modifiers/ColorizeModifierTest.php b/tests/Drivers/Imagick/Modifiers/ColorizeModifierTest.php new file mode 100644 index 00000000..2f964276 --- /dev/null +++ b/tests/Drivers/Imagick/Modifiers/ColorizeModifierTest.php @@ -0,0 +1,24 @@ +readTestImage('tile.png'); + $image = $image->modify(new ColorizeModifier(100, -100, -100)); + $this->assertColor(251, 0, 0, 255, $image->pickColor(5, 5)); + $this->assertColor(239, 0, 0, 255, $image->pickColor(15, 15)); + } +} diff --git a/tests/Drivers/Imagick/Modifiers/ContainModifierTest.php b/tests/Drivers/Imagick/Modifiers/ContainModifierTest.php new file mode 100644 index 00000000..5cbcf2dc --- /dev/null +++ b/tests/Drivers/Imagick/Modifiers/ContainModifierTest.php @@ -0,0 +1,34 @@ +readTestImage('blocks.png'); + $this->assertEquals(640, $image->width()); + $this->assertEquals(480, $image->height()); + $result = $image->modify(new ContainModifier(200, 100, 'ff0')); + $this->assertEquals(200, $image->width()); + $this->assertEquals(100, $image->height()); + $this->assertColor(255, 255, 0, 255, $image->pickColor(0, 0)); + $this->assertColor(0, 0, 0, 0, $image->pickColor(140, 10)); + $this->assertColor(255, 255, 0, 255, $image->pickColor(175, 10)); + $this->assertEquals(200, $result->width()); + $this->assertEquals(100, $result->height()); + $this->assertColor(255, 255, 0, 255, $result->pickColor(0, 0)); + $this->assertColor(0, 0, 0, 0, $result->pickColor(140, 10)); + $this->assertColor(255, 255, 0, 255, $result->pickColor(175, 10)); + } +} diff --git a/tests/Drivers/Imagick/Modifiers/ContrastModifierTest.php b/tests/Drivers/Imagick/Modifiers/ContrastModifierTest.php new file mode 100644 index 00000000..aac38443 --- /dev/null +++ b/tests/Drivers/Imagick/Modifiers/ContrastModifierTest.php @@ -0,0 +1,24 @@ +readTestImage('trim.png'); + $this->assertEquals('00aef0', $image->pickColor(14, 14)->toHex()); + $image->modify(new ContrastModifier(30)); + $this->assertEquals('00fcff', $image->pickColor(14, 14)->toHex()); + } +} diff --git a/tests/Drivers/Imagick/Modifiers/CoverModifierTest.php b/tests/Drivers/Imagick/Modifiers/CoverModifierTest.php new file mode 100644 index 00000000..a0d66ac9 --- /dev/null +++ b/tests/Drivers/Imagick/Modifiers/CoverModifierTest.php @@ -0,0 +1,30 @@ +readTestImage('blocks.png'); + $this->assertEquals(640, $image->width()); + $this->assertEquals(480, $image->height()); + $image->modify(new CoverModifier(100, 100, 'center')); + $this->assertEquals(100, $image->width()); + $this->assertEquals(100, $image->height()); + $this->assertColor(255, 0, 0, 255, $image->pickColor(90, 90)); + $this->assertColor(0, 255, 0, 255, $image->pickColor(65, 70)); + $this->assertColor(0, 0, 255, 255, $image->pickColor(70, 52)); + $this->assertTransparency($image->pickColor(90, 30)); + } +} diff --git a/tests/Drivers/Imagick/Modifiers/CropModifierTest.php b/tests/Drivers/Imagick/Modifiers/CropModifierTest.php new file mode 100644 index 00000000..6889c247 --- /dev/null +++ b/tests/Drivers/Imagick/Modifiers/CropModifierTest.php @@ -0,0 +1,27 @@ +readTestImage('blocks.png'); + $image = $image->modify(new CropModifier(200, 200, 0, 0, 'bottom-right')); + $this->assertEquals(200, $image->width()); + $this->assertEquals(200, $image->height()); + $this->assertColor(255, 0, 0, 255, $image->pickColor(5, 5)); + $this->assertColor(255, 0, 0, 255, $image->pickColor(100, 100)); + $this->assertColor(255, 0, 0, 255, $image->pickColor(190, 190)); + } +} diff --git a/tests/Drivers/Imagick/Modifiers/DrawEllipseModifierTest.php b/tests/Drivers/Imagick/Modifiers/DrawEllipseModifierTest.php new file mode 100644 index 00000000..63840c7e --- /dev/null +++ b/tests/Drivers/Imagick/Modifiers/DrawEllipseModifierTest.php @@ -0,0 +1,24 @@ +readTestImage('trim.png'); + $this->assertEquals('00aef0', $image->pickColor(14, 14)->toHex()); + $drawable = new Ellipse(10, 10, new Point(14, 14)); + $drawable->setBackgroundColor('b53717'); + $image->modify(new DrawEllipseModifier($drawable)); + $this->assertEquals('b53717', $image->pickColor(14, 14)->toHex()); + } +} diff --git a/tests/Drivers/Imagick/Modifiers/DrawLineModifierTest.php b/tests/Drivers/Imagick/Modifiers/DrawLineModifierTest.php new file mode 100644 index 00000000..6fbb406e --- /dev/null +++ b/tests/Drivers/Imagick/Modifiers/DrawLineModifierTest.php @@ -0,0 +1,24 @@ +readTestImage('trim.png'); + $this->assertEquals('00aef0', $image->pickColor(14, 14)->toHex()); + $line = new Line(new Point(0, 0), new Point(10, 0), 4); + $line->setBackgroundColor('b53517'); + $image->modify(new DrawLineModifier($line)); + $this->assertEquals('b53517', $image->pickColor(0, 0)->toHex()); + } +} diff --git a/tests/Drivers/Imagick/Modifiers/DrawPixelModifierTest.php b/tests/Drivers/Imagick/Modifiers/DrawPixelModifierTest.php new file mode 100644 index 00000000..54247467 --- /dev/null +++ b/tests/Drivers/Imagick/Modifiers/DrawPixelModifierTest.php @@ -0,0 +1,25 @@ +readTestImage('trim.png'); + $this->assertEquals('00aef0', $image->pickColor(14, 14)->toHex()); + $image->modify(new DrawPixelModifier(new Point(14, 14), 'ffffff')); + $this->assertEquals('ffffff', $image->pickColor(14, 14)->toHex()); + } +} diff --git a/tests/Drivers/Imagick/Modifiers/DrawPolygonModifierTest.php b/tests/Drivers/Imagick/Modifiers/DrawPolygonModifierTest.php new file mode 100644 index 00000000..f4384064 --- /dev/null +++ b/tests/Drivers/Imagick/Modifiers/DrawPolygonModifierTest.php @@ -0,0 +1,24 @@ +readTestImage('trim.png'); + $this->assertEquals('00aef0', $image->pickColor(14, 14)->toHex()); + $drawable = new Polygon([new Point(0, 0), new Point(15, 15), new Point(20, 20)]); + $drawable->setBackgroundColor('b53717'); + $image->modify(new DrawPolygonModifier($drawable)); + $this->assertEquals('b53717', $image->pickColor(14, 14)->toHex()); + } +} diff --git a/tests/Drivers/Imagick/Modifiers/DrawRectangleModifierTest.php b/tests/Drivers/Imagick/Modifiers/DrawRectangleModifierTest.php new file mode 100644 index 00000000..53886edb --- /dev/null +++ b/tests/Drivers/Imagick/Modifiers/DrawRectangleModifierTest.php @@ -0,0 +1,24 @@ +readTestImage('trim.png'); + $this->assertEquals('00aef0', $image->pickColor(14, 14)->toHex()); + $rectangle = new Rectangle(300, 200, new Point(14, 14)); + $rectangle->setBackgroundColor('ffffff'); + $image->modify(new DrawRectangleModifier($rectangle)); + $this->assertEquals('ffffff', $image->pickColor(14, 14)->toHex()); + } +} diff --git a/tests/Drivers/Imagick/Modifiers/FillModifierTest.php b/tests/Drivers/Imagick/Modifiers/FillModifierTest.php new file mode 100644 index 00000000..611fbfdb --- /dev/null +++ b/tests/Drivers/Imagick/Modifiers/FillModifierTest.php @@ -0,0 +1,38 @@ +readTestImage('blocks.png'); + $this->assertEquals('0000ff', $image->pickColor(420, 270)->toHex()); + $this->assertEquals('ff0000', $image->pickColor(540, 400)->toHex()); + $image->modify(new FillModifier(new Color(204, 204, 204), new Point(540, 400))); + $this->assertEquals('0000ff', $image->pickColor(420, 270)->toHex()); + $this->assertEquals('cccccc', $image->pickColor(540, 400)->toHex()); + } + + public function testFillAllColor(): void + { + $image = $this->readTestImage('blocks.png'); + $this->assertEquals('0000ff', $image->pickColor(420, 270)->toHex()); + $this->assertEquals('ff0000', $image->pickColor(540, 400)->toHex()); + $image->modify(new FillModifier(new Color(204, 204, 204))); + $this->assertEquals('cccccc', $image->pickColor(420, 270)->toHex()); + $this->assertEquals('cccccc', $image->pickColor(540, 400)->toHex()); + } +} diff --git a/tests/Drivers/Imagick/Modifiers/FlipFlopModifierTest.php b/tests/Drivers/Imagick/Modifiers/FlipFlopModifierTest.php new file mode 100644 index 00000000..236b22bf --- /dev/null +++ b/tests/Drivers/Imagick/Modifiers/FlipFlopModifierTest.php @@ -0,0 +1,34 @@ +readTestImage('tile.png'); + $this->assertEquals('b4e000', $image->pickColor(0, 0)->toHex()); + $image->modify(new FlipModifier()); + $this->assertEquals('00000000', $image->pickColor(0, 0)->toHex()); + } + + public function testFlopImage(): void + { + $image = $this->readTestImage('tile.png'); + $this->assertEquals('b4e000', $image->pickColor(0, 0)->toHex()); + $image->modify(new FlopModifier()); + $this->assertEquals('00000000', $image->pickColor(0, 0)->toHex()); + } +} diff --git a/tests/Drivers/Imagick/Modifiers/GammaModifierTest.php b/tests/Drivers/Imagick/Modifiers/GammaModifierTest.php new file mode 100644 index 00000000..837b6310 --- /dev/null +++ b/tests/Drivers/Imagick/Modifiers/GammaModifierTest.php @@ -0,0 +1,24 @@ +readTestImage('trim.png'); + $this->assertEquals('00aef0', $image->pickColor(0, 0)->toHex()); + $image->modify(new GammaModifier(2.1)); + $this->assertEquals('00d5f8', $image->pickColor(0, 0)->toHex()); + } +} diff --git a/tests/Drivers/Imagick/Modifiers/GreyscaleModifierTest.php b/tests/Drivers/Imagick/Modifiers/GreyscaleModifierTest.php new file mode 100644 index 00000000..58682656 --- /dev/null +++ b/tests/Drivers/Imagick/Modifiers/GreyscaleModifierTest.php @@ -0,0 +1,24 @@ +readTestImage('trim.png'); + $this->assertFalse($image->pickColor(0, 0)->isGreyscale()); + $image->modify(new GreyscaleModifier()); + $this->assertTrue($image->pickColor(0, 0)->isGreyscale()); + } +} diff --git a/tests/Drivers/Imagick/Modifiers/InvertModifierTest.php b/tests/Drivers/Imagick/Modifiers/InvertModifierTest.php new file mode 100644 index 00000000..a298d32e --- /dev/null +++ b/tests/Drivers/Imagick/Modifiers/InvertModifierTest.php @@ -0,0 +1,26 @@ +readTestImage('trim.png'); + $this->assertEquals('00aef0', $image->pickColor(0, 0)->toHex()); + $this->assertEquals('ffa601', $image->pickColor(25, 25)->toHex()); + $image->modify(new InvertModifier()); + $this->assertEquals('ff510f', $image->pickColor(0, 0)->toHex()); + $this->assertEquals('0059fe', $image->pickColor(25, 25)->toHex()); + } +} diff --git a/tests/Drivers/Imagick/Modifiers/PixelateModifierTest.php b/tests/Drivers/Imagick/Modifiers/PixelateModifierTest.php new file mode 100644 index 00000000..d60ca68f --- /dev/null +++ b/tests/Drivers/Imagick/Modifiers/PixelateModifierTest.php @@ -0,0 +1,34 @@ +readTestImage('trim.png'); + $this->assertEquals('00aef0', $image->pickColor(0, 0)->toHex()); + $this->assertEquals('00aef0', $image->pickColor(14, 14)->toHex()); + $image->modify(new PixelateModifier(10)); + + list($r, $g, $b) = $image->pickColor(0, 0)->toArray(); + $this->assertEquals(0, $r); + $this->assertEquals(174, $g); + $this->assertEquals(240, $b); + + list($r, $g, $b) = $image->pickColor(14, 14)->toArray(); + $this->assertEquals(107, $r); + $this->assertEquals(171, $g); + $this->assertEquals(140, $b); + } +} diff --git a/tests/Drivers/Imagick/Modifiers/PlaceModifierTest.php b/tests/Drivers/Imagick/Modifiers/PlaceModifierTest.php new file mode 100644 index 00000000..c02238e6 --- /dev/null +++ b/tests/Drivers/Imagick/Modifiers/PlaceModifierTest.php @@ -0,0 +1,24 @@ +readTestImage('test.jpg'); + $this->assertEquals('febc44', $image->pickColor(300, 25)->toHex()); + $image->modify(new PlaceModifier(__DIR__ . '/../../../images/circle.png', 'top-right', 0, 0)); + $this->assertEquals('33260e', $image->pickColor(300, 25)->toHex()); + } +} diff --git a/tests/Drivers/Imagick/Modifiers/RemoveAnimationModifierTest.php b/tests/Drivers/Imagick/Modifiers/RemoveAnimationModifierTest.php new file mode 100644 index 00000000..6442255f --- /dev/null +++ b/tests/Drivers/Imagick/Modifiers/RemoveAnimationModifierTest.php @@ -0,0 +1,34 @@ +readTestImage('animation.gif'); + $this->assertEquals(8, count($image)); + $result = $image->modify(new RemoveAnimationModifier(2)); + $this->assertEquals(1, count($image)); + $this->assertEquals(1, count($result)); + } + + public function testApplyPercent(): void + { + $image = $this->readTestImage('animation.gif'); + $this->assertEquals(8, count($image)); + $result = $image->modify(new RemoveAnimationModifier('20%')); + $this->assertEquals(1, count($image)); + $this->assertEquals(1, count($result)); + } +} diff --git a/tests/Drivers/Imagick/Modifiers/ResizeCanvasModifierTest.php b/tests/Drivers/Imagick/Modifiers/ResizeCanvasModifierTest.php new file mode 100644 index 00000000..a7ab3edb --- /dev/null +++ b/tests/Drivers/Imagick/Modifiers/ResizeCanvasModifierTest.php @@ -0,0 +1,55 @@ +createTestImage(1, 1); + $this->assertEquals(1, $image->width()); + $this->assertEquals(1, $image->height()); + $image->modify(new ResizeCanvasModifier(3, 3, 'ff0', 'center')); + $this->assertEquals(3, $image->width()); + $this->assertEquals(3, $image->height()); + $this->assertColor(255, 255, 0, 255, $image->pickColor(0, 0)); + $this->assertColor(255, 0, 0, 255, $image->pickColor(1, 1)); + $this->assertColor(255, 255, 0, 255, $image->pickColor(2, 2)); + } + + public function testModifyWithTransparency(): void + { + $image = $this->readTestImage('tile.png'); + $this->assertEquals(16, $image->width()); + $this->assertEquals(16, $image->height()); + $image->modify(new ResizeCanvasModifier(18, 18, 'ff0', 'center')); + $this->assertEquals(18, $image->width()); + $this->assertEquals(18, $image->height()); + $this->assertColor(255, 255, 0, 255, $image->pickColor(0, 0)); + $this->assertColor(180, 224, 0, 255, $image->pickColor(1, 1)); + $this->assertColor(180, 224, 0, 255, $image->pickColor(2, 2)); + $this->assertColor(255, 255, 0, 255, $image->pickColor(17, 17)); + $this->assertTransparency($image->pickColor(12, 1)); + } + + public function testModifyEdge(): void + { + $image = $this->createTestImage(1, 1); + $this->assertColor(255, 0, 0, 255, $image->pickColor(0, 0)); + $image->modify(new ResizeCanvasModifier(null, 2, 'ff0', 'bottom')); + $this->assertEquals(1, $image->width()); + $this->assertEquals(2, $image->height()); + $this->assertColor(255, 255, 0, 255, $image->pickColor(0, 0)); + $this->assertColor(255, 0, 0, 255, $image->pickColor(0, 1)); + } +} diff --git a/tests/Drivers/Imagick/Modifiers/ResizeCanvasRelativeModifierTest.php b/tests/Drivers/Imagick/Modifiers/ResizeCanvasRelativeModifierTest.php new file mode 100644 index 00000000..1e54a0ac --- /dev/null +++ b/tests/Drivers/Imagick/Modifiers/ResizeCanvasRelativeModifierTest.php @@ -0,0 +1,44 @@ +createTestImage(1, 1); + $this->assertEquals(1, $image->width()); + $this->assertEquals(1, $image->height()); + $image->modify(new ResizeCanvasRelativeModifier(2, 2, 'ff0', 'center')); + $this->assertEquals(3, $image->width()); + $this->assertEquals(3, $image->height()); + $this->assertColor(255, 255, 0, 255, $image->pickColor(0, 0)); + $this->assertColor(255, 0, 0, 255, $image->pickColor(1, 1)); + $this->assertColor(255, 255, 0, 255, $image->pickColor(2, 2)); + } + + public function testModifyWithTransparency(): void + { + $image = $this->readTestImage('tile.png'); + $this->assertEquals(16, $image->width()); + $this->assertEquals(16, $image->height()); + $image->modify(new ResizeCanvasRelativeModifier(2, 2, 'ff0', 'center')); + $this->assertEquals(18, $image->width()); + $this->assertEquals(18, $image->height()); + $this->assertColor(255, 255, 0, 255, $image->pickColor(0, 0)); + $this->assertColor(180, 224, 0, 255, $image->pickColor(1, 1)); + $this->assertColor(180, 224, 0, 255, $image->pickColor(2, 2)); + $this->assertColor(255, 255, 0, 255, $image->pickColor(17, 17)); + $this->assertTransparency($image->pickColor(12, 1)); + } +} diff --git a/tests/Drivers/Imagick/Modifiers/ResizeModifierTest.php b/tests/Drivers/Imagick/Modifiers/ResizeModifierTest.php new file mode 100644 index 00000000..1139637a --- /dev/null +++ b/tests/Drivers/Imagick/Modifiers/ResizeModifierTest.php @@ -0,0 +1,27 @@ +readTestImage('blocks.png'); + $this->assertEquals(640, $image->width()); + $this->assertEquals(480, $image->height()); + $image->modify(new ResizeModifier(200, 100)); + $this->assertEquals(200, $image->width()); + $this->assertEquals(100, $image->height()); + $this->assertColor(255, 0, 0, 255, $image->pickColor(150, 70)); + } +} diff --git a/tests/Drivers/Imagick/Modifiers/ResolutionModifierTest.php b/tests/Drivers/Imagick/Modifiers/ResolutionModifierTest.php new file mode 100644 index 00000000..d20339ba --- /dev/null +++ b/tests/Drivers/Imagick/Modifiers/ResolutionModifierTest.php @@ -0,0 +1,26 @@ +readTestImage('test.jpg'); + $this->assertEquals(72.0, $image->resolution()->x()); + $this->assertEquals(72.0, $image->resolution()->y()); + $image->modify(new ResolutionModifier(1, 2)); + $this->assertEquals(1.0, $image->resolution()->x()); + $this->assertEquals(2.0, $image->resolution()->y()); + } +} diff --git a/tests/Drivers/Imagick/Modifiers/RotateModifierTest.php b/tests/Drivers/Imagick/Modifiers/RotateModifierTest.php new file mode 100644 index 00000000..62c0216f --- /dev/null +++ b/tests/Drivers/Imagick/Modifiers/RotateModifierTest.php @@ -0,0 +1,26 @@ +readTestImage('test.jpg'); + $this->assertEquals(320, $image->width()); + $this->assertEquals(240, $image->height()); + $image->modify(new RotateModifier(90, 'fff')); + $this->assertEquals(240, $image->width()); + $this->assertEquals(320, $image->height()); + } +} diff --git a/tests/Drivers/Imagick/Modifiers/SharpenModifierTest.php b/tests/Drivers/Imagick/Modifiers/SharpenModifierTest.php new file mode 100644 index 00000000..d9c11d7f --- /dev/null +++ b/tests/Drivers/Imagick/Modifiers/SharpenModifierTest.php @@ -0,0 +1,24 @@ +readTestImage('trim.png'); + $this->assertEquals('60ab96', $image->pickColor(15, 14)->toHex()); + $image->modify(new SharpenModifier(10)); + $this->assertEquals('4faca6', $image->pickColor(15, 14)->toHex()); + } +} diff --git a/tests/EllipseCommandTest.php b/tests/EllipseCommandTest.php deleted file mode 100644 index d3b8b2b3..00000000 --- a/tests/EllipseCommandTest.php +++ /dev/null @@ -1,43 +0,0 @@ -shouldReceive('getDriverName')->once()->andReturn('Gd'); - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getDriver')->once()->andReturn($driver); - $image->shouldReceive('getCore')->once()->andReturn($resource); - $command = new EllipseCommand([250, 150, 10, 20]); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertFalse($command->hasOutput()); - } - - public function testImagick() - { - $imagick = Mockery::mock('\Imagick'); - $imagick->shouldReceive('drawimage'); - $driver = Mockery::mock('\Intervention\Image\Imagick\Driver'); - $driver->shouldReceive('getDriverName')->once()->andReturn('Imagick'); - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getDriver')->once()->andReturn($driver); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - - $command = new EllipseCommand([250, 150, 10, 20]); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertFalse($command->hasOutput()); - } - -} diff --git a/tests/EllipseShapeTest.php b/tests/EllipseShapeTest.php deleted file mode 100644 index 9c857275..00000000 --- a/tests/EllipseShapeTest.php +++ /dev/null @@ -1,55 +0,0 @@ -assertInstanceOf('Intervention\Image\Gd\Shapes\EllipseShape', $ellipse); - $this->assertEquals(250, $ellipse->width); - $this->assertEquals(150, $ellipse->height); - - } - - public function testGdApplyToImage() - { - $core = imagecreatetruecolor(300, 200); - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($core); - $ellipse = new EllipseGd(250, 150); - $result = $ellipse->applyToImage($image, 10, 20); - $this->assertInstanceOf('Intervention\Image\Gd\Shapes\EllipseShape', $ellipse); - $this->assertTrue($result); - } - - public function testImagickConstructor() - { - $ellipse = new EllipseImagick(250, 150); - $this->assertInstanceOf('Intervention\Image\Imagick\Shapes\EllipseShape', $ellipse); - $this->assertEquals(250, $ellipse->width); - $this->assertEquals(150, $ellipse->height); - - } - - public function testImagickApplyToImage() - { - $core = Mockery::mock('\Imagick'); - $core->shouldReceive('drawimage')->once(); - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($core); - $ellipse = new EllipseImagick(250, 150); - $result = $ellipse->applyToImage($image, 10, 20); - $this->assertInstanceOf('Intervention\Image\Imagick\Shapes\EllipseShape', $ellipse); - $this->assertTrue($result); - } - -} diff --git a/tests/EncodedImageTest.php b/tests/EncodedImageTest.php new file mode 100644 index 00000000..a848ee95 --- /dev/null +++ b/tests/EncodedImageTest.php @@ -0,0 +1,49 @@ +assertInstanceOf(EncodedImage::class, $image); + } + + public function testSave(): void + { + $image = new EncodedImage('foo', 'bar'); + $path = __DIR__ . '/foo.tmp'; + $this->assertFalse(file_exists($path)); + $image->save($path); + $this->assertTrue(file_exists($path)); + $this->assertEquals('foo', file_get_contents($path)); + unlink($path); + } + + public function testToDataUri(): void + { + $image = new EncodedImage('foo', 'bar'); + $this->assertEquals('data:bar;base64,Zm9v', $image->toDataUri()); + } + + public function testToString(): void + { + $image = new EncodedImage('foo', 'bar'); + $this->assertEquals('foo', (string) $image); + } + + public function testMimetype(): void + { + $image = new EncodedImage('foo'); + $this->assertEquals('application/octet-stream', $image->mimetype()); + + $image = new EncodedImage('foo', 'image/jpeg'); + $this->assertEquals('image/jpeg', $image->mimetype()); + } +} diff --git a/tests/EncoderTest.php b/tests/EncoderTest.php deleted file mode 100644 index f68818df..00000000 --- a/tests/EncoderTest.php +++ /dev/null @@ -1,339 +0,0 @@ -shouldReceive('getCore')->once()->andReturn($core); - $image->shouldReceive('setEncoded')->once()->andReturn($image); - $img = $encoder->process($image, 'jpg', 90); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertEquals('image/jpeg; charset=binary', $this->getMime($encoder->result)); - } - - public function testProcessPngGd() - { - $core = imagecreatefromjpeg(__DIR__.'/images/test.jpg'); - $encoder = new GdEncoder; - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($core); - $image->shouldReceive('setEncoded')->once()->andReturn($image); - $img = $encoder->process($image, 'png', 90); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertEquals('image/png; charset=binary', $this->getMime($encoder->result)); - } - - public function testProcessGifGd() - { - $core = imagecreatefromjpeg(__DIR__.'/images/test.jpg'); - $encoder = new GdEncoder; - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($core); - $image->shouldReceive('setEncoded')->once()->andReturn($image); - $img = $encoder->process($image, 'gif', 90); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertEquals('image/gif; charset=binary', $this->getMime($encoder->result)); - } - - public function testProcessWebpGd() - { - if (function_exists('imagewebp')) { - $core = imagecreatefromjpeg(__DIR__.'/images/test.jpg'); - $encoder = new GdEncoder; - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($core); - $image->shouldReceive('setEncoded')->once()->andReturn($image); - $img = $encoder->process($image, 'webp', 90); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertEquals('image/webp; charset=binary', $this->getMime($encoder->result)); - } - } - - public function testProcessWebpGdWithUnSupportedPalette() - { - if (function_exists('imagewebp')) { - $core = imagecreatefrompng(__DIR__.'/images/black-friday.png'); - $encoder = new GdEncoder; - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($core); - $image->shouldReceive('setEncoded')->once()->andReturn($image); - $img = $encoder->process($image, 'webp', 90); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertEquals('image/webp; charset=binary', $this->getMime($encoder->result)); - } - } - - public function testProcessAvifGd() - { - if (function_exists('imageavif')) { - $core = imagecreatefromjpeg(__DIR__.'/images/test.jpg'); - $encoder = new GdEncoder; - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($core); - $image->shouldReceive('setEncoded')->once()->andReturn($image); - $img = $encoder->process($image, 'avif', 90); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertEquals('image/avif; charset=binary', $this->getMime($encoder->result)); - } - } - - /** - * @expectedException \Intervention\Image\Exception\NotSupportedException - */ - public function testProcessHeicGd() - { - $core = imagecreatefromjpeg(__DIR__.'/images/test.jpg'); - $encoder = new GdEncoder; - $image = Mockery::mock('\Intervention\Image\Image'); - $img = $encoder->process($image, 'heic', 90); - $this->assertInstanceOf('Intervention\Image\Image', $img); - } - - /** - * @expectedException \Intervention\Image\Exception\NotSupportedException - */ - public function testProcessTiffGd() - { - $core = imagecreatefromjpeg(__DIR__.'/images/test.jpg'); - $encoder = new GdEncoder; - $image = Mockery::mock('\Intervention\Image\Image'); - $img = $encoder->process($image, 'tif', 90); - $this->assertInstanceOf('Intervention\Image\Image', $img); - } - - public function testProcessBmpGd() - { - if (function_exists('imagebmp')) { - $core = imagecreatefromjpeg(__DIR__.'/images/test.jpg'); - $encoder = new GdEncoder; - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($core); - $image->shouldReceive('setEncoded')->once()->andReturn($image); - $img = $encoder->process($image, 'bmp', 90); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertEquals('image/x-ms-bmp; charset=binary', $this->getMime($encoder->result)); - } - } - - /** - * @expectedException \Intervention\Image\Exception\NotSupportedException - */ - public function testProcessIcoGd() - { - $core = imagecreatefromjpeg(__DIR__.'/images/test.jpg'); - $encoder = new GdEncoder; - $image = Mockery::mock('\Intervention\Image\Image'); - $img = $encoder->process($image, 'ico', 90); - $this->assertInstanceOf('Intervention\Image\Image', $img); - } - - /** - * @expectedException \Intervention\Image\Exception\NotSupportedException - */ - public function testProcessPsdGd() - { - $core = imagecreatefromjpeg(__DIR__.'/images/test.jpg'); - $encoder = new GdEncoder; - $image = Mockery::mock('\Intervention\Image\Image'); - $img = $encoder->process($image, 'psd', 90); - $this->assertInstanceOf('Intervention\Image\Image', $img); - } - - public function testProcessUnknownWithMimeGd() - { - $core = imagecreatefromjpeg(__DIR__.'/images/test.jpg'); - $encoder = new GdEncoder; - $image = Mockery::mock('\Intervention\Image\Image'); - $image->mime = 'image/jpeg'; - $image->shouldReceive('getCore')->once()->andReturn($core); - $image->shouldReceive('setEncoded')->once()->andReturn($image); - $img = $encoder->process($image, null); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertEquals('image/jpeg; charset=binary', $this->getMime($encoder->result)); - } - - public function testProcessUnknownGd() - { - $core = imagecreatefromjpeg(__DIR__.'/images/test.jpg'); - $encoder = new GdEncoder; - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($core); - $image->shouldReceive('setEncoded')->once()->andReturn($image); - $img = $encoder->process($image, null); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertEquals('image/jpeg; charset=binary', $this->getMime($encoder->result)); - } - - public function testProcessJpegImagick() - { - $core = $this->getImagickMock('jpeg'); - $encoder = new ImagickEncoder; - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($core); - $image->shouldReceive('setEncoded')->once()->andReturn($image); - $img = $encoder->process($image, 'jpg', 90); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertEquals('mock-jpeg', $encoder->result); - } - - public function testProcessPngImagick() - { - $core = $this->getImagickMock('png'); - $encoder = new ImagickEncoder; - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($core); - $image->shouldReceive('setEncoded')->once()->andReturn($image); - $img = $encoder->process($image, 'png', 90); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertEquals('mock-png', $encoder->result); - } - - public function testProcessGifImagick() - { - $core = $this->getImagickMock('gif'); - $encoder = new ImagickEncoder; - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($core); - $image->shouldReceive('setEncoded')->once()->andReturn($image); - $img = $encoder->process($image, 'gif', 90); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertEquals('mock-gif', $encoder->result); - } - - /** - * @expectedException \Intervention\Image\Exception\NotSupportedException - */ - public function testProcessWebpImagick() - { - $encoder = new ImagickEncoder; - $image = Mockery::mock('\Intervention\Image\Image'); - $img = $encoder->process($image, 'webp', 90); - } - - /** - * @expectedException \Intervention\Image\Exception\NotSupportedException - */ - public function testProcessAvifImagick() - { - $encoder = new ImagickEncoder; - $image = Mockery::mock('\Intervention\Image\Image'); - $img = $encoder->process($image, 'avif', 90); - } - - /** - * @expectedException \Intervention\Image\Exception\NotSupportedException - */ - public function testProcessHeicImagick() - { - $encoder = new ImagickEncoder; - $image = Mockery::mock('\Intervention\Image\Image'); - $img = $encoder->process($image, 'heic', 90); - } - - public function testProcessTiffImagick() - { - $core = $this->getImagickMock('tiff'); - $encoder = new ImagickEncoder; - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($core); - $image->shouldReceive('setEncoded')->once()->andReturn($image); - $img = $encoder->process($image, 'tiff', 90); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertEquals('mock-tiff', $encoder->result); - } - - public function testProcessBmpImagick() - { - $core = $this->getImagickMock('bmp'); - $encoder = new ImagickEncoder; - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($core); - $image->shouldReceive('setEncoded')->once()->andReturn($image); - $img = $encoder->process($image, 'bmp', 90); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertEquals('mock-bmp', $encoder->result); - } - - public function testProcessIcoImagick() - { - $core = $this->getImagickMock('ico'); - $encoder = new ImagickEncoder; - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($core); - $image->shouldReceive('setEncoded')->once()->andReturn($image); - $img = $encoder->process($image, 'ico', 90); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertEquals('mock-ico', $encoder->result); - } - - public function testProcessPsdImagick() - { - $core = $this->getImagickMock('psd'); - $encoder = new ImagickEncoder; - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($core); - $image->shouldReceive('setEncoded')->once()->andReturn($image); - $img = $encoder->process($image, 'psd', 90); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertEquals('mock-psd', $encoder->result); - } - - public function testProcessUnknownWithMimeImagick() - { - $core = $this->getImagickMock('jpeg'); - $encoder = new ImagickEncoder; - $image = Mockery::mock('\Intervention\Image\Image'); - $image->mime = 'image/jpeg'; - $image->shouldReceive('getCore')->once()->andReturn($core); - $image->shouldReceive('setEncoded')->once()->andReturn($image); - $img = $encoder->process($image, null); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertEquals('mock-jpeg', $encoder->result); - } - - public function testProcessUnknownImagick() - { - $core = $this->getImagickMock('jpeg'); - $encoder = new ImagickEncoder; - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($core); - $image->shouldReceive('setEncoded')->once()->andReturn($image); - $img = $encoder->process($image, null); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertEquals('mock-jpeg', $encoder->result); - } - - public function getImagickMock($type) - { - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('setformat')->with($type)->once(); - $imagick->shouldReceive('setimageformat')->once(); - $imagick->shouldReceive('setcompression')->once(); - $imagick->shouldReceive('setimagecompression')->once(); - $imagick->shouldReceive('setcompressionquality'); - $imagick->shouldReceive('setimagecompressionquality'); - $imagick->shouldReceive('setimagebackgroundcolor'); - $imagick->shouldReceive('setbackgroundcolor'); - $imagick->shouldReceive('mergeimagelayers')->andReturn($imagick); - $imagick->shouldReceive('getimagesblob')->once()->andReturn(sprintf('mock-%s', $type)); - return $imagick; - } - - public function getMime($data) - { - $finfo = new finfo(FILEINFO_MIME); - return $finfo->buffer($data); - } -} diff --git a/tests/ExifCommandTest.php b/tests/ExifCommandTest.php deleted file mode 100644 index 8b051c95..00000000 --- a/tests/ExifCommandTest.php +++ /dev/null @@ -1,112 +0,0 @@ -dirname = __DIR__.'/images'; - $image->basename = 'exif.jpg'; - $command = new ExifCommand([]); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertTrue($command->hasOutput()); - $this->assertInternalType('array', $command->getOutput()); - } - - public function testFetchDefined() - { - $image = new Image; - $image->dirname = __DIR__.'/images'; - $image->basename = 'exif.jpg'; - $command = new ExifCommand(['Artist']); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertTrue($command->hasOutput()); - $this->assertEquals('Oliver Vogel', $command->getOutput()); - } - - public function testFetchNonExisting() - { - $image = new Image; - $image->dirname = __DIR__.'/images'; - $image->basename = 'exif.jpg'; - $command = new ExifCommand(['xxx']); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertTrue($command->hasOutput()); - $this->assertEquals(null, $command->getOutput()); - } - - public function testFetchFromPng() - { - $image = new Image; - $image->dirname = __DIR__.'/images'; - $image->basename = 'star.png'; - $command = new ExifCommand(['Orientation']); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertTrue($command->hasOutput()); - $this->assertEquals(null, $command->getOutput()); - } - - public function testImagickFetchAll() - { - $image = $this->imagick()->make(__DIR__.'/images/exif.jpg'); - $command = new \Intervention\Image\Imagick\Commands\ExifCommand([]); - $command->dontPreferExtension(); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertTrue($command->hasOutput()); - $this->assertInternalType('array', $command->getOutput()); - $this->assertEquals('Oliver Vogel', $command->getOutput()['Artist']); - } - - public function testImagickFetchDefined() - { - $image = $this->imagick()->make(__DIR__.'/images/exif.jpg'); - $command = new \Intervention\Image\Imagick\Commands\ExifCommand(['Artist']); - $command->dontPreferExtension(); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertTrue($command->hasOutput()); - $this->assertEquals('Oliver Vogel', $command->getOutput()); - } - - public function testImagickNonExisting() - { - $image = $this->imagick()->make(__DIR__.'/images/exif.jpg'); - $command = new \Intervention\Image\Imagick\Commands\ExifCommand(['xx']); - $command->dontPreferExtension(); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertTrue($command->hasOutput()); - $this->assertEquals(null, $command->getOutput()); - } - - public function testImagickFallbackToExifExtenstion() - { - $image = $this->imagick()->make(__DIR__.'/images/exif.jpg'); - $command = new \Intervention\Image\Imagick\Commands\ExifCommand(['Artist']); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertTrue($command->hasOutput()); - $this->assertEquals('Oliver Vogel', $command->getOutput()); - } - - private function imagick() - { - return new \Intervention\Image\ImageManager([ - 'driver' => 'imagick' - ]); - } -} diff --git a/tests/FileTest.php b/tests/FileTest.php index e1c01fd2..86e8b7d6 100644 --- a/tests/FileTest.php +++ b/tests/FileTest.php @@ -1,28 +1,47 @@ setFileInfoFromPath('tests/images/test.jpg'); - $this->assertEquals('tests/images', $file->dirname); - $this->assertEquals('test.jpg', $file->basename); - $this->assertEquals('jpg', $file->extension); - $this->assertEquals('test', $file->filename); - $this->assertEquals('image/jpeg', $file->mime); + $file = new File('foo'); + $this->assertInstanceOf(File::class, $file); } - public function testBasePath() + public function testSave(): void { - $file = new File; - $this->assertNull(null, $file->basePath() ?: ''); + $filename = __DIR__ . '/file_' . strval(hrtime(true)) . '.test'; + $file = new File('foo'); + $file->save($filename); + $this->assertTrue(file_exists($filename)); + unlink($filename); + } - $file->dirname = 'foo'; - $file->basename = 'bar'; - $this->assertEquals('foo/bar', $file->basePath()); + public function testToString(): void + { + $file = new File('foo'); + $string = $file->toString(); + $this->assertEquals('foo', $string); + $this->assertEquals('foo', (string) $string); + } + + public function testToFilePointer(): void + { + $file = new File('foo'); + $fp = $file->toFilePointer(); + $this->assertIsResource($fp); + } + + public function testSize(): void + { + $file = new File('foo'); + $this->assertEquals(3, $file->size()); } } diff --git a/tests/FillCommandTest.php b/tests/FillCommandTest.php deleted file mode 100644 index cbd3f1ed..00000000 --- a/tests/FillCommandTest.php +++ /dev/null @@ -1,93 +0,0 @@ -shouldReceive('getCore')->once()->andReturn($resource); - $image->shouldReceive('getWidth')->once()->andReturn(800); - $image->shouldReceive('getHeight')->once()->andReturn(600); - $command = new FillGd(['666666']); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testGdFillArray() - { - $resource = imagecreatefromjpeg(__DIR__.'/images/test.jpg'); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($resource); - $image->shouldReceive('getWidth')->once()->andReturn(800); - $image->shouldReceive('getHeight')->once()->andReturn(600); - $command = new FillGd([[50, 50, 50]]); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testGdFillArrayWithAlpha() - { - $resource = imagecreatefromjpeg(__DIR__.'/images/test.jpg'); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($resource); - $image->shouldReceive('getWidth')->once()->andReturn(800); - $image->shouldReceive('getHeight')->once()->andReturn(600); - $command = new FillGd([[50, 50, 50, .50]]); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testGdFillWithCoordinates() - { - $driver = Mockery::mock('\Intervention\Image\Gd\Driver'); - $resource = imagecreatefromjpeg(__DIR__.'/images/test.jpg'); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getDriver')->once()->andReturn($driver); - $image->shouldReceive('getCore')->times(2)->andReturn($resource); - $image->shouldReceive('getWidth')->once()->andReturn(800); - $image->shouldReceive('getHeight')->once()->andReturn(600); - $image->shouldReceive('setCore')->once(); - $driver->shouldReceive('newImage')->with(800, 600)->once()->andReturn($image); - $command = new FillGd(['#666666', 0, 0]); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagickFill() - { - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('drawimage')->once()->andReturn(true); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getWidth')->once()->andReturn(800); - $image->shouldReceive('getHeight')->once()->andReturn(600); - $image->shouldReceive('getCore')->andReturn($imagick); - $command = new FillImagick(['666666']); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagickFillWithCoordinates() - { - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('getimagepixelcolor')->once()->andReturn('#000000'); - $imagick->shouldReceive('transparentpaintimage')->once()->andReturn(true); - $imagick->shouldReceive('compositeimage')->times(3)->andReturn(true); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->andReturn($imagick); - $image->shouldReceive('getWidth')->andReturn(800); - $image->shouldReceive('getHeight')->andReturn(600); - $command = new FillImagick(['666666', 0, 0]); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/FitCommandTest.php b/tests/FitCommandTest.php deleted file mode 100644 index 23b1cb3b..00000000 --- a/tests/FitCommandTest.php +++ /dev/null @@ -1,93 +0,0 @@ -shouldReceive('getWidth')->times(2)->andReturn(800); - $cropped_size->shouldReceive('getHeight')->times(2)->andReturn(400); - $cropped_size->shouldReceive('resize')->with(200, 100, null)->once()->andReturn($cropped_size); - $cropped_size->pivot = Mockery::mock('\Intervention\Image\Point', [0, 100]); - $original_size = Mockery::mock('\Intervention\Image\Size', [800, 600]); - $original_size->shouldReceive('fit')->with(Mockery::any(), 'center')->once()->andReturn($cropped_size); - $resource = imagecreatefromjpeg(__DIR__.'/images/test.jpg'); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getSize')->once()->andReturn($original_size); - $image->shouldReceive('getCore')->once()->andReturn($resource); - $image->shouldReceive('setCore')->once(); - $command = new FitGd([200, 100]); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testGdFitWithPosition() - { - $cropped_size = Mockery::mock('\Intervention\Image\Size', [800, 400]); - $cropped_size->shouldReceive('getWidth')->times(2)->andReturn(800); - $cropped_size->shouldReceive('getHeight')->times(2)->andReturn(400); - $cropped_size->shouldReceive('resize')->with(200, 100, null)->once()->andReturn($cropped_size); - $cropped_size->pivot = Mockery::mock('\Intervention\Image\Point', [0, 100]); - $original_size = Mockery::mock('\Intervention\Image\Size', [800, 600]); - $original_size->shouldReceive('fit')->with(Mockery::any(), 'top-left')->once()->andReturn($cropped_size); - $resource = imagecreatefromjpeg(__DIR__.'/images/test.jpg'); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getSize')->once()->andReturn($original_size); - $image->shouldReceive('getCore')->once()->andReturn($resource); - $image->shouldReceive('setCore')->once(); - $command = new FitGd([200, 100, null, 'top-left']); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagickFit() - { - $cropped_size = Mockery::mock('\Intervention\Image\Size', [800, 400]); - $cropped_size->shouldReceive('getWidth')->once()->andReturn(200); - $cropped_size->shouldReceive('getHeight')->once()->andReturn(100); - $cropped_size->shouldReceive('resize')->with(200, 100, null)->once()->andReturn($cropped_size); - $cropped_size->pivot = Mockery::mock('\Intervention\Image\Point', [0, 100]); - $original_size = Mockery::mock('\Intervention\Image\Size', [800, 600]); - $original_size->shouldReceive('fit')->with(Mockery::any(), 'center')->once()->andReturn($cropped_size); - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('cropimage')->with(800, 400, 0, 100)->andReturn(true); - $imagick->shouldReceive('scaleimage')->with(200, 100)->once()->andReturn(true); - $imagick->shouldReceive('setimagepage')->with(0, 0, 0, 0)->andReturn(true); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getSize')->once()->andReturn($original_size); - $image->shouldReceive('getCore')->times(3)->andReturn($imagick); - $command = new FitImagick([200, 100]); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagickFitWithPosition() - { - $cropped_size = Mockery::mock('\Intervention\Image\Size', [800, 400]); - $cropped_size->shouldReceive('getWidth')->once()->andReturn(200); - $cropped_size->shouldReceive('getHeight')->once()->andReturn(100); - $cropped_size->shouldReceive('resize')->with(200, 100, null)->once()->andReturn($cropped_size); - $cropped_size->pivot = Mockery::mock('\Intervention\Image\Point', [0, 100]); - $original_size = Mockery::mock('\Intervention\Image\Size', [800, 600]); - $original_size->shouldReceive('fit')->with(Mockery::any(), 'top-left')->once()->andReturn($cropped_size); - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('cropimage')->with(800, 400, 0, 100)->andReturn(true); - $imagick->shouldReceive('scaleimage')->with(200, 100)->once()->andReturn(true); - $imagick->shouldReceive('setimagepage')->with(0, 0, 0, 0)->andReturn(true); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getSize')->once()->andReturn($original_size); - $image->shouldReceive('getCore')->times(3)->andReturn($imagick); - $command = new FitImagick([200, 100, null, 'top-left']); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/FlipCommandTest.php b/tests/FlipCommandTest.php deleted file mode 100644 index 09370eb6..00000000 --- a/tests/FlipCommandTest.php +++ /dev/null @@ -1,45 +0,0 @@ -shouldReceive('getSize')->once()->andReturn($size); - $image->shouldReceive('getCore')->once()->andReturn($resource); - $image->shouldReceive('setCore')->once(); - $command = new FlipGd(['h']); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagick() - { - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('flopimage')->with()->andReturn(true); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - $command = new FlipImagick(['h']); - $result = $command->execute($image); - $this->assertTrue($result); - - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('flipimage')->with()->andReturn(true); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - $command = new FlipImagick(['v']); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/GammaCommandTest.php b/tests/GammaCommandTest.php deleted file mode 100644 index 6430236d..00000000 --- a/tests/GammaCommandTest.php +++ /dev/null @@ -1,34 +0,0 @@ -shouldReceive('getCore')->once()->andReturn($resource); - $command = new GammaGd([1.4]); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagick() - { - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('gammaimage')->with(1.4)->once()->andReturn(true); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - $command = new GammaImagick([1.4]); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/GdColorTest.php b/tests/GdColorTest.php deleted file mode 100644 index 7fa9f65f..00000000 --- a/tests/GdColorTest.php +++ /dev/null @@ -1,296 +0,0 @@ -validateColor($c, 255, 255, 255, 127); - } - - public function testParseNull() - { - $c = new Color; - $c->parse(null); - $this->validateColor($c, 255, 255, 255, 127); - } - - public function testParseInteger() - { - $c = new Color; - $c->parse(850736919); - $this->validateColor($c, 181, 55, 23, 50); - } - - public function testParseArray() - { - $c = new Color; - $c->parse([181, 55, 23, 0.5]); - $this->validateColor($c, 181, 55, 23, 64); - } - - public function testParseHexString() - { - $c = new Color; - $c->parse('#b53717'); - $this->validateColor($c, 181, 55, 23, 0); - } - - public function testParseRgbaString() - { - $c = new Color; - $c->parse('rgba(181, 55, 23, 1)'); - $this->validateColor($c, 181, 55, 23, 0); - } - - public function testInitFromInteger() - { - $c = new Color; - $c->initFromInteger(0); - $this->validateColor($c, 0, 0, 0, 0); - $c->initFromInteger(2147483647); - $this->validateColor($c, 255, 255, 255, 127); - $c->initFromInteger(16777215); - $this->validateColor($c, 255, 255, 255, 0); - $c->initFromInteger(2130706432); - $this->validateColor($c, 0, 0, 0, 127); - $c->initFromInteger(850736919); - $this->validateColor($c, 181, 55, 23, 50); - } - - public function testInitFromArray() - { - $c = new Color; - $c->initFromArray([0, 0, 0, 0]); - $this->validateColor($c, 0, 0, 0, 127); - $c->initFromArray([0, 0, 0, 1]); - $this->validateColor($c, 0, 0, 0, 0); - $c->initFromArray([255, 255, 255, 1]); - $this->validateColor($c, 255, 255, 255, 0); - $c->initFromArray([255, 255, 255, 0]); - $this->validateColor($c, 255, 255, 255, 127); - $c->initFromArray([255, 255, 255, 0.5]); - $this->validateColor($c, 255, 255, 255, 64); - $c->initFromArray([0, 0, 0]); - $this->validateColor($c, 0, 0, 0, 0); - $c->initFromArray([255, 255, 255]); - $this->validateColor($c, 255, 255, 255, 0); - $c->initFromArray([181, 55, 23]); - $this->validateColor($c, 181, 55, 23, 0); - $c->initFromArray([181, 55, 23, 0.5]); - $this->validateColor($c, 181, 55, 23, 64); - } - - public function testInitFromHexString() - { - $c = new Color; - $c->initFromString('#cccccc'); - $this->validateColor($c, 204, 204, 204, 0); - $c->initFromString('#b53717'); - $this->validateColor($c, 181, 55, 23, 0); - $c->initFromString('ffffff'); - $this->validateColor($c, 255, 255, 255, 0); - $c->initFromString('ff00ff'); - $this->validateColor($c, 255, 0, 255, 0); - $c->initFromString('#000'); - $this->validateColor($c, 0, 0, 0, 0); - $c->initFromString('000'); - $this->validateColor($c, 0, 0, 0, 0); - } - - public function testInitFromRgbString() - { - $c = new Color; - $c->initFromString('rgb(1, 14, 144)'); - $this->validateColor($c, 1, 14, 144, 0); - $c->initFromString('rgb (255, 255, 255)'); - $this->validateColor($c, 255, 255, 255, 0); - $c->initFromString('rgb(0,0,0)'); - $this->validateColor($c, 0, 0, 0, 0); - $c->initFromString('rgba(0,0,0,0)'); - $this->validateColor($c, 0, 0, 0, 127); - $c->initFromString('rgba(0,0,0,0.5)'); - $this->validateColor($c, 0, 0, 0, 64); - $c->initFromString('rgba(255, 0, 0, 0.5)'); - $this->validateColor($c, 255, 0, 0, 64); - $c->initFromString('rgba(204, 204, 204, 0.9)'); - $this->validateColor($c, 204, 204, 204, 13); - } - - public function testInitFromRgb() - { - $c = new Color; - $c->initFromRgb(0, 0, 0); - $this->validateColor($c, 0, 0, 0, 0); - $c->initFromRgb(255, 255, 255); - $this->validateColor($c, 255, 255, 255, 0); - $c->initFromRgb(181, 55, 23); - $this->validateColor($c, 181, 55, 23, 0); - } - - public function testInitFromRgba() - { - $c = new Color; - $c->initFromRgba(0, 0, 0, 1); - $this->validateColor($c, 0, 0, 0, 0); - $c->initFromRgba(255, 255, 255, 1); - $this->validateColor($c, 255, 255, 255, 0); - $c->initFromRgba(181, 55, 23, 1); - $this->validateColor($c, 181, 55, 23, 0); - $c->initFromRgba(181, 55, 23, 0); - $this->validateColor($c, 181, 55, 23, 127); - $c->initFromRgba(181, 55, 23, 0.5); - $this->validateColor($c, 181, 55, 23, 64); - } - - public function testGetInt() - { - $c = new Color; - $i = $c->getInt(); - $this->assertInternalType('int', $i); - $this->assertEquals(2147483647, $i); - - $c = new Color([255, 255, 255]); - $i = $c->getInt(); - $this->assertInternalType('int', $i); - $this->assertEquals($i, 16777215); - - $c = new Color([255, 255, 255, 1]); - $i = $c->getInt(); - $this->assertInternalType('int', $i); - $this->assertEquals($i, 16777215); - - $c = new Color([181, 55, 23, 0.5]); - $i = $c->getInt(); - $this->assertInternalType('int', $i); - $this->assertEquals($i, 1085617943); - - $c = new Color([181, 55, 23, 1]); - $i = $c->getInt(); - $this->assertInternalType('int', $i); - $this->assertEquals($i, 11876119); - - $c = new Color([0, 0, 0, 0]); - $i = $c->getInt(); - $this->assertInternalType('int', $i); - $this->assertEquals($i, 2130706432); - } - - public function testGetHex() - { - $c = new Color; - $i = $c->getHex(); - $this->assertInternalType('string', $i); - $this->assertEquals($i, 'ffffff'); - - $c = new Color([255, 255, 255, 1]); - $i = $c->getHex(); - $this->assertInternalType('string', $i); - $this->assertEquals($i, 'ffffff'); - - $c = new Color([181, 55, 23, 0.5]); - $i = $c->getHex(); - $this->assertInternalType('string', $i); - $this->assertEquals($i, 'b53717'); - - $c = new Color([0, 0, 0, 0]); - $i = $c->getHex('#'); - $this->assertInternalType('string', $i); - $this->assertEquals($i, '#000000'); - } - - public function testGetArray() - { - $c = new Color; - $i = $c->getArray(); - $this->assertInternalType('array', $i); - $this->assertEquals($i, [255, 255, 255, 0]); - - $c = new Color([255, 255, 255, 1]); - $i = $c->getArray(); - $this->assertInternalType('array', $i); - $this->assertEquals($i, [255, 255, 255, 1]); - - $c = new Color([181, 55, 23, 0.5]); - $i = $c->getArray(); - $this->assertInternalType('array', $i); - $this->assertEquals($i, [181, 55, 23, 0.5]); - - $c = new Color([0, 0, 0, 1]); - $i = $c->getArray(); - $this->assertInternalType('array', $i); - $this->assertEquals($i, [0, 0, 0, 1]); - } - - public function testGetRgba() - { - $c = new Color; - $i = $c->getRgba(); - $this->assertInternalType('string', $i); - $this->assertEquals($i, 'rgba(255, 255, 255, 0.00)'); - - $c = new Color([255, 255, 255, 1]); - $i = $c->getRgba(); - $this->assertInternalType('string', $i); - $this->assertEquals($i, 'rgba(255, 255, 255, 1.00)'); - - $c = new Color([181, 55, 23, 0.5]); - $i = $c->getRgba(); - $this->assertInternalType('string', $i); - $this->assertEquals($i, 'rgba(181, 55, 23, 0.50)'); - - $c = new Color([0, 0, 0, 1]); - $i = $c->getRgba(); - $this->assertInternalType('string', $i); - $this->assertEquals($i, 'rgba(0, 0, 0, 1.00)'); - } - - public function testDiffers() - { - $c1 = new Color([0, 0, 0]); - $c2 = new Color([0, 0, 0]); - $this->assertEquals(false, $c1->differs($c2)); - - $c1 = new Color([1, 0, 0]); - $c2 = new Color([0, 0, 0]); - $this->assertEquals(true, $c1->differs($c2)); - - $c1 = new Color([1, 0, 0]); - $c2 = new Color([0, 0, 0]); - $this->assertEquals(false, $c1->differs($c2, 10)); - - $c1 = new Color([127, 127, 127]); - $c2 = new Color([0, 0, 0]); - $this->assertEquals(true, $c1->differs($c2, 49)); - - $c1 = new Color([127, 127, 127]); - $c2 = new Color([0, 0, 0]); - $this->assertEquals(false, $c1->differs($c2, 50)); - } - - /** - * @expectedException \Intervention\Image\Exception\NotReadableException - */ - public function testParseUnknown() - { - $c = new Color('xxxxxxxxxxxxxxxxxxxx'); - } - - private function validateColor($obj, $r, $g, $b, $a) - { - $this->assertInstanceOf('Intervention\Image\Gd\Color', $obj); - $this->assertInternalType('int', $r); - $this->assertInternalType('int', $g); - $this->assertInternalType('int', $b); - $this->assertInternalType('int', $a); - $this->assertEquals($obj->r, $r); - $this->assertEquals($obj->g, $g); - $this->assertEquals($obj->b, $b); - $this->assertEquals($obj->a, $a); - } -} diff --git a/tests/GdSystemTest.php b/tests/GdSystemTest.php deleted file mode 100644 index 7d7d5ecd..00000000 --- a/tests/GdSystemTest.php +++ /dev/null @@ -1,1703 +0,0 @@ -manager()->make('tests/images/circle.png'); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('resource', $img->getCore()); - $this->assertInternalType('resource', $img->getCore()); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(50, $img->getWidth()); - $this->assertEquals(50, $img->getHeight()); - $this->assertEquals('image/png', $img->mime); - $this->assertEquals('tests/images', $img->dirname); - $this->assertEquals('circle.png', $img->basename); - $this->assertEquals('png', $img->extension); - $this->assertEquals('circle', $img->filename); - $this->assertEquals('image/png', $img->mime); - } - - /** - * @expectedException \Intervention\Image\Exception\NotReadableException - */ - public function testMakeFromPathBroken() - { - $this->manager()->make('tests/images/broken.png'); - } - - /** - * @expectedException \Intervention\Image\Exception\NotReadableException - */ - public function testMakeFromNotExisting() - { - $this->manager()->make('tests/images/not_existing.png'); - } - - public function testMakeFromString() - { - $str = file_get_contents('tests/images/circle.png'); - $img = $this->manager()->make($str); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('resource', $img->getCore()); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(50, $img->getWidth()); - $this->assertEquals(50, $img->getHeight()); - $this->assertEquals('image/png', $img->mime); - } - - public function testMakeFromResource() - { - $resource = imagecreatefrompng('tests/images/circle.png'); - $img = $this->manager()->make($resource); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('resource', $img->getCore()); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(50, $img->getWidth()); - $this->assertEquals(50, $img->getHeight()); - } - - public function testMakeFromDataUrl() - { - $img = $this->manager()->make('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAGElEQVQYlWM8c+bMfwYiABMxikYVUk8hAHWzA3cRvs4UAAAAAElFTkSuQmCC'); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('resource', $img->getCore()); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(10, $img->getWidth()); - $this->assertEquals(10, $img->getHeight()); - } - - public function testMakeFromBase64() - { - $img = $this->manager()->make('iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAGElEQVQYlWM8c+bMfwYiABMxikYVUk8hAHWzA3cRvs4UAAAAAElFTkSuQmCC'); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('resource', $img->getCore()); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(10, $img->getWidth()); - $this->assertEquals(10, $img->getHeight()); - } - - public function testMakeFromBase64WithNewlines() - { - $data = 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+' . "\n" . - '9AAAAGElEQVQYlWM8c+bMfwYiABMxikYVUk8hAHWzA3' . "\n" . - 'cRvs4UAAAAAElFTkSuQmCC'; - - $img = $this->manager()->make($data); - - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('resource', $img->getCore()); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(10, $img->getWidth()); - $this->assertEquals(10, $img->getHeight()); - } - - public function testMakeFromWebp() - { - if (function_exists('imagecreatefromwebp')) { - $img = $this->manager()->make('tests/images/test.webp'); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('resource', $img->getCore()); - $this->assertEquals(16, $img->getWidth()); - $this->assertEquals(16, $img->getHeight()); - $this->assertEquals('image/webp', $img->mime); - $this->assertEquals('tests/images', $img->dirname); - $this->assertEquals('test.webp', $img->basename); - $this->assertEquals('webp', $img->extension); - $this->assertEquals('test', $img->filename); - } - } - - public function testCanvas() - { - $img = $this->manager()->canvas(30, 20); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('resource', $img->getCore()); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(30, $img->getWidth()); - $this->assertEquals(20, $img->getHeight()); - $this->assertTransparentPosition($img, 0, 0); - } - - public function testCanvasWithSolidBackground() - { - $img = $this->manager()->canvas(30, 20, 'b53717'); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('resource', $img->getCore()); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(30, $img->getWidth()); - $this->assertEquals(20, $img->getHeight()); - $this->assertEquals('#b53717', $img->pickColor(15, 15, 'hex')); - } - - public function testGetSize() - { - $img = $this->manager()->make('tests/images/tile.png'); - $size = $img->getSize(); - $this->assertInstanceOf('Intervention\Image\Size', $size); - $this->assertInternalType('int', $size->width); - $this->assertInternalType('int', $size->height); - $this->assertEquals(16, $size->width); - $this->assertEquals(16, $size->height); - } - - public function testResizeImage() - { - $img = $this->manager()->make('tests/images/circle.png'); - $img->resize(120, 150); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('resource', $img->getCore()); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(120, $img->getWidth()); - $this->assertEquals(150, $img->getHeight()); - $this->assertTransparentPosition($img, 0, 0); - } - - public function testResizeImageOnlyWidth() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->resize(120, null); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('resource', $img->getCore()); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(120, $img->getWidth()); - $this->assertEquals(16, $img->getHeight()); - $this->assertTransparentPosition($img, 0, 15); - } - - public function testResizeImageOnlyHeight() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->resize(null, 150); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('resource', $img->getCore()); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(16, $img->getWidth()); - $this->assertEquals(150, $img->getHeight()); - $this->assertTransparentPosition($img, 15, 0); - } - - public function testResizeImageAutoHeight() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->resize(50, null, function ($constraint) { $constraint->aspectRatio(); }); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('resource', $img->getCore()); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(50, $img->getWidth()); - $this->assertEquals(50, $img->getHeight()); - $this->assertTransparentPosition($img, 30, 0); - } - - public function testResizeImageAutoWidth() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->resize(null, 50, function ($constraint) { $constraint->aspectRatio(); }); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('resource', $img->getCore()); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(50, $img->getWidth()); - $this->assertEquals(50, $img->getHeight()); - $this->assertTransparentPosition($img, 30, 0); - } - - public function testResizeDominantWidth() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->resize(100, 120, function ($constraint) { $constraint->aspectRatio(); }); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('resource', $img->getCore()); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(100, $img->getWidth()); - $this->assertEquals(100, $img->getHeight()); - $this->assertTransparentPosition($img, 60, 0); - } - - public function testResizeImagePreserveSimpleUpsizing() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->resize(100, 100, function ($constraint) { $constraint->aspectRatio(); $constraint->upsize(); }); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('resource', $img->getCore()); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(16, $img->getWidth()); - $this->assertEquals(16, $img->getHeight()); - $this->assertTransparentPosition($img, 15, 0); - } - - public function testWidenImage() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->widen(100); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('resource', $img->getCore()); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(100, $img->getWidth()); - $this->assertEquals(100, $img->getHeight()); - $this->assertTransparentPosition($img, 60, 0); - } - - public function testWidenImageWithConstraint() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->widen(100, function ($constraint) {$constraint->upsize();}); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('resource', $img->getCore()); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(16, $img->getWidth()); - $this->assertEquals(16, $img->getHeight()); - $this->assertTransparentPosition($img, 8, 0); - } - - public function testHeightenImage() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->heighten(100); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('resource', $img->getCore()); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(100, $img->getWidth()); - $this->assertEquals(100, $img->getHeight()); - $this->assertTransparentPosition($img, 60, 0); - } - - public function testHeightenImageWithConstraint() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->heighten(100, function ($constraint) {$constraint->upsize();}); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('resource', $img->getCore()); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(16, $img->getWidth()); - $this->assertEquals(16, $img->getHeight()); - $this->assertTransparentPosition($img, 8, 0); - } - - public function testResizeCanvasCenter() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->resizeCanvas(10, 10); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(10, $img->getWidth()); - $this->assertEquals(10, $img->getHeight()); - $this->assertColorAtPosition('#b4e000', $img, 0, 4); - $this->assertColorAtPosition('#445160', $img, 5, 5); - $this->assertTransparentPosition($img, 0, 5); - $this->assertTransparentPosition($img, 5, 4); - } - - public function testResizeCanvasTopLeft() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->resizeCanvas(10, 10, 'top-left'); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(10, $img->getWidth()); - $this->assertEquals(10, $img->getHeight()); - $this->assertColorAtPosition('#b4e000', $img, 0, 7); - $this->assertColorAtPosition('#445160', $img, 8, 8); - $this->assertTransparentPosition($img, 0, 8); - $this->assertTransparentPosition($img, 8, 7); - } - - public function testResizeCanvasTop() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->resizeCanvas(10, 10, 'top'); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(10, $img->getWidth()); - $this->assertEquals(10, $img->getHeight()); - $this->assertColorAtPosition('#b4e000', $img, 0, 7); - $this->assertColorAtPosition('#445160', $img, 5, 8); - $this->assertTransparentPosition($img, 0, 8); - $this->assertTransparentPosition($img, 5, 7); - } - - public function testResizeCanvasTopRight() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->resizeCanvas(10, 10, 'top-right'); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(10, $img->getWidth()); - $this->assertEquals(10, $img->getHeight()); - $this->assertColorAtPosition('#b4e000', $img, 0, 7); - $this->assertColorAtPosition('#445160', $img, 2, 8); - $this->assertTransparentPosition($img, 0, 8); - $this->assertTransparentPosition($img, 2, 7); - } - - public function testResizeCanvasLeft() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->resizeCanvas(10, 10, 'left'); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(10, $img->getWidth()); - $this->assertEquals(10, $img->getHeight()); - $this->assertColorAtPosition('#b4e000', $img, 0, 4); - $this->assertColorAtPosition('#445160', $img, 8, 5); - $this->assertTransparentPosition($img, 0, 5); - $this->assertTransparentPosition($img, 8, 4); - } - - public function testResizeCanvasRight() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->resizeCanvas(10, 10, 'right'); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(10, $img->getWidth()); - $this->assertEquals(10, $img->getHeight()); - $this->assertColorAtPosition('#b4e000', $img, 0, 4); - $this->assertColorAtPosition('#445160', $img, 2, 5); - $this->assertTransparentPosition($img, 0, 5); - $this->assertTransparentPosition($img, 2, 4); - } - - public function testResizeCanvasBottomLeft() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->resizeCanvas(10, 10, 'bottom-left'); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(10, $img->getWidth()); - $this->assertEquals(10, $img->getHeight()); - $this->assertColorAtPosition('#b4e000', $img, 0, 1); - $this->assertColorAtPosition('#445160', $img, 8, 2); - $this->assertTransparentPosition($img, 0, 2); - $this->assertTransparentPosition($img, 8, 1); - } - - public function testResizeCanvasBottomRight() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->resizeCanvas(10, 10, 'bottom-right'); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(10, $img->getWidth()); - $this->assertEquals(10, $img->getHeight()); - $this->assertColorAtPosition('#b4e000', $img, 0, 1); - $this->assertColorAtPosition('#445160', $img, 2, 2); - $this->assertTransparentPosition($img, 0, 2); - $this->assertTransparentPosition($img, 2, 1); - } - - public function testResizeCanvasBottom() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->resizeCanvas(10, 10, 'bottom'); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(10, $img->getWidth()); - $this->assertEquals(10, $img->getHeight()); - $this->assertColorAtPosition('#b4e000', $img, 0, 1); - $this->assertColorAtPosition('#445160', $img, 5, 2); - $this->assertTransparentPosition($img, 0, 2); - $this->assertTransparentPosition($img, 5, 1); - } - - public function testResizeCanvasRelativeWithBackground() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->resizeCanvas(4, 4, 'center', true, '#ff00ff'); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(20, $img->getWidth()); - $this->assertEquals(20, $img->getHeight()); - $this->assertColorAtPosition('#ff00ff', $img, 0, 0); - $this->assertColorAtPosition('#ff00ff', $img, 19, 19); - $this->assertColorAtPosition('#b4e000', $img, 2, 9); - $this->assertColorAtPosition('#445160', $img, 10, 10); - $this->assertTransparentPosition($img, 2, 10); - $this->assertTransparentPosition($img, 10, 9); - } - - public function testResizeCanvasJustWidth() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->resizeCanvas(10, null); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(10, $img->getWidth()); - $this->assertEquals(16, $img->getHeight()); - $this->assertColorAtPosition('#b4e000', $img, 0, 7); - $this->assertColorAtPosition('#445160', $img, 5, 8); - $this->assertTransparentPosition($img, 0, 8); - $this->assertTransparentPosition($img, 5, 7); - } - - public function testResizeCanvasJustHeight() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->resizeCanvas(null, 10); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(16, $img->getWidth()); - $this->assertEquals(10, $img->getHeight()); - $this->assertColorAtPosition('#b4e000', $img, 0, 4); - $this->assertColorAtPosition('#445160', $img, 8, 5); - $this->assertTransparentPosition($img, 0, 5); - $this->assertTransparentPosition($img, 8, 4); - } - - public function testResizeCanvasSmallerWidthLargerHeight() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->resizeCanvas(10, 20); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(10, $img->getWidth()); - $this->assertEquals(20, $img->getHeight()); - $this->assertColorAtPosition('#b4e000', $img, 0, 9); - $this->assertColorAtPosition('#445160', $img, 5, 10); - $this->assertTransparentPosition($img, 0, 10); - $this->assertTransparentPosition($img, 5, 9); - } - - public function testResizeCanvasLargerWidthSmallerHeight() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->resizeCanvas(20, 10); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(20, $img->getWidth()); - $this->assertEquals(10, $img->getHeight()); - $this->assertColorAtPosition('#b4e000', $img, 2, 4); - $this->assertColorAtPosition('#445160', $img, 10, 5); - $this->assertTransparentPosition($img, 0, 0); - $this->assertTransparentPosition($img, 2, 5); - $this->assertTransparentPosition($img, 10, 4); - } - - public function testResizeCanvasNegative() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->resizeCanvas(-4, -4); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(12, $img->getWidth()); - $this->assertEquals(12, $img->getHeight()); - $this->assertColorAtPosition('#b4e000', $img, 0, 5); - $this->assertColorAtPosition('#445160', $img, 6, 6); - $this->assertTransparentPosition($img, 0, 6); - $this->assertTransparentPosition($img, 6, 5); - } - - public function testResizeCanvasLargerHeightAutoWidth() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->resizeCanvas(null, 20, 'bottom-left', false, '#ff00ff'); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(16, $img->getWidth()); - $this->assertEquals(20, $img->getHeight()); - $this->assertColorAtPosition('#ff00ff', $img, 0, 0); - $this->assertColorAtPosition('#b4e000', $img, 0, 4); - $this->assertColorAtPosition('#b4e000', $img, 0, 11); - $this->assertColorAtPosition('#445160', $img, 8, 12); - $this->assertTransparentPosition($img, 0, 12); - $this->assertTransparentPosition($img, 8, 11); - } - - public function testResizeCanvasBorderNonRelative() - { - $img = $this->manager()->canvas(1, 1, 'ff0000'); - $img->resizeCanvas(17, 17, 'center', false, '333333'); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(17, $img->getWidth()); - $this->assertEquals(17, $img->getHeight()); - $this->assertColorAtPosition('#333333', $img, 0, 0); - $this->assertColorAtPosition('#333333', $img, 5, 5); - $this->assertColorAtPosition('#333333', $img, 7, 7); - $this->assertColorAtPosition('#ff0000', $img, 8, 8); - } - - public function testCropImage() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->crop(6, 6); // should be centered without pos. - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(6, $img->getWidth()); - $this->assertEquals(6, $img->getHeight()); - $this->assertColorAtPosition('#b4e000', $img, 0, 2); - $this->assertColorAtPosition('#445160', $img, 3, 3); - $this->assertTransparentPosition($img, 0, 3); - $this->assertTransparentPosition($img, 3, 2); - } - - public function testCropImageWithPosition() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->crop(4, 4, 7, 7); // should be centered without pos. - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(4, $img->getWidth()); - $this->assertEquals(4, $img->getHeight()); - $this->assertColorAtPosition('#b4e000', $img, 0, 0); - $this->assertColorAtPosition('#445160', $img, 1, 1); - $this->assertTransparentPosition($img, 0, 1); - $this->assertTransparentPosition($img, 1, 0); - } - - public function testFitImageSquare() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->fit(6); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(6, $img->getWidth()); - $this->assertEquals(6, $img->getHeight()); - $this->assertColorAtPosition('#b4e000', $img, 0, 2); - $this->assertColorAtPosition('#445060', $img, 3, 3); - $this->assertTransparentPosition($img, 0, 3); - $this->assertTransparentPosition($img, 3, 2); - } - - public function testFitImageRectangle() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->fit(12, 6); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(12, $img->getWidth()); - $this->assertEquals(6, $img->getHeight()); - $this->assertColorAtPosition('#b4e000', $img, 0, 2); - $this->assertColorAtPosition('#445160', $img, 6, 3); - $this->assertTransparentPosition($img, 0, 3); - $this->assertTransparentPosition($img, 6, 2); - } - - public function testFitImageWithConstraintUpsize() - { - $img = $this->manager()->make('tests/images/trim.png'); - $img->fit(300, 150, function ($constraint) {$constraint->upsize();}); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(50, $img->getWidth()); - $this->assertEquals(25, $img->getHeight()); - $this->assertColorAtPosition('#00aef0', $img, 0, 0); - $this->assertColorAtPosition('#afa94c', $img, 17, 0); - $this->assertColorAtPosition('#ffa601', $img, 24, 0); - } - - public function testFlipImageHorizontal() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->flip('h'); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(16, $img->getWidth()); - $this->assertEquals(16, $img->getHeight()); - $this->assertColorAtPosition('#b4e000', $img, 8, 7); - $this->assertColorAtPosition('#445160', $img, 0, 8); - $this->assertTransparentPosition($img, 0, 7); - $this->assertTransparentPosition($img, 8, 8); - } - - public function testFlipImageVertical() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->flip('v'); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(16, $img->getWidth()); - $this->assertEquals(16, $img->getHeight()); - $this->assertColorAtPosition('#b4e000', $img, 0, 8); - $this->assertColorAtPosition('#445160', $img, 8, 7); - $this->assertTransparentPosition($img, 0, 7); - $this->assertTransparentPosition($img, 8, 8); - } - - public function testRotateImage() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->rotate(90); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(16, $img->getWidth()); - $this->assertEquals(16, $img->getHeight()); - $this->assertColorAtPosition('#b4e000', $img, 0, 8); - $this->assertColorAtPosition('#445160', $img, 8, 7); - $this->assertTransparentPosition($img, 0, 7); - $this->assertTransparentPosition($img, 8, 8); - } - - public function testInsertImage() - { - $watermark = $this->manager()->canvas(16, 16, '#0000ff'); // create watermark - - // top-left anchor - $img = $this->manager()->canvas(32, 32, '#ff0000'); // create canvas - $img->insert($watermark, 'top-left', 0, 0); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals($img->getWidth(), 32); - $this->assertEquals($img->getHeight(), 32); - $this->assertEquals('#0000ff', $img->pickColor(0, 0, 'hex')); - $this->assertEquals('#ff0000', $img->pickColor(16, 16, 'hex')); - - // top-left anchor coordinates - $img = $this->manager()->canvas(32, 32, '#ff0000'); // create canvas - $img->insert($watermark, 'top-left', 10, 10); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals($img->getWidth(), 32); - $this->assertEquals($img->getHeight(), 32); - $this->assertEquals('#ff0000', $img->pickColor(9, 9, 'hex')); - $this->assertEquals('#0000ff', $img->pickColor(10, 10, 'hex')); - - // top anchor - $img = $this->manager()->canvas(32, 32, '#ff0000'); // create canvas - $img->insert($watermark, 'top', 0, 0); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals($img->getWidth(), 32); - $this->assertEquals($img->getHeight(), 32); - $this->assertEquals('#ff0000', $img->pickColor(0, 0, 'hex')); - $this->assertEquals('#0000ff', $img->pickColor(23, 15, 'hex')); - - // top anchor coordinates - $img = $this->manager()->canvas(32, 32, '#ff0000'); // create canvas - $img->insert($watermark, 'top', 10, 10); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals($img->getWidth(), 32); - $this->assertEquals($img->getHeight(), 32); - $this->assertEquals('#0000ff', $img->pickColor(18, 10, 'hex')); - $this->assertEquals('#ff0000', $img->pickColor(31, 26, 'hex')); - - // top-right anchor - $img = $this->manager()->canvas(32, 32, '#ff0000'); // create canvas - $img->insert($watermark, 'top-right', 0, 0); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals($img->getWidth(), 32); - $this->assertEquals($img->getHeight(), 32); - $this->assertEquals('#ff0000', $img->pickColor(15, 0, 'hex')); - $this->assertEquals('#0000ff', $img->pickColor(31, 0, 'hex')); - - // top-right anchor coordinates - $img = $this->manager()->canvas(32, 32, '#ff0000'); // create canvas - $img->insert($watermark, 'top-right', 10, 10); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals($img->getWidth(), 32); - $this->assertEquals($img->getHeight(), 32); - $this->assertEquals('#ff0000', $img->pickColor(6, 9, 'hex')); - $this->assertEquals('#0000ff', $img->pickColor(21, 25, 'hex')); - - // left anchor - $img = $this->manager()->canvas(32, 32, '#ff0000'); // create canvas - $img->insert($watermark, 'left', 0, 0); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals($img->getWidth(), 32); - $this->assertEquals($img->getHeight(), 32); - $this->assertEquals('#0000ff', $img->pickColor(15, 23, 'hex')); - $this->assertEquals('#ff0000', $img->pickColor(0, 7, 'hex')); - - // left anchor coordinates - $img = $this->manager()->canvas(32, 32, '#ff0000'); // create canvas - $img->insert($watermark, 'left', 10, 10); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals($img->getWidth(), 32); - $this->assertEquals($img->getHeight(), 32); - $this->assertEquals('#ff0000', $img->pickColor(8, 23, 'hex')); - $this->assertEquals('#ff0000', $img->pickColor(10, 7, 'hex')); - $this->assertEquals('#0000ff', $img->pickColor(25, 23, 'hex')); - $this->assertEquals('#0000ff', $img->pickColor(25, 8, 'hex')); - - // right anchor - $img = $this->manager()->canvas(32, 32, '#ff0000'); // create canvas - $img->insert($watermark, 'right', 0, 0); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals($img->getWidth(), 32); - $this->assertEquals($img->getHeight(), 32); - $this->assertEquals('#0000ff', $img->pickColor(31, 23, 'hex')); - $this->assertEquals('#ff0000', $img->pickColor(15, 15, 'hex')); - - // right anchor coordinates - $img = $this->manager()->canvas(32, 32, '#ff0000'); // create canvas - $img->insert($watermark, 'right', 10, 10); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals($img->getWidth(), 32); - $this->assertEquals($img->getHeight(), 32); - $this->assertEquals('#ff0000', $img->pickColor(5, 8, 'hex')); - $this->assertEquals('#ff0000', $img->pickColor(22, 23, 'hex')); - $this->assertEquals('#ff0000', $img->pickColor(21, 7, 'hex')); - $this->assertEquals('#0000ff', $img->pickColor(6, 8, 'hex')); - $this->assertEquals('#0000ff', $img->pickColor(21, 23, 'hex')); - $this->assertEquals('#0000ff', $img->pickColor(6, 23, 'hex')); - - // bottom-left anchor - $img = $this->manager()->canvas(32, 32, '#ff0000'); // create canvas - $img->insert($watermark, 'bottom-left', 0, 0); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals($img->getWidth(), 32); - $this->assertEquals($img->getHeight(), 32); - $this->assertEquals('#0000ff', $img->pickColor(15, 31, 'hex')); - $this->assertEquals('#ff0000', $img->pickColor(0, 15, 'hex')); - - // bottom-left anchor coordinates - $img = $this->manager()->canvas(32, 32, '#ff0000'); // create canvas - $img->insert($watermark, 'bottom-left', 10, 10); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals($img->getWidth(), 32); - $this->assertEquals($img->getHeight(), 32); - $this->assertEquals('#0000ff', $img->pickColor(10, 21, 'hex')); - $this->assertEquals('#ff0000', $img->pickColor(9, 20, 'hex')); - - // bottom anchor - $img = $this->manager()->canvas(32, 32, '#ff0000'); // create canvas - $img->insert($watermark, 'bottom', 0, 0); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals($img->getWidth(), 32); - $this->assertEquals($img->getHeight(), 32); - $this->assertEquals('#0000ff', $img->pickColor(8, 16, 'hex')); - $this->assertEquals('#ff0000', $img->pickColor(8, 15, 'hex')); - - // bottom anchor coordinates - $img = $this->manager()->canvas(32, 32, '#ff0000'); // create canvas - $img->insert($watermark, 'bottom', 10, 10); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals($img->getWidth(), 32); - $this->assertEquals($img->getHeight(), 32); - $this->assertEquals('#ff0000', $img->pickColor(5, 8, 'hex')); - $this->assertEquals('#ff0000', $img->pickColor(23, 22, 'hex')); - $this->assertEquals('#ff0000', $img->pickColor(24, 21, 'hex')); - $this->assertEquals('#ff0000', $img->pickColor(7, 6, 'hex')); - $this->assertEquals('#0000ff', $img->pickColor(8, 6, 'hex')); - $this->assertEquals('#0000ff', $img->pickColor(23, 21, 'hex')); - $this->assertEquals('#0000ff', $img->pickColor(23, 6, 'hex')); - - // bottom-right anchor - $img = $this->manager()->canvas(32, 32, '#ff0000'); // create canvas - $img->insert($watermark, 'bottom-right', 0, 0); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals($img->getWidth(), 32); - $this->assertEquals($img->getHeight(), 32); - $this->assertEquals('#0000ff', $img->pickColor(16, 16, 'hex')); - $this->assertEquals('#ff0000', $img->pickColor(15, 16, 'hex')); - - // bottom-right anchor coordinates - $img = $this->manager()->canvas(32, 32, '#ff0000'); // create canvas - $img->insert($watermark, 'bottom-right', 10, 10); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals($img->getWidth(), 32); - $this->assertEquals($img->getHeight(), 32); - $this->assertEquals('#0000ff', $img->pickColor(21, 21, 'hex')); - $this->assertEquals('#ff0000', $img->pickColor(22, 22, 'hex')); - - // center anchor - $img = $this->manager()->canvas(32, 32, '#ff0000'); // create canvas - $img->insert($watermark, 'center', 0, 0); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals($img->getWidth(), 32); - $this->assertEquals($img->getHeight(), 32); - $this->assertEquals('#0000ff', $img->pickColor(23, 23, 'hex')); - $this->assertEquals('#ff0000', $img->pickColor(8, 7, 'hex')); - - // center anchor coordinates / coordinates will be ignored for center - $img = $this->manager()->canvas(32, 32, '#ff0000'); // create canvas - $img->insert($watermark, 'center', 10, 10); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals($img->getWidth(), 32); - $this->assertEquals($img->getHeight(), 32); - $this->assertEquals('#0000ff', $img->pickColor(23, 23, 'hex')); - $this->assertEquals('#ff0000', $img->pickColor(8, 7, 'hex')); - } - - public function testInsertWithAlphaChannel() - { - $img = $this->manager()->canvas(50, 50, 'ff0000'); - $img->insert('tests/images/circle.png'); - $this->assertColorAtPosition('#ff0000', $img, 0, 0); - $this->assertColorAtPosition('#320000', $img, 30, 30); - } - - public function testInsertAfterResize() - { - $img = $this->manager()->make('tests/images/trim.png'); - $img->resize(16, 16)->insert('tests/images/tile.png'); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(16, $img->getWidth()); - $this->assertEquals(16, $img->getHeight()); - $this->assertColorAtPosition('#b4e000', $img, 0, 7); - $this->assertColorAtPosition('#00aef0', $img, 0, 8); - $this->assertColorAtPosition('#445160', $img, 8, 8); - $this->assertColorAtPosition('#ffa601', $img, 8, 7); - } - - public function testInsertResource() - { - $resource = imagecreatefrompng('tests/images/tile.png'); - $img = $this->manager()->make('tests/images/trim.png'); - $img->insert($resource); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertColorAtPosition('#b4e000', $img, 0, 7); - $this->assertColorAtPosition('#00aef0', $img, 0, 8); - $this->assertColorAtPosition('#445160', $img, 8, 8); - $this->assertColorAtPosition('#00aef0', $img, 8, 7); - $this->assertColorAtPosition('#ffa601', $img, 24, 24); - } - - public function testInsertBinary() - { - $data = file_get_contents('tests/images/tile.png'); - $img = $this->manager()->make('tests/images/trim.png'); - $img->insert($data); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertColorAtPosition('#b4e000', $img, 0, 7); - $this->assertColorAtPosition('#00aef0', $img, 0, 8); - $this->assertColorAtPosition('#445160', $img, 8, 8); - $this->assertColorAtPosition('#00aef0', $img, 8, 7); - $this->assertColorAtPosition('#ffa601', $img, 24, 24); - } - - public function testInsertInterventionImage() - { - $obj = $this->manager()->make('tests/images/tile.png'); - $img = $this->manager()->make('tests/images/trim.png'); - $img->insert($obj); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertColorAtPosition('#b4e000', $img, 0, 7); - $this->assertColorAtPosition('#00aef0', $img, 0, 8); - $this->assertColorAtPosition('#445160', $img, 8, 8); - $this->assertColorAtPosition('#00aef0', $img, 8, 7); - $this->assertColorAtPosition('#ffa601', $img, 24, 24); - } - - public function testOpacity() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->opacity(50); - $checkColor = $img->pickColor(7, 7, 'array'); - $this->assertEquals($checkColor[0], 180); - $this->assertEquals($checkColor[1], 224); - $this->assertEquals($checkColor[2], 0); - $this->assertEquals($checkColor[3], 0.5); - $checkColor = $img->pickColor(8, 8, 'array'); - $this->assertEquals($checkColor[0], 68); - $this->assertEquals($checkColor[1], 81); - $this->assertEquals($checkColor[2], 96); - $this->assertEquals($checkColor[3], 0.5); - $this->assertTransparentPosition($img, 0, 11); - } - - public function testMaskImage() - { - $img = $this->manager()->make('tests/images/trim.png'); - $img->mask('tests/images/gradient.png'); - $this->assertTransparentPosition($img, 0, 0); - $this->assertTransparentPosition($img, 23, 23); - $checkColor = $img->pickColor(23, 24, 'array'); - $this->assertEquals($checkColor[0], 255); - $this->assertEquals($checkColor[1], 166); - $this->assertEquals($checkColor[2], 1); - $this->assertEquals($checkColor[3], 0.97); - $checkColor = $img->pickColor(39, 25, 'array'); - $this->assertEquals($checkColor[0], 0); - $this->assertEquals($checkColor[1], 174); - $this->assertEquals($checkColor[2], 240); - $this->assertEquals($checkColor[3], 0.32); - } - - public function testMaskImageWithAlpha() - { - $img = $this->manager()->make('tests/images/trim.png'); - $img->mask('tests/images/star.png', true); - $this->assertTransparentPosition($img, 0, 0); - $this->assertTransparentPosition($img, 16, 16); - $checkColor = $img->pickColor(18, 18, 'array'); - $this->assertEquals($checkColor[0], 255); - $this->assertEquals($checkColor[1], 166); - $this->assertEquals($checkColor[2], 1); - $this->assertEquals($checkColor[3], 0.65); - $checkColor = $img->pickColor(24, 10, 'array'); - $this->assertEquals($checkColor[0], 0); - $this->assertEquals($checkColor[1], 174); - $this->assertEquals($checkColor[2], 240); - $this->assertEquals($checkColor[3], 0.80); - } - - public function testPixelateImage() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->pixelate(20); - $this->assertInstanceOf('Intervention\Image\Image', $img); - } - - public function testGreyscaleImage() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->greyscale(); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertTransparentPosition($img, 8, 0); - $this->assertColorAtPosition('#b9b9b9', $img, 0, 0); - } - - public function testInvertImage() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->invert(); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertTransparentPosition($img, 8, 0); - $this->assertColorAtPosition('#4b1fff', $img, 0, 0); - } - - public function testBlurImage() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->blur(1); - $this->assertInstanceOf('Intervention\Image\Image', $img); - } - - public function testFillImageWithColor() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->fill('b53717'); - $this->assertColorAtPosition('#b53717', $img, 0, 0); - $this->assertColorAtPosition('#b53717', $img, 15, 15); - } - - public function testFillImageWithColorAtPosition() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->fill('b53717', 0, 0); - $this->assertTransparentPosition($img, 0, 8); - $this->assertColorAtPosition('#b53717', $img, 0, 0); - $this->assertColorAtPosition('#445160', $img, 15, 15); - } - - public function testFillImageWithResource() - { - $resource = imagecreatefrompng('tests/images/tile.png'); - $img = $this->manager()->make('tests/images/trim.png'); - $img->fill($resource, 0, 0); - $this->assertColorAtPosition('#b4e000', $img, 0, 0); - $this->assertColorAtPosition('#445160', $img, 8, 8); - $this->assertColorAtPosition('#00aef0', $img, 8, 7); - $this->assertColorAtPosition('#ffa601', $img, 20, 20); - } - - public function testFillImageWithBinary() - { - $data = file_get_contents('tests/images/tile.png'); - $img = $this->manager()->make('tests/images/trim.png'); - $img->fill($data, 0, 0); - $this->assertColorAtPosition('#b4e000', $img, 0, 0); - $this->assertColorAtPosition('#445160', $img, 8, 8); - $this->assertColorAtPosition('#00aef0', $img, 8, 7); - $this->assertColorAtPosition('#ffa601', $img, 20, 20); - } - - public function testFillImageWithInterventionImage() - { - $obj = $this->manager()->make('tests/images/tile.png'); - $img = $this->manager()->make('tests/images/trim.png'); - $img->fill($obj, 0, 0); - $this->assertColorAtPosition('#b4e000', $img, 0, 0); - $this->assertColorAtPosition('#445160', $img, 8, 8); - $this->assertColorAtPosition('#00aef0', $img, 8, 7); - $this->assertColorAtPosition('#ffa601', $img, 20, 20); - } - - public function testPixelImage() - { - $img = $this->manager()->make('tests/images/tile.png'); - $coords = [[5, 5], [12, 12]]; - $img = $img->pixel('fdf5e4', $coords[0][0], $coords[0][1]); - $img = $img->pixel([255, 255, 255], $coords[1][0], $coords[1][1]); - $this->assertEquals('#fdf5e4', $img->pickColor($coords[0][0], $coords[0][1], 'hex')); - $this->assertEquals('#ffffff', $img->pickColor($coords[1][0], $coords[1][1], 'hex')); - } - - public function testTextImage() - { - $img = $this->manager()->canvas(16, 16, 'ffffff'); - $img = $img->text('0', 3, 11); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertEquals('a9e2b15452b2a4637b65625188d206f6', $img->checksum()); - - - $img = $this->manager()->canvas(16, 16, 'ffffff'); - $img = $img->text('0', 8, 2, function($font) { - $font->align('center'); - $font->valign('top'); - $font->color('000000'); - }); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertEquals('649f3f529d3931c56601155fd2680959', $img->checksum()); - - $img = $this->manager()->canvas(16, 16, 'ffffff'); - $img = $img->text('0', 8, 8, function($font) { - $font->align('right'); - $font->valign('middle'); - $font->file(2); - $font->color('000000'); - }); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertEquals('c0dda67589c46a90d78a97b891a811ee', $img->checksum()); - } - - public function testRectangleImage() - { - $img = $this->manager()->canvas(16, 16, 'ffffff'); - $img->rectangle(5, 5, 11, 11, function ($draw) { $draw->background('#ff0000'); $draw->border(1, '#0000ff'); }); - $this->assertEquals('e95487dcc29daf371a0e9190bff8dbfe', $img->checksum()); - } - - public function testLineImage() - { - $img = $this->manager()->canvas(16, 16, 'ffffff'); - $img->line(0, 0, 15, 15, function ($draw) { $draw->color('#ff0000'); }); - $this->assertEquals('a6237d34f6e95f30d2fc91a46bd058e6', $img->checksum()); - } - - public function testEllipseImage() - { - $img = $this->manager()->canvas(16, 16, 'ffffff'); - $img->ellipse(12, 8, 8, 8, function ($draw) { $draw->background('#ff0000'); $draw->border(1, '#0000ff'); }); - $this->assertEquals('080d9dd92ebe22f976c3c703cba33510', $img->checksum()); - } - - public function testCircleImage() - { - $img = $this->manager()->canvas(16, 16, 'ffffff'); - $img->circle(12, 8, 8, function ($draw) { $draw->background('#ff0000'); $draw->border(1, '#0000ff'); }); - $this->assertEquals('c3bff06c20244ba14e898e39ea0efd76', $img->checksum()); - } - - public function testPolygonImage() - { - $img = $this->manager()->canvas(16, 16, 'ffffff'); - $points = [3, 3, 11, 11, 7, 13]; - $img->polygon($points, function ($draw) { $draw->background('#ff0000'); $draw->border(1, '#0000ff'); }); - $this->assertEquals('e534ff90c8026f9317b99071fda01ed4', $img->checksum()); - } - - public function testResetImage() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->backup(); - $img->resize(30, 20); - $img->reset(); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(16, $img->getWidth()); - $this->assertEquals(16, $img->getHeight()); - } - - public function testResetEmptyImage() - { - $img = $this->manager()->canvas(16, 16, '#0000ff'); - $img->backup(); - $img->resize(30, 20); - $img->fill('#ff0000'); - $img->reset(); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(16, $img->getWidth()); - $this->assertEquals(16, $img->getHeight()); - $this->assertColorAtPosition('#0000ff', $img, 0, 0); - } - - public function testResetKeepTransparency() - { - $img = $this->manager()->make('tests/images/circle.png'); - $img->backup(); - $img->reset(); - $this->assertTransparentPosition($img, 0, 0); - } - - public function testResetToNamed() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->backup('original'); - $img->resize(30, 20); - $img->backup('30x20'); - - // reset to original - $img->reset('original'); - $this->assertEquals(16, $img->getWidth()); - $this->assertEquals(16, $img->getHeight()); - - // reset to 30x20 - // $img->reset('30x20'); - // $this->assertEquals(30, $img->getWidth()); - // $this->assertEquals(20, $img->getHeight()); - - // reset to original again - $img->reset('original'); - $this->assertEquals(16, $img->getWidth()); - $this->assertEquals(16, $img->getHeight()); - } - - public function testLimitColors() - { - $img = $this->manager()->make('tests/images/trim.png'); - $img->limitColors(4); - $this->assertLessThanOrEqual(5, imagecolorstotal($img->getCore())); - } - - public function testLimitColorsKeepTransparency() - { - $img = $this->manager()->make('tests/images/star.png'); - $img->limitColors(16); - $this->assertLessThanOrEqual(17, imagecolorstotal($img->getCore())); - $this->assertTransparentPosition($img, 0, 0); - $this->assertColorAtPosition('#0c02b4', $img, 6, 12); - $this->assertColorAtPosition('#fcbe04', $img, 22, 24); - } - - public function testLimitColorsKeepTransparencyWithMatte() - { - $img = $this->manager()->make('tests/images/star.png'); - $img->limitColors(64, '#00ff00'); - $this->assertLessThanOrEqual(65, imagecolorstotal($img->getCore())); - $this->assertTransparentPosition($img, 0, 0); - $this->assertColorAtPosition('#04f204', $img, 12, 10); - $this->assertColorAtPosition('#e40214', $img, 16, 21); - } - - public function testLimitColorsNullWithMatte() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->limitColors(null, '#ff00ff'); - $this->assertColorAtPosition('#b4e000', $img, 0, 0); - $this->assertColorAtPosition('#445160', $img, 8, 8); - $this->assertColorAtPosition('#ff00ff', $img, 0, 8); - $this->assertColorAtPosition('#ff00ff', $img, 15, 0); - } - - public function testPickColorFromTrueColor() - { - $img = $this->manager()->make('tests/images/star.png'); - $c = $img->pickColor(0, 0); - $this->assertEquals(255, $c[0]); - $this->assertEquals(255, $c[1]); - $this->assertEquals(255, $c[2]); - $this->assertEquals(0, $c[3]); - - $c = $img->pickColor(11, 11); - $this->assertEquals(34, $c[0]); - $this->assertEquals(0, $c[1]); - $this->assertEquals(160, $c[2]); - $this->assertEquals(0.46, $c[3]); - - $c = $img->pickColor(16, 16); - $this->assertEquals(231, $c[0]); - $this->assertEquals(0, $c[1]); - $this->assertEquals(18, $c[2]); - $this->assertEquals(1, $c[3]); - } - - public function testPickColorFromIndexed() - { - $img = $this->manager()->make('tests/images/tile.png'); - $c = $img->pickColor(0, 0); - $this->assertEquals(180, $c[0]); - $this->assertEquals(224, $c[1]); - $this->assertEquals(0, $c[2]); - $this->assertEquals(1, $c[3]); - - $c = $img->pickColor(8, 8); - $this->assertEquals(68, $c[0]); - $this->assertEquals(81, $c[1]); - $this->assertEquals(96, $c[2]); - $this->assertEquals(1, $c[3]); - - $c = $img->pickColor(0, 15); - $this->assertEquals(255, $c[0]); - $this->assertEquals(255, $c[1]); - $this->assertEquals(255, $c[2]); - $this->assertEquals(0, $c[3]); - } - - public function testPickColorFromPalette() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->limitColors(200); - - $c = $img->pickColor(0, 0); - $this->assertEquals(180, $c[0]); - $this->assertEquals(226, $c[1]); - $this->assertEquals(4, $c[2]); - $this->assertEquals(1, $c[3]); - - $c = $img->pickColor(8, 8); - $this->assertEquals(68, $c[0]); - $this->assertEquals(82, $c[1]); - $this->assertEquals(100, $c[2]); - $this->assertEquals(1, $c[3]); - - $c = $img->pickColor(0, 15); - $this->assertEquals(255, $c[0]); - $this->assertEquals(255, $c[1]); - $this->assertEquals(255, $c[2]); - $this->assertEquals(0, $c[3]); - } - - public function testInterlaceImage() - { - $img = $this->manager()->make('tests/images/trim.png'); - $img->interlace(); - $img->encode('png'); - $this->assertTrue((ord($img->encoded[28]) != '0')); - $img->interlace(false); - $img->encode('png'); - $this->assertFalse((ord($img->encoded[28]) != '0')); - } - - public function testGammaImage() - { - $img = $this->manager()->make('tests/images/trim.png'); - $img->gamma(1.6); - $this->assertColorAtPosition('#00c9f6', $img, 0, 0); - $this->assertColorAtPosition('#ffc308', $img, 24, 24); - } - - public function testBrightnessImage() - { - $img = $this->manager()->make('tests/images/trim.png'); - $img->brightness(35); - $this->assertColorAtPosition('#59ffff', $img, 0, 0); - $this->assertColorAtPosition('#ffff5a', $img, 24, 24); - } - - public function testContrastImage() - { - $img = $this->manager()->make('tests/images/trim.png'); - $img->contrast(35); - $this->assertColorAtPosition('#00d4ff', $img, 0, 0); - $this->assertColorAtPosition('#ffc500', $img, 24, 24); - } - - public function testColorizeImage() - { - $img = $this->manager()->make('tests/images/trim.png'); - $img->colorize(40, 25, -50); - $this->assertColorAtPosition('#66ee70', $img, 0, 0); - $this->assertColorAtPosition('#ffe600', $img, 24, 24); - } - - public function testTrimGradient() - { - $canvas = $this->manager()->make('tests/images/gradient.png'); - - $img = clone $canvas; - $img->trim(); - $this->assertEquals($img->getWidth(), 46); - $this->assertEquals($img->getHeight(), 46); - - $img = clone $canvas; - $img->trim(null, null, 10); - $this->assertEquals($img->getWidth(), 38); - $this->assertEquals($img->getHeight(), 38); - - $img = clone $canvas; - $img->trim(null, null, 20); - $this->assertEquals($img->getWidth(), 34); - $this->assertEquals($img->getHeight(), 34); - - $img = clone $canvas; - $img->trim(null, null, 30); - $this->assertEquals($img->getWidth(), 30); - $this->assertEquals($img->getHeight(), 30); - - $img = clone $canvas; - $img->trim(null, null, 40); - $this->assertEquals($img->getWidth(), 26); - $this->assertEquals($img->getHeight(), 26); - - $img = clone $canvas; - $img->trim(null, null, 50); - $this->assertEquals($img->getWidth(), 22); - $this->assertEquals($img->getHeight(), 22); - - $img = clone $canvas; - $img->trim(null, null, 60); - $this->assertEquals($img->getWidth(), 20); - $this->assertEquals($img->getHeight(), 20); - - $img = clone $canvas; - $img->trim(null, null, 70); - $this->assertEquals($img->getWidth(), 16); - $this->assertEquals($img->getHeight(), 16); - - $img = clone $canvas; - $img->trim(null, null, 80); - $this->assertEquals($img->getWidth(), 12); - $this->assertEquals($img->getHeight(), 12); - - $img = clone $canvas; - $img->trim(null, null, 90); - $this->assertEquals($img->getWidth(), 8); - $this->assertEquals($img->getHeight(), 8); - } - - public function testTrimOnlyLeftAndRight() - { - $img = $this->manager()->make('tests/images/gradient.png'); - $img->trim(null, ['left', 'right'], 60); - $this->assertEquals($img->getWidth(), 20); - $this->assertEquals($img->getHeight(), 50); - } - - public function testTrimOnlyTopAndBottom() - { - $img = $this->manager()->make('tests/images/gradient.png'); - $img->trim(null, ['top', 'bottom'], 60); - $this->assertEquals($img->getWidth(), 50); - $this->assertEquals($img->getHeight(), 20); - } - - public function testTrimOnlyTop() - { - $img = $this->manager()->make('tests/images/gradient.png'); - $img->trim(null, 'top', 60); - $this->assertEquals($img->getWidth(), 50); - $this->assertEquals($img->getHeight(), 35); - } - - public function testTrimOnlyBottom() - { - $img = $this->manager()->make('tests/images/gradient.png'); - $img->trim(null, 'top', 60); - $this->assertEquals($img->getWidth(), 50); - $this->assertEquals($img->getHeight(), 35); - } - - public function testTrimWithFeather() - { - $canvas = $this->manager()->make('tests/images/trim.png'); - - $img = clone $canvas; - $feather = 5; - $img->trim(null, null, null, $feather); - $this->assertEquals($img->getWidth(), 28 + $feather * 2); - $this->assertEquals($img->getHeight(), 28 + $feather * 2); - - $img = clone $canvas; - $feather = 10; - $img->trim(null, null, null, $feather); - $this->assertEquals($img->getWidth(), 28 + $feather * 2); - $this->assertEquals($img->getHeight(), 28 + $feather * 2); - - $img = clone $canvas; - $feather = 20; // must respect original dimensions of image - $img->trim(null, null, null, $feather); - $this->assertEquals($img->getWidth(), 50); - $this->assertEquals($img->getHeight(), 50); - - $img = clone $canvas; - $feather = -5; - $img->trim(null, null, null, $feather); - $this->assertEquals($img->getWidth(), 28 + $feather * 2); - $this->assertEquals($img->getHeight(), 28 + $feather * 2); - - $img = clone $canvas; - $feather = -10; - $img->trim(null, null, null, $feather); - $this->assertEquals($img->getWidth(), 28 + $feather * 2); - $this->assertEquals($img->getHeight(), 28 + $feather * 2); - - // trim only left and right with feather - $img = clone $canvas; - $feather = 10; - $img->trim(null, ['left', 'right'], null, $feather); - $this->assertEquals($img->getWidth(), 28 + $feather * 2); - $this->assertEquals($img->getHeight(), 50); - - // trim only top and bottom with feather - $img = clone $canvas; - $feather = 10; - $img->trim(null, ['top', 'bottom'], null, $feather); - $this->assertEquals($img->getWidth(), 50); - $this->assertEquals($img->getHeight(), 28 + $feather * 2); - - // trim with tolerance and feather - $canvas = $this->manager()->make('tests/images/gradient.png'); - - $img = clone $canvas; - $feather = 2; - $img->trim(null, null, 10, $feather); - $this->assertEquals($img->getWidth(), 38 + $feather * 2); - $this->assertEquals($img->getHeight(), 38 + $feather * 2); - - $img = clone $canvas; - $feather = 5; - $img->trim(null, null, 10, $feather); - $this->assertEquals($img->getWidth(), 38 + $feather * 2); - $this->assertEquals($img->getHeight(), 38 + $feather * 2); - - $img = clone $canvas; - $feather = 10; // should respect original dimensions - $img->trim(null, null, 20, $feather); - $this->assertEquals($img->getWidth(), 50); - $this->assertEquals($img->getHeight(), 50); - } - - public function testEncodeDefault() - { - $img = $this->manager()->make('tests/images/trim.png'); - $img->encode(); - $this->assertInternalType('resource', imagecreatefromstring($img->encoded)); - } - - public function testEncodeJpeg() - { - $img = $this->manager()->make('tests/images/trim.png'); - $img->encode('jpg'); - $this->assertInternalType('resource', imagecreatefromstring($img->encoded)); - } - - public function testEncodeGif() - { - $img = $this->manager()->make('tests/images/trim.png'); - $img->encode('gif'); - $this->assertInternalType('resource', imagecreatefromstring($img->encoded)); - } - - public function testEncodeWebp() - { - if (function_exists('imagewebp')) { - $img = $this->manager()->make('tests/images/trim.png'); - $data = (string) $img->encode('webp'); - $this->assertEquals('image/webp; charset=binary', $this->getMime($data)); - } - } - - public function testEncodeDataUrl() - { - $img = $this->manager()->make('tests/images/trim.png'); - $img->encode('data-url'); - $this->assertEquals('data:image/png;base64', substr($img->encoded, 0, 21)); - } - - public function testExifReadAll() - { - $img = $this->manager()->make('tests/images/exif.jpg'); - $data = $img->exif(); - $this->assertInternalType('array', $data); - $this->assertEquals(19, count($data)); - } - - public function testExifReadKey() - { - $img = $this->manager()->make('tests/images/exif.jpg'); - $data = $img->exif('Artist'); - $this->assertInternalType('string', $data); - $this->assertEquals('Oliver Vogel', $data); - } - - public function testExifReadNotExistingKey() - { - $img = $this->manager()->make('tests/images/exif.jpg'); - $data = $img->exif('xxx'); - $this->assertEquals(null, $data); - } - - public function testSaveImage() - { - $save_as = 'tests/tmp/foo.jpg'; - $img = $this->manager()->make('tests/images/trim.png'); - $img->save($save_as, 80); - $this->assertFileExists($save_as); - $this->assertEquals($img->dirname, 'tests/tmp'); - $this->assertEquals($img->basename, 'foo.jpg'); - $this->assertEquals($img->extension, 'jpg'); - $this->assertEquals($img->filename, 'foo'); - $this->assertEquals($img->mime, 'image/jpeg'); - @unlink($save_as); - - $save_as = 'tests/tmp/foo.png'; - $img = $this->manager()->make('tests/images/trim.png'); - $img->save($save_as); - $this->assertEquals($img->dirname, 'tests/tmp'); - $this->assertEquals($img->basename, 'foo.png'); - $this->assertEquals($img->extension, 'png'); - $this->assertEquals($img->filename, 'foo'); - $this->assertEquals($img->mime, 'image/png'); - $this->assertFileExists($save_as); - @unlink($save_as); - - $save_as = 'tests/tmp/foo.jpg'; - $img = $this->manager()->make('tests/images/trim.png'); - $img->save($save_as, 0); - $this->assertEquals($img->dirname, 'tests/tmp'); - $this->assertEquals($img->basename, 'foo.jpg'); - $this->assertEquals($img->extension, 'jpg'); - $this->assertEquals($img->filename, 'foo'); - $this->assertEquals($img->mime, 'image/jpeg'); - $this->assertFileExists($save_as); - @unlink($save_as); - } - - public function testSaveImageWithoutParameter() - { - $path = 'tests/tmp/bar.png'; - - // create temp. test image (red) - $img = $this->manager()->canvas(16, 16, '#ff0000'); - $img->save($path); - $img->destroy(); - - // open test image again - $img = $this->manager()->make($path); - $this->assertColorAtPosition('#ff0000', $img, 0, 0); - - // fill with green and save wthout paramater - $img->fill('#00ff00'); - $img->save(); - $img->destroy(); - - // re-open test image (should be green) - $img = $this->manager()->make($path); - $this->assertColorAtPosition('#00ff00', $img, 0, 0); - $img->destroy(); - - @unlink($path); - } - - public function testDestroy() - { - $img = $this->manager()->make('tests/images/trim.png'); - $img->backup(); - $img->destroy(); - // destroy should affect core - $this->assertEquals(get_resource_type($img->getCore()), 'Unknown'); - // destroy should affect backup - $this->assertEquals(get_resource_type($img->getBackup()), 'Unknown'); - } - - public function testStringConversion() - { - $img = $this->manager()->make('tests/images/trim.png'); - $value = strval($img); - $this->assertInternalType('string', $value); - } - - public function testFilter() - { - $img = $this->manager()->make('tests/images/trim.png'); - $img->filter(new \Intervention\Image\Filters\DemoFilter(10)); - $this->assertColorAtPosition('#818181', $img, 0, 0); - $this->assertColorAtPosition('#939393', $img, 18, 18); - $this->assertColorAtPosition('#939393', $img, 18, 18); - $this->assertColorAtPosition('#adadad', $img, 25, 25); - $this->assertColorAtPosition('#939393', $img, 35, 35); - } - - public function testCloneImageObject() - { - $img = $this->manager()->make('tests/images/trim.png'); - $cln = clone $img; - - // destroy original - $img->destroy(); - unset($img); - - // clone should be still intact - $this->assertInstanceOf('Intervention\Image\Image', $cln); - $this->assertInternalType('resource', $cln->getCore()); - } - - public function testGifConversionKeepsTransparency() - { - $save_as = 'tests/tmp/foo.gif'; - - // create gif image from transparent png - $img = $this->manager()->make('tests/images/star.png'); - $img->save($save_as); - - // new gif image should be transparent - $img = $this->manager()->make($save_as); - $this->assertTransparentPosition($img, 0, 0); - @unlink($save_as); - } - - private function assertColorAtPosition($color, $img, $x, $y) - { - $pick = $img->pickColor($x, $y, 'hex'); - $this->assertEquals($color, $pick); - $this->assertInstanceOf('Intervention\Image\Image', $img); - } - - private function assertTransparentPosition($img, $x, $y, $transparent = 0) - { - // background should be transparent - $color = $img->pickColor($x, $y, 'array'); - $this->assertEquals($transparent, $color[3]); // alpha channel - } - - private function manager() - { - return new \Intervention\Image\ImageManager([ - 'driver' => 'gd' - ]); - } - - private function getMime($data) - { - $finfo = new finfo(FILEINFO_MIME); - return $finfo->buffer($data); - } -} diff --git a/tests/Geometry/PixelTest.php b/tests/Geometry/PixelTest.php new file mode 100644 index 00000000..f034abdf --- /dev/null +++ b/tests/Geometry/PixelTest.php @@ -0,0 +1,23 @@ +setBackgroundColor($color); + $this->assertInstanceOf(ColorInterface::class, $pixel->backgroundColor()); + $this->assertInstanceOf(Pixel::class, $result); + } +} diff --git a/tests/Geometry/PointTest.php b/tests/Geometry/PointTest.php new file mode 100644 index 00000000..7ce5b871 --- /dev/null +++ b/tests/Geometry/PointTest.php @@ -0,0 +1,90 @@ +assertInstanceOf(Point::class, $point); + $this->assertEquals(0, $point->x()); + $this->assertEquals(0, $point->y()); + } + + public function testConstructorWithParameters() + { + $point = new Point(40, 50); + $this->assertInstanceOf(Point::class, $point); + $this->assertEquals(40, $point->x()); + $this->assertEquals(50, $point->y()); + } + + public function testGetSetX() + { + $point = new Point(0, 0); + $point->setX(100); + $this->assertEquals(100, $point->x()); + $this->assertEquals(0, $point->y()); + } + + public function testGetSetY() + { + $point = new Point(0, 0); + $point->setY(100); + $this->assertEquals(0, $point->x()); + $this->assertEquals(100, $point->y()); + } + + public function testmoveX() + { + $point = new Point(50, 50); + $point->moveX(100); + $this->assertEquals(150, $point->x()); + $this->assertEquals(50, $point->y()); + } + + public function testmoveY() + { + $point = new Point(50, 50); + $point->moveY(100); + $this->assertEquals(50, $point->x()); + $this->assertEquals(150, $point->y()); + } + + public function testSetPosition() + { + $point = new Point(0, 0); + $point->setPosition(100, 200); + $this->assertEquals(100, $point->x()); + $this->assertEquals(200, $point->y()); + } + + public function testRotate() + { + $point = new Point(30, 0); + $point->rotate(90, new Point(0, 0)); + $this->assertEquals(0, $point->x()); + $this->assertEquals(30, $point->y()); + + $point->rotate(90, new Point(0, 0)); + $this->assertEquals(-30, $point->x()); + $this->assertEquals(0, $point->y()); + + $point = new Point(300, 200); + $point->rotate(90, new Point(0, 0)); + $this->assertEquals(-200, $point->x()); + $this->assertEquals(300, $point->y()); + + $point = new Point(0, 74); + $point->rotate(45, new Point(0, 0)); + $this->assertEquals(-52, $point->x()); + $this->assertEquals(52, $point->y()); + } +} diff --git a/tests/Geometry/PolygonTest.php b/tests/Geometry/PolygonTest.php new file mode 100644 index 00000000..c394b44c --- /dev/null +++ b/tests/Geometry/PolygonTest.php @@ -0,0 +1,361 @@ +assertInstanceOf(Polygon::class, $poly); + $this->assertEquals(0, $poly->count()); + } + + public function testCount(): void + { + $poly = new Polygon([new Point(), new Point()]); + $this->assertEquals(2, $poly->count()); + } + + public function testArrayAccess(): void + { + $poly = new Polygon([new Point(), new Point()]); + $this->assertInstanceOf(Point::class, $poly[0]); + $this->assertInstanceOf(Point::class, $poly[1]); + } + + public function testAddPoint(): void + { + $poly = new Polygon([new Point(), new Point()]); + $this->assertEquals(2, $poly->count()); + $result = $poly->addPoint(new Point()); + $this->assertEquals(3, $poly->count()); + $this->assertInstanceOf(Polygon::class, $result); + } + + public function testGetCenterPoint(): void + { + $poly = new Polygon([ + new Point(0, 0), + new Point(20, 0), + new Point(20, -20), + new Point(0, -20), + ]); + + $result = $poly->centerPoint(); + $this->assertEquals(10, $result->x()); + $this->assertEquals(-10, $result->y()); + + $poly = new Polygon([ + new Point(0, 0), + new Point(300, 0), + new Point(300, -200), + new Point(0, -200), + ], new Point(0, 0)); + + $result = $poly->centerPoint(); + $this->assertEquals(150, $result->x()); + $this->assertEquals(-100, $result->y()); + } + + public function testGetWidth(): void + { + $poly = new Polygon([ + new Point(12, 45), + new Point(-23, -49), + new Point(3, 566), + ]); + + $this->assertEquals($poly->width(), 35); + } + + public function testGetHeight(): void + { + $poly = new Polygon([ + new Point(12, 45), + new Point(-23, -49), + new Point(3, 566), + ]); + + $this->assertEquals(615, $poly->height()); + + $poly = new Polygon([ + new Point(250, 207), + new Point(473, 207), + new Point(473, 250), + new Point(250, 250), + ], new Point(250, 250)); + + $this->assertEquals(43, $poly->height()); + } + + public function testFirst(): void + { + $poly = new Polygon([ + new Point(12, 45), + new Point(-23, -49), + new Point(3, 566), + ]); + + $this->assertEquals(12, $poly->first()->x()); + $this->assertEquals(45, $poly->first()->y()); + } + + public function testLast(): void + { + $poly = new Polygon([ + new Point(12, 45), + new Point(-23, -49), + new Point(3, 566), + ]); + + $this->assertEquals(3, $poly->last()->x()); + $this->assertEquals(566, $poly->last()->y()); + } + + public function testGetPivotPoint(): void + { + $poly = new Polygon(); + $this->assertInstanceOf(Point::class, $poly->pivot()); + } + + public function testGetMostLeftPoint(): void + { + $poly = new Polygon([ + new Point(0, 0), + new Point(300, 0), + new Point(300, -200), + new Point(-32, -200), + ], new Point(0, 0)); + + $result = $poly->mostLeftPoint(); + $this->assertEquals(-32, $result->x()); + $this->assertEquals(-200, $result->y()); + } + + public function testGetMostRightPoint(): void + { + $poly = new Polygon([ + new Point(0, 0), + new Point(350, 0), + new Point(300, -200), + new Point(-32, -200), + ], new Point(0, 0)); + + $result = $poly->mostRightPoint(); + $this->assertEquals(350, $result->x()); + $this->assertEquals(0, $result->y()); + } + + public function testGetMostTopPoint(): void + { + $poly = new Polygon([ + new Point(0, 100), + new Point(350, 0), + new Point(300, -200), + new Point(-32, 200), + ], new Point(0, 0)); + + $result = $poly->mostTopPoint(); + $this->assertEquals(-32, $result->x()); + $this->assertEquals(200, $result->y()); + } + + public function testGetMostBottomPoint(): void + { + $poly = new Polygon([ + new Point(0, 100), + new Point(350, 0), + new Point(300, -200), + new Point(-32, 200), + ], new Point(0, 0)); + + $result = $poly->mostBottomPoint(); + $this->assertEquals(300, $result->x()); + $this->assertEquals(-200, $result->y()); + } + + public function testAlignCenter(): void + { + $poly = new Polygon([ + new Point(0, 0), + new Point(300, 0), + new Point(300, -200), + new Point(0, -200), + ], new Point(0, 0)); + + $result = $poly->align('center'); + + $this->assertInstanceOf(Polygon::class, $result); + $this->assertEquals(-150, $result[0]->x()); + $this->assertEquals(0, $result[0]->y()); + $this->assertEquals(150, $result[1]->x()); + $this->assertEquals(0, $result[1]->y()); + $this->assertEquals(150, $result[2]->x()); + $this->assertEquals(-200, $result[2]->y()); + $this->assertEquals(-150, $result[3]->x()); + $this->assertEquals(-200, $result[3]->y()); + + $poly = new Polygon([ + new Point(0, 0), + new Point(300, 0), + new Point(300, -200), + new Point(0, -200), + ], new Point(-1000, -1000)); + + $result = $poly->align('center'); + + $this->assertInstanceOf(Polygon::class, $result); + $this->assertEquals(-1150, $result[0]->x()); + $this->assertEquals(0, $result[0]->y()); + $this->assertEquals(-850, $result[1]->x()); + $this->assertEquals(0, $result[1]->y()); + $this->assertEquals(-850, $result[2]->x()); + $this->assertEquals(-200, $result[2]->y()); + $this->assertEquals(-1150, $result[3]->x()); + $this->assertEquals(-200, $result[3]->y()); + } + + public function testAlignLeft(): void + { + $poly = new Polygon([ + new Point(0, 0), + new Point(300, 0), + new Point(300, -200), + new Point(0, -200), + ], new Point(100, 100)); + + $result = $poly->align('left'); + + $this->assertInstanceOf(Polygon::class, $result); + $this->assertEquals(100, $result[0]->x()); + $this->assertEquals(0, $result[0]->y()); + $this->assertEquals(400, $result[1]->x()); + $this->assertEquals(0, $result[1]->y()); + $this->assertEquals(400, $result[2]->x()); + $this->assertEquals(-200, $result[2]->y()); + $this->assertEquals(100, $result[3]->x()); + $this->assertEquals(-200, $result[3]->y()); + + $poly = new Polygon([ + new Point(0, 0), + new Point(300, 0), + new Point(300, -200), + new Point(0, -200), + ], new Point(-1000, -1000)); + + $result = $poly->align('left'); + + $this->assertInstanceOf(Polygon::class, $result); + $this->assertEquals(-1000, $result[0]->x()); + $this->assertEquals(0, $result[0]->y()); + $this->assertEquals(-700, $result[1]->x()); + $this->assertEquals(0, $result[1]->y()); + $this->assertEquals(-700, $result[2]->x()); + $this->assertEquals(-200, $result[2]->y()); + $this->assertEquals(-1000, $result[3]->x()); + $this->assertEquals(-200, $result[3]->y()); + } + + public function testAlignRight(): void + { + $poly = new Polygon([ + new Point(0, 0), + new Point(300, 0), + new Point(300, -200), + new Point(0, -200), + ], new Point(100, 100)); + + $result = $poly->align('right'); + + $this->assertInstanceOf(Polygon::class, $result); + $this->assertEquals(-200, $result[0]->x()); + $this->assertEquals(0, $result[0]->y()); + $this->assertEquals(100, $result[1]->x()); + $this->assertEquals(0, $result[1]->y()); + $this->assertEquals(100, $result[2]->x()); + $this->assertEquals(-200, $result[2]->y()); + $this->assertEquals(-200, $result[3]->x()); + $this->assertEquals(-200, $result[3]->y()); + + $poly = new Polygon([ + new Point(0, 0), + new Point(300, 0), + new Point(300, -200), + new Point(0, -200), + ], new Point(-1000, -1000)); + + $result = $poly->align('right'); + + $this->assertInstanceOf(Polygon::class, $result); + $this->assertEquals(-1300, $result[0]->x()); + $this->assertEquals(0, $result[0]->y()); + $this->assertEquals(-1000, $result[1]->x()); + $this->assertEquals(0, $result[1]->y()); + $this->assertEquals(-1000, $result[2]->x()); + $this->assertEquals(-200, $result[2]->y()); + $this->assertEquals(-1300, $result[3]->x()); + $this->assertEquals(-200, $result[3]->y()); + } + + public function testValignMiddle(): void + { + $poly = new Polygon([ + new Point(-21, -22), + new Point(91, -135), + new Point(113, -113), + new Point(0, 0), + ], new Point(250, 250)); + + $result = $poly->valign('middle'); + + $this->assertInstanceOf(Polygon::class, $result); + $this->assertEquals(-21, $result[0]->x()); + $this->assertEquals(296, $result[0]->y()); + $this->assertEquals(91, $result[1]->x()); + $this->assertEquals(183, $result[1]->y()); + $this->assertEquals(113, $result[2]->x()); + $this->assertEquals(205, $result[2]->y()); + $this->assertEquals(0, $result[3]->x()); + $this->assertEquals(318, $result[3]->y()); + } + + public function testRotate(): void + { + $poly = new Polygon([ + new Point(0, 0), + new Point(50, 0), + new Point(50, -50), + new Point(0, -50), + ]); + + $result = $poly->rotate(45); + $this->assertInstanceOf(Polygon::class, $result); + $this->assertEquals(0, $result[0]->x()); + $this->assertEquals(0, $result[0]->y()); + $this->assertEquals(35, $result[1]->x()); + $this->assertEquals(35, $result[1]->y()); + $this->assertEquals(70, $result[2]->x()); + $this->assertEquals(0, $result[2]->y()); + $this->assertEquals(35, $result[3]->x()); + $this->assertEquals(-35, $result[3]->y()); + } + + public function testToArray(): void + { + $poly = new Polygon([ + new Point(0, 0), + new Point(50, 0), + new Point(50, -50), + new Point(0, -50), + ]); + + $this->assertEquals([0, 0, 50, 0, 50, -50, 0, -50], $poly->toArray()); + } +} diff --git a/tests/Geometry/RectangleResizerTest.php b/tests/Geometry/RectangleResizerTest.php new file mode 100644 index 00000000..bcc569b4 --- /dev/null +++ b/tests/Geometry/RectangleResizerTest.php @@ -0,0 +1,449 @@ +assertInstanceOf(RectangleResizer::class, $resizer); + + $resizer = RectangleResizer::to(height: 100); + $this->assertInstanceOf(RectangleResizer::class, $resizer); + + $resizer = RectangleResizer::to(100); + $this->assertInstanceOf(RectangleResizer::class, $resizer); + + $resizer = RectangleResizer::to(100, 100); + $this->assertInstanceOf(RectangleResizer::class, $resizer); + } + + public function testToWidth(): void + { + $resizer = new RectangleResizer(); + $result = $resizer->toWidth(100); + $this->assertInstanceOf(RectangleResizer::class, $result); + } + + public function testToHeight(): void + { + $resizer = new RectangleResizer(); + $result = $resizer->toHeight(100); + $this->assertInstanceOf(RectangleResizer::class, $result); + } + + public function testToSize(): void + { + $resizer = new RectangleResizer(); + $resizer = $resizer->toSize(new Rectangle(200, 100)); + $this->assertInstanceOf(RectangleResizer::class, $resizer); + } + + public function testResize() + { + $size = new Rectangle(300, 200); + $resizer = new RectangleResizer(); + $resizer->toWidth(150); + $result = $resizer->resize($size); + $this->assertEquals(150, $result->width()); + $this->assertEquals(200, $result->height()); + + $size = new Rectangle(300, 200); + $resizer = new RectangleResizer(); + $resizer->toWidth(20); + $resizer->toHeight(10); + $result = $resizer->resize($size); + $this->assertEquals(20, $result->width()); + $this->assertEquals(10, $result->height()); + + $size = new Rectangle(300, 200); + $resizer = new RectangleResizer(width: 150); + $result = $resizer->resize($size); + $this->assertEquals(150, $result->width()); + $this->assertEquals(200, $result->height()); + + $size = new Rectangle(300, 200); + $resizer = new RectangleResizer(height: 10, width: 20); + $result = $resizer->resize($size); + $this->assertEquals(20, $result->width()); + $this->assertEquals(10, $result->height()); + } + + public function testResizeDown() + { + // 800x600 > 1000x2000 = 800x600 + $size = new Rectangle(800, 600); + $resizer = new RectangleResizer(); + $resizer->toWidth(1000); + $resizer->toHeight(2000); + $result = $resizer->resizeDown($size); + $this->assertEquals(800, $result->width()); + $this->assertEquals(600, $result->height()); + + // 800x600 > 400x1000 = 400x600 + $size = new Rectangle(800, 600); + $resizer = new RectangleResizer(); + $resizer->toWidth(400); + $resizer->toHeight(1000); + $result = $resizer->resizeDown($size); + $this->assertEquals(400, $result->width()); + $this->assertEquals(600, $result->height()); + + // 800x600 > 1000x400 = 800x400 + $size = new Rectangle(800, 600); + $resizer = new RectangleResizer(); + $resizer->toWidth(1000); + $resizer->toHeight(400); + $result = $resizer->resizeDown($size); + $this->assertEquals(800, $result->width()); + $this->assertEquals(400, $result->height()); + + // 800x600 > 400x300 = 400x300 + $size = new Rectangle(800, 600); + $resizer = new RectangleResizer(); + $resizer->toWidth(400); + $resizer->toHeight(300); + $result = $resizer->resizeDown($size); + $this->assertEquals(400, $result->width()); + $this->assertEquals(300, $result->height()); + + // 800x600 > 1000xnull = 800x600 + $size = new Rectangle(800, 600); + $resizer = new RectangleResizer(); + $resizer->toWidth(1000); + $result = $resizer->resizeDown($size); + $this->assertEquals(800, $result->width()); + $this->assertEquals(600, $result->height()); + + // 800x600 > nullx1000 = 800x600 + $size = new Rectangle(800, 600); + $resizer = new RectangleResizer(); + $resizer->toHeight(1000); + $result = $resizer->resizeDown($size); + $this->assertEquals(800, $result->width()); + $this->assertEquals(600, $result->height()); + } + + public function testScale() + { + // 800x600 > 1000x2000 = 1000x750 + $size = new Rectangle(800, 600); + $resizer = new RectangleResizer(); + $resizer->toWidth(1000); + $resizer->toHeight(2000); + $result = $resizer->scale($size); + $this->assertEquals(1000, $result->width()); + $this->assertEquals(750, $result->height()); + + // 800x600 > 2000x1000 = 1333x1000 + $size = new Rectangle(800, 600); + $resizer = new RectangleResizer(); + $resizer->toWidth(2000); + $resizer->toHeight(1000); + $result = $resizer->scale($size); + $this->assertEquals(1333, $result->width()); + $this->assertEquals(1000, $result->height()); + + // // 800x600 > nullx3000 = 4000x3000 + $size = new Rectangle(800, 600); + $resizer = new RectangleResizer(); + $resizer->toHeight(3000); + $result = $resizer->scale($size); + $this->assertEquals(4000, $result->width()); + $this->assertEquals(3000, $result->height()); + + // // 800x600 > 8000xnull = 8000x6000 + $size = new Rectangle(800, 600); + $resizer = new RectangleResizer(); + $resizer->toWidth(8000); + $result = $resizer->scale($size); + $this->assertEquals(8000, $result->width()); + $this->assertEquals(6000, $result->height()); + + // // 800x600 > 100x400 = 100x75 + $size = new Rectangle(800, 600); + $resizer = new RectangleResizer(); + $resizer->toWidth(100); + $resizer->toHeight(400); + $result = $resizer->scale($size); + $this->assertEquals(100, $result->width()); + $this->assertEquals(75, $result->height()); + + // // 800x600 > 400x100 = 133x100 + $size = new Rectangle(800, 600); + $resizer = new RectangleResizer(); + $resizer->toWidth(400); + $resizer->toHeight(100); + $result = $resizer->scale($size); + $this->assertEquals(133, $result->width()); + $this->assertEquals(100, $result->height()); + + // // 800x600 > nullx300 = 400x300 + $size = new Rectangle(800, 600); + $resizer = new RectangleResizer(); + $resizer->toHeight(300); + $result = $resizer->scale($size); + $this->assertEquals(400, $result->width()); + $this->assertEquals(300, $result->height()); + + // // 800x600 > 80xnull = 80x60 + $size = new Rectangle(800, 600); + $resizer = new RectangleResizer(); + $resizer->toWidth(80); + $result = $resizer->scale($size); + $this->assertEquals(80, $result->width()); + $this->assertEquals(60, $result->height()); + + // // 640x480 > 225xnull = 225x169 + $size = new Rectangle(640, 480); + $resizer = new RectangleResizer(); + $resizer->toWidth(225); + $result = $resizer->scale($size); + $this->assertEquals(225, $result->width()); + $this->assertEquals(169, $result->height()); + + // // 640x480 > 223xnull = 223x167 + $size = new Rectangle(640, 480); + $resizer = new RectangleResizer(); + $resizer->toWidth(223); + $result = $resizer->scale($size); + $this->assertEquals(223, $result->width()); + $this->assertEquals(167, $result->height()); + + // // 600x800 > 300x300 = 225x300 + $size = new Rectangle(600, 800); + $resizer = new RectangleResizer(); + $resizer->toWidth(300); + $resizer->toHeight(300); + $result = $resizer->scale($size); + $this->assertEquals(225, $result->width()); + $this->assertEquals(300, $result->height()); + + // // 800x600 > 400x10 = 13x10 + $size = new Rectangle(800, 600); + $resizer = new RectangleResizer(); + $resizer->toWidth(400); + $resizer->toHeight(10); + $result = $resizer->scale($size); + $this->assertEquals(13, $result->width()); + $this->assertEquals(10, $result->height()); + + // // 800x600 > 1000x1200 = 1000x750 + $size = new Rectangle(800, 600); + $resizer = new RectangleResizer(); + $resizer->toWidth(1000); + $resizer->toHeight(1200); + $result = $resizer->scale($size); + $this->assertEquals(1000, $result->width()); + $this->assertEquals(750, $result->height()); + + $size = new Rectangle(12000, 12); + $resizer = new RectangleResizer(); + $resizer->toWidth(4000); + $resizer->toHeight(3000); + $result = $resizer->scale($size); + $this->assertEquals(4000, $result->width()); + $this->assertEquals(4, $result->height()); + + $size = new Rectangle(12, 12000); + $resizer = new RectangleResizer(); + $resizer->toWidth(4000); + $resizer->toHeight(3000); + $result = $resizer->scale($size); + $this->assertEquals(3, $result->width()); + $this->assertEquals(3000, $result->height()); + + $size = new Rectangle(12000, 6000); + $resizer = new RectangleResizer(); + $resizer->toWidth(4000); + $resizer->toHeight(3000); + $result = $resizer->scale($size); + $this->assertEquals(4000, $result->width()); + $this->assertEquals(2000, $result->height()); + } + + public function testScaleDown() + { + $size = new Rectangle(800, 600); + $resizer = new RectangleResizer(); + $resizer->toWidth(1000); + $resizer->toHeight(2000); + $result = $resizer->scaleDown($size); + $this->assertEquals(800, $result->width()); + $this->assertEquals(600, $result->height()); + + $size = new Rectangle(800, 600); + $resizer = new RectangleResizer(); + $resizer->toWidth(1000); + $resizer->toHeight(600); + $result = $resizer->scaleDown($size); + $this->assertEquals(800, $result->width()); + $this->assertEquals(600, $result->height()); + + $size = new Rectangle(800, 600); + $resizer = new RectangleResizer(); + $resizer->toWidth(1000); + $resizer->toHeight(300); + $result = $resizer->scaleDown($size); + $this->assertEquals(400, $result->width()); + $this->assertEquals(300, $result->height()); + + $size = new Rectangle(800, 600); + $resizer = new RectangleResizer(); + $resizer->toWidth(400); + $resizer->toHeight(1000); + $result = $resizer->scaleDown($size); + $this->assertEquals(400, $result->width()); + $this->assertEquals(300, $result->height()); + + $size = new Rectangle(800, 600); + $resizer = new RectangleResizer(); + $resizer->toWidth(400); + $result = $resizer->scaleDown($size); + $this->assertEquals(400, $result->width()); + $this->assertEquals(300, $result->height()); + + $size = new Rectangle(800, 600); + $resizer = new RectangleResizer(); + $resizer->toHeight(300); + $result = $resizer->scaleDown($size); + $this->assertEquals(400, $result->width()); + $this->assertEquals(300, $result->height()); + + $size = new Rectangle(800, 600); + $resizer = new RectangleResizer(); + $resizer->toWidth(1000); + $result = $resizer->scaleDown($size); + $this->assertEquals(800, $result->width()); + $this->assertEquals(600, $result->height()); + + $size = new Rectangle(800, 600); + $resizer = new RectangleResizer(); + $resizer->toHeight(1000); + $result = $resizer->scaleDown($size); + $this->assertEquals(800, $result->width()); + $this->assertEquals(600, $result->height()); + + $size = new Rectangle(800, 600); + $resizer = new RectangleResizer(); + $resizer->toWidth(100); + $result = $resizer->scaleDown($size); + $this->assertEquals(100, $result->width()); + $this->assertEquals(75, $result->height()); + + $size = new Rectangle(800, 600); + $resizer = new RectangleResizer(); + $resizer->toWidth(300); + $resizer->toHeight(200); + $result = $resizer->scaleDown($size); + $this->assertEquals(267, $result->width()); + $this->assertEquals(200, $result->height()); + + $size = new Rectangle(600, 800); + $resizer = new RectangleResizer(); + $resizer->toWidth(300); + $resizer->toHeight(300); + $result = $resizer->scaleDown($size); + $this->assertEquals(225, $result->width()); + $this->assertEquals(300, $result->height()); + + $size = new Rectangle(800, 600); + $resizer = new RectangleResizer(); + $resizer->toWidth(400); + $resizer->toHeight(10); + $result = $resizer->scaleDown($size); + $this->assertEquals(13, $result->width()); + $this->assertEquals(10, $result->height()); + } + + /** + * @dataProvider coverDataProvider + */ + public function testCover($origin, $target, $result): void + { + $resizer = new RectangleResizer(); + $resizer->toSize($target); + $resized = $resizer->cover($origin); + $this->assertEquals($result->width(), $resized->width()); + $this->assertEquals($result->height(), $resized->height()); + } + + public function coverDataProvider(): array + { + return [ + [new Rectangle(800, 600), new Rectangle(100, 100), new Rectangle(133, 100)], + [new Rectangle(800, 600), new Rectangle(200, 100), new Rectangle(200, 150)], + [new Rectangle(800, 600), new Rectangle(100, 200), new Rectangle(267, 200)], + [new Rectangle(800, 600), new Rectangle(2000, 10), new Rectangle(2000, 1500)], + [new Rectangle(800, 600), new Rectangle(10, 2000), new Rectangle(2667, 2000)], + [new Rectangle(800, 600), new Rectangle(800, 600), new Rectangle(800, 600)], + [new Rectangle(400, 300), new Rectangle(120, 120), new Rectangle(160, 120)], + [new Rectangle(600, 800), new Rectangle(100, 100), new Rectangle(100, 133)], + [new Rectangle(100, 100), new Rectangle(800, 600), new Rectangle(800, 800)], + ]; + } + + /** + * @dataProvider containDataProvider + */ + public function testContain($origin, $target, $result): void + { + $resizer = new RectangleResizer(); + $resizer->toSize($target); + $resized = $resizer->contain($origin); + $this->assertEquals($result->width(), $resized->width()); + $this->assertEquals($result->height(), $resized->height()); + } + + public function containDataProvider(): array + { + return [ + [new Rectangle(800, 600), new Rectangle(100, 100), new Rectangle(100, 75)], + [new Rectangle(800, 600), new Rectangle(200, 100), new Rectangle(133, 100)], + [new Rectangle(800, 600), new Rectangle(100, 200), new Rectangle(100, 75)], + [new Rectangle(800, 600), new Rectangle(2000, 10), new Rectangle(13, 10)], + [new Rectangle(800, 600), new Rectangle(10, 2000), new Rectangle(10, 8)], + [new Rectangle(800, 600), new Rectangle(800, 600), new Rectangle(800, 600)], + [new Rectangle(400, 300), new Rectangle(120, 120), new Rectangle(120, 90)], + [new Rectangle(600, 800), new Rectangle(100, 100), new Rectangle(75, 100)], + [new Rectangle(100, 100), new Rectangle(800, 600), new Rectangle(600, 600)], + ]; + } + + /** + * @dataProvider cropDataProvider + */ + public function testCrop($origin, $target, $position, $result): void + { + $resizer = new RectangleResizer(); + $resizer->toSize($target); + $resized = $resizer->crop($origin, $position); + $this->assertEquals($result->width(), $resized->width()); + $this->assertEquals($result->height(), $resized->height()); + $this->assertEquals($result->pivot()->x(), $resized->pivot()->x()); + $this->assertEquals($result->pivot()->y(), $resized->pivot()->y()); + } + + public function cropDataProvider(): array + { + return [ + [new Rectangle(800, 600), new Rectangle(100, 100), 'center', new Rectangle(100, 100, new Point(350, 250))], + [new Rectangle(800, 600), new Rectangle(200, 100), 'center', new Rectangle(200, 100, new Point(300, 250))], + [new Rectangle(800, 600), new Rectangle(100, 200), 'center', new Rectangle(100, 200, new Point(350, 200))], + [new Rectangle(800, 600), new Rectangle(2000, 10), 'center', new Rectangle(2000, 10, new Point(-600, 295))], + [new Rectangle(800, 600), new Rectangle(10, 2000), 'center', new Rectangle(10, 2000, new Point(395, -700))], + [new Rectangle(800, 600), new Rectangle(800, 600), 'center', new Rectangle(800, 600, new Point(0, 0))], + [new Rectangle(400, 300), new Rectangle(120, 120), 'center', new Rectangle(120, 120, new Point(140, 90))], + [new Rectangle(600, 800), new Rectangle(100, 100), 'center', new Rectangle(100, 100, new Point(250, 350))], + ]; + } +} diff --git a/tests/Geometry/RectangleTest.php b/tests/Geometry/RectangleTest.php new file mode 100644 index 00000000..3305f790 --- /dev/null +++ b/tests/Geometry/RectangleTest.php @@ -0,0 +1,248 @@ +assertEquals(0, $rectangle[0]->x()); + $this->assertEquals(0, $rectangle[0]->y()); + $this->assertEquals(300, $rectangle[1]->x()); + $this->assertEquals(0, $rectangle[1]->y()); + $this->assertEquals(300, $rectangle[2]->x()); + $this->assertEquals(-200, $rectangle[2]->y()); + $this->assertEquals(0, $rectangle[3]->x()); + $this->assertEquals(-200, $rectangle[3]->y()); + $this->assertEquals(300, $rectangle->width()); + $this->assertEquals(200, $rectangle->height()); + } + + public function testSetSize(): void + { + $rectangle = new Rectangle(300, 200); + $rectangle->setSize(12, 34); + $this->assertEquals(12, $rectangle->width()); + $this->assertEquals(34, $rectangle->height()); + } + + public function testSetWidth(): void + { + $rectangle = new Rectangle(300, 200); + $this->assertEquals(300, $rectangle->width()); + $rectangle->setWidth(400); + $this->assertEquals(400, $rectangle->width()); + } + + public function testSetHeight(): void + { + $rectangle = new Rectangle(300, 200); + $this->assertEquals(200, $rectangle->height()); + $rectangle->setHeight(800); + $this->assertEquals(800, $rectangle->height()); + } + + public function testGetAspectRatio() + { + $size = new Rectangle(800, 600); + $this->assertEquals(1.333, round($size->aspectRatio(), 3)); + + $size = new Rectangle(100, 100); + $this->assertEquals(1, $size->aspectRatio()); + + $size = new Rectangle(1920, 1080); + $this->assertEquals(1.778, round($size->aspectRatio(), 3)); + } + + public function testFitsInto() + { + $box = new Rectangle(800, 600); + $fits = $box->fitsInto(new Rectangle(100, 100)); + $this->assertFalse($fits); + + $box = new Rectangle(800, 600); + $fits = $box->fitsInto(new Rectangle(1000, 100)); + $this->assertFalse($fits); + + $box = new Rectangle(800, 600); + $fits = $box->fitsInto(new Rectangle(100, 1000)); + $this->assertFalse($fits); + + $box = new Rectangle(800, 600); + $fits = $box->fitsInto(new Rectangle(800, 600)); + $this->assertTrue($fits); + + $box = new Rectangle(800, 600); + $fits = $box->fitsInto(new Rectangle(1000, 1000)); + $this->assertTrue($fits); + + $box = new Rectangle(100, 100); + $fits = $box->fitsInto(new Rectangle(800, 600)); + $this->assertTrue($fits); + + $box = new Rectangle(100, 100); + $fits = $box->fitsInto(new Rectangle(80, 60)); + $this->assertFalse($fits); + } + + public function testIsLandscape() + { + $box = new Rectangle(100, 100); + $this->assertFalse($box->isLandscape()); + + $box = new Rectangle(100, 200); + $this->assertFalse($box->isLandscape()); + + $box = new Rectangle(300, 200); + $this->assertTrue($box->isLandscape()); + } + + public function testIsPortrait() + { + $box = new Rectangle(100, 100); + $this->assertFalse($box->isPortrait()); + + $box = new Rectangle(200, 100); + $this->assertFalse($box->isPortrait()); + + $box = new Rectangle(200, 300); + $this->assertTrue($box->isPortrait()); + } + + public function testSetGetPivot(): void + { + $box = new Rectangle(800, 600); + $pivot = $box->pivot(); + $this->assertInstanceOf(Point::class, $pivot); + $this->assertEquals(0, $pivot->x()); + $result = $box->setPivot(new Point(10, 0)); + $this->assertInstanceOf(Rectangle::class, $result); + $this->assertEquals(10, $box->pivot()->x()); + } + + public function testAlignPivot(): void + { + $box = new Rectangle(640, 480); + $this->assertEquals(0, $box->pivot()->x()); + $this->assertEquals(0, $box->pivot()->y()); + + $box->movePivot('top-left', 3, 3); + $this->assertEquals(3, $box->pivot()->x()); + $this->assertEquals(3, $box->pivot()->y()); + + $box->movePivot('top', 3, 3); + $this->assertEquals(323, $box->pivot()->x()); + $this->assertEquals(3, $box->pivot()->y()); + + $box->movePivot('top-right', 3, 3); + $this->assertEquals(637, $box->pivot()->x()); + $this->assertEquals(3, $box->pivot()->y()); + + $box->movePivot('left', 3, 3); + $this->assertEquals(3, $box->pivot()->x()); + $this->assertEquals(243, $box->pivot()->y()); + + $box->movePivot('center', 3, 3); + $this->assertEquals(323, $box->pivot()->x()); + $this->assertEquals(243, $box->pivot()->y()); + + $box->movePivot('right', 3, 3); + $this->assertEquals(637, $box->pivot()->x()); + $this->assertEquals(243, $box->pivot()->y()); + + $box->movePivot('bottom-left', 3, 3); + $this->assertEquals(3, $box->pivot()->x()); + $this->assertEquals(477, $box->pivot()->y()); + + $box->movePivot('bottom', 3, 3); + $this->assertEquals(323, $box->pivot()->x()); + $this->assertEquals(477, $box->pivot()->y()); + + $result = $box->movePivot('bottom-right', 3, 3); + $this->assertEquals(637, $box->pivot()->x()); + $this->assertEquals(477, $box->pivot()->y()); + + $this->assertInstanceOf(Rectangle::class, $result); + } + + public function testAlignPivotTo(): void + { + $container = new Rectangle(800, 600); + $size = new Rectangle(200, 100); + $size->alignPivotTo($container, 'center'); + $this->assertEquals(300, $size->pivot()->x()); + $this->assertEquals(250, $size->pivot()->y()); + + $container = new Rectangle(800, 600); + $size = new Rectangle(100, 100); + $size->alignPivotTo($container, 'center'); + $this->assertEquals(350, $size->pivot()->x()); + $this->assertEquals(250, $size->pivot()->y()); + + $container = new Rectangle(800, 600); + $size = new Rectangle(800, 600); + $size->alignPivotTo($container, 'center'); + $this->assertEquals(0, $size->pivot()->x()); + $this->assertEquals(0, $size->pivot()->y()); + + $container = new Rectangle(100, 100); + $size = new Rectangle(800, 600); + $size->alignPivotTo($container, 'center'); + $this->assertEquals(-350, $size->pivot()->x()); + $this->assertEquals(-250, $size->pivot()->y()); + + $container = new Rectangle(100, 100); + $size = new Rectangle(800, 600); + $size->alignPivotTo($container, 'bottom-right'); + $this->assertEquals(-700, $size->pivot()->x()); + $this->assertEquals(-500, $size->pivot()->y()); + } + + public function testgetRelativePositionTo(): void + { + $container = new Rectangle(800, 600); + $input = new Rectangle(200, 100); + $container->movePivot('top-left'); + $input->movePivot('top-left'); + $pos = $container->relativePositionTo($input); + $this->assertEquals(0, $pos->x()); + $this->assertEquals(0, $pos->y()); + + $container = new Rectangle(800, 600); + $input = new Rectangle(200, 100); + $container->movePivot('center'); + $input->movePivot('top-left'); + $pos = $container->relativePositionTo($input); + $this->assertEquals(400, $pos->x()); + $this->assertEquals(300, $pos->y()); + + $container = new Rectangle(800, 600); + $input = new Rectangle(200, 100); + $container->movePivot('bottom-right'); + $input->movePivot('top-right'); + $pos = $container->relativePositionTo($input); + $this->assertEquals(600, $pos->x()); + $this->assertEquals(600, $pos->y()); + + $container = new Rectangle(800, 600); + $input = new Rectangle(200, 100); + $container->movePivot('center'); + $input->movePivot('center'); + $pos = $container->relativePositionTo($input); + $this->assertEquals(300, $pos->x()); + $this->assertEquals(250, $pos->y()); + + $container = new Rectangle(100, 200); + $input = new Rectangle(100, 100); + $container->movePivot('center'); + $input->movePivot('center'); + $pos = $container->relativePositionTo($input); + $this->assertEquals(0, $pos->x()); + $this->assertEquals(50, $pos->y()); + } +} diff --git a/tests/GetsizeCommandTest.php b/tests/GetsizeCommandTest.php deleted file mode 100644 index d67f3b7f..00000000 --- a/tests/GetsizeCommandTest.php +++ /dev/null @@ -1,39 +0,0 @@ -shouldReceive('getCore')->times(2)->andReturn($resource); - $command = new GetSizeGd([]); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertTrue($command->hasOutput()); - $this->assertInstanceOf('Intervention\Image\Size', $command->getOutput()); - } - - public function testImagick() - { - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('getimagewidth')->with(); - $imagick->shouldReceive('getimageheight')->with(); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - $command = new GetSizeImagick([]); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertTrue($command->hasOutput()); - $this->assertInstanceOf('Intervention\Image\Size', $command->getOutput()); - } -} diff --git a/tests/GreyscaleCommandTest.php b/tests/GreyscaleCommandTest.php deleted file mode 100644 index 84298199..00000000 --- a/tests/GreyscaleCommandTest.php +++ /dev/null @@ -1,34 +0,0 @@ -shouldReceive('getCore')->once()->andReturn($resource); - $command = new GreyscaleGd([]); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagick() - { - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('modulateimage')->with(100, 0, 100)->andReturn(true); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - $command = new GreyscaleImagick([]); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/HeightenCommandTest.php b/tests/HeightenCommandTest.php deleted file mode 100644 index 4016ff7d..00000000 --- a/tests/HeightenCommandTest.php +++ /dev/null @@ -1,49 +0,0 @@ -aspectRatio(); }; - $resource = imagecreatefromjpeg(__DIR__.'/images/test.jpg'); - $image = Mockery::mock('Intervention\Image\Image'); - $size = Mockery::mock('Intervention\Image\Size', [800, 600]); - $size->shouldReceive('resize')->once()->andReturn($size); - $size->shouldReceive('getWidth')->once()->andReturn(800); - $size->shouldReceive('getHeight')->once()->andReturn(600); - $image->shouldReceive('getWidth')->once()->andReturn(800); - $image->shouldReceive('getHeight')->once()->andReturn(600); - $image->shouldReceive('getSize')->once()->andReturn($size); - $image->shouldReceive('getCore')->once()->andReturn($resource); - $image->shouldReceive('setCore')->once(); - $command = new HeightenGd([200]); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagick() - { - $callback = function ($constraint) { $constraint->upsize(); }; - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('scaleimage')->with(300, 200)->once()->andReturn(true); - $size = Mockery::mock('Intervention\Image\Size', [800, 600]); - $size->shouldReceive('resize')->once()->andReturn($size); - $size->shouldReceive('getWidth')->once()->andReturn(300); - $size->shouldReceive('getHeight')->once()->andReturn(200); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - $image->shouldReceive('getSize')->once()->andReturn($size); - $command = new HeightenImagick([200]); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/ImageManagerStaticTest.php b/tests/ImageManagerStaticTest.php deleted file mode 100644 index b4bb3f5d..00000000 --- a/tests/ImageManagerStaticTest.php +++ /dev/null @@ -1,36 +0,0 @@ -getManager(); - $this->assertInstanceOf('Intervention\Image\ImageManager', $m); - } - - public function testMake() - { - $manager = Mockery::mock('Intervention\Image\ImageManager'); - $manager->shouldReceive('make')->with('foo')->once(); - $managerStatic = new ImageManagerStatic($manager); - $managerStatic->make('foo'); - } - - public function testCanvas() - { - $manager = Mockery::mock('Intervention\Image\ImageManager'); - $manager->shouldReceive('canvas')->with(100, 100, null)->once(); - $managerStatic = new ImageManagerStatic($manager); - $managerStatic->canvas(100, 100); - } -} diff --git a/tests/ImageManagerTest.php b/tests/ImageManagerTest.php index 9312208a..5094a504 100644 --- a/tests/ImageManagerTest.php +++ b/tests/ImageManagerTest.php @@ -1,40 +1,73 @@ 'foo', 'bar' => 'baz']; - $manager = new ImageManager($config); - $this->assertEquals('foo', $manager->config['driver']); - $this->assertEquals('baz', $manager->config['bar']); + $manager = new ImageManager(new GdDriver()); + $this->assertInstanceOf(ImageManager::class, $manager); + + $manager = new ImageManager(GdDriver::class); + $this->assertInstanceOf(ImageManager::class, $manager); } - public function testConfigure() + public function testWithDriver(): void { - $overwrite = ['driver' => 'none', 'bar' => 'none']; - $config = ['driver' => 'foo', 'bar' => 'baz']; - $manager = new ImageManager($overwrite); - $manager->configure($config); - $this->assertEquals('foo', $manager->config['driver']); - $this->assertEquals('baz', $manager->config['bar']); + $manager = ImageManager::withDriver(new GdDriver()); + $this->assertInstanceOf(ImageManager::class, $manager); + + $manager = ImageManager::withDriver(GdDriver::class); + $this->assertInstanceOf(ImageManager::class, $manager); } - public function testConfigureObject() + public function testDriverStatics(): void { - $config = ['driver' => new Intervention\Image\Imagick\Driver()]; - $manager = new ImageManager($config); + $manager = ImageManager::gd(); + $this->assertInstanceOf(ImageManager::class, $manager); - $image = $manager->make('data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'); - $this->assertInstanceOf('Intervention\Image\Image', $image); - $this->assertInstanceOf('Imagick', $image->getCore()); + $manager = ImageManager::imagick(); + $this->assertInstanceOf(ImageManager::class, $manager); + } + + /** @requires extension gd */ + public function testCreateGd() + { + $manager = new ImageManager(GdDriver::class); + $image = $manager->create(5, 4); + $this->assertInstanceOf(ImageInterface::class, $image); + } + + /** @requires extension gd */ + public function testReadGd() + { + $manager = new ImageManager(GdDriver::class); + $image = $manager->read(__DIR__ . '/images/red.gif'); + $this->assertInstanceOf(ImageInterface::class, $image); + } + + /** @requires extension imagick */ + public function testCreateImagick() + { + $manager = new ImageManager(ImagickDriver::class); + $image = $manager->create(5, 4); + $this->assertInstanceOf(ImageInterface::class, $image); + } + + /** @requires extension imagick */ + public function testReadImagick() + { + $manager = new ImageManager(ImagickDriver::class); + $image = $manager->read(__DIR__ . '/images/red.gif'); + $this->assertInstanceOf(ImageInterface::class, $image); } } diff --git a/tests/ImageTest.php b/tests/ImageTest.php deleted file mode 100644 index 870658cf..00000000 --- a/tests/ImageTest.php +++ /dev/null @@ -1,143 +0,0 @@ -getTestImage(); - $this->assertEquals('mock', $image->getCore()); - } - - public function testCommandCall() - { - $image = $this->getTestImage(); - $result = $image->test(1, 2, 3); - $this->assertEquals('mock', $result); - } - - public function testEncode() - { - $image = $this->getTestImage(); - $image->getDriver()->shouldReceive('encode')->with($image, 'png', 90)->once(); - $image->encode('png', 90); - } - - public function testSave() - { - $save_as = __DIR__.'/tmp/test.jpg'; - $image = $this->getTestImage(); - $image->getDriver()->shouldReceive('encode')->with($image, 'jpg', 85)->once()->andReturn('mock'); - $image = $image->save($save_as, 85); - $this->assertInstanceOf('\Intervention\Image\Image', $image); - $this->assertFileExists($save_as); - $this->assertEquals($image->basename, 'test.jpg'); - $this->assertEquals($image->extension, 'jpg'); - $this->assertEquals($image->filename, 'test'); - @unlink($save_as); - } - - public function testFormatSave() - { - $save_as = __DIR__.'/tmp/test'; - - $config = ['driver' => new Intervention\Image\Imagick\Driver()]; - $manager = new ImageManager($config); - - $image = $manager->make('data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'); - $this->assertInstanceOf('Intervention\Image\Image', $image); - $this->assertInstanceOf('Imagick', $image->getCore()); - - $gifCore = $image->getCore(); - $this->assertEquals($gifCore->getImageMimeType(), 'image/gif'); - $image->save($save_as, null, 'jpg'); - - $this->assertEquals(\mime_content_type($save_as), 'image/jpeg'); - @unlink($save_as); - } - - public function testIsEncoded() - { - $image = $this->getTestImage(); - $this->assertFalse($image->isEncoded()); - - $image->setEncoded('foo'); - $this->assertTrue($image->isEncoded()); - } - - public function testFilter() - { - $demoFilter = Mockery::mock('\Intervention\Image\Filters\DemoFilter', [15]); - $image = $this->getTestImage(); - $demoFilter->shouldReceive('applyFilter')->with($image)->once()->andReturn($image); - $image->filter($demoFilter); - } - - public function testMime() - { - $image = $this->getTestImage(); - $this->assertEquals('image/png', $image->mime()); - } - - /** - * @expectedException \Intervention\Image\Exception\RuntimeException - */ - public function testGetBackupWithoutBackuo() - { - $image = $this->getTestImage(); - $image->getBackup(); - } - - public function testSetGetBackup() - { - $image = $this->getTestImage(); - $image->setBackup('foo'); - $backup = $image->getBackup(); - $this->assertEquals('foo', $backup); - } - - public function testGetBackups() - { - $image = $this->getTestImage(); - $backups = $image->getBackups(); - $this->assertEquals([], $backups); - - $image = $this->getTestImage(); - $image->setBackup('foo'); - $image->setBackup('bar'); - $image->setBackup('baz'); - $backups = $image->getBackups(); - $this->assertEquals(['default' => 'baz'], $backups); - - $image = $this->getTestImage(); - $image->setBackup('foo', 'a'); - $image->setBackup('bar', 'b'); - $image->setBackup('baz', 'c'); - $backups = $image->getBackups(); - $this->assertEquals(['a' => 'foo', 'b' => 'bar', 'c' => 'baz'], $backups); - } - - private function getTestImage() - { - $size = Mockery::mock('\Intervention\Image\Size', [800, 600]); - $driver = Mockery::mock('\Intervention\Image\AbstractDriver'); - $command = Mockery::mock('\Intervention\Image\Commands\AbstractCommand'); - $command->shouldReceive('hasOutput')->andReturn(true); - $command->shouldReceive('getOutput')->andReturn('mock'); - $driver->shouldReceive('executeCommand')->andReturn($command); - $image = new Image($driver, 'mock'); - $image->mime = 'image/png'; - $image->dirname = './tmp'; - $image->basename = 'foo.png'; - - return $image; - } -} diff --git a/tests/ImagickColorTest.php b/tests/ImagickColorTest.php deleted file mode 100644 index c51ec4da..00000000 --- a/tests/ImagickColorTest.php +++ /dev/null @@ -1,338 +0,0 @@ -pixel = Mockery::mock('ImagickPixel'); - $c->pixel->shouldReceive('getcolorvalue')->with(Imagick::COLOR_RED)->andReturn(0.956862745098); - $this->assertEquals(244, $c->getRedValue()); - - $c = new Color; - $c->pixel = Mockery::mock('ImagickPixel'); - $c->pixel->shouldReceive('getcolorvalue')->with(Imagick::COLOR_GREEN)->andReturn(0.0470588235294); - $this->assertEquals(12, $c->getGreenValue()); - - $c = new Color; - $c->pixel = Mockery::mock('ImagickPixel'); - $c->pixel->shouldReceive('getcolorvalue')->with(Imagick::COLOR_BLUE)->andReturn(0.0862745098039); - $this->assertEquals(22, $c->getBlueValue()); - - $c = new Color; - $c->pixel = Mockery::mock('ImagickPixel'); - $c->pixel->shouldReceive('getcolorvalue')->with(Imagick::COLOR_ALPHA)->andReturn(1); - $this->assertEquals(1, $c->getAlphaValue()); - - $c = new Color; - $c->pixel = Mockery::mock('ImagickPixel'); - $c->pixel->shouldReceive('getcolorvalue')->with(Imagick::COLOR_ALPHA)->andReturn(1); - $this->assertEquals(1, $c->getAlphaValue()); - } - - public function testConstructor() - { - $c = new Color; - $this->validateColor($c, 255, 255, 255, 0); - } - - public function testParseNull() - { - $c = new Color; - $c->parse(null); - $this->validateColor($c, 255, 255, 255, 0); - } - - public function testParseInteger() - { - $c = new Color; - $c->parse(16777215); - $this->validateColor($c, 255, 255, 255, 0); - - $c = new Color; - $c->parse(4294967295); - $this->validateColor($c, 255, 255, 255, 1); - } - - public function testParseArray() - { - $c = new Color; - $c->parse([181, 55, 23, 0.5]); - $this->validateColor($c, 181, 55, 23, 0.5); - } - - public function testParseHexString() - { - $c = new Color; - $c->parse('#b53717'); - $this->validateColor($c, 181, 55, 23, 1); - } - - public function testParseRgbaString() - { - $c = new Color; - $c->parse('rgba(181, 55, 23, 1)'); - $this->validateColor($c, 181, 55, 23, 1); - } - - public function testInitFromInteger() - { - $c = new Color; - $c->initFromInteger(0); - $this->validateColor($c, 0, 0, 0, 0); - $c->initFromInteger(2147483647); - $this->validateColor($c, 255, 255, 255, 0.5); - $c->initFromInteger(16777215); - $this->validateColor($c, 255, 255, 255, 0); - $c->initFromInteger(2130706432); - $this->validateColor($c, 0, 0, 0, 0.5); - $c->initFromInteger(867514135); - $this->validateColor($c, 181, 55, 23, 0.2); - } - - public function testInitFromArray() - { - $c = new Color; - $c->initFromArray([0, 0, 0, 0]); - $this->validateColor($c, 0, 0, 0, 0); - $c->initFromArray([0, 0, 0, 1]); - $this->validateColor($c, 0, 0, 0, 1); - $c->initFromArray([255, 255, 255, 1]); - $this->validateColor($c, 255, 255, 255, 1); - $c->initFromArray([255, 255, 255, 0]); - $this->validateColor($c, 255, 255, 255, 0); - $c->initFromArray([255, 255, 255, 0.5]); - $this->validateColor($c, 255, 255, 255, 0.5); - $c->initFromArray([0, 0, 0]); - $this->validateColor($c, 0, 0, 0, 1); - $c->initFromArray([255, 255, 255]); - $this->validateColor($c, 255, 255, 255, 1); - $c->initFromArray([181, 55, 23]); - $this->validateColor($c, 181, 55, 23, 1); - $c->initFromArray([181, 55, 23, 0.5]); - $this->validateColor($c, 181, 55, 23, 0.5); - } - - public function testInitFromHexString() - { - $c = new Color; - $c->initFromString('#cccccc'); - $this->validateColor($c, 204, 204, 204, 1); - $c->initFromString('#b53717'); - $this->validateColor($c, 181, 55, 23, 1); - $c->initFromString('ffffff'); - $this->validateColor($c, 255, 255, 255, 1); - $c->initFromString('ff00ff'); - $this->validateColor($c, 255, 0, 255, 1); - $c->initFromString('#000'); - $this->validateColor($c, 0, 0, 0, 1); - $c->initFromString('000'); - $this->validateColor($c, 0, 0, 0, 1); - } - - public function testInitFromRgbString() - { - $c = new Color; - $c->initFromString('rgb(1, 14, 144)'); - $this->validateColor($c, 1, 14, 144, 1); - $c->initFromString('rgb (255, 255, 255)'); - $this->validateColor($c, 255, 255, 255, 1); - $c->initFromString('rgb(0,0,0)'); - $this->validateColor($c, 0, 0, 0, 1); - $c->initFromString('rgba(0,0,0,0)'); - $this->validateColor($c, 0, 0, 0, 0); - $c->initFromString('rgba(0,0,0,0.5)'); - $this->validateColor($c, 0, 0, 0, 0.5); - $c->initFromString('rgba(255, 0, 0, 0.5)'); - $this->validateColor($c, 255, 0, 0, 0.5); - $c->initFromString('rgba(204, 204, 204, 0.9)'); - $this->validateColor($c, 204, 204, 204, 0.9); - } - - public function testInitFromRgb() - { - $c = new Color; - $c->initFromRgb(0, 0, 0); - $this->validateColor($c, 0, 0, 0, 1); - $c->initFromRgb(255, 255, 255); - $this->validateColor($c, 255, 255, 255, 1); - $c->initFromRgb(181, 55, 23); - $this->validateColor($c, 181, 55, 23, 1); - } - - public function testInitFromRgba() - { - $c = new Color; - $c->initFromRgba(0, 0, 0, 1); - $this->validateColor($c, 0, 0, 0, 1); - $c->initFromRgba(255, 255, 255, 1); - $this->validateColor($c, 255, 255, 255, 1); - $c->initFromRgba(181, 55, 23, 1); - $this->validateColor($c, 181, 55, 23, 1); - $c->initFromRgba(181, 55, 23, 0); - $this->validateColor($c, 181, 55, 23, 0); - $c->initFromRgba(181, 55, 23, 0.5); - $this->validateColor($c, 181, 55, 23, 0.5); - } - - public function testGetInt() - { - $c = new Color; - $i = $c->getInt(); - $this->assertInternalType('int', $i); - $this->assertEquals($i, 16777215); - - $c = new Color([255, 255, 255]); - $i = $c->getInt(); - $this->assertInternalType('int', $i); - $this->assertEquals($i, 4294967295); - - $c = new Color([255, 255, 255, 1]); - $i = $c->getInt(); - $this->assertInternalType('int', $i); - $this->assertEquals($i, 4294967295); - - $c = new Color([181, 55, 23, 0.2]); - $i = $c->getInt(); - $this->assertInternalType('int', $i); - $this->assertEquals($i, 867514135); - - $c = new Color([255, 255, 255, 0.5]); - $i = $c->getInt(); - $this->assertInternalType('int', $i); - $this->assertEquals($i, 2164260863); - - $c = new Color([181, 55, 23, 1]); - $i = $c->getInt(); - $this->assertInternalType('int', $i); - $this->assertEquals($i, 4290066199); - - $c = new Color([0, 0, 0, 0]); - $i = $c->getInt(); - $this->assertInternalType('int', $i); - $this->assertEquals($i, 0); - } - - public function testGetHex() - { - $c = new Color; - $i = $c->getHex(); - $this->assertInternalType('string', $i); - $this->assertEquals($i, 'ffffff'); - - $c = new Color([255, 255, 255, 1]); - $i = $c->getHex(); - $this->assertInternalType('string', $i); - $this->assertEquals($i, 'ffffff'); - - $c = new Color([181, 55, 23, 0.5]); - $i = $c->getHex(); - $this->assertInternalType('string', $i); - $this->assertEquals($i, 'b53717'); - - $c = new Color([0, 0, 0, 0]); - $i = $c->getHex('#'); - $this->assertInternalType('string', $i); - $this->assertEquals($i, '#000000'); - } - - public function testGetArray() - { - $c = new Color; - $i = $c->getArray(); - $this->assertInternalType('array', $i); - $this->assertEquals($i, [255, 255, 255, 0]); - - $c = new Color([255, 255, 255, 1]); - $i = $c->getArray(); - $this->assertInternalType('array', $i); - $this->assertEquals($i, [255, 255, 255, 1]); - - $c = new Color([181, 55, 23, 0.5]); - $i = $c->getArray(); - $this->assertInternalType('array', $i); - $this->assertEquals($i, [181, 55, 23, 0.5]); - - $c = new Color([0, 0, 0, 1]); - $i = $c->getArray(); - $this->assertInternalType('array', $i); - $this->assertEquals($i, [0, 0, 0, 1]); - } - - public function testGetRgba() - { - $c = new Color; - $i = $c->getRgba(); - $this->assertInternalType('string', $i); - $this->assertEquals($i, 'rgba(255, 255, 255, 0.00)'); - - $c = new Color([255, 255, 255, 1]); - $i = $c->getRgba(); - $this->assertInternalType('string', $i); - $this->assertEquals($i, 'rgba(255, 255, 255, 1.00)'); - - $c = new Color([181, 55, 23, 0.5]); - $i = $c->getRgba(); - $this->assertInternalType('string', $i); - $this->assertEquals($i, 'rgba(181, 55, 23, 0.50)'); - - $c = new Color([0, 0, 0, 1]); - $i = $c->getRgba(); - $this->assertInternalType('string', $i); - $this->assertEquals($i, 'rgba(0, 0, 0, 1.00)'); - - $c = new Color([255, 255, 255, 0.5]); - $i = $c->getRgba(); - $this->assertInternalType('string', $i); - $this->assertEquals($i, 'rgba(255, 255, 255, 0.50)'); - } - - public function testDiffers() - { - $c1 = new Color([0, 0, 0]); - $c2 = new Color([0, 0, 0]); - $this->assertEquals(false, $c1->differs($c2)); - - $c1 = new Color([1, 0, 0]); - $c2 = new Color([0, 0, 0]); - $this->assertEquals(true, $c1->differs($c2)); - - $c1 = new Color([1, 0, 0]); - $c2 = new Color([0, 0, 0]); - $this->assertEquals(false, $c1->differs($c2, 10)); - - $c1 = new Color([127, 127, 127]); - $c2 = new Color([0, 0, 0]); - $this->assertEquals(true, $c1->differs($c2, 49)); - - $c1 = new Color([127, 127, 127]); - $c2 = new Color([0, 0, 0]); - $this->assertEquals(false, $c1->differs($c2, 50)); - } - - /** - * @expectedException \Intervention\Image\Exception\NotReadableException - */ - public function testParseUnknown() - { - $c = new Color('xxxxxxxxxxxxxxxxxxxx'); - } - - private function validateColor($obj, $r, $g, $b, $a) - { - $this->assertInstanceOf('Intervention\Image\Imagick\Color', $obj); - $this->assertInstanceOf('ImagickPixel', $obj->pixel); - $this->assertEquals($r, round($obj->getRedValue(), 2)); - $this->assertEquals($g, round($obj->getGreenValue(), 2)); - $this->assertEquals($b, round($obj->getBlueValue(), 2)); - $this->assertEquals($a, round($obj->getAlphaValue(), 2)); - } -} diff --git a/tests/ImagickSystemTest.php b/tests/ImagickSystemTest.php deleted file mode 100644 index 25e961c6..00000000 --- a/tests/ImagickSystemTest.php +++ /dev/null @@ -1,1650 +0,0 @@ -manager()->make('tests/images/circle.png'); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInstanceOf('Imagick', $img->getCore()); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(50, $img->getWidth()); - $this->assertEquals(50, $img->getHeight()); - $this->assertEquals('image/png', $img->mime); - $this->assertEquals('tests/images', $img->dirname); - $this->assertEquals('circle.png', $img->basename); - $this->assertEquals('png', $img->extension); - $this->assertEquals('circle', $img->filename); - $this->assertEquals('image/png', $img->mime); - } - - public function testMakeFromString() - { - $str = file_get_contents('tests/images/circle.png'); - $img = $this->manager()->make($str); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInstanceOf('Imagick', $img->getCore()); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(50, $img->getWidth()); - $this->assertEquals(50, $img->getHeight()); - $this->assertEquals('image/png', $img->mime); - } - - public function testMakeFromImagick() - { - $imagick = new \Imagick; - $imagick->readImage('tests/images/circle.png'); - $img = $this->manager()->make($imagick); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInstanceOf('Imagick', $img->getCore()); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(50, $img->getWidth()); - $this->assertEquals(50, $img->getHeight()); - } - - public function testMakeFromDataUrl() - { - $str = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAGElEQVQYlWM8c+bMfwYiABMxikYVUk8hAHWzA3cRvs4UAAAAAElFTkSuQmCC'; - $img = $this->manager()->make($str); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInstanceOf('Imagick', $img->getCore()); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(10, $img->getWidth()); - $this->assertEquals(10, $img->getHeight()); - $this->assertEquals('image/png', $img->mime); - } - - public function testMakeFromBase64() - { - $str = 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAGElEQVQYlWM8c+bMfwYiABMxikYVUk8hAHWzA3cRvs4UAAAAAElFTkSuQmCC'; - $img = $this->manager()->make($str); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInstanceOf('Imagick', $img->getCore()); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(10, $img->getWidth()); - $this->assertEquals(10, $img->getHeight()); - $this->assertEquals('image/png', $img->mime); - } - - public function testMakeFromBase64WithNewlines() - { - $data = 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+' . "\n" . - '9AAAAGElEQVQYlWM8c+bMfwYiABMxikYVUk8hAHWzA3' . "\n" . - 'cRvs4UAAAAAElFTkSuQmCC'; - - $img = $this->manager()->make($data); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInstanceOf('Imagick', $img->getCore()); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(10, $img->getWidth()); - $this->assertEquals(10, $img->getHeight()); - $this->assertEquals('image/png', $img->mime); - } - - - public function testCanvas() - { - $img = $this->manager()->canvas(30, 20); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInstanceOf('Imagick', $img->getCore()); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(30, $img->getWidth()); - $this->assertEquals(20, $img->getHeight()); - $this->assertTransparentPosition($img, 0, 0); - } - - public function testCanvasWithSolidBackground() - { - $img = $this->manager()->canvas(30, 20, 'b53717'); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInstanceOf('Imagick', $img->getCore()); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(30, $img->getWidth()); - $this->assertEquals(20, $img->getHeight()); - $this->assertEquals('#b53717', $img->pickColor(15, 15, 'hex')); - } - - public function testGetSize() - { - $img = $this->manager()->make('tests/images/tile.png'); - $size = $img->getSize(); - $this->assertInstanceOf('Intervention\Image\Size', $size); - $this->assertInternalType('int', $size->width); - $this->assertInternalType('int', $size->height); - $this->assertEquals(16, $size->width); - $this->assertEquals(16, $size->height); - } - - public function testResizeImage() - { - $img = $this->manager()->make('tests/images/circle.png'); - $img->resize(120, 150); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInstanceOf('Imagick', $img->getCore()); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(120, $img->getWidth()); - $this->assertEquals(150, $img->getHeight()); - $this->assertTransparentPosition($img, 0, 0); - } - - public function testResizeImageOnlyWidth() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->resize(120, null); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInstanceOf('Imagick', $img->getCore()); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(120, $img->getWidth()); - $this->assertEquals(16, $img->getHeight()); - $this->assertTransparentPosition($img, 0, 15); - } - - public function testResizeImageOnlyHeight() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->resize(null, 150); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInstanceOf('Imagick', $img->getCore()); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(16, $img->getWidth()); - $this->assertEquals(150, $img->getHeight()); - $this->assertTransparentPosition($img, 15, 0); - } - - public function testResizeImageAutoHeight() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->resize(50, null, function ($constraint) { $constraint->aspectRatio(); }); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInstanceOf('Imagick', $img->getCore()); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(50, $img->getWidth()); - $this->assertEquals(50, $img->getHeight()); - $this->assertTransparentPosition($img, 30, 0); - } - - public function testResizeImageAutoWidth() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->resize(null, 50, function ($constraint) { $constraint->aspectRatio(); }); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInstanceOf('Imagick', $img->getCore()); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(50, $img->getWidth()); - $this->assertEquals(50, $img->getHeight()); - $this->assertTransparentPosition($img, 30, 0); - } - - public function testResizeDominantWidth() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->resize(100, 120, function ($constraint) { $constraint->aspectRatio(); }); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInstanceOf('Imagick', $img->getCore()); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(100, $img->getWidth()); - $this->assertEquals(100, $img->getHeight()); - $this->assertTransparentPosition($img, 60, 0); - } - - public function testResizeImagePreserveSimpleUpsizing() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->resize(100, 100, function ($constraint) { $constraint->aspectRatio(); $constraint->upsize(); }); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInstanceOf('Imagick', $img->getCore()); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(16, $img->getWidth()); - $this->assertEquals(16, $img->getHeight()); - $this->assertTransparentPosition($img, 15, 0); - } - - public function testWidenImage() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->widen(100); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInstanceOf('Imagick', $img->getCore()); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(100, $img->getWidth()); - $this->assertEquals(100, $img->getHeight()); - $this->assertTransparentPosition($img, 60, 0); - } - - public function testWidenImageWithConstraint() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->widen(100, function ($constraint) {$constraint->upsize();}); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInstanceOf('Imagick', $img->getCore()); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(16, $img->getWidth()); - $this->assertEquals(16, $img->getHeight()); - $this->assertTransparentPosition($img, 8, 0); - } - - public function testHeightenImage() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->heighten(100); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInstanceOf('Imagick', $img->getCore()); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(100, $img->getWidth()); - $this->assertEquals(100, $img->getHeight()); - $this->assertTransparentPosition($img, 60, 0); - } - - public function testHeightenImageWithConstraint() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->heighten(100, function ($constraint) {$constraint->upsize();}); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInstanceOf('Imagick', $img->getCore()); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(16, $img->getWidth()); - $this->assertEquals(16, $img->getHeight()); - $this->assertTransparentPosition($img, 8, 0); - } - - public function testResizeCanvasCenter() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->resizeCanvas(10, 10); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(10, $img->getWidth()); - $this->assertEquals(10, $img->getHeight()); - $this->assertColorAtPosition('#b4e000', $img, 0, 4); - $this->assertColorAtPosition('#445160', $img, 5, 5); - $this->assertTransparentPosition($img, 0, 5); - $this->assertTransparentPosition($img, 5, 4); - } - - public function testResizeCanvasTopLeft() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->resizeCanvas(10, 10, 'top-left'); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(10, $img->getWidth()); - $this->assertEquals(10, $img->getHeight()); - $this->assertColorAtPosition('#b4e000', $img, 0, 7); - $this->assertColorAtPosition('#445160', $img, 8, 8); - $this->assertTransparentPosition($img, 0, 8); - $this->assertTransparentPosition($img, 8, 7); - } - - public function testResizeCanvasTop() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->resizeCanvas(10, 10, 'top'); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(10, $img->getWidth()); - $this->assertEquals(10, $img->getHeight()); - $this->assertColorAtPosition('#b4e000', $img, 0, 7); - $this->assertColorAtPosition('#445160', $img, 5, 8); - $this->assertTransparentPosition($img, 0, 8); - $this->assertTransparentPosition($img, 5, 7); - } - - public function testResizeCanvasTopRight() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->resizeCanvas(10, 10, 'top-right'); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(10, $img->getWidth()); - $this->assertEquals(10, $img->getHeight()); - $this->assertColorAtPosition('#b4e000', $img, 0, 7); - $this->assertColorAtPosition('#445160', $img, 2, 8); - $this->assertTransparentPosition($img, 0, 8); - $this->assertTransparentPosition($img, 2, 7); - } - - public function testResizeCanvasLeft() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->resizeCanvas(10, 10, 'left'); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(10, $img->getWidth()); - $this->assertEquals(10, $img->getHeight()); - $this->assertColorAtPosition('#b4e000', $img, 0, 4); - $this->assertColorAtPosition('#445160', $img, 8, 5); - $this->assertTransparentPosition($img, 0, 5); - $this->assertTransparentPosition($img, 8, 4); - } - - public function testResizeCanvasRight() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->resizeCanvas(10, 10, 'right'); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(10, $img->getWidth()); - $this->assertEquals(10, $img->getHeight()); - $this->assertColorAtPosition('#b4e000', $img, 0, 4); - $this->assertColorAtPosition('#445160', $img, 2, 5); - $this->assertTransparentPosition($img, 0, 5); - $this->assertTransparentPosition($img, 2, 4); - } - - public function testResizeCanvasBottomLeft() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->resizeCanvas(10, 10, 'bottom-left'); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(10, $img->getWidth()); - $this->assertEquals(10, $img->getHeight()); - $this->assertColorAtPosition('#b4e000', $img, 0, 1); - $this->assertColorAtPosition('#445160', $img, 8, 2); - $this->assertTransparentPosition($img, 0, 2); - $this->assertTransparentPosition($img, 8, 1); - } - - public function testResizeCanvasBottomRight() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->resizeCanvas(10, 10, 'bottom-right'); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(10, $img->getWidth()); - $this->assertEquals(10, $img->getHeight()); - $this->assertColorAtPosition('#b4e000', $img, 0, 1); - $this->assertColorAtPosition('#445160', $img, 2, 2); - $this->assertTransparentPosition($img, 0, 2); - $this->assertTransparentPosition($img, 2, 1); - } - - public function testResizeCanvasBottom() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->resizeCanvas(10, 10, 'bottom'); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(10, $img->getWidth()); - $this->assertEquals(10, $img->getHeight()); - $this->assertColorAtPosition('#b4e000', $img, 0, 1); - $this->assertColorAtPosition('#445160', $img, 5, 2); - $this->assertTransparentPosition($img, 0, 2); - $this->assertTransparentPosition($img, 5, 1); - } - - public function testResizeCanvasRelativeWithBackground() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->resizeCanvas(4, 4, 'center', true, '#ff00ff'); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(20, $img->getWidth()); - $this->assertEquals(20, $img->getHeight()); - $this->assertColorAtPosition('#ff00ff', $img, 0, 0); - $this->assertColorAtPosition('#ff00ff', $img, 19, 19); - $this->assertColorAtPosition('#b4e000', $img, 2, 9); - $this->assertColorAtPosition('#445160', $img, 10, 10); - $this->assertTransparentPosition($img, 2, 10); - $this->assertTransparentPosition($img, 10, 9); - } - - public function testResizeCanvasJustWidth() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->resizeCanvas(10, null); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(10, $img->getWidth()); - $this->assertEquals(16, $img->getHeight()); - $this->assertColorAtPosition('#b4e000', $img, 0, 7); - $this->assertColorAtPosition('#445160', $img, 5, 8); - $this->assertTransparentPosition($img, 0, 8); - $this->assertTransparentPosition($img, 5, 7); - } - - public function testResizeCanvasJustHeight() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->resizeCanvas(null, 10); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(16, $img->getWidth()); - $this->assertEquals(10, $img->getHeight()); - $this->assertColorAtPosition('#b4e000', $img, 0, 4); - $this->assertColorAtPosition('#445160', $img, 8, 5); - $this->assertTransparentPosition($img, 0, 5); - $this->assertTransparentPosition($img, 8, 4); - } - - public function testResizeCanvasSmallerWidthLargerHeight() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->resizeCanvas(10, 20); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(10, $img->getWidth()); - $this->assertEquals(20, $img->getHeight()); - $this->assertColorAtPosition('#b4e000', $img, 0, 9); - $this->assertColorAtPosition('#445160', $img, 5, 10); - $this->assertTransparentPosition($img, 0, 10); - $this->assertTransparentPosition($img, 5, 9); - } - - public function testResizeCanvasLargerWidthSmallerHeight() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->resizeCanvas(20, 10); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(20, $img->getWidth()); - $this->assertEquals(10, $img->getHeight()); - $this->assertColorAtPosition('#b4e000', $img, 2, 4); - $this->assertColorAtPosition('#445160', $img, 10, 5); - $this->assertTransparentPosition($img, 0, 0); - $this->assertTransparentPosition($img, 2, 5); - $this->assertTransparentPosition($img, 10, 4); - } - - public function testResizeCanvasNegative() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->resizeCanvas(-4, -4); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(12, $img->getWidth()); - $this->assertEquals(12, $img->getHeight()); - $this->assertColorAtPosition('#b4e000', $img, 0, 5); - $this->assertColorAtPosition('#445160', $img, 6, 6); - $this->assertTransparentPosition($img, 0, 6); - $this->assertTransparentPosition($img, 6, 5); - } - - public function testResizeCanvasLargerHeightAutoWidth() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->resizeCanvas(null, 20, 'bottom-left', false, '#ff00ff'); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(16, $img->getWidth()); - $this->assertEquals(20, $img->getHeight()); - $this->assertColorAtPosition('#ff00ff', $img, 0, 0); - $this->assertColorAtPosition('#b4e000', $img, 0, 4); - $this->assertColorAtPosition('#b4e000', $img, 0, 11); - $this->assertColorAtPosition('#445160', $img, 8, 12); - $this->assertTransparentPosition($img, 0, 12); - $this->assertTransparentPosition($img, 8, 11); - } - - public function testResizeCanvasBorderNonRelative() - { - $img = $this->manager()->canvas(1, 1, 'ff0000'); - $img->resizeCanvas(17, 17, 'center', false, '333333'); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(17, $img->getWidth()); - $this->assertEquals(17, $img->getHeight()); - $this->assertColorAtPosition('#333333', $img, 0, 0); - $this->assertColorAtPosition('#333333', $img, 5, 5); - $this->assertColorAtPosition('#333333', $img, 7, 7); - $this->assertColorAtPosition('#ff0000', $img, 8, 8); - } - - public function testCropImage() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->crop(6, 6); // should be centered without pos. - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(6, $img->getWidth()); - $this->assertEquals(6, $img->getHeight()); - $this->assertColorAtPosition('#b4e000', $img, 0, 2); - $this->assertColorAtPosition('#445160', $img, 3, 3); - $this->assertTransparentPosition($img, 0, 3); - $this->assertTransparentPosition($img, 3, 2); - } - - public function testCropImageWithPosition() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->crop(4, 4, 7, 7); // should be centered without pos. - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(4, $img->getWidth()); - $this->assertEquals(4, $img->getHeight()); - $this->assertColorAtPosition('#b4e000', $img, 0, 0); - $this->assertColorAtPosition('#445160', $img, 1, 1); - $this->assertTransparentPosition($img, 0, 1); - $this->assertTransparentPosition($img, 1, 0); - } - - public function testFitImageSquare() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->fit(6); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(6, $img->getWidth()); - $this->assertEquals(6, $img->getHeight()); - $this->assertColorAtPosition('#b4e000', $img, 0, 2); - $this->assertColorAtPosition('#445160', $img, 3, 3); - $this->assertTransparentPosition($img, 0, 3); - $this->assertTransparentPosition($img, 3, 2); - } - - public function testFitImageRectangle() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->fit(12, 6); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(12, $img->getWidth()); - $this->assertEquals(6, $img->getHeight()); - $this->assertColorAtPosition('#b4e000', $img, 0, 2); - $this->assertColorAtPosition('#445160', $img, 6, 3); - $this->assertTransparentPosition($img, 0, 3); - $this->assertTransparentPosition($img, 6, 2); - } - - public function testFitImageWithConstraintUpsize() - { - $img = $this->manager()->make('tests/images/trim.png'); - $img->fit(300, 150, function ($constraint) {$constraint->upsize();}); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(50, $img->getWidth()); - $this->assertEquals(25, $img->getHeight()); - $this->assertColorAtPosition('#00aef0', $img, 0, 0); - $this->assertColorAtPosition('#afa94c', $img, 17, 0); - $this->assertColorAtPosition('#ffa601', $img, 24, 0); - } - - public function testFlipImageHorizontal() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->flip('h'); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(16, $img->getWidth()); - $this->assertEquals(16, $img->getHeight()); - $this->assertColorAtPosition('#b4e000', $img, 8, 7); - $this->assertColorAtPosition('#445160', $img, 0, 8); - $this->assertTransparentPosition($img, 0, 7); - $this->assertTransparentPosition($img, 8, 8); - } - - public function testFlipImageVertical() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->flip('v'); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(16, $img->getWidth()); - $this->assertEquals(16, $img->getHeight()); - $this->assertColorAtPosition('#b4e000', $img, 0, 8); - $this->assertColorAtPosition('#445160', $img, 8, 7); - $this->assertTransparentPosition($img, 0, 7); - $this->assertTransparentPosition($img, 8, 8); - } - - public function testRotateImage() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->rotate(90); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(16, $img->getWidth()); - $this->assertEquals(16, $img->getHeight()); - $this->assertColorAtPosition('#b4e000', $img, 0, 8); - $this->assertColorAtPosition('#445160', $img, 8, 7); - $this->assertTransparentPosition($img, 0, 7); - $this->assertTransparentPosition($img, 8, 8); - } - - public function testInsertImage() - { - $watermark = $this->manager()->canvas(16, 16, '#0000ff'); // create watermark - - // top-left anchor - $img = $this->manager()->canvas(32, 32, '#ff0000'); // create canvas - $img->insert($watermark, 'top-left', 0, 0); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals($img->getWidth(), 32); - $this->assertEquals($img->getHeight(), 32); - $this->assertEquals('#0000ff', $img->pickColor(0, 0, 'hex')); - $this->assertEquals('#ff0000', $img->pickColor(16, 16, 'hex')); - - // top-left anchor coordinates - $img = $this->manager()->canvas(32, 32, '#ff0000'); // create canvas - $img->insert($watermark, 'top-left', 10, 10); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals($img->getWidth(), 32); - $this->assertEquals($img->getHeight(), 32); - $this->assertEquals('#ff0000', $img->pickColor(9, 9, 'hex')); - $this->assertEquals('#0000ff', $img->pickColor(10, 10, 'hex')); - - // top anchor - $img = $this->manager()->canvas(32, 32, '#ff0000'); // create canvas - $img->insert($watermark, 'top', 0, 0); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals($img->getWidth(), 32); - $this->assertEquals($img->getHeight(), 32); - $this->assertEquals('#ff0000', $img->pickColor(0, 0, 'hex')); - $this->assertEquals('#0000ff', $img->pickColor(23, 15, 'hex')); - - // top anchor coordinates - $img = $this->manager()->canvas(32, 32, '#ff0000'); // create canvas - $img->insert($watermark, 'top', 10, 10); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals($img->getWidth(), 32); - $this->assertEquals($img->getHeight(), 32); - $this->assertEquals('#0000ff', $img->pickColor(18, 10, 'hex')); - $this->assertEquals('#ff0000', $img->pickColor(31, 26, 'hex')); - - // top-right anchor - $img = $this->manager()->canvas(32, 32, '#ff0000'); // create canvas - $img->insert($watermark, 'top-right', 0, 0); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals($img->getWidth(), 32); - $this->assertEquals($img->getHeight(), 32); - $this->assertEquals('#ff0000', $img->pickColor(15, 0, 'hex')); - $this->assertEquals('#0000ff', $img->pickColor(31, 0, 'hex')); - - // top-right anchor coordinates - $img = $this->manager()->canvas(32, 32, '#ff0000'); // create canvas - $img->insert($watermark, 'top-right', 10, 10); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals($img->getWidth(), 32); - $this->assertEquals($img->getHeight(), 32); - $this->assertEquals('#ff0000', $img->pickColor(6, 9, 'hex')); - $this->assertEquals('#0000ff', $img->pickColor(21, 25, 'hex')); - - // left anchor - $img = $this->manager()->canvas(32, 32, '#ff0000'); // create canvas - $img->insert($watermark, 'left', 0, 0); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals($img->getWidth(), 32); - $this->assertEquals($img->getHeight(), 32); - $this->assertEquals('#0000ff', $img->pickColor(15, 23, 'hex')); - $this->assertEquals('#ff0000', $img->pickColor(0, 7, 'hex')); - - // left anchor coordinates - $img = $this->manager()->canvas(32, 32, '#ff0000'); // create canvas - $img->insert($watermark, 'left', 10, 10); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals($img->getWidth(), 32); - $this->assertEquals($img->getHeight(), 32); - $this->assertEquals('#ff0000', $img->pickColor(8, 23, 'hex')); - $this->assertEquals('#ff0000', $img->pickColor(10, 7, 'hex')); - $this->assertEquals('#0000ff', $img->pickColor(25, 23, 'hex')); - $this->assertEquals('#0000ff', $img->pickColor(25, 8, 'hex')); - - // right anchor - $img = $this->manager()->canvas(32, 32, '#ff0000'); // create canvas - $img->insert($watermark, 'right', 0, 0); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals($img->getWidth(), 32); - $this->assertEquals($img->getHeight(), 32); - $this->assertEquals('#0000ff', $img->pickColor(31, 23, 'hex')); - $this->assertEquals('#ff0000', $img->pickColor(15, 15, 'hex')); - - // right anchor coordinates - $img = $this->manager()->canvas(32, 32, '#ff0000'); // create canvas - $img->insert($watermark, 'right', 10, 10); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals($img->getWidth(), 32); - $this->assertEquals($img->getHeight(), 32); - $this->assertEquals('#ff0000', $img->pickColor(5, 8, 'hex')); - $this->assertEquals('#ff0000', $img->pickColor(22, 23, 'hex')); - $this->assertEquals('#ff0000', $img->pickColor(21, 7, 'hex')); - $this->assertEquals('#0000ff', $img->pickColor(6, 8, 'hex')); - $this->assertEquals('#0000ff', $img->pickColor(21, 23, 'hex')); - $this->assertEquals('#0000ff', $img->pickColor(6, 23, 'hex')); - - // bottom-left anchor - $img = $this->manager()->canvas(32, 32, '#ff0000'); // create canvas - $img->insert($watermark, 'bottom-left', 0, 0); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals($img->getWidth(), 32); - $this->assertEquals($img->getHeight(), 32); - $this->assertEquals('#0000ff', $img->pickColor(15, 31, 'hex')); - $this->assertEquals('#ff0000', $img->pickColor(0, 15, 'hex')); - - // bottom-left anchor coordinates - $img = $this->manager()->canvas(32, 32, '#ff0000'); // create canvas - $img->insert($watermark, 'bottom-left', 10, 10); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals($img->getWidth(), 32); - $this->assertEquals($img->getHeight(), 32); - $this->assertEquals('#0000ff', $img->pickColor(10, 21, 'hex')); - $this->assertEquals('#ff0000', $img->pickColor(9, 20, 'hex')); - - // bottom anchor - $img = $this->manager()->canvas(32, 32, '#ff0000'); // create canvas - $img->insert($watermark, 'bottom', 0, 0); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals($img->getWidth(), 32); - $this->assertEquals($img->getHeight(), 32); - $this->assertEquals('#0000ff', $img->pickColor(8, 16, 'hex')); - $this->assertEquals('#ff0000', $img->pickColor(8, 15, 'hex')); - - // bottom anchor coordinates - $img = $this->manager()->canvas(32, 32, '#ff0000'); // create canvas - $img->insert($watermark, 'bottom', 10, 10); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals($img->getWidth(), 32); - $this->assertEquals($img->getHeight(), 32); - $this->assertEquals('#ff0000', $img->pickColor(5, 8, 'hex')); - $this->assertEquals('#ff0000', $img->pickColor(23, 22, 'hex')); - $this->assertEquals('#ff0000', $img->pickColor(24, 21, 'hex')); - $this->assertEquals('#ff0000', $img->pickColor(7, 6, 'hex')); - $this->assertEquals('#0000ff', $img->pickColor(8, 6, 'hex')); - $this->assertEquals('#0000ff', $img->pickColor(23, 21, 'hex')); - $this->assertEquals('#0000ff', $img->pickColor(23, 6, 'hex')); - - // bottom-right anchor - $img = $this->manager()->canvas(32, 32, '#ff0000'); // create canvas - $img->insert($watermark, 'bottom-right', 0, 0); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals($img->getWidth(), 32); - $this->assertEquals($img->getHeight(), 32); - $this->assertEquals('#0000ff', $img->pickColor(16, 16, 'hex')); - $this->assertEquals('#ff0000', $img->pickColor(15, 16, 'hex')); - - // bottom-right anchor coordinates - $img = $this->manager()->canvas(32, 32, '#ff0000'); // create canvas - $img->insert($watermark, 'bottom-right', 10, 10); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals($img->getWidth(), 32); - $this->assertEquals($img->getHeight(), 32); - $this->assertEquals('#0000ff', $img->pickColor(21, 21, 'hex')); - $this->assertEquals('#ff0000', $img->pickColor(22, 22, 'hex')); - - // center anchor - $img = $this->manager()->canvas(32, 32, '#ff0000'); // create canvas - $img->insert($watermark, 'center', 0, 0); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals($img->getWidth(), 32); - $this->assertEquals($img->getHeight(), 32); - $this->assertEquals('#0000ff', $img->pickColor(23, 23, 'hex')); - $this->assertEquals('#ff0000', $img->pickColor(8, 7, 'hex')); - - // center anchor coordinates / coordinates will be ignored for center - $img = $this->manager()->canvas(32, 32, '#ff0000'); // create canvas - $img->insert($watermark, 'center', 10, 10); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals($img->getWidth(), 32); - $this->assertEquals($img->getHeight(), 32); - $this->assertEquals('#0000ff', $img->pickColor(23, 23, 'hex')); - $this->assertEquals('#ff0000', $img->pickColor(8, 7, 'hex')); - } - - public function testInsertWithAlphaChannel() - { - $img = $this->manager()->canvas(50, 50, 'ff0000'); - $img->insert('tests/images/circle.png'); - $this->assertColorAtPosition('#ff0000', $img, 0, 0); - $this->assertColorAtPosition('#330000', $img, 30, 30); - } - - public function testInsertAfterResize() - { - $img = $this->manager()->make('tests/images/trim.png'); - $img->resize(16, 16)->insert('tests/images/tile.png'); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(16, $img->getWidth()); - $this->assertEquals(16, $img->getHeight()); - $this->assertColorAtPosition('#b4e000', $img, 0, 7); - $this->assertColorAtPosition('#00aef0', $img, 0, 8); - $this->assertColorAtPosition('#445160', $img, 8, 8); - $this->assertColorAtPosition('#ffa601', $img, 8, 7); - } - - public function testInsertImagick() - { - $imagick = new \Imagick; - $imagick->readImage('tests/images/tile.png'); - $img = $this->manager()->make('tests/images/trim.png'); - $img->insert($imagick); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertColorAtPosition('#b4e000', $img, 0, 7); - $this->assertColorAtPosition('#00aef0', $img, 0, 8); - $this->assertColorAtPosition('#445160', $img, 8, 8); - $this->assertColorAtPosition('#00aef0', $img, 8, 7); - $this->assertColorAtPosition('#ffa601', $img, 24, 24); - } - - public function testInsertBinary() - { - $data = file_get_contents('tests/images/tile.png'); - $img = $this->manager()->make('tests/images/trim.png'); - $img->insert($data); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertColorAtPosition('#b4e000', $img, 0, 7); - $this->assertColorAtPosition('#00aef0', $img, 0, 8); - $this->assertColorAtPosition('#445160', $img, 8, 8); - $this->assertColorAtPosition('#00aef0', $img, 8, 7); - $this->assertColorAtPosition('#ffa601', $img, 24, 24); - } - - public function testInsertInterventionImage() - { - $obj = $this->manager()->make('tests/images/tile.png'); - $img = $this->manager()->make('tests/images/trim.png'); - $img->insert($obj); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertColorAtPosition('#b4e000', $img, 0, 7); - $this->assertColorAtPosition('#00aef0', $img, 0, 8); - $this->assertColorAtPosition('#445160', $img, 8, 8); - $this->assertColorAtPosition('#00aef0', $img, 8, 7); - $this->assertColorAtPosition('#ffa601', $img, 24, 24); - } - - public function testOpacity() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->opacity(50); - $checkColor = $img->pickColor(7, 7, 'array'); - $this->assertEquals($checkColor[0], 180); - $this->assertEquals($checkColor[1], 224); - $this->assertEquals($checkColor[2], 0); - $this->assertEquals($checkColor[3], 0.5); - $checkColor = $img->pickColor(8, 8, 'array'); - $this->assertEquals($checkColor[0], 68); - $this->assertEquals($checkColor[1], 81); - $this->assertEquals($checkColor[2], 96); - $this->assertEquals($checkColor[3], 0.5); - $this->assertTransparentPosition($img, 0, 11); - } - - public function testMaskImage() - { - $img = $this->manager()->make('tests/images/trim.png'); - $img->mask('tests/images/gradient.png'); - $this->assertTransparentPosition($img, 0, 0); - $this->assertTransparentPosition($img, 18, 18); - $this->assertTransparentPosition($img, 23, 23); - $this->assertTransparentPosition($img, 30, 30); - $alpha = $img->pickColor(23, 24, 'array'); - $this->assertLessThan(1, $alpha[3]); - $this->assertGreaterThanOrEqual(0, $alpha[3]); - $alpha = $img->pickColor(35, 25, 'array'); - $this->assertLessThan(1, $alpha[3]); - $this->assertGreaterThanOrEqual(0, $alpha[3]); - $alpha = $img->pickColor(25, 42, 'array'); - $this->assertLessThan(1, $alpha[3]); - $this->assertGreaterThanOrEqual(0, $alpha[3]); - } - - public function testMaskImageWithAlpha() - { - $img = $this->manager()->make('tests/images/trim.png'); - $img->mask('tests/images/star.png', true); - $this->assertTransparentPosition($img, 0, 0); - $this->assertTransparentPosition($img, 16, 16); - $this->assertTransparentPosition($img, 36, 36); - $this->assertTransparentPosition($img, 47, 47); - $alpha = $img->pickColor(18, 18, 'array'); - $this->assertLessThan(1, $alpha[3]); - $this->assertGreaterThanOrEqual(0, $alpha[3]); - $alpha = $img->pickColor(22, 35, 'array'); - $this->assertLessThan(1, $alpha[3]); - $this->assertGreaterThanOrEqual(0, $alpha[3]); - } - - public function testPixelateImage() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->pixelate(20); - $this->assertInstanceOf('Intervention\Image\Image', $img); - } - - public function testGreyscaleImage() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->greyscale(); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertTransparentPosition($img, 8, 0); - $this->assertColorAtPosition('#707070', $img, 0, 0); - } - - public function testInvertImage() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->invert(); - $this->assertInstanceOf('Intervention\Image\Image', $img); - $this->assertTransparentPosition($img, 8, 0); - $this->assertColorAtPosition('#4b1fff', $img, 0, 0); - } - - public function testBlurImage() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->blur(1); - $this->assertInstanceOf('Intervention\Image\Image', $img); - } - - public function testFillImageWithColor() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->fill('b53717'); - $this->assertColorAtPosition('#b53717', $img, 0, 0); - $this->assertColorAtPosition('#b53717', $img, 15, 15); - } - - public function testFillImageWithColorAtPosition() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->fill('b53717', 0, 0); - $this->assertTransparentPosition($img, 0, 8); - $this->assertColorAtPosition('#b53717', $img, 0, 0); - $this->assertColorAtPosition('#445160', $img, 15, 15); - } - - public function testFillImageWithImagick() - { - $imagick = new \Imagick; - $imagick->readImage('tests/images/tile.png'); - $img = $this->manager()->make('tests/images/trim.png'); - $img->fill($imagick, 0, 0); - $this->assertColorAtPosition('#b4e000', $img, 0, 0); - $this->assertColorAtPosition('#445160', $img, 8, 8); - $this->assertColorAtPosition('#00aef0', $img, 8, 7); - $this->assertColorAtPosition('#ffa601', $img, 20, 20); - } - - public function testFillImageWithBinary() - { - $data = file_get_contents('tests/images/tile.png'); - $img = $this->manager()->make('tests/images/trim.png'); - $img->fill($data, 0, 0); - $this->assertColorAtPosition('#b4e000', $img, 0, 0); - $this->assertColorAtPosition('#445160', $img, 8, 8); - $this->assertColorAtPosition('#00aef0', $img, 8, 7); - $this->assertColorAtPosition('#ffa601', $img, 20, 20); - } - - public function testFillImageWithInterventionImage() - { - $obj = $this->manager()->make('tests/images/tile.png'); - $img = $this->manager()->make('tests/images/trim.png'); - $img->fill($obj, 0, 0); - $this->assertColorAtPosition('#b4e000', $img, 0, 0); - $this->assertColorAtPosition('#445160', $img, 8, 8); - $this->assertColorAtPosition('#00aef0', $img, 8, 7); - $this->assertColorAtPosition('#ffa601', $img, 20, 20); - } - - public function testPixelImage() - { - $img = $this->manager()->make('tests/images/tile.png'); - $coords = [[5, 5], [12, 12]]; - $img = $img->pixel('fdf5e4', $coords[0][0], $coords[0][1]); - $img = $img->pixel([255, 255, 255], $coords[1][0], $coords[1][1]); - $this->assertEquals('#fdf5e4', $img->pickColor($coords[0][0], $coords[0][1], 'hex')); - $this->assertEquals('#ffffff', $img->pickColor($coords[1][0], $coords[1][1], 'hex')); - } - - public function testRectangleImage() - { - $img = $this->manager()->canvas(16, 16, 'ffffff'); - $img->rectangle(5, 5, 11, 11, function ($draw) { $draw->background('#ff0000'); $draw->border(1, '#0000ff'); }); - $this->assertEquals('32ceca9759d1973dd461b39664df604d', $img->checksum()); - } - - public function testLineImage() - { - $img = $this->manager()->canvas(16, 16, 'ffffff'); - $img->line(0, 0, 15, 15, function ($draw) { $draw->color('#ff0000'); }); - $this->assertEquals('f5c585019bff361d91e2928b2ac2286b', $img->checksum()); - } - - public function testEllipseImage() - { - $img = $this->manager()->canvas(16, 16, 'ffffff'); - $img->ellipse(12, 8, 8, 8, function ($draw) { $draw->background('#ff0000'); $draw->border(1, '#0000ff'); }); - $this->assertEquals('9dc5bbec6d45868610c082a1d67640b5', $img->checksum()); - } - - public function testCircleImage() - { - $img = $this->manager()->canvas(16, 16, 'ffffff'); - $img->circle(12, 8, 8, function ($draw) { $draw->background('#ff0000'); $draw->border(1, '#0000ff'); }); - $this->assertEquals('a433c7c1a842ef83e1cb45875371358c', $img->checksum()); - } - - public function testPolygonImage() - { - $img = $this->manager()->canvas(16, 16, 'ffffff'); - $points = [3, 3, 11, 11, 7, 13]; - $img->polygon($points, function ($draw) { $draw->background('#ff0000'); $draw->border(1, '#0000ff'); }); - $this->assertEquals('e301afe179da858d441ad8fc0eb5490a', $img->checksum()); - } - - public function testResetImage() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->backup(); - $img->resize(30, 20); - $img->reset(); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(16, $img->getWidth()); - $this->assertEquals(16, $img->getHeight()); - } - - public function testResetEmptyImage() - { - $img = $this->manager()->canvas(16, 16, '#0000ff'); - $img->backup(); - $img->resize(30, 20); - $img->fill('#ff0000'); - $img->reset(); - $this->assertInternalType('int', $img->getWidth()); - $this->assertInternalType('int', $img->getHeight()); - $this->assertEquals(16, $img->getWidth()); - $this->assertEquals(16, $img->getHeight()); - $this->assertColorAtPosition('#0000ff', $img, 0, 0); - } - - public function testResetKeepTransparency() - { - $img = $this->manager()->make('tests/images/circle.png'); - $img->backup(); - $img->reset(); - $this->assertTransparentPosition($img, 0, 0); - } - - public function testResetToNamed() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->backup('original'); - $img->resize(30, 20); - $img->backup('30x20'); - - // reset to original - $img->reset('original'); - $this->assertEquals(16, $img->getWidth()); - $this->assertEquals(16, $img->getHeight()); - - // reset to 30x20 - $img->reset('30x20'); - $this->assertEquals(30, $img->getWidth()); - $this->assertEquals(20, $img->getHeight()); - - // reset to original again - $img->reset('original'); - $this->assertEquals(16, $img->getWidth()); - $this->assertEquals(16, $img->getHeight()); - } - - public function testLimitColors() - { - $img = $this->manager()->make('tests/images/trim.png'); - $img->limitColors(4); - $this->assertLessThanOrEqual(5, $img->getCore()->getImageColors()); - } - - public function testLimitColorsKeepTransparency() - { - $img = $this->manager()->make('tests/images/star.png'); - $img->limitColors(16); - $this->assertLessThanOrEqual(17, $img->getCore()->getImageColors()); - $this->assertTransparentPosition($img, 0, 0); - $this->assertColorAtPosition('#680098', $img, 6, 12); - $this->assertColorAtPosition('#c2596a', $img, 22, 24); - } - - public function testLimitColorsKeepTransparencyWithMatte() - { - $img = $this->manager()->make('tests/images/star.png'); - $img->limitColors(32, '#00ff00'); - $this->assertLessThanOrEqual(33, $img->getCore()->getImageColors()); - $this->assertTransparentPosition($img, 0, 0); - $this->assertColorAtPosition('#00ff00', $img, 12, 10); - $this->assertColorAtPosition('#00ff00', $img, 22, 17); - $this->assertColorAtPosition('#e70012', $img, 16, 21); - } - - public function testLimitColorsNullWithMatte() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->limitColors(null, '#ff00ff'); - $this->assertColorAtPosition('#b4e000', $img, 0, 0); - $this->assertColorAtPosition('#445160', $img, 8, 8); - $this->assertColorAtPosition('#ff00ff', $img, 0, 8); - $this->assertColorAtPosition('#ff00ff', $img, 15, 0); - } - - public function testPickColorFromTrueColor() - { - $img = $this->manager()->make('tests/images/star.png'); - $c = $img->pickColor(0, 0); - $this->assertEquals(255, $c[0]); - $this->assertEquals(255, $c[1]); - $this->assertEquals(255, $c[2]); - $this->assertEquals(0, $c[3]); - - $c = $img->pickColor(11, 11); - $this->assertEquals(34, $c[0]); - $this->assertEquals(0, $c[1]); - $this->assertEquals(160, $c[2]); - $this->assertEquals(0.47, $c[3]); - - $c = $img->pickColor(16, 16); - $this->assertEquals(231, $c[0]); - $this->assertEquals(0, $c[1]); - $this->assertEquals(18, $c[2]); - $this->assertEquals(1, $c[3]); - } - - public function testPickColorFromIndexed() - { - $img = $this->manager()->make('tests/images/tile.png'); - $c = $img->pickColor(0, 0); - $this->assertEquals(180, $c[0]); - $this->assertEquals(224, $c[1]); - $this->assertEquals(0, $c[2]); - $this->assertEquals(1, $c[3]); - - $c = $img->pickColor(8, 8); - $this->assertEquals(68, $c[0]); - $this->assertEquals(81, $c[1]); - $this->assertEquals(96, $c[2]); - $this->assertEquals(1, $c[3]); - - $c = $img->pickColor(0, 15); - $this->assertEquals(0, $c[0]); - $this->assertEquals(0, $c[1]); - $this->assertEquals(0, $c[2]); - $this->assertEquals(0, $c[3]); - } - - public function testPickColorFromPalette() - { - $img = $this->manager()->make('tests/images/tile.png'); - $img->getCore()->quantizeImage(200, \Imagick::COLORSPACE_RGB, 0, false, false); - - $c = $img->pickColor(0, 0); - $this->assertEquals(180, $c[0]); - $this->assertEquals(224, $c[1]); - $this->assertEquals(0, $c[2]); - $this->assertEquals(1, $c[3]); - - $c = $img->pickColor(8, 8); - $this->assertEquals(68, $c[0]); - $this->assertEquals(81, $c[1]); - $this->assertEquals(96, $c[2]); - $this->assertEquals(1, $c[3]); - - $c = $img->pickColor(0, 15); - $this->assertEquals(0, $c[0]); - $this->assertEquals(0, $c[1]); - $this->assertEquals(0, $c[2]); - $this->assertEquals(0, $c[3]); - } - - public function testInterlaceImage() - { - $img = $this->manager()->make('tests/images/trim.png'); - $img->interlace(); - $img->encode('png'); - $this->assertTrue((ord($img->encoded[28]) != '0')); - $img->interlace(false); - $img->encode('png'); - $this->assertFalse((ord($img->encoded[28]) != '0')); - } - - public function testGammaImage() - { - $img = $this->manager()->make('tests/images/trim.png'); - $img->gamma(1.6); - $this->assertColorAtPosition('#00c9f6', $img, 0, 0); - $this->assertColorAtPosition('#ffc308', $img, 24, 24); - } - - public function testBrightnessImage() - { - $img = $this->manager()->make('tests/images/trim.png'); - $img->brightness(35); - $this->assertColorAtPosition('#45ccff', $img, 0, 0); - $this->assertColorAtPosition('#ffc55b', $img, 24, 24); - } - - public function testContrastImage() - { - $img = $this->manager()->make('tests/images/trim.png'); - $img->contrast(35); - $this->assertColorAtPosition('#00feff', $img, 0, 0); - $this->assertColorAtPosition('#fffd04', $img, 24, 24); - } - - public function testColorizeImage() - { - $img = $this->manager()->make('tests/images/trim.png'); - $img->colorize(40, 25, -50); - $this->assertColorAtPosition('#00ece2', $img, 0, 0); - $this->assertColorAtPosition('#ffea00', $img, 24, 24); - } - - public function testTrimGradient() - { - $canvas = $this->manager()->make('tests/images/gradient.png'); - - $img = clone $canvas; - $img->trim(); - $this->assertEquals($img->getWidth(), 46); - $this->assertEquals($img->getHeight(), 46); - - $img = clone $canvas; - $img->trim(null, null, 10); - $this->assertEquals($img->getWidth(), 38); - $this->assertEquals($img->getHeight(), 38); - - $img = clone $canvas; - $img->trim(null, null, 20); - $this->assertEquals($img->getWidth(), 34); - $this->assertEquals($img->getHeight(), 34); - - $img = clone $canvas; - $img->trim(null, null, 30); - $this->assertEquals($img->getWidth(), 30); - $this->assertEquals($img->getHeight(), 30); - - $img = clone $canvas; - $img->trim(null, null, 40); - $this->assertEquals($img->getWidth(), 26); - $this->assertEquals($img->getHeight(), 26); - - $img = clone $canvas; - $img->trim(null, null, 50); - $this->assertEquals($img->getWidth(), 22); - $this->assertEquals($img->getHeight(), 22); - - $img = clone $canvas; - $img->trim(null, null, 60); - $this->assertEquals($img->getWidth(), 20); - $this->assertEquals($img->getHeight(), 20); - - $img = clone $canvas; - $img->trim(null, null, 70); - $this->assertEquals($img->getWidth(), 16); - $this->assertEquals($img->getHeight(), 16); - - $img = clone $canvas; - $img->trim(null, null, 80); - $this->assertEquals($img->getWidth(), 12); - $this->assertEquals($img->getHeight(), 12); - - $img = clone $canvas; - $img->trim(null, null, 90); - $this->assertEquals($img->getWidth(), 8); - $this->assertEquals($img->getHeight(), 8); - } - - public function testTrimOnlyLeftAndRight() - { - $img = $this->manager()->make('tests/images/gradient.png'); - $img->trim(null, ['left', 'right'], 60); - $this->assertEquals($img->getWidth(), 20); - $this->assertEquals($img->getHeight(), 50); - } - - public function testTrimOnlyTopAndBottom() - { - $img = $this->manager()->make('tests/images/gradient.png'); - $img->trim(null, ['top', 'bottom'], 60); - $this->assertEquals($img->getWidth(), 50); - $this->assertEquals($img->getHeight(), 20); - } - - public function testTrimOnlyTop() - { - $img = $this->manager()->make('tests/images/gradient.png'); - $img->trim(null, 'top', 60); - $this->assertEquals($img->getWidth(), 50); - $this->assertEquals($img->getHeight(), 35); - } - - public function testTrimOnlyBottom() - { - $img = $this->manager()->make('tests/images/gradient.png'); - $img->trim(null, 'top', 60); - $this->assertEquals($img->getWidth(), 50); - $this->assertEquals($img->getHeight(), 35); - } - - public function testTrimWithFeather() - { - $img = $this->manager()->make('tests/images/trim.png'); - $feather = 5; - $img->trim(null, null, null, $feather); - $this->assertEquals($img->getWidth(), 28 + $feather * 2); - $this->assertEquals($img->getHeight(), 28 + $feather * 2); - $img->destroy(); - - $img = $this->manager()->make('tests/images/trim.png'); - $feather = 10; - $img->trim(null, null, null, $feather); - $this->assertEquals($img->getWidth(), 28 + $feather * 2); - $this->assertEquals($img->getHeight(), 28 + $feather * 2); - $img->destroy(); - - $img = $this->manager()->make('tests/images/trim.png'); - $feather = 20; // must respect original dimensions of image - $img->trim(null, null, null, $feather); - $this->assertEquals($img->getWidth(), 50); - $this->assertEquals($img->getHeight(), 50); - $img->destroy(); - - $img = $this->manager()->make('tests/images/trim.png'); - $feather = -5; - $img->trim(null, null, null, $feather); - $this->assertEquals($img->getWidth(), 28 + $feather * 2); - $this->assertEquals($img->getHeight(), 28 + $feather * 2); - $img->destroy(); - - $img = $this->manager()->make('tests/images/trim.png'); - $feather = -10; - $img->trim(null, null, null, $feather); - $this->assertEquals($img->getWidth(), 28 + $feather * 2); - $this->assertEquals($img->getHeight(), 28 + $feather * 2); - $img->destroy(); - - // trim only left and right with feather - $img = $this->manager()->make('tests/images/trim.png'); - $feather = 10; - $img->trim(null, ['left', 'right'], null, $feather); - $this->assertEquals($img->getWidth(), 28 + $feather * 2); - $this->assertEquals($img->getHeight(), 50); - $img->destroy(); - - // trim only top and bottom with feather - $img = $this->manager()->make('tests/images/trim.png'); - $feather = 10; - $img->trim(null, ['top', 'bottom'], null, $feather); - $this->assertEquals($img->getWidth(), 50); - $this->assertEquals($img->getHeight(), 28 + $feather * 2); - $img->destroy(); - - // trim with tolerance and feather - $img = $this->manager()->make('tests/images/gradient.png'); - $feather = 2; - $img->trim(null, null, 10, $feather); - $this->assertEquals($img->getWidth(), 38 + $feather * 2); - $this->assertEquals($img->getHeight(), 38 + $feather * 2); - $img->destroy(); - - $img = $this->manager()->make('tests/images/gradient.png'); - $feather = 5; - $img->trim(null, null, 10, $feather); - $this->assertEquals($img->getWidth(), 38 + $feather * 2); - $this->assertEquals($img->getHeight(), 38 + $feather * 2); - $img->destroy(); - - $img = $this->manager()->make('tests/images/gradient.png'); - $feather = 10; // should respect original dimensions - $img->trim(null, null, 20, $feather); - $this->assertEquals($img->getWidth(), 50); - $this->assertEquals($img->getHeight(), 50); - $img->destroy(); - } - - public function testEncodeDefault() - { - $img = $this->manager()->make('tests/images/trim.png'); - $img->encode(); - $mime = finfo_buffer(finfo_open(FILEINFO_MIME_TYPE), $img->encoded); - $this->assertEquals('image/png', $mime); - } - - public function testEncodeJpeg() - { - $img = $this->manager()->make('tests/images/trim.png'); - $img->encode('jpg'); - $mime = finfo_buffer(finfo_open(FILEINFO_MIME_TYPE), $img->encoded); - $this->assertEquals('image/jpeg', $mime); - } - - public function testEncodeGif() - { - $img = $this->manager()->make('tests/images/trim.png'); - $img->encode('gif'); - $mime = finfo_buffer(finfo_open(FILEINFO_MIME_TYPE), $img->encoded); - $this->assertEquals('image/gif', $mime); - } - - public function testEncodeDataUrl() - { - $img = $this->manager()->make('tests/images/trim.png'); - $img->encode('data-url'); - $this->assertEquals('data:image/png;base64', substr($img->encoded, 0, 21)); - } - - public function testExifReadAll() - { - $img = $this->manager()->make('tests/images/exif.jpg'); - $data = $img->exif(); - $this->assertInternalType('array', $data); - $this->assertGreaterThanOrEqual(13, count($data)); - } - - public function testExifReadKey() - { - $img = $this->manager()->make('tests/images/exif.jpg'); - $data = $img->exif('Artist'); - $this->assertInternalType('string', $data); - $this->assertEquals('Oliver Vogel', $data); - } - - public function testExifReadNotExistingKey() - { - $img = $this->manager()->make('tests/images/exif.jpg'); - $data = $img->exif('xxx'); - $this->assertEquals(null, $data); - } - - public function testSaveImage() - { - $save_as = 'tests/tmp/foo.jpg'; - $img = $this->manager()->make('tests/images/trim.png'); - $img->save($save_as, 80); - $this->assertFileExists($save_as); - $this->assertEquals($img->dirname, 'tests/tmp'); - $this->assertEquals($img->basename, 'foo.jpg'); - $this->assertEquals($img->extension, 'jpg'); - $this->assertEquals($img->filename, 'foo'); - $this->assertEquals($img->mime, 'image/jpeg'); - @unlink($save_as); - - $save_as = 'tests/tmp/foo.png'; - $img = $this->manager()->make('tests/images/trim.png'); - $img->save($save_as); - $this->assertEquals($img->dirname, 'tests/tmp'); - $this->assertEquals($img->basename, 'foo.png'); - $this->assertEquals($img->extension, 'png'); - $this->assertEquals($img->filename, 'foo'); - $this->assertEquals($img->mime, 'image/png'); - $this->assertFileExists($save_as); - @unlink($save_as); - - $save_as = 'tests/tmp/foo.jpg'; - $img = $this->manager()->make('tests/images/trim.png'); - $img->save($save_as, 0); - $this->assertEquals($img->dirname, 'tests/tmp'); - $this->assertEquals($img->basename, 'foo.jpg'); - $this->assertEquals($img->extension, 'jpg'); - $this->assertEquals($img->filename, 'foo'); - $this->assertEquals($img->mime, 'image/jpeg'); - $this->assertFileExists($save_as); - @unlink($save_as); - } - - public function testSaveImageWithoutParameter() - { - $path = 'tests/tmp/bar.png'; - - // create temp. test image (red) - $img = $this->manager()->canvas(16, 16, '#ff0000'); - $img->save($path); - $img->destroy(); - - // open test image again - $img = $this->manager()->make($path); - $this->assertColorAtPosition('#ff0000', $img, 0, 0); - - // fill with green and save wthout paramater - $img->fill('#00ff00'); - $img->save(); - $img->destroy(); - - // re-open test image (should be green) - $img = $this->manager()->make($path); - $this->assertColorAtPosition('#00ff00', $img, 0, 0); - $img->destroy(); - - @unlink($path); - } - - /** - * @expectedException ImagickException - */ - public function testDestroy() - { - $img = $this->manager()->make('tests/images/trim.png'); - $img->destroy(); - $img->getCore()->getImageWidth(); // try to get width (should throw exception) - } - - /** - * @expectedException Exception - */ - public function testDestroyWithBackup() - { - $img = $this->manager()->make('tests/images/trim.png'); - $img->backup(); - $img->destroy(); - $img->getBackup()->getImageWidth(); // try to get width (should throw exception) - } - - public function testStringConversion() - { - $img = $this->manager()->make('tests/images/trim.png'); - $value = strval($img); - $this->assertInternalType('string', $value); - } - - public function testFilter() - { - $img = $this->manager()->make('tests/images/trim.png'); - $img->filter(new \Intervention\Image\Filters\DemoFilter(10)); - $this->assertInstanceOf('Intervention\Image\Image', $img); - } - - public function testCloneImageObject() - { - $img = $this->manager()->make('tests/images/trim.png'); - $cln = clone $img; - - // destroy original - $img->destroy(); - unset($img); - - // clone should be still intact - $this->assertInstanceOf('Intervention\Image\Image', $cln); - $this->assertInstanceOf('Imagick', $cln->getCore()); - } - - public function testGifConversionKeepsTransparency() - { - $save_as = 'tests/tmp/foo.gif'; - - // create gif image from transparent png - $img = $this->manager()->make('tests/images/star.png'); - $img->save($save_as); - - // new gif image should be transparent - $img = $this->manager()->make($save_as); - $this->assertTransparentPosition($img, 0, 0); - @unlink($save_as); - } - - private function assertColorAtPosition($color, $img, $x, $y) - { - $pick = $img->pickColor($x, $y, 'hex'); - $this->assertEquals($color, $pick); - $this->assertInstanceOf('Intervention\Image\Image', $img); - } - - private function assertTransparentPosition($img, $x, $y, $transparent = 0) - { - // background should be transparent - $color = $img->pickColor($x, $y, 'array'); - $this->assertEquals($transparent, $color[3]); // alpha channel - } - - private function manager() - { - return new \Intervention\Image\ImageManager([ - 'driver' => 'imagick' - ]); - } -} diff --git a/tests/InsertCommandTest.php b/tests/InsertCommandTest.php deleted file mode 100644 index fa0b521c..00000000 --- a/tests/InsertCommandTest.php +++ /dev/null @@ -1,67 +0,0 @@ -shouldReceive('align')->with('center', 10, 20)->once()->andReturn($image_size); - $watermark_size = Mockery::mock('\Intervention\Image\Size', [800, 600]); - $watermark_size->shouldReceive('align')->with('center')->once()->andReturn($watermark_size); - $image_size->shouldReceive('relativePosition')->with($watermark_size)->once()->andReturn($position); - - $path = __DIR__.'/images/test.jpg'; - $resource = imagecreatefromjpeg($path); - $watermark = Mockery::mock('Intervention\Image\Image'); - $driver = Mockery::mock('Intervention\Image\Gd\Driver'); - $driver->shouldReceive('init')->with($path)->once()->andReturn($watermark); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getDriver')->once()->andReturn($driver); - $image->shouldReceive('getCore')->times(2)->andReturn($resource); - $image->shouldReceive('getSize')->once()->andReturn($image_size); - $watermark->shouldReceive('getSize')->once()->andReturn($watermark_size); - $watermark->shouldReceive('getCore')->once()->andReturn($resource); - - $command = new InsertGd([$path, 'center', 10, 20]); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagick() - { - $position = Mockery::mock('\Intervention\Image\Point', [10, 20]); - - $image_size = Mockery::mock('\Intervention\Image\Size', [800, 600]); - $image_size->shouldReceive('align')->with('center', 10, 20)->once()->andReturn($image_size); - $watermark_size = Mockery::mock('\Intervention\Image\Size', [800, 600]); - $watermark_size->shouldReceive('align')->with('center')->once()->andReturn($watermark_size); - $image_size->shouldReceive('relativePosition')->with($watermark_size)->once()->andReturn($position); - - $path = __DIR__.'/images/test.jpg'; - $watermark = Mockery::mock('Intervention\Image\Image'); - $driver = Mockery::mock('Intervention\Image\Imagick\Driver'); - $driver->shouldReceive('init')->with($path)->once()->andReturn($watermark); - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('compositeimage')->with($imagick, \Imagick::COMPOSITE_DEFAULT, 10, 20)->andReturn(true); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - $image->shouldReceive('getDriver')->once()->andReturn($driver); - $image->shouldReceive('getSize')->once()->andReturn($image_size); - $watermark->shouldReceive('getSize')->once()->andReturn($watermark_size); - $watermark->shouldReceive('getCore')->once()->andReturn($imagick); - $command = new InsertImagick([$path, 'center', 10, 20]); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/InterlaceCommandTest.php b/tests/InterlaceCommandTest.php deleted file mode 100644 index 907bc2cb..00000000 --- a/tests/InterlaceCommandTest.php +++ /dev/null @@ -1,34 +0,0 @@ -shouldReceive('getCore')->once()->andReturn($resource); - $command = new InterlaceGd([true]); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagick() - { - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('setinterlacescheme')->with(\Imagick::INTERLACE_LINE)->andReturn(true); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - $command = new InterlaceImagick([true]); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/InvertCommandTest.php b/tests/InvertCommandTest.php deleted file mode 100644 index 3cad4dda..00000000 --- a/tests/InvertCommandTest.php +++ /dev/null @@ -1,34 +0,0 @@ -shouldReceive('getCore')->once()->andReturn($resource); - $command = new InvertGd([]); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagick() - { - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('negateimage')->with(false)->andReturn(true); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - $command = new InvertImagick([]); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/IptcCommandTest.php b/tests/IptcCommandTest.php deleted file mode 100644 index 27c1ef34..00000000 --- a/tests/IptcCommandTest.php +++ /dev/null @@ -1,72 +0,0 @@ -dirname = __DIR__.'/images'; - $image->basename = 'iptc.jpg'; - $command = new IptcCommand([]); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertTrue($command->hasOutput()); - $this->assertInternalType('array', $command->getOutput()); - } - - public function testFetchDefined() - { - $image = Mockery::mock('Intervention\Image\Image'); - $image->dirname = __DIR__.'/images'; - $image->basename = 'exif.jpg'; - $command = new IptcCommand(['AuthorByline']); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertTrue($command->hasOutput()); - $this->assertEquals('Oliver Vogel', $command->getOutput()); - } - - - public function testFetchNonExisting() - { - $image = Mockery::mock('Intervention\Image\Image'); - $image->dirname = __DIR__.'/images'; - $image->basename = 'exif.jpg'; - $command = new IptcCommand(['xxx']); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertTrue($command->hasOutput()); - $this->assertEquals(null, $command->getOutput()); - } - - - public function testFetchFromPng() - { - $image = Mockery::mock('Intervention\Image\Image'); - $image->dirname = __DIR__.'/images'; - $image->basename = 'star.png'; - $command = new IptcCommand(['Orientation']); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertTrue($command->hasOutput()); - $this->assertEquals(null, $command->getOutput()); - } - - public function testReturnNullOnIptcReadFail() - { - $image = Mockery::mock('Intervention\Image\Image'); - $command = new IptcCommand(['Orientation']); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertTrue($command->hasOutput()); - $this->assertEquals(null, $command->getOutput()); - } -} diff --git a/tests/LimitColorsCommandTest.php b/tests/LimitColorsCommandTest.php deleted file mode 100644 index e76d57a4..00000000 --- a/tests/LimitColorsCommandTest.php +++ /dev/null @@ -1,43 +0,0 @@ -shouldReceive('getCore')->once()->andReturn($resource); - $image->shouldReceive('setCore')->once(); - $image->shouldReceive('getSize')->once()->andReturn($size); - $command = new LimitColorsGd([16]); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagick() - { - $size = Mockery::mock('\Intervention\Image\Size', [32, 32]); - $imagick = Mockery::mock('\Imagick'); - $imagick->shouldReceive('separateimagechannel')->with(\Imagick::CHANNEL_ALPHA)->times(2); - $imagick->shouldReceive('transparentpaintimage')->with('#ffffff', 0, 0, false)->once(); - $imagick->shouldReceive('negateimage')->with(false)->once(); - $imagick->shouldReceive('quantizeimage')->with(16, \Imagick::COLORSPACE_RGB, 0, false, false)->once(); - $imagick->shouldReceive('compositeimage')->once(); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getSize')->once()->andReturn($size); - $image->shouldReceive('getCore')->times(3)->andReturn($imagick); - $command = new LimitColorsImagick([16]); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/LineCommandTest.php b/tests/LineCommandTest.php deleted file mode 100644 index 2dadb2a0..00000000 --- a/tests/LineCommandTest.php +++ /dev/null @@ -1,43 +0,0 @@ -shouldReceive('getDriverName')->once()->andReturn('Gd'); - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getDriver')->once()->andReturn($driver); - $image->shouldReceive('getCore')->once()->andReturn($resource); - $command = new LineCommand([10, 15, 100, 150]); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertFalse($command->hasOutput()); - } - - public function testImagick() - { - $imagick = Mockery::mock('\Imagick'); - $imagick->shouldReceive('drawimage'); - $driver = Mockery::mock('\Intervention\Image\Imagick\Driver'); - $driver->shouldReceive('getDriverName')->once()->andReturn('Imagick'); - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getDriver')->once()->andReturn($driver); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - - $command = new LineCommand([10, 15, 100, 150]); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertFalse($command->hasOutput()); - } - -} diff --git a/tests/LineShapeTest.php b/tests/LineShapeTest.php deleted file mode 100644 index b95f71bf..00000000 --- a/tests/LineShapeTest.php +++ /dev/null @@ -1,50 +0,0 @@ -assertInstanceOf('Intervention\Image\Gd\Shapes\LineShape', $line); - $this->assertEquals(10, $line->x); - $this->assertEquals(15, $line->y); - - // imagick - $line = new LineImagick(10, 15); - $this->assertInstanceOf('Intervention\Image\Imagick\Shapes\LineShape', $line); - $this->assertEquals(10, $line->x); - $this->assertEquals(15, $line->y); - } - - public function testApplyToImage() - { - // gd - $core = imagecreatetruecolor(300, 200); - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($core); - $line = new LineGd(10, 15); - $result = $line->applyToImage($image, 100, 200); - $this->assertInstanceOf('Intervention\Image\Gd\Shapes\LineShape', $line); - $this->assertTrue($result); - - // imagick - $core = Mockery::mock('\Imagick'); - $core->shouldReceive('drawimage')->once(); - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($core); - $line = new LineImagick(10, 15); - $result = $line->applyToImage($image, 100, 200); - $this->assertInstanceOf('Intervention\Image\Imagick\Shapes\LineShape', $line); - $this->assertTrue($result); - } -} diff --git a/tests/MaskCommandTest.php b/tests/MaskCommandTest.php deleted file mode 100644 index 6330670a..00000000 --- a/tests/MaskCommandTest.php +++ /dev/null @@ -1,68 +0,0 @@ -shouldReceive('getSize')->once()->andReturn($mask_size); - $mask_image->shouldReceive('pickColor')->andReturn([0,0,0,0]); - - $canvas_image = Mockery::mock('Intervention\Image\Image'); - $canvas_core = imagecreatetruecolor(32, 32); - $canvas_image->shouldReceive('getCore')->times(2)->andReturn($canvas_core); - $canvas_image->shouldReceive('pixel'); - - $driver = Mockery::mock('Intervention\Image\Gd\Driver'); - $driver->shouldReceive('newImage')->with(32, 32, [0,0,0,0])->once()->andReturn($canvas_image); - $driver->shouldReceive('init')->with($mask_path)->once()->andReturn($mask_image); - - $image_size = Mockery::mock('Intervention\Image\Size', [32, 32]); - $image_core = imagecreatefrompng(__DIR__.'/images/trim.png'); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getSize')->once()->andReturn($image_size); - $image->shouldReceive('getDriver')->times(2)->andReturn($driver); - $image->shouldReceive('pickColor')->andReturn([0,0,0,0]); - $image->shouldReceive('setCore')->with($canvas_core)->once(); - - $command = new MaskGd([$mask_path, true]); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagick() - { - $mask_core = Mockery::mock('Imagick'); - $mask_path = __DIR__.'images/star.png'; - $mask_image = Mockery::mock('Intervention\Image\Image'); - $mask_image->shouldReceive('getCore')->once()->andReturn($mask_core); - $mask_size = Mockery::mock('Intervention\Image\Size', [32, 32]); - $mask_image->shouldReceive('getSize')->once()->andReturn($mask_size); - - $driver = Mockery::mock('Intervention\Image\Imagick\Driver'); - $driver->shouldReceive('init')->with($mask_path)->once()->andReturn($mask_image); - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('setimagematte')->with(true)->once(); - $imagick->shouldReceive('compositeimage')->with($mask_core, \Imagick::COMPOSITE_DSTIN, 0, 0)->once(); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - $image_size = Mockery::mock('Intervention\Image\Size', [32, 32]); - $image->shouldReceive('getSize')->once()->andReturn($image_size); - $image->shouldReceive('getDriver')->once()->andReturn($driver); - - $command = new MaskImagick([$mask_path, true]); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/ModifierStackTest.php b/tests/ModifierStackTest.php new file mode 100644 index 00000000..037d8803 --- /dev/null +++ b/tests/ModifierStackTest.php @@ -0,0 +1,43 @@ +assertInstanceOf(ModifierStack::class, $stack); + } + + public function testPush(): void + { + $stack = new ModifierStack([]); + $result = $stack->push(new GreyscaleModifier()); + $this->assertInstanceOf(ModifierStack::class, $result); + } + + public function testApply(): void + { + $image = Mockery::mock(ImageInterface::class); + + $modifier1 = Mockery::mock(ModifierInterface::class)->makePartial(); + $modifier1->shouldReceive('apply')->once()->with($image); + + $modifier2 = Mockery::mock(ModifierInterface::class)->makePartial(); + $modifier2->shouldReceive('apply')->once()->with($image); + + $stack = new ModifierStack([$modifier1, $modifier2]); + $result = $stack->apply($image); + $this->assertInstanceOf(ImageInterface::class, $result); + } +} diff --git a/tests/OpacityCommandTest.php b/tests/OpacityCommandTest.php deleted file mode 100644 index aac04971..00000000 --- a/tests/OpacityCommandTest.php +++ /dev/null @@ -1,44 +0,0 @@ -shouldReceive('getCore')->once()->andReturn($mask_core); - - $resource = imagecreatefrompng(__DIR__.'/images/trim.png'); - $driver = Mockery::mock('\Intervention\Image\Gd\Driver'); - $driver->shouldReceive('newImage')->with(32, 32, 'rgba(0, 0, 0, 0.5)')->andReturn($mask); - - $size = Mockery::mock('\Intervention\Image\Size', [32, 32]); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getDriver')->once()->andReturn($driver); - $image->shouldReceive('getSize')->once()->andReturn($size); - $image->shouldReceive('mask')->with($mask_core, true)->once(); - $command = new OpacityGd([50]); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagick() - { - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('evaluateimage')->with(\Imagick::EVALUATE_DIVIDE, 2, \Imagick::CHANNEL_ALPHA)->andReturn(true); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - $command = new OpacityImagick([50]); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/OrientateCommandTest.php b/tests/OrientateCommandTest.php deleted file mode 100644 index 884fcbb1..00000000 --- a/tests/OrientateCommandTest.php +++ /dev/null @@ -1,94 +0,0 @@ -shouldReceive('exif')->with('Orientation')->once()->andReturn(2); - $image->shouldReceive('flip')->once(); - $command = new OrientateCommand([]); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testExecuteOrientationThree() - { - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('exif')->with('Orientation')->once()->andReturn(3); - $image->shouldReceive('rotate')->with(180)->once(); - $command = new OrientateCommand([]); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testExecuteOrientationFour() - { - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('exif')->with('Orientation')->once()->andReturn(4); - $image->shouldReceive('rotate')->with(180)->once()->andReturn($image); - $image->shouldReceive('flip')->once(); - $command = new OrientateCommand([]); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testExecuteOrientationFive() - { - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('exif')->with('Orientation')->once()->andReturn(5); - $image->shouldReceive('rotate')->with(270)->once()->andReturn($image); - $image->shouldReceive('flip')->once(); - $command = new OrientateCommand([]); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testExecuteOrientationSix() - { - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('exif')->with('Orientation')->once()->andReturn(6); - $image->shouldReceive('rotate')->with(270)->once(); - $command = new OrientateCommand([]); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testExecuteOrientationSeven() - { - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('exif')->with('Orientation')->once()->andReturn(7); - $image->shouldReceive('rotate')->with(90)->once()->andReturn($image); - $image->shouldReceive('flip')->once(); - $command = new OrientateCommand([]); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testExecuteOrientationEight() - { - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('exif')->with('Orientation')->once()->andReturn(8); - $image->shouldReceive('rotate')->with(90)->once(); - $command = new OrientateCommand([]); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testExecuteOrientationNoExifData() - { - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('exif')->with('Orientation')->once()->andReturn(null); - $command = new OrientateCommand([]); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/PickColorCommandTest.php b/tests/PickColorCommandTest.php deleted file mode 100644 index fecc676f..00000000 --- a/tests/PickColorCommandTest.php +++ /dev/null @@ -1,67 +0,0 @@ -shouldReceive('getCore')->times(2)->andReturn($resource); - $command = new PickColorGd([1, 2]); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertTrue($command->hasOutput()); - $this->assertInternalType('array', $command->getOutput()); - $this->assertEquals(4, count($command->getOutput())); - } - - public function testGdWithFormat() - { - $resource = imagecreatefromjpeg(__DIR__.'/images/test.jpg'); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->times(2)->andReturn($resource); - $command = new PickColorGd([1, 2, 'hex']); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertTrue($command->hasOutput()); - $this->assertInternalType('string', $command->getOutput()); - $this->assertEquals('#ffffff', $command->getOutput()); - } - - public function testImagickWithCoordinates() - { - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('getimagepixelcolor')->with(1, 2)->andReturn(new ImagickPixel); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - $command = new PickColorImagick([1, 2]); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertTrue($command->hasOutput()); - $this->assertInternalType('array', $command->getOutput()); - $this->assertEquals(4, count($command->getOutput())); - } - - public function testImagickWithFormat() - { - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('getimagepixelcolor')->with(1, 2)->andReturn(new ImagickPixel('#ff0000')); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - $command = new PickColorImagick([1, 2, 'hex']); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertTrue($command->hasOutput()); - $this->assertInternalType('string', $command->getOutput()); - $this->assertEquals('#ff0000', $command->getOutput()); - } -} diff --git a/tests/PixelCommandTest.php b/tests/PixelCommandTest.php deleted file mode 100644 index ad1681d7..00000000 --- a/tests/PixelCommandTest.php +++ /dev/null @@ -1,34 +0,0 @@ -shouldReceive('getCore')->once()->andReturn($resource); - $command = new PixelGd(['#b53717', 10, 20]); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagick() - { - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('drawimage')->once()->andReturn(true); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - $command = new PixelImagick(['#b53717', 10, 20]); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/PixelateCommandTest.php b/tests/PixelateCommandTest.php deleted file mode 100644 index 29eba75f..00000000 --- a/tests/PixelateCommandTest.php +++ /dev/null @@ -1,37 +0,0 @@ -shouldReceive('getCore')->once()->andReturn($resource); - $command = new PixelateGd([10]); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagick() - { - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('scaleimage')->with(80, 60)->once()->andReturn(true); - $imagick->shouldReceive('scaleimage')->with(800, 600)->once()->andReturn(true); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->times(2)->andReturn($imagick); - $image->shouldReceive('getWidth')->once()->andReturn(800); - $image->shouldReceive('getHeight')->once()->andReturn(600); - $command = new PixelateImagick([10]); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/PointTest.php b/tests/PointTest.php deleted file mode 100644 index 816c1b13..00000000 --- a/tests/PointTest.php +++ /dev/null @@ -1,47 +0,0 @@ -assertInstanceOf('Intervention\Image\Point', $point); - $this->assertEquals(0, $point->x); - $this->assertEquals(0, $point->y); - } - - public function testConstructorWithParameters() - { - $point = new Point(40, 50); - $this->assertInstanceOf('Intervention\Image\Point', $point); - $this->assertEquals(40, $point->x); - $this->assertEquals(50, $point->y); - } - - public function testSetX() - { - $point = new Point(0, 0); - $point->setX(100); - $this->assertEquals(100, $point->x); - $this->assertEquals(0, $point->y); - } - - public function testSetY() - { - $point = new Point(0, 0); - $point->setY(100); - $this->assertEquals(0, $point->x); - $this->assertEquals(100, $point->y); - } - - public function testSetPosition() - { - $point = new Point(0, 0); - $point->setPosition(100, 200); - $this->assertEquals(100, $point->x); - $this->assertEquals(200, $point->y); - } -} diff --git a/tests/PolygonCommandTest.php b/tests/PolygonCommandTest.php deleted file mode 100644 index 1580d8bc..00000000 --- a/tests/PolygonCommandTest.php +++ /dev/null @@ -1,45 +0,0 @@ -shouldReceive('getDriverName')->once()->andReturn('Gd'); - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getDriver')->once()->andReturn($driver); - $image->shouldReceive('getCore')->once()->andReturn($resource); - $command = new PolygonCommand([$points]); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertFalse($command->hasOutput()); - } - - public function testImagick() - { - $points = [1, 2, 3, 4, 5, 6]; - $imagick = Mockery::mock('\Imagick'); - $imagick->shouldReceive('drawimage'); - $driver = Mockery::mock('\Intervention\Image\Imagick\Driver'); - $driver->shouldReceive('getDriverName')->once()->andReturn('Imagick'); - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getDriver')->once()->andReturn($driver); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - - $command = new PolygonCommand([$points]); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertFalse($command->hasOutput()); - } - -} diff --git a/tests/PolygonShapeTest.php b/tests/PolygonShapeTest.php deleted file mode 100644 index be0001c4..00000000 --- a/tests/PolygonShapeTest.php +++ /dev/null @@ -1,57 +0,0 @@ -assertInstanceOf('Intervention\Image\Gd\Shapes\PolygonShape', $polygon); - $this->assertEquals([1, 2, 3, 4, 5, 6], $polygon->points); - - } - - public function testGdApplyToImage() - { - $core = imagecreatetruecolor(300, 200); - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($core); - $polygon = new PolygonGd([1, 2, 3, 4, 5, 6]); - $result = $polygon->applyToImage($image); - $this->assertInstanceOf('Intervention\Image\Gd\Shapes\PolygonShape', $polygon); - $this->assertTrue($result); - } - - public function testImagickConstructor() - { - $polygon = new PolygonImagick([1, 2, 3, 4, 5, 6]); - $this->assertInstanceOf('Intervention\Image\Imagick\Shapes\PolygonShape', $polygon); - $this->assertEquals([ - ['x' => 1, 'y' => 2], - ['x' => 3, 'y' => 4], - ['x' => 5, 'y' => 6]], - $polygon->points); - - } - - public function testImagickApplyToImage() - { - $core = Mockery::mock('\Imagick'); - $core->shouldReceive('drawimage')->once(); - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($core); - $polygon = new PolygonImagick([1, 2, 3, 4, 5, 6]); - $result = $polygon->applyToImage($image); - $this->assertInstanceOf('Intervention\Image\Imagick\Shapes\PolygonShape', $polygon); - $this->assertTrue($result); - } - -} diff --git a/tests/PsrResponseCommandTest.php b/tests/PsrResponseCommandTest.php deleted file mode 100644 index f7753f04..00000000 --- a/tests/PsrResponseCommandTest.php +++ /dev/null @@ -1,58 +0,0 @@ -'; - - $image = Mockery::mock('Intervention\Image\Image'); - $stream = \GuzzleHttp\Psr7\stream_for($encodedContent); - - $image->shouldReceive('stream') - ->with('jpg', 87) - ->once() - ->andReturn($stream); - - $image->shouldReceive('getEncoded') - ->twice() - ->andReturn($encodedContent); - - $command = new PsrResponseCommand(['jpg', 87]); - $result = $command->execute($image); - - $this->assertTrue($result); - $this->assertTrue($command->hasOutput()); - - $output = $command->getOutput(); - - $this->assertInstanceOf('Psr\Http\Message\ResponseInterface', $output); - - /** - * @var \Psr\Http\Message\ResponseInterface $output - */ - $this->assertEquals($stream, $output->getBody()); - $this->assertEquals($encodedContent, (string)$output->getBody()); - - $this->assertTrue($output->hasHeader('Content-Type')); - $this->assertTrue($output->hasHeader('Content-Length')); - - $this->assertTrue(in_array($output->getHeaderLine('Content-Type'), [ - 'application/xml', - 'text/xml', - ])); - - $this->assertEquals( - strlen($encodedContent), - $output->getHeaderLine('Content-Length') - ); - } -} diff --git a/tests/RectangleCommandTest.php b/tests/RectangleCommandTest.php deleted file mode 100644 index 3def6859..00000000 --- a/tests/RectangleCommandTest.php +++ /dev/null @@ -1,43 +0,0 @@ -shouldReceive('getDriverName')->once()->andReturn('Gd'); - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getDriver')->once()->andReturn($driver); - $image->shouldReceive('getCore')->once()->andReturn($resource); - $command = new RectangleCommand([10, 15, 100, 150]); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertFalse($command->hasOutput()); - } - - public function testImagick() - { - $imagick = Mockery::mock('\Imagick'); - $imagick->shouldReceive('drawimage'); - $driver = Mockery::mock('\Intervention\Image\Imagick\Driver'); - $driver->shouldReceive('getDriverName')->once()->andReturn('Imagick'); - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getDriver')->once()->andReturn($driver); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - - $command = new RectangleCommand([10, 15, 100, 150]); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertFalse($command->hasOutput()); - } - -} diff --git a/tests/RectangleShapeTest.php b/tests/RectangleShapeTest.php deleted file mode 100644 index d4d7b2a0..00000000 --- a/tests/RectangleShapeTest.php +++ /dev/null @@ -1,54 +0,0 @@ -assertInstanceOf('Intervention\Image\Gd\Shapes\RectangleShape', $rectangle); - $this->assertEquals(10, $rectangle->x1); - $this->assertEquals(15, $rectangle->y1); - $this->assertEquals(100, $rectangle->x2); - $this->assertEquals(150, $rectangle->y2); - - // imagick - $rectangle = new RectangleImagick(10, 15, 100, 150); - $this->assertInstanceOf('Intervention\Image\Imagick\Shapes\RectangleShape', $rectangle); - $this->assertEquals(10, $rectangle->x1); - $this->assertEquals(15, $rectangle->y1); - $this->assertEquals(100, $rectangle->x2); - $this->assertEquals(150, $rectangle->y2); - } - - public function testApplyToImage() - { - // gd - $core = imagecreatetruecolor(300, 200); - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($core); - $rectangle = new RectangleGd(10, 15, 100, 150); - $result = $rectangle->applyToImage($image, 10, 20); - $this->assertInstanceOf('Intervention\Image\Gd\Shapes\RectangleShape', $rectangle); - $this->assertTrue($result); - - // imagick - $core = Mockery::mock('\Imagick'); - $core->shouldReceive('drawimage')->once(); - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($core); - $rectangle = new RectangleImagick(10, 15, 100, 150); - $result = $rectangle->applyToImage($image, 10, 20); - $this->assertInstanceOf('Intervention\Image\Imagick\Shapes\RectangleShape', $rectangle); - $this->assertTrue($result); - } -} diff --git a/tests/ResetCommandTest.php b/tests/ResetCommandTest.php deleted file mode 100644 index 29a545a2..00000000 --- a/tests/ResetCommandTest.php +++ /dev/null @@ -1,71 +0,0 @@ -shouldReceive('cloneCore')->with($resource)->once()->andReturn($resource); - $image->shouldReceive('getCore')->once()->andReturn($resource); - $image->shouldReceive('getDriver')->once()->andReturn($driver); - $image->shouldReceive('setCore')->once(); - $image->shouldReceive('getBackup')->once()->andReturn($resource); - $command = new ResetGd([]); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testGdWithName() - { - $size = Mockery::mock('Intervention\Image\Size', [800, 600]); - $resource = imagecreatefromjpeg(__DIR__.'/images/test.jpg'); - $image = Mockery::mock('Intervention\Image\Image'); - $driver = Mockery::mock('Intervention\Image\Gd\Driver'); - $driver->shouldReceive('cloneCore')->with($resource)->once()->andReturn($resource); - $image->shouldReceive('getDriver')->once()->andReturn($driver); - $image->shouldReceive('getCore')->once()->andReturn($resource); - $image->shouldReceive('setCore')->once(); - $image->shouldReceive('getBackup')->once()->withArgs(['fooBackup'])->andReturn($resource); - $command = new ResetGd(['fooBackup']); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagickWithoutName() - { - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('clear')->once(); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - $image->shouldReceive('setCore')->once(); - $image->shouldReceive('getBackup')->once()->andReturn($imagick); - $command = new ResetImagick([]); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagickWithName() - { - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('clear')->once(); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - $image->shouldReceive('setCore')->once(); - $image->shouldReceive('getBackup')->once()->withArgs(['fooBackup'])->andReturn($imagick); - $command = new ResetImagick(['fooBackup']); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/ResizeCanvasCommandTest.php b/tests/ResizeCanvasCommandTest.php deleted file mode 100644 index fb6480a1..00000000 --- a/tests/ResizeCanvasCommandTest.php +++ /dev/null @@ -1,80 +0,0 @@ -shouldReceive('align')->with('center')->andReturn($canvas_size); - $canvas_size->shouldReceive('relativePosition')->andReturn($canvas_pos); - $image_pos = Mockery::mock('\Intervention\Image\Point', [0, 0]); - $image_size = Mockery::mock('\Intervention\Image\Size', [800, 600]); - $image_size->shouldReceive('align')->with('center')->andReturn($image_size); - $image_size->shouldReceive('relativePosition')->andReturn($image_pos); - $canvas = Mockery::mock('\Intervention\Image\Image'); - $canvas->shouldReceive('getCore')->times(5)->andReturn($resource); - $canvas->shouldReceive('getSize')->andReturn($canvas_size); - $driver = Mockery::mock('\Intervention\Image\Gd\Driver'); - $driver->shouldReceive('newImage')->with(820, 640, '#b53717')->once()->andReturn($canvas); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getDriver')->once()->andReturn($driver); - $image->shouldReceive('getSize')->once()->andReturn($image_size); - $image->shouldReceive('getWidth')->once()->andReturn(800); - $image->shouldReceive('getHeight')->once()->andReturn(600); - $image->shouldReceive('getCore')->once()->andReturn($resource); - $image->shouldReceive('setCore')->once(); - $command = new ResizeCanvasGd([20, 40, 'center', true, '#b53717']); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagick() - { - $canvas_pos = Mockery::mock('\Intervention\Image\Point', [0, 0]); - $canvas_size = Mockery::mock('\Intervention\Image\Size', [820, 640]); - $canvas_size->shouldReceive('align')->with('center')->andReturn($canvas_size); - $canvas_size->shouldReceive('relativePosition')->andReturn($canvas_pos); - $image_pos = Mockery::mock('\Intervention\Image\Point', [0, 0]); - $image_size = Mockery::mock('\Intervention\Image\Size', [800, 600]); - $image_size->shouldReceive('align')->with('center')->andReturn($image_size); - $image_size->shouldReceive('relativePosition')->andReturn($image_pos); - $canvas = Mockery::mock('\Intervention\Image\Image'); - - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('cropimage')->with(800, 600, 0, 0)->once(); - $imagick->shouldReceive('compositeimage')->with($imagick, 40, 0, 0)->once(); - $imagick->shouldReceive('setimagepage')->with(0, 0, 0, 0)->once(); - $imagick->shouldReceive('drawimage')->once(); - $imagick->shouldReceive('transparentpaintimage')->once(); - $imagick->shouldReceive('getimagecolorspace')->once(); - $imagick->shouldReceive('setimagecolorspace')->once(); - - $canvas->shouldReceive('getCore')->times(6)->andReturn($imagick); - $canvas->shouldReceive('getSize')->andReturn($canvas_size); - $canvas->shouldReceive('pickColor')->with(0, 0, 'hex')->once()->andReturn('#000000'); - $driver = Mockery::mock('\Intervention\Image\Gd\Driver'); - $driver->shouldReceive('newImage')->with(820, 640, '#b53717')->once()->andReturn($canvas); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getDriver')->once()->andReturn($driver); - $image->shouldReceive('getSize')->once()->andReturn($image_size); - $image->shouldReceive('getWidth')->once()->andReturn(800); - $image->shouldReceive('getHeight')->once()->andReturn(600); - $image->shouldReceive('getCore')->times(3)->andReturn($imagick); - $image->shouldReceive('setCore')->once(); - $command = new ResizeCanvasImagick([20, 40, 'center', true, '#b53717']); - $result = $command->execute($image); - $this->assertTrue($result); - } - -} diff --git a/tests/ResizeCommandTest.php b/tests/ResizeCommandTest.php deleted file mode 100644 index 130ea4b2..00000000 --- a/tests/ResizeCommandTest.php +++ /dev/null @@ -1,49 +0,0 @@ -upsize(); }; - $resource = imagecreatefromjpeg(__DIR__.'/images/test.jpg'); - $image = Mockery::mock('Intervention\Image\Image'); - $size = Mockery::mock('Intervention\Image\Size', [800, 600]); - $size->shouldReceive('resize')->with(300, 200, $callback)->once()->andReturn($size); - $size->shouldReceive('getWidth')->once()->andReturn(800); - $size->shouldReceive('getHeight')->once()->andReturn(600); - $image->shouldReceive('getWidth')->once()->andReturn(800); - $image->shouldReceive('getHeight')->once()->andReturn(600); - $image->shouldReceive('getSize')->once()->andReturn($size); - $image->shouldReceive('getCore')->once()->andReturn($resource); - $image->shouldReceive('setCore')->once(); - $command = new ResizeCommandGd([300, 200, $callback]); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagick() - { - $callback = function ($constraint) { $constraint->upsize(); }; - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('scaleimage')->with(300, 200)->once()->andReturn(true); - $size = Mockery::mock('Intervention\Image\Size', [800, 600]); - $size->shouldReceive('resize')->with(300, 200, $callback)->once()->andReturn($size); - $size->shouldReceive('getWidth')->once()->andReturn(300); - $size->shouldReceive('getHeight')->once()->andReturn(200); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - $image->shouldReceive('getSize')->once()->andReturn($size); - $command = new ResizeCommandImagick([300, 200, $callback]); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/ResolutionTest.php b/tests/ResolutionTest.php new file mode 100644 index 00000000..08c8967c --- /dev/null +++ b/tests/ResolutionTest.php @@ -0,0 +1,56 @@ +assertInstanceOf(Resolution::class, $resolution); + } + + public function testXY(): void + { + $resolution = new Resolution(1.2, 3.4); + $this->assertEquals(1.2, $resolution->x()); + $this->assertEquals(3.4, $resolution->y()); + } + + public function testPerInch(): void + { + $resolution = new Resolution(300, 150); // per inch + $this->assertEquals(300, $resolution->perInch()->x()); + $this->assertEquals(150, $resolution->perInch()->y()); + + $resolution = new Resolution(300, 150, Resolution::PER_CM); + $this->assertEquals(118.11024, round($resolution->perInch()->x(), 5)); + $this->assertEquals(59.05512, round($resolution->perInch()->y(), 5)); + } + + public function testPerCm(): void + { + $resolution = new Resolution(118.11024, 59.05512); // per inch + $this->assertEquals(300, round($resolution->perCm()->x())); + $this->assertEquals(150, round($resolution->perCm()->y())); + + $resolution = new Resolution(300, 150, Resolution::PER_CM); + $this->assertEquals(300, $resolution->perCm()->x()); + $this->assertEquals(150, $resolution->perCm()->y()); + } + + public function testToString(): void + { + $resolution = new Resolution(300, 150, Resolution::PER_CM); + $this->assertEquals('300.00 x 150.00 dpcm', $resolution->toString()); + + $resolution = new Resolution(300, 150, Resolution::PER_INCH); + $this->assertEquals('300.00 x 150.00 dpi', $resolution->toString()); + $this->assertEquals('300.00 x 150.00 dpi', (string) $resolution); + } +} diff --git a/tests/ResponseTest.php b/tests/ResponseTest.php deleted file mode 100644 index 6a10b2c6..00000000 --- a/tests/ResponseTest.php +++ /dev/null @@ -1,30 +0,0 @@ -assertInstanceOf('\Intervention\Image\Response', $response); - $this->assertInstanceOf('\Intervention\Image\Image', $response->image); - } - - public function testConstructorWithParameters() - { - $image = Mockery::mock('\Intervention\Image\Image'); - $response = new Response($image, 'jpg', 75); - $this->assertInstanceOf('\Intervention\Image\Response', $response); - $this->assertInstanceOf('\Intervention\Image\Image', $response->image); - $this->assertEquals('jpg', $response->format); - $this->assertEquals(75, $response->quality); - } -} diff --git a/tests/RotateCommandTest.php b/tests/RotateCommandTest.php deleted file mode 100644 index 48facd16..00000000 --- a/tests/RotateCommandTest.php +++ /dev/null @@ -1,48 +0,0 @@ -shouldReceive('getCore')->once()->andReturn($resource); - $image->shouldReceive('setCore')->once()->andReturn($resource); - $command = new RotateGd([45, '#b53717']); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagick() - { - $pixel = Mockery::mock('ImagickPixel', ['#b53717']); - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('rotateimage')->andReturn(true); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - $command = new RotateImagick([45, '#b53717']); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagickWithLargeRotation() - { - $rotation = 45; - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('rotateimage')->with(Mockery::type('object'), -$rotation)->andReturn(true); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - $command = new RotateImagick([$rotation + (360 * 1000), '#b53717']); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/SharpenCommandTest.php b/tests/SharpenCommandTest.php deleted file mode 100644 index ed187d87..00000000 --- a/tests/SharpenCommandTest.php +++ /dev/null @@ -1,34 +0,0 @@ -shouldReceive('getCore')->once()->andReturn($resource); - $command = new SharpenGd([50]); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagick() - { - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('unsharpmaskimage')->with(1, 1, 8, 0)->andReturn(true); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - $command = new SharpenImagick([50]); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/SizeTest.php b/tests/SizeTest.php deleted file mode 100644 index 35ced232..00000000 --- a/tests/SizeTest.php +++ /dev/null @@ -1,436 +0,0 @@ -assertInstanceOf('Intervention\Image\Size', $size); - $this->assertInstanceOf('Intervention\Image\Point', $size->pivot); - $this->assertEquals(1, $size->width); - $this->assertEquals(1, $size->height); - } - - public function testConstructorWithCoordinates() - { - $pivot = Mockery::mock('Intervention\Image\Point'); - $size = new Size(300, 200, $pivot); - $this->assertInstanceOf('Intervention\Image\Size', $size); - $this->assertInstanceOf('Intervention\Image\Point', $size->pivot); - $this->assertEquals(300, $size->width); - $this->assertEquals(200, $size->height); - } - - public function testGetWidth() - { - $size = new Size(800, 600); - $this->assertEquals(800, $size->getWidth()); - } - - public function testGetHeight() - { - $size = new Size(800, 600); - $this->assertEquals(600, $size->getHeight()); - } - - public function testGetRatio() - { - $size = new Size(800, 600); - $this->assertEquals(1.33333333333, $size->getRatio()); - - $size = new Size(100, 100); - $this->assertEquals(1, $size->getRatio()); - - $size = new Size(1920, 1080); - $this->assertEquals(1.777777777778, $size->getRatio()); - } - - public function testResize() - { - $size = new Size(800, 600); - $size->resize(1000, 2000); - $this->assertEquals(1000, $size->width); - $this->assertEquals(2000, $size->height); - - $size = new Size(800, 600); - $size->resize(2000, null); - $this->assertEquals(2000, $size->width); - $this->assertEquals(600, $size->height); - - $size = new Size(800, 600); - $size->resize(null, 1000); - $this->assertEquals(800, $size->width); - $this->assertEquals(1000, $size->height); - } - - public function testResizeWithCallbackAspectRatio() - { - $size = new Size(800, 600); - $size->resize(1000, 2000, function ($c) { $c->aspectRatio(); }); - $this->assertEquals(1000, $size->width); - $this->assertEquals(750, $size->height); - - $size = new Size(800, 600); - $size->resize(2000, 1000, function ($c) { $c->aspectRatio(); }); - $this->assertEquals(1333, $size->width); - $this->assertEquals(1000, $size->height); - - $size = new Size(800, 600); - $size->resize(null, 3000, function ($c) { $c->aspectRatio(); }); - $this->assertEquals(4000, $size->width); - $this->assertEquals(3000, $size->height); - - $size = new Size(800, 600); - $size->resize(8000, null, function ($c) { $c->aspectRatio(); }); - $this->assertEquals(8000, $size->width); - $this->assertEquals(6000, $size->height); - - $size = new Size(800, 600); - $size->resize(100, 400, function ($c) { $c->aspectRatio(); }); - $this->assertEquals(100, $size->width); - $this->assertEquals(75, $size->height); - - $size = new Size(800, 600); - $size->resize(400, 100, function ($c) { $c->aspectRatio(); }); - $this->assertEquals(133, $size->width); - $this->assertEquals(100, $size->height); - - $size = new Size(800, 600); - $size->resize(null, 300, function ($c) { $c->aspectRatio(); }); - $this->assertEquals(400, $size->width); - $this->assertEquals(300, $size->height); - - $size = new Size(800, 600); - $size->resize(80, null, function ($c) { $c->aspectRatio(); }); - $this->assertEquals(80, $size->width); - $this->assertEquals(60, $size->height); - - $size = new Size(640, 480); - $size->resize(225, null, function ($c) { $c->aspectRatio(); }); - $this->assertEquals(225, $size->width); - $this->assertEquals(169, $size->height); - - $size = new Size(640, 480); - $size->resize(223, null, function ($c) { $c->aspectRatio(); }); - $this->assertEquals(223, $size->width); - $this->assertEquals(167, $size->height); - - $size = new Size(600, 800); - $size->resize(300, 300, function ($c) { $c->aspectRatio(); }); - $this->assertEquals(225, $size->width); - $this->assertEquals(300, $size->height); - - $size = new Size(800, 600); - $size->resize(400, 10, function ($c) { $c->aspectRatio(); }); - $this->assertEquals(13, $size->width); - $this->assertEquals(10, $size->height); - - $size = new Size(800, 600); - $size->resize(1000, 1200, function ($c) { $c->aspectRatio(); }); - $this->assertEquals(1000, $size->width); - $this->assertEquals(750, $size->height); - } - - public function testResizeWithCallbackUpsize() - { - $size = new Size(800, 600); - $size->resize(1000, 2000, function ($c) { $c->upsize(); }); - $this->assertEquals(800, $size->width); - $this->assertEquals(600, $size->height); - - $size = new Size(800, 600); - $size->resize(400, 1000, function ($c) { $c->upsize(); }); - $this->assertEquals(400, $size->width); - $this->assertEquals(600, $size->height); - - $size = new Size(800, 600); - $size->resize(1000, 400, function ($c) { $c->upsize(); }); - $this->assertEquals(800, $size->width); - $this->assertEquals(400, $size->height); - - $size = new Size(800, 600); - $size->resize(400, 300, function ($c) { $c->upsize(); }); - $this->assertEquals(400, $size->width); - $this->assertEquals(300, $size->height); - - $size = new Size(800, 600); - $size->resize(1000, null, function ($c) { $c->upsize(); }); - $this->assertEquals(800, $size->width); - $this->assertEquals(600, $size->height); - - $size = new Size(800, 600); - $size->resize(null, 1000, function ($c) { $c->upsize(); }); - $this->assertEquals(800, $size->width); - $this->assertEquals(600, $size->height); - } - - public function testResizeWithCallbackAspectRatioAndUpsize() - { - $size = new Size(800, 600); - $size->resize(1000, 2000, function ($c) { $c->aspectRatio(); $c->upsize(); }); - $this->assertEquals(800, $size->width); - $this->assertEquals(600, $size->height); - - $size = new Size(800, 600); - $size->resize(1000, 600, function ($c) { $c->aspectRatio(); $c->upsize(); }); - $this->assertEquals(800, $size->width); - $this->assertEquals(600, $size->height); - - $size = new Size(800, 600); - $size->resize(1000, 300, function ($c) { $c->aspectRatio(); $c->upsize(); }); - $this->assertEquals(400, $size->width); - $this->assertEquals(300, $size->height); - - $size = new Size(800, 600); - $size->resize(400, 1000, function ($c) { $c->aspectRatio(); $c->upsize(); }); - $this->assertEquals(400, $size->width); - $this->assertEquals(300, $size->height); - - $size = new Size(800, 600); - $size->resize(400, null, function ($c) { $c->aspectRatio(); $c->upsize(); }); - $this->assertEquals(400, $size->width); - $this->assertEquals(300, $size->height); - - $size = new Size(800, 600); - $size->resize(null, 300, function ($c) { $c->aspectRatio(); $c->upsize(); }); - $this->assertEquals(400, $size->width); - $this->assertEquals(300, $size->height); - - $size = new Size(800, 600); - $size->resize(1000, null, function ($c) { $c->aspectRatio(); $c->upsize(); }); - $this->assertEquals(800, $size->width); - $this->assertEquals(600, $size->height); - - $size = new Size(800, 600); - $size->resize(null, 1000, function ($c) { $c->aspectRatio(); $c->upsize(); }); - $this->assertEquals(800, $size->width); - $this->assertEquals(600, $size->height); - - $size = new Size(800, 600); - $size->resize(100, 100, function ($c) { $c->aspectRatio(); $c->upsize(); }); - $this->assertEquals(100, $size->width); - $this->assertEquals(75, $size->height); - - $size = new Size(800, 600); - $size->resize(300, 200, function ($c) { $c->aspectRatio(); $c->upsize(); }); - $this->assertEquals(267, $size->width); - $this->assertEquals(200, $size->height); - - $size = new Size(600, 800); - $size->resize(300, 300, function ($c) { $c->aspectRatio(); $c->upsize(); }); - $this->assertEquals(225, $size->width); - $this->assertEquals(300, $size->height); - - $size = new Size(800, 600); - $size->resize(400, 10, function ($c) { $c->aspectRatio(); $c->upsize(); }); - $this->assertEquals(13, $size->width); - $this->assertEquals(10, $size->height); - } - - public function testRelativePosition() - { - $container = new Size(800, 600); - $input = new Size(200, 100); - $container->align('top-left'); - $input->align('top-left'); - $pos = $container->relativePosition($input); - $this->assertEquals(0, $pos->x); - $this->assertEquals(0, $pos->y); - - $container = new Size(800, 600); - $input = new Size(200, 100); - $container->align('center'); - $input->align('top-left'); - $pos = $container->relativePosition($input); - $this->assertEquals(400, $pos->x); - $this->assertEquals(300, $pos->y); - - $container = new Size(800, 600); - $input = new Size(200, 100); - $container->align('bottom-right'); - $input->align('top-right'); - $pos = $container->relativePosition($input); - $this->assertEquals(600, $pos->x); - $this->assertEquals(600, $pos->y); - - $container = new Size(800, 600); - $input = new Size(200, 100); - $container->align('center'); - $input->align('center'); - $pos = $container->relativePosition($input); - $this->assertEquals(300, $pos->x); - $this->assertEquals(250, $pos->y); - } - - public function testAlign() - { - $width = 640; - $height = 480; - $pivot = Mockery::mock('Intervention\Image\Point'); - $pivot->shouldReceive('setPosition')->with(0, 0)->once(); - $pivot->shouldReceive('setPosition')->with(intval($width/2), 0)->once(); - $pivot->shouldReceive('setPosition')->with($width, 0)->once(); - $pivot->shouldReceive('setPosition')->with(0, intval($height/2))->once(); - $pivot->shouldReceive('setPosition')->with(intval($width/2), intval($height/2))->once(); - $pivot->shouldReceive('setPosition')->with($width, intval($height/2))->once(); - $pivot->shouldReceive('setPosition')->with(0, $height)->once(); - $pivot->shouldReceive('setPosition')->with(intval($width/2), $height)->once(); - $pivot->shouldReceive('setPosition')->with($width, $height)->once(); - - $box = new Size($width, $height, $pivot); - $box->align('top-left'); - $box->align('top'); - $box->align('top-right'); - $box->align('left'); - $box->align('center'); - $box->align('right'); - $box->align('bottom-left'); - $box->align('bottom'); - $b = $box->align('bottom-right'); - $this->assertInstanceOf('Intervention\Image\Size', $b); - } - - public function testFit() - { - $box = new Size(800, 600); - $fitted = $box->fit(new Size(100, 100)); - $this->assertEquals(600, $fitted->width); - $this->assertEquals(600, $fitted->height); - $this->assertEquals(100, $fitted->pivot->x); - $this->assertEquals(0, $fitted->pivot->y); - - $box = new Size(800, 600); - $fitted = $box->fit(new Size(200, 100)); - $this->assertEquals(800, $fitted->width); - $this->assertEquals(400, $fitted->height); - $this->assertEquals(0, $fitted->pivot->x); - $this->assertEquals(100, $fitted->pivot->y); - - $box = new Size(800, 600); - $fitted = $box->fit(new Size(100, 200)); - $this->assertEquals(300, $fitted->width); - $this->assertEquals(600, $fitted->height); - $this->assertEquals(250, $fitted->pivot->x); - $this->assertEquals(0, $fitted->pivot->y); - - $box = new Size(800, 600); - $fitted = $box->fit(new Size(2000, 10)); - $this->assertEquals(800, $fitted->width); - $this->assertEquals(4, $fitted->height); - $this->assertEquals(0, $fitted->pivot->x); - $this->assertEquals(298, $fitted->pivot->y); - - $box = new Size(800, 600); - $fitted = $box->fit(new Size(10, 2000)); - $this->assertEquals(3, $fitted->width); - $this->assertEquals(600, $fitted->height); - $this->assertEquals(399, $fitted->pivot->x); - $this->assertEquals(0, $fitted->pivot->y); - - $box = new Size(800, 600); - $fitted = $box->fit(new Size(800, 600)); - $this->assertEquals(800, $fitted->width); - $this->assertEquals(600, $fitted->height); - $this->assertEquals(0, $fitted->pivot->x); - $this->assertEquals(0, $fitted->pivot->y); - - $box = new Size(400, 300); - $fitted = $box->fit(new Size(120, 120)); - $this->assertEquals(300, $fitted->width); - $this->assertEquals(300, $fitted->height); - $this->assertEquals(50, $fitted->pivot->x); - $this->assertEquals(0, $fitted->pivot->y); - - $box = new Size(600, 800); - $fitted = $box->fit(new Size(100, 100)); - $this->assertEquals(600, $fitted->width); - $this->assertEquals(600, $fitted->height); - $this->assertEquals(0, $fitted->pivot->x); - $this->assertEquals(100, $fitted->pivot->y); - } - - /** - * @dataProvider providerFitWithPosition - */ - public function testFitWithPosition(Size $box, $position, $x, $y) - { - $fitted = $box->fit(new Size(100, 100), $position); - $this->assertEquals(600, $fitted->width); - $this->assertEquals(600, $fitted->height); - $this->assertEquals($x, $fitted->pivot->x); - $this->assertEquals($y, $fitted->pivot->y); - } - - public function providerFitWithPosition() - { - return [ - [new Size(800, 600), 'top-left', 0, 0], - [new Size(800, 600), 'top', 100, 0], - [new Size(800, 600), 'top-right', 200, 0], - [new Size(800, 600), 'left', 0, 0], - [new Size(800, 600), 'center', 100, 0], - [new Size(800, 600), 'right', 200, 0], - [new Size(800, 600), 'bottom-left', 0, 0], - [new Size(800, 600), 'bottom', 100, 0], - [new Size(800, 600), 'bottom-right', 200, 0], - - [new Size(600, 800), 'top-left', 0, 0], - [new Size(600, 800), 'top', 0, 0], - [new Size(600, 800), 'top-right', 0, 0], - [new Size(600, 800), 'left', 0, 100], - [new Size(600, 800), 'center', 0, 100], - [new Size(600, 800), 'right', 0, 100], - [new Size(600, 800), 'bottom-left', 0, 200], - [new Size(600, 800), 'bottom', 0, 200], - [new Size(600, 800), 'bottom-right', 0, 200], - ]; - } - - public function testFitsInto() - { - $box = new Size(800, 600); - $fits = $box->fitsInto(new Size(100, 100)); - $this->assertFalse($fits); - - $box = new Size(800, 600); - $fits = $box->fitsInto(new Size(1000, 100)); - $this->assertFalse($fits); - - $box = new Size(800, 600); - $fits = $box->fitsInto(new Size(100, 1000)); - $this->assertFalse($fits); - - $box = new Size(800, 600); - $fits = $box->fitsInto(new Size(800, 600)); - $this->assertTrue($fits); - - $box = new Size(800, 600); - $fits = $box->fitsInto(new Size(1000, 1000)); - $this->assertTrue($fits); - - $box = new Size(100, 100); - $fits = $box->fitsInto(new Size(800, 600)); - $this->assertTrue($fits); - - $box = new Size(100, 100); - $fits = $box->fitsInto(new Size(80, 60)); - $this->assertFalse($fits); - } - - /** - * @expectedException \Intervention\Image\Exception\InvalidArgumentException - */ - public function testInvalidResize() - { - $size = new Size(800, 600); - $size->resize(null, null); - } -} diff --git a/tests/StreamCommandTest.php b/tests/StreamCommandTest.php deleted file mode 100644 index 1af12dbd..00000000 --- a/tests/StreamCommandTest.php +++ /dev/null @@ -1,36 +0,0 @@ -shouldReceive('encode') - ->with('jpg', 87) - ->once() - ->andReturnSelf(); - - $image->shouldReceive('getEncoded') - ->once() - ->andReturn($encodedContent); - - $command = new StreamCommand(['jpg', 87]); - $result = $command->execute($image); - - $this->assertTrue($result); - $this->assertTrue($command->hasOutput()); - - $output = $command->getOutput(); - $this->assertInstanceOf('Psr\Http\Message\StreamInterface', $output); - $this->assertEquals($encodedContent, (string)$output); - } -} diff --git a/tests/TestCase.php b/tests/TestCase.php new file mode 100644 index 00000000..f40ecea7 --- /dev/null +++ b/tests/TestCase.php @@ -0,0 +1,45 @@ +getTestImagePath($filename)); + } + + protected function assertColor($r, $g, $b, $a, ColorInterface $color) + { + $this->assertEquals([$r, $g, $b, $a], $color->toArray()); + } + + protected function assertTransparency(ColorInterface $color) + { + $this->assertInstanceOf(RgbColor::class, $color); + $channel = $color->channel(Alpha::class); + $this->assertEquals(0, $channel->value()); + } + + protected function assertMimeType(string|array $allowed, string $input): void + { + $pointer = fopen('php://temp', 'rw'); + fputs($pointer, $input); + rewind($pointer); + $detected = mime_content_type($pointer); + fclose($pointer); + + $allowed = is_string($allowed) ? [$allowed] : $allowed; + $this->assertTrue(in_array($detected, $allowed)); + } +} diff --git a/tests/TextCommandTest.php b/tests/TextCommandTest.php deleted file mode 100644 index 8b19cbf0..00000000 --- a/tests/TextCommandTest.php +++ /dev/null @@ -1,32 +0,0 @@ -shouldReceive('getDriverName')->once()->andReturn('Gd'); - $image = Mockery::mock('\Intervention\Image\Image'); - $image->shouldReceive('getDriver')->once()->andReturn($driver); - $image->shouldReceive('getCore')->once()->andReturn($resource); - $command = new TextCommand(['test', 10, 20]); - $result = $command->execute($image); - $this->assertTrue($result); - $this->assertFalse($command->hasOutput()); - } - - public function testImagick() - { - # code... - } - -} diff --git a/tests/Traits/CanCreateGdTestImage.php b/tests/Traits/CanCreateGdTestImage.php new file mode 100644 index 00000000..165b9d2f --- /dev/null +++ b/tests/Traits/CanCreateGdTestImage.php @@ -0,0 +1,51 @@ +handle( + $this->getTestImagePath($filename) + ); + } + + public function createTestImage(int $width, int $height): Image + { + $gd = imagecreatetruecolor($width, $height); + imagefill($gd, 0, 0, imagecolorallocate($gd, 255, 0, 0)); + + return new Image( + new Driver(), + new Core([ + new Frame($gd) + ]) + ); + } + + public function createTestAnimation(): Image + { + $gd1 = imagecreatetruecolor(3, 2); + imagefill($gd1, 0, 0, imagecolorallocate($gd1, 255, 0, 0)); + $gd2 = imagecreatetruecolor(3, 2); + imagefill($gd2, 0, 0, imagecolorallocate($gd1, 0, 255, 0)); + $gd3 = imagecreatetruecolor(3, 2); + imagefill($gd3, 0, 0, imagecolorallocate($gd1, 0, 0, 255)); + + return new Image( + new Driver(), + new Core([ + new Frame($gd1), + new Frame($gd2), + new Frame($gd3), + ]) + ); + } +} diff --git a/tests/Traits/CanCreateImagickTestImage.php b/tests/Traits/CanCreateImagickTestImage.php new file mode 100644 index 00000000..d9692084 --- /dev/null +++ b/tests/Traits/CanCreateImagickTestImage.php @@ -0,0 +1,36 @@ +handle( + sprintf('%s/../images/%s', __DIR__, $filename) + ); + } + + public function createTestImage(int $width, int $height): Image + { + $background = new ImagickPixel('rgb(255, 0, 0)'); + $imagick = new Imagick(); + $imagick->newImage($width, $height, $background, 'png'); + $imagick->setType(Imagick::IMGTYPE_UNDEFINED); + $imagick->setImageType(Imagick::IMGTYPE_UNDEFINED); + $imagick->setColorspace(Imagick::COLORSPACE_SRGB); + $imagick->setImageResolution(96, 96); + + return new Image( + new Driver(), + new Core($imagick) + ); + } +} diff --git a/tests/TrimCommandTest.php b/tests/TrimCommandTest.php deleted file mode 100644 index b7f5c770..00000000 --- a/tests/TrimCommandTest.php +++ /dev/null @@ -1,54 +0,0 @@ -shouldReceive('differs')->with($baseColor, 45)->andReturn(true); - $image->shouldReceive('getCore')->once()->andReturn($resource); - $image->shouldReceive('getWidth')->once()->andReturn(800); - $image->shouldReceive('getHeight')->once()->andReturn(600); - $image->shouldReceive('pickColor')->with(0, 0, 'object')->times(2)->andReturn($baseColor); - $image->shouldReceive('pickColor')->with(799, 0, 'object')->once()->andReturn($baseColor); - $image->shouldReceive('setCore')->once(); - $command = new TrimGd(['top-left', ['left', 'right'], 45, 2]); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagick() - { - $baseColorPixel = new \ImagickPixel; - $baseColor = Mockery::mock('Intervention\Image\Gd\Color'); - $baseColor->shouldReceive('getPixel')->once()->andReturn($baseColorPixel); - $imagick = Mockery::mock('Imagick'); - $imagick->width = 100; - $imagick->height = 100; - $imagick->shouldReceive('borderimage')->with($baseColorPixel, 1, 1)->once()->andReturn(true); - $imagick->shouldReceive('trimimage')->with(29632.5)->once()->andReturn(true); - $imagick->shouldReceive('getimagepage')->once()->andReturn(['x' => 50, 'y' => 50]); - $imagick->shouldReceive('cropimage')->with(104, 202, 47, 0)->once()->andReturn(true); - $imagick->shouldReceive('setimagepage')->with(0, 0, 0, 0)->once()->andReturn(true); - $imagick->shouldReceive('destroy')->with()->once()->andReturn(true); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getWidth')->once()->andReturn(800); - $image->shouldReceive('getHeight')->once()->andReturn(600); - $image->shouldReceive('pickColor')->with(0, 0, 'object')->once()->andReturn($baseColor); - $image->shouldReceive('getCore')->times(3)->andReturn($imagick); - $command = new TrimImagick(['top-left', ['left', 'right'], 45, 2]); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/Typography/FontFactoryTest.php b/tests/Typography/FontFactoryTest.php new file mode 100644 index 00000000..7f319227 --- /dev/null +++ b/tests/Typography/FontFactoryTest.php @@ -0,0 +1,42 @@ +assertInstanceOf(FontInterface::class, $result); + $this->assertEquals('foo.ttf', $result->filename()); + } + + public function testBuildWithCallback(): void + { + $factory = new FontFactory(function ($font) { + $font->filename('foo.ttf'); + $font->color('#b01735'); + $font->size(70); + $font->align('center'); + $font->valign('middle'); + $font->lineHeight(1.6); + $font->angle(10); + }); + + $result = $factory(); + $this->assertInstanceOf(FontInterface::class, $result); + $this->assertEquals('foo.ttf', $result->filename()); + $this->assertEquals('#b01735', $result->color()); + $this->assertEquals(70, $result->size()); + $this->assertEquals('center', $result->alignment()); + $this->assertEquals('middle', $result->valignment()); + $this->assertEquals(1.6, $result->lineHeight()); + $this->assertEquals(10, $result->angle()); + } +} diff --git a/tests/Typography/FontTest.php b/tests/Typography/FontTest.php new file mode 100644 index 00000000..311bc52a --- /dev/null +++ b/tests/Typography/FontTest.php @@ -0,0 +1,82 @@ +assertInstanceOf(Font::class, $font); + $this->assertEquals('foo.ttf', $font->filename()); + } + + public function testSetGetSize(): void + { + $font = new Font(); + $this->assertEquals(12, $font->size()); + $result = $font->setSize(123); + $this->assertInstanceOf(Font::class, $result); + $this->assertEquals(123, $font->size()); + } + + public function testSetGetAngle(): void + { + $font = new Font(); + $this->assertEquals(0, $font->angle()); + $result = $font->setAngle(123); + $this->assertInstanceOf(Font::class, $result); + $this->assertEquals(123, $font->angle()); + } + + public function testSetGetFilename(): void + { + $font = new Font(); + $this->assertEquals(null, $font->filename()); + $this->assertFalse($font->hasFilename()); + $filename = $this->getTestImagePath(); + $result = $font->setFilename($filename); + $this->assertTrue($font->hasFilename()); + $this->assertInstanceOf(Font::class, $result); + $this->assertEquals($filename, $font->filename()); + } + + public function testSetGetColor(): void + { + $font = new Font(); + $this->assertEquals('000000', $font->color()); + $result = $font->setColor('fff'); + $this->assertInstanceOf(Font::class, $result); + $this->assertEquals('fff', $font->color()); + } + + public function testSetGetAlignment(): void + { + $font = new Font(); + $this->assertEquals('left', $font->alignment()); + $result = $font->setAlignment('center'); + $this->assertInstanceOf(Font::class, $result); + $this->assertEquals('center', $font->alignment()); + } + + public function testSetGetValignment(): void + { + $font = new Font(); + $this->assertEquals('bottom', $font->valignment()); + $result = $font->setValignment('center'); + $this->assertInstanceOf(Font::class, $result); + $this->assertEquals('center', $font->valignment()); + } + + public function testSetGetLineHeight(): void + { + $font = new Font(); + $this->assertEquals(1.25, $font->lineHeight()); + $result = $font->setLineHeight(3.2); + $this->assertInstanceOf(Font::class, $result); + $this->assertEquals(3.2, $font->lineHeight()); + } +} diff --git a/tests/Typography/LineTest.php b/tests/Typography/LineTest.php new file mode 100644 index 00000000..8616412e --- /dev/null +++ b/tests/Typography/LineTest.php @@ -0,0 +1,33 @@ +assertInstanceOf(Line::class, $line); + } + + public function testToString(): void + { + $line = new Line('foo'); + $this->assertEquals('foo', (string) $line); + } + + public function testSetGetPosition(): void + { + $line = new Line('foo'); + $this->assertEquals(0, $line->position()->x()); + $this->assertEquals(0, $line->position()->y()); + + $line->setPosition(new Point(10, 11)); + $this->assertEquals(10, $line->position()->x()); + $this->assertEquals(11, $line->position()->y()); + } +} diff --git a/tests/Typography/TextBlockTest.php b/tests/Typography/TextBlockTest.php new file mode 100644 index 00000000..60f7cf35 --- /dev/null +++ b/tests/Typography/TextBlockTest.php @@ -0,0 +1,46 @@ +getTestBlock(); + $this->assertInstanceOf(TextBlock::class, $block); + $this->assertEquals(3, $block->count()); + } + + public function testLines(): void + { + $block = $this->getTestBlock(); + $this->assertCount(3, $block->lines()); + } + + public function testGetLine(): void + { + $block = $this->getTestBlock(); + $this->assertEquals('foo', $block->line(0)); + $this->assertEquals('FooBar', $block->line(1)); + $this->assertEquals('bar', $block->line(2)); + } + + public function testLongestLine(): void + { + $block = $this->getTestBlock(); + $result = $block->longestLine(); + $this->assertEquals('FooBar', (string) $result); + } +} diff --git a/tests/WidenCommandTest.php b/tests/WidenCommandTest.php deleted file mode 100644 index 3d8622d0..00000000 --- a/tests/WidenCommandTest.php +++ /dev/null @@ -1,49 +0,0 @@ -aspectRatio(); }; - $resource = imagecreatefromjpeg(__DIR__.'/images/test.jpg'); - $image = Mockery::mock('Intervention\Image\Image'); - $size = Mockery::mock('Intervention\Image\Size', [800, 600]); - $size->shouldReceive('resize')->once()->andReturn($size); - $size->shouldReceive('getWidth')->once()->andReturn(800); - $size->shouldReceive('getHeight')->once()->andReturn(600); - $image->shouldReceive('getWidth')->once()->andReturn(800); - $image->shouldReceive('getHeight')->once()->andReturn(600); - $image->shouldReceive('getSize')->once()->andReturn($size); - $image->shouldReceive('getCore')->once()->andReturn($resource); - $image->shouldReceive('setCore')->once(); - $command = new WidenGd([200]); - $result = $command->execute($image); - $this->assertTrue($result); - } - - public function testImagick() - { - $callback = function ($constraint) { $constraint->upsize(); }; - $imagick = Mockery::mock('Imagick'); - $imagick->shouldReceive('scaleimage')->with(300, 200)->once()->andReturn(true); - $size = Mockery::mock('Intervention\Image\Size', [800, 600]); - $size->shouldReceive('resize')->once()->andReturn($size); - $size->shouldReceive('getWidth')->once()->andReturn(300); - $size->shouldReceive('getHeight')->once()->andReturn(200); - $image = Mockery::mock('Intervention\Image\Image'); - $image->shouldReceive('getCore')->once()->andReturn($imagick); - $image->shouldReceive('getSize')->once()->andReturn($size); - $command = new WidenImagick([200]); - $result = $command->execute($image); - $this->assertTrue($result); - } -} diff --git a/tests/images/animation.gif b/tests/images/animation.gif new file mode 100644 index 00000000..c45bb777 Binary files /dev/null and b/tests/images/animation.gif differ diff --git a/tests/images/black-friday.png b/tests/images/black-friday.png deleted file mode 100644 index 129c9e94..00000000 Binary files a/tests/images/black-friday.png and /dev/null differ diff --git a/tests/images/blocks.png b/tests/images/blocks.png new file mode 100644 index 00000000..d57fabe3 Binary files /dev/null and b/tests/images/blocks.png differ diff --git a/tests/images/blue.gif b/tests/images/blue.gif new file mode 100644 index 00000000..4be6587b Binary files /dev/null and b/tests/images/blue.gif differ diff --git a/tests/images/broken.png b/tests/images/broken.png deleted file mode 100644 index eaecd5c6..00000000 Binary files a/tests/images/broken.png and /dev/null differ diff --git a/tests/images/cats.gif b/tests/images/cats.gif new file mode 100644 index 00000000..307d4f0e Binary files /dev/null and b/tests/images/cats.gif differ diff --git a/tests/images/cmyk.jpg b/tests/images/cmyk.jpg new file mode 100644 index 00000000..1459b2c0 Binary files /dev/null and b/tests/images/cmyk.jpg differ diff --git a/tests/images/gradient.bmp b/tests/images/gradient.bmp new file mode 100644 index 00000000..08661077 Binary files /dev/null and b/tests/images/gradient.bmp differ diff --git a/tests/images/gradient.gif b/tests/images/gradient.gif new file mode 100644 index 00000000..0371d6a2 Binary files /dev/null and b/tests/images/gradient.gif differ diff --git a/tests/images/gradient.png b/tests/images/gradient.png deleted file mode 100644 index 47f1be21..00000000 Binary files a/tests/images/gradient.png and /dev/null differ diff --git a/tests/images/green.gif b/tests/images/green.gif new file mode 100644 index 00000000..99c38625 Binary files /dev/null and b/tests/images/green.gif differ diff --git a/tests/images/iptc.jpg b/tests/images/iptc.jpg deleted file mode 100644 index 849dd0a3..00000000 Binary files a/tests/images/iptc.jpg and /dev/null differ diff --git a/tests/images/red.gif b/tests/images/red.gif new file mode 100644 index 00000000..408dff18 Binary files /dev/null and b/tests/images/red.gif differ diff --git a/tests/images/star.png b/tests/images/star.png deleted file mode 100644 index def6448d..00000000 Binary files a/tests/images/star.png and /dev/null differ diff --git a/tests/images/test.jpg b/tests/images/test.jpg index 4bb65491..0b02a305 100644 Binary files a/tests/images/test.jpg and b/tests/images/test.jpg differ diff --git a/tests/images/test.webp b/tests/images/test.webp deleted file mode 100755 index ecd28246..00000000 Binary files a/tests/images/test.webp and /dev/null differ diff --git a/tests/tmp/.gitkeep b/tests/tmp/.gitkeep deleted file mode 100644 index e69de29b..00000000