diff --git a/README.md b/README.md index 8ec588a..029714f 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,7 @@ # Uokvirivac -uokvirivac slika \ No newline at end of file +Okvirovi idu u `okvirovi` folder. +Moraju biti uspravni sa transparentnom radnom povrsinom. +Ime mora biti dodano u `$okvirovi` a velicina mora biti dodana u `$radne_velicine`. + + diff --git a/cache/.keep b/cache/.keep new file mode 100644 index 0000000..e69de29 diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..4775e13 --- /dev/null +++ b/composer.json @@ -0,0 +1,5 @@ +{ + "require": { + "imagine/imagine": "~1.2.3" + } +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..fa5f3b1 --- /dev/null +++ b/composer.lock @@ -0,0 +1,77 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "523332b5ac51b610cbd632ce713d9247", + "packages": [ + { + "name": "imagine/imagine", + "version": "1.2.3", + "source": { + "type": "git", + "url": "https://github.com/avalanche123/Imagine.git", + "reference": "cb2361e5bb4410b681462d8e4f912bc5dabf84ab" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/avalanche123/Imagine/zipball/cb2361e5bb4410b681462d8e4f912bc5dabf84ab", + "reference": "cb2361e5bb4410b681462d8e4f912bc5dabf84ab", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "2.2.*", + "phpunit/phpunit": "^4.8 || ^5.7 || ^6.5 || ^7.5 || ^8.4" + }, + "suggest": { + "ext-gd": "to use the GD implementation", + "ext-gmagick": "to use the Gmagick implementation", + "ext-imagick": "to use the Imagick implementation" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-develop": "0.7-dev" + } + }, + "autoload": { + "psr-4": { + "Imagine\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bulat Shakirzyanov", + "email": "mallluhuct@gmail.com", + "homepage": "http://avalanche123.com" + } + ], + "description": "Image processing for PHP 5.3", + "homepage": "http://imagine.readthedocs.org/", + "keywords": [ + "drawing", + "graphics", + "image manipulation", + "image processing" + ], + "time": "2019-12-04T09:55:33+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [], + "plugin-api-version": "1.1.0" +} diff --git a/composer.phar b/composer.phar new file mode 100755 index 0000000..0587d15 Binary files /dev/null and b/composer.phar differ diff --git a/image.php b/image.php new file mode 100644 index 0000000..58e5b81 --- /dev/null +++ b/image.php @@ -0,0 +1,67 @@ +open(__DIR__ . '/okvirovi/' . $okvir); +$slika_image = $imagine->open(__DIR__ . '/slike/' . $slika . ".$ekstenzija"); + + +$okvir_size = $okvir_image->getSize(); +$unutrasnji_size = $radne_velicine[$okvir_id]; +$slika_size = $slika_image->getSize(); + +$finalna_dimenzija = $okvir_size->getHeight(); + +// smanji sliku da moze stati u okvir + +$slika_vodoravna = $slika_size->getWidth() > $slika_size->getHeight(); +if ($slika_vodoravna) { + $okvir_image->rotate(90); + $okvir_size = $okvir_image->getSize(); + $unutrasnji_size = rotiraj_za_90($unutrasnji_size); + } + +$slika_size = $slika_size->scale( best_fit_odnos($unutrasnji_size, $slika_size) ); + + +$slika_image = $slika_image->thumbnail($slika_size, \Imagine\Image\ImageInterface::THUMBNAIL_OUTBOUND ); +$slika_size = $slika_image->getSize(); + +// napravi bijelo platno velicine okvira +// +$palette = $slika_image->palette(); +$color = $palette->color('#FFF', 0); +$gotova_slika = $imagine->create($okvir_size, $color); + +// zalijepi sliku na centar platna + + $pocetak_s_lijeva = ($okvir_size->getWidth() - $slika_size->getWidth()) / 2; + $pocetak_odozgo = ($okvir_size->getHeight() - $slika_size->getHeight()) / 2; + $gotova_slika->paste($slika_image, new Imagine\Image\Point($pocetak_s_lijeva,$pocetak_odozgo)); + + // uokviri platno +$gotova_slika->paste($okvir_image, new Imagine\Image\Point(0,0)); + +// snimi i prikazi +// $gotova_slika->save(__DIR__ . "/cache/tip" . $okvir_id . "slika" . $slika . ".jpg")->show("jpg"); +// koristiti CDN za kes + diff --git a/index.php b/index.php new file mode 100644 index 0000000..50cce95 --- /dev/null +++ b/index.php @@ -0,0 +1,3 @@ + 'Okvir-za-slike-BERGUR-18x24cm-srebrna.png', + 1 => 'Okvir-za-slike-CHAYKA-13x16cm-s-ružama.png', + 2 => 'Okvir-za-slike-ERLAND-18x23cm-roza.png', + 3 => 'Okvir-za-slike-OSCAR-13x18cm-bijela.png', + 4 => 'Okvir-za-slike-OSCAR-13x18cm-crna.png', + 5 => 'Okvir-za-slike-OSCAR-21x30cm-bijela.png', + 6 => 'Okvir-za-slike-OSCAR-21x30cm-crna.png', + 7 => 'Okvir-za-slike-OSCAR-30x40cm-bijela.png', + 8 => 'Okvir-za-slike-OSCAR-30x40cm-crna.png', + 9 => 'Okvir-za-slike-OSCAR-60x90cm-crna.png', + 10 => 'Okvir-za-slike-TORD-13x18-cm-drvo.png', + 11 => 'Okvir-za-slike-TORD-21x30cm-drvo.png', + 12 => 'Okvir-za-slike-TORD-30x40cm-drvo.png', + 13 => 'Okvir-za-slike-TORD-50x70cm-drvo.png', + 14 => 'Okvir-za-slike-VAGN-13x18cm-sivi..png', + 15 => 'Okvir-za-slike-VAGN-18x24cm-zeleni.png', + 16 => 'Okvir-za-slike-VALTER-10x15cm-bijela.png', + 17 => 'Okvir-za-slike-VALTER-10x15cm-crna.png', + 18 => 'Okvir-za-slike-VALTER-13x18cm-bijela.png', + 19 => 'Okvir-za-slike-VALTER-15x21cm-crna-SDP.png', + 20 => 'Okvir-za-slike-VALTER-18x24cm-bijela.png', + 21 => 'Okvir-za-slike-VALTER-30x40cm-bijela.png', + 22 => 'Okvir-za-slike-VALTER-40x50cm-crna.png', + 23 => 'Okvir-za-slike-VALTER-50x70cm-crna.png', +); + +$radne_velicine = array( +0 => new Imagine\Image\Box(273, 362), +1 => new Imagine\Image\Box(241, 354), +2 => new Imagine\Image\Box(213, 317), +3 => new Imagine\Image\Box(291, 404), +4 => new Imagine\Image\Box(277, 389), +5 => new Imagine\Image\Box(293, 426), +6 => new Imagine\Image\Box(297, 427), +7 => new Imagine\Image\Box(328, 437), +8 => new Imagine\Image\Box(324, 440), +9 => new Imagine\Image\Box(280, 418), +10 => new Imagine\Image\Box(256, 362), +11 => new Imagine\Image\Box(297, 425), +12 => new Imagine\Image\Box(322, 430), +13 => new Imagine\Image\Box(318, 448), +14 => new Imagine\Image\Box(179, 247), +15 => new Imagine\Image\Box(213, 288), +16 => new Imagine\Image\Box(253, 387), +17 => new Imagine\Image\Box(259, 395), +18 => new Imagine\Image\Box(281, 402), +19 => new Imagine\Image\Box(328, 433), +20 => new Imagine\Image\Box(316, 423), +21 => new Imagine\Image\Box(341, 458), +22 => new Imagine\Image\Box(351, 439), +23 => new Imagine\Image\Box(320, 454), +); + +function rotiraj_za_90($box) { + return new Imagine\Image\Box($box->getHeight(), $box->getWidth()); +} + +function best_fit_odnos($box1, $box2) { + $odnos_sirina = $box1->getWidth() / $box2->getWidth(); + $odnos_duzina = $box1->getHeight() / $box2->getHeight(); + return min($odnos_sirina, $odnos_duzina); +} diff --git a/okvirovi/Okvir-za-slike-BERGUR-18x24cm-srebrna.png b/okvirovi/Okvir-za-slike-BERGUR-18x24cm-srebrna.png new file mode 100644 index 0000000..7d0fa08 Binary files /dev/null and b/okvirovi/Okvir-za-slike-BERGUR-18x24cm-srebrna.png differ diff --git a/okvirovi/Okvir-za-slike-CHAYKA-13x16cm-s-ružama.png b/okvirovi/Okvir-za-slike-CHAYKA-13x16cm-s-ružama.png new file mode 100644 index 0000000..58fb174 Binary files /dev/null and b/okvirovi/Okvir-za-slike-CHAYKA-13x16cm-s-ružama.png differ diff --git a/okvirovi/Okvir-za-slike-ERLAND-18x23cm-roza.png b/okvirovi/Okvir-za-slike-ERLAND-18x23cm-roza.png new file mode 100644 index 0000000..399f288 Binary files /dev/null and b/okvirovi/Okvir-za-slike-ERLAND-18x23cm-roza.png differ diff --git a/okvirovi/Okvir-za-slike-OSCAR-13x18cm-bijela.png b/okvirovi/Okvir-za-slike-OSCAR-13x18cm-bijela.png new file mode 100644 index 0000000..e97025c Binary files /dev/null and b/okvirovi/Okvir-za-slike-OSCAR-13x18cm-bijela.png differ diff --git a/okvirovi/Okvir-za-slike-OSCAR-13x18cm-crna.png b/okvirovi/Okvir-za-slike-OSCAR-13x18cm-crna.png new file mode 100644 index 0000000..6b5b1e4 Binary files /dev/null and b/okvirovi/Okvir-za-slike-OSCAR-13x18cm-crna.png differ diff --git a/okvirovi/Okvir-za-slike-OSCAR-21x30cm-bijela.png b/okvirovi/Okvir-za-slike-OSCAR-21x30cm-bijela.png new file mode 100644 index 0000000..cea2d7f Binary files /dev/null and b/okvirovi/Okvir-za-slike-OSCAR-21x30cm-bijela.png differ diff --git a/okvirovi/Okvir-za-slike-OSCAR-21x30cm-crna.png b/okvirovi/Okvir-za-slike-OSCAR-21x30cm-crna.png new file mode 100644 index 0000000..0a18ce4 Binary files /dev/null and b/okvirovi/Okvir-za-slike-OSCAR-21x30cm-crna.png differ diff --git a/okvirovi/Okvir-za-slike-OSCAR-30x40cm-bijela.png b/okvirovi/Okvir-za-slike-OSCAR-30x40cm-bijela.png new file mode 100644 index 0000000..ade8a47 Binary files /dev/null and b/okvirovi/Okvir-za-slike-OSCAR-30x40cm-bijela.png differ diff --git a/okvirovi/Okvir-za-slike-OSCAR-30x40cm-crna.png b/okvirovi/Okvir-za-slike-OSCAR-30x40cm-crna.png new file mode 100644 index 0000000..358350c Binary files /dev/null and b/okvirovi/Okvir-za-slike-OSCAR-30x40cm-crna.png differ diff --git a/okvirovi/Okvir-za-slike-OSCAR-60x90cm-crna.png b/okvirovi/Okvir-za-slike-OSCAR-60x90cm-crna.png new file mode 100644 index 0000000..e2376bb Binary files /dev/null and b/okvirovi/Okvir-za-slike-OSCAR-60x90cm-crna.png differ diff --git a/okvirovi/Okvir-za-slike-TORD-13x18-cm-drvo.png b/okvirovi/Okvir-za-slike-TORD-13x18-cm-drvo.png new file mode 100644 index 0000000..f4356da Binary files /dev/null and b/okvirovi/Okvir-za-slike-TORD-13x18-cm-drvo.png differ diff --git a/okvirovi/Okvir-za-slike-TORD-21x30cm-drvo.png b/okvirovi/Okvir-za-slike-TORD-21x30cm-drvo.png new file mode 100644 index 0000000..ab98076 Binary files /dev/null and b/okvirovi/Okvir-za-slike-TORD-21x30cm-drvo.png differ diff --git a/okvirovi/Okvir-za-slike-TORD-30x40cm-drvo.png b/okvirovi/Okvir-za-slike-TORD-30x40cm-drvo.png new file mode 100644 index 0000000..ef667b9 Binary files /dev/null and b/okvirovi/Okvir-za-slike-TORD-30x40cm-drvo.png differ diff --git a/okvirovi/Okvir-za-slike-TORD-50x70cm-drvo.png b/okvirovi/Okvir-za-slike-TORD-50x70cm-drvo.png new file mode 100644 index 0000000..432e2aa Binary files /dev/null and b/okvirovi/Okvir-za-slike-TORD-50x70cm-drvo.png differ diff --git a/okvirovi/Okvir-za-slike-VAGN-13x18cm-sivi..png b/okvirovi/Okvir-za-slike-VAGN-13x18cm-sivi..png new file mode 100644 index 0000000..ab474d7 Binary files /dev/null and b/okvirovi/Okvir-za-slike-VAGN-13x18cm-sivi..png differ diff --git a/okvirovi/Okvir-za-slike-VAGN-18x24cm-zeleni.png b/okvirovi/Okvir-za-slike-VAGN-18x24cm-zeleni.png new file mode 100644 index 0000000..2737cc4 Binary files /dev/null and b/okvirovi/Okvir-za-slike-VAGN-18x24cm-zeleni.png differ diff --git a/okvirovi/Okvir-za-slike-VALTER-10x15cm-bijela.png b/okvirovi/Okvir-za-slike-VALTER-10x15cm-bijela.png new file mode 100644 index 0000000..3036e18 Binary files /dev/null and b/okvirovi/Okvir-za-slike-VALTER-10x15cm-bijela.png differ diff --git a/okvirovi/Okvir-za-slike-VALTER-10x15cm-crna.png b/okvirovi/Okvir-za-slike-VALTER-10x15cm-crna.png new file mode 100644 index 0000000..b0b8b71 Binary files /dev/null and b/okvirovi/Okvir-za-slike-VALTER-10x15cm-crna.png differ diff --git a/okvirovi/Okvir-za-slike-VALTER-13x18cm-bijela.png b/okvirovi/Okvir-za-slike-VALTER-13x18cm-bijela.png new file mode 100644 index 0000000..dd5bdcc Binary files /dev/null and b/okvirovi/Okvir-za-slike-VALTER-13x18cm-bijela.png differ diff --git a/okvirovi/Okvir-za-slike-VALTER-15x21cm-crna-SDP.png b/okvirovi/Okvir-za-slike-VALTER-15x21cm-crna-SDP.png new file mode 100644 index 0000000..e508dbd Binary files /dev/null and b/okvirovi/Okvir-za-slike-VALTER-15x21cm-crna-SDP.png differ diff --git a/okvirovi/Okvir-za-slike-VALTER-18x24cm-bijela.png b/okvirovi/Okvir-za-slike-VALTER-18x24cm-bijela.png new file mode 100644 index 0000000..9de8574 Binary files /dev/null and b/okvirovi/Okvir-za-slike-VALTER-18x24cm-bijela.png differ diff --git a/okvirovi/Okvir-za-slike-VALTER-30x40cm-bijela.png b/okvirovi/Okvir-za-slike-VALTER-30x40cm-bijela.png new file mode 100644 index 0000000..ea97558 Binary files /dev/null and b/okvirovi/Okvir-za-slike-VALTER-30x40cm-bijela.png differ diff --git a/okvirovi/Okvir-za-slike-VALTER-40x50cm-crna.png b/okvirovi/Okvir-za-slike-VALTER-40x50cm-crna.png new file mode 100644 index 0000000..fd95b78 Binary files /dev/null and b/okvirovi/Okvir-za-slike-VALTER-40x50cm-crna.png differ diff --git a/okvirovi/Okvir-za-slike-VALTER-50x70cm-crna.png b/okvirovi/Okvir-za-slike-VALTER-50x70cm-crna.png new file mode 100644 index 0000000..a89ffb2 Binary files /dev/null and b/okvirovi/Okvir-za-slike-VALTER-50x70cm-crna.png differ diff --git a/slike/.keep b/slike/.keep new file mode 100644 index 0000000..e69de29 diff --git a/util_radne_povrsine.php b/util_radne_povrsine.php new file mode 100644 index 0000000..cecaa94 --- /dev/null +++ b/util_radne_povrsine.php @@ -0,0 +1,44 @@ +open(__DIR__ . '/okvirovi/' . $okvir); + $okvir_size = $okvir_image->getSize(); + $pronasao_transparentnost = false; + + // za svaki piksel + for ($i = 2; $i < $okvir_size->getWidth() ; $i++) { + for ($j = 2; $j < $okvir_size->getHeight() ; $j++) { + // dobavi boju + $boja = $okvir_image->getColorAt(new Imagine\Image\Point($i, $j)); + // provjeri jel transparentna + if($boja->getAlpha() < 90) { + $sirina = $okvir_size->getWidth() - (2 * $i); + $duzina = $okvir_size->getHeight() - (2 * $j); + // vrati velicinu povrsine + // pod pretpostavkom simetricnosti okvira + echo "$okvirid => new Imagine\Image\Box($sirina, $duzina),\n"; + $pronasao_transparentnost = true; + break; + } + } + if ($pronasao_transparentnost) { + break; + } + } + $okvirid++; +} diff --git a/vendor/autoload.php b/vendor/autoload.php new file mode 100644 index 0000000..6fff2bc --- /dev/null +++ b/vendor/autoload.php @@ -0,0 +1,7 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Autoload; + +/** + * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. + * + * $loader = new \Composer\Autoload\ClassLoader(); + * + * // register classes with namespaces + * $loader->add('Symfony\Component', __DIR__.'/component'); + * $loader->add('Symfony', __DIR__.'/framework'); + * + * // activate the autoloader + * $loader->register(); + * + * // to enable searching the include path (eg. for PEAR packages) + * $loader->setUseIncludePath(true); + * + * In this example, if you try to use a class in the Symfony\Component + * namespace or one of its children (Symfony\Component\Console for instance), + * the autoloader will first look for the class under the component/ + * directory, and it will then fallback to the framework/ directory if not + * found before giving up. + * + * This class is loosely based on the Symfony UniversalClassLoader. + * + * @author Fabien Potencier + * @author Jordi Boggiano + * @see http://www.php-fig.org/psr/psr-0/ + * @see http://www.php-fig.org/psr/psr-4/ + */ +class ClassLoader +{ + // PSR-4 + private $prefixLengthsPsr4 = array(); + private $prefixDirsPsr4 = array(); + private $fallbackDirsPsr4 = array(); + + // PSR-0 + private $prefixesPsr0 = array(); + private $fallbackDirsPsr0 = array(); + + private $useIncludePath = false; + private $classMap = array(); + private $classMapAuthoritative = false; + private $missingClasses = array(); + private $apcuPrefix; + + public function getPrefixes() + { + if (!empty($this->prefixesPsr0)) { + return call_user_func_array('array_merge', $this->prefixesPsr0); + } + + return array(); + } + + public function getPrefixesPsr4() + { + return $this->prefixDirsPsr4; + } + + public function getFallbackDirs() + { + return $this->fallbackDirsPsr0; + } + + public function getFallbackDirsPsr4() + { + return $this->fallbackDirsPsr4; + } + + public function getClassMap() + { + return $this->classMap; + } + + /** + * @param array $classMap Class to filename map + */ + public function addClassMap(array $classMap) + { + if ($this->classMap) { + $this->classMap = array_merge($this->classMap, $classMap); + } else { + $this->classMap = $classMap; + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, either + * appending or prepending to the ones previously set for this prefix. + * + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 root directories + * @param bool $prepend Whether to prepend the directories + */ + public function add($prefix, $paths, $prepend = false) + { + if (!$prefix) { + if ($prepend) { + $this->fallbackDirsPsr0 = array_merge( + (array) $paths, + $this->fallbackDirsPsr0 + ); + } else { + $this->fallbackDirsPsr0 = array_merge( + $this->fallbackDirsPsr0, + (array) $paths + ); + } + + return; + } + + $first = $prefix[0]; + if (!isset($this->prefixesPsr0[$first][$prefix])) { + $this->prefixesPsr0[$first][$prefix] = (array) $paths; + + return; + } + if ($prepend) { + $this->prefixesPsr0[$first][$prefix] = array_merge( + (array) $paths, + $this->prefixesPsr0[$first][$prefix] + ); + } else { + $this->prefixesPsr0[$first][$prefix] = array_merge( + $this->prefixesPsr0[$first][$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, either + * appending or prepending to the ones previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-4 base directories + * @param bool $prepend Whether to prepend the directories + * + * @throws \InvalidArgumentException + */ + public function addPsr4($prefix, $paths, $prepend = false) + { + if (!$prefix) { + // Register directories for the root namespace. + if ($prepend) { + $this->fallbackDirsPsr4 = array_merge( + (array) $paths, + $this->fallbackDirsPsr4 + ); + } else { + $this->fallbackDirsPsr4 = array_merge( + $this->fallbackDirsPsr4, + (array) $paths + ); + } + } elseif (!isset($this->prefixDirsPsr4[$prefix])) { + // Register directories for a new namespace. + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } elseif ($prepend) { + // Prepend directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + (array) $paths, + $this->prefixDirsPsr4[$prefix] + ); + } else { + // Append directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + $this->prefixDirsPsr4[$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, + * replacing any others previously set for this prefix. + * + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 base directories + */ + public function set($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr0 = (array) $paths; + } else { + $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, + * replacing any others previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-4 base directories + * + * @throws \InvalidArgumentException + */ + public function setPsr4($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr4 = (array) $paths; + } else { + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } + } + + /** + * Turns on searching the include path for class files. + * + * @param bool $useIncludePath + */ + public function setUseIncludePath($useIncludePath) + { + $this->useIncludePath = $useIncludePath; + } + + /** + * Can be used to check if the autoloader uses the include path to check + * for classes. + * + * @return bool + */ + public function getUseIncludePath() + { + return $this->useIncludePath; + } + + /** + * Turns off searching the prefix and fallback directories for classes + * that have not been registered with the class map. + * + * @param bool $classMapAuthoritative + */ + public function setClassMapAuthoritative($classMapAuthoritative) + { + $this->classMapAuthoritative = $classMapAuthoritative; + } + + /** + * Should class lookup fail if not found in the current class map? + * + * @return bool + */ + public function isClassMapAuthoritative() + { + return $this->classMapAuthoritative; + } + + /** + * APCu prefix to use to cache found/not-found classes, if the extension is enabled. + * + * @param string|null $apcuPrefix + */ + public function setApcuPrefix($apcuPrefix) + { + $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; + } + + /** + * The APCu prefix in use, or null if APCu caching is not enabled. + * + * @return string|null + */ + public function getApcuPrefix() + { + return $this->apcuPrefix; + } + + /** + * Registers this instance as an autoloader. + * + * @param bool $prepend Whether to prepend the autoloader or not + */ + public function register($prepend = false) + { + spl_autoload_register(array($this, 'loadClass'), true, $prepend); + } + + /** + * Unregisters this instance as an autoloader. + */ + public function unregister() + { + spl_autoload_unregister(array($this, 'loadClass')); + } + + /** + * Loads the given class or interface. + * + * @param string $class The name of the class + * @return bool|null True if loaded, null otherwise + */ + public function loadClass($class) + { + if ($file = $this->findFile($class)) { + includeFile($file); + + return true; + } + } + + /** + * Finds the path to the file where the class is defined. + * + * @param string $class The name of the class + * + * @return string|false The path if found, false otherwise + */ + public function findFile($class) + { + // class map lookup + if (isset($this->classMap[$class])) { + return $this->classMap[$class]; + } + if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { + return false; + } + if (null !== $this->apcuPrefix) { + $file = apcu_fetch($this->apcuPrefix.$class, $hit); + if ($hit) { + return $file; + } + } + + $file = $this->findFileWithExtension($class, '.php'); + + // Search for Hack files if we are running on HHVM + if (false === $file && defined('HHVM_VERSION')) { + $file = $this->findFileWithExtension($class, '.hh'); + } + + if (null !== $this->apcuPrefix) { + apcu_add($this->apcuPrefix.$class, $file); + } + + if (false === $file) { + // Remember that this class does not exist. + $this->missingClasses[$class] = true; + } + + return $file; + } + + private function findFileWithExtension($class, $ext) + { + // PSR-4 lookup + $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; + + $first = $class[0]; + if (isset($this->prefixLengthsPsr4[$first])) { + $subPath = $class; + while (false !== $lastPos = strrpos($subPath, '\\')) { + $subPath = substr($subPath, 0, $lastPos); + $search = $subPath . '\\'; + if (isset($this->prefixDirsPsr4[$search])) { + $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); + foreach ($this->prefixDirsPsr4[$search] as $dir) { + if (file_exists($file = $dir . $pathEnd)) { + return $file; + } + } + } + } + } + + // PSR-4 fallback dirs + foreach ($this->fallbackDirsPsr4 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { + return $file; + } + } + + // PSR-0 lookup + if (false !== $pos = strrpos($class, '\\')) { + // namespaced class name + $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) + . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); + } else { + // PEAR-like class name + $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; + } + + if (isset($this->prefixesPsr0[$first])) { + foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { + if (0 === strpos($class, $prefix)) { + foreach ($dirs as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + } + } + } + + // PSR-0 fallback dirs + foreach ($this->fallbackDirsPsr0 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + + // PSR-0 include paths. + if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { + return $file; + } + + return false; + } +} + +/** + * Scope isolated include. + * + * Prevents access to $this/self from included files. + */ +function includeFile($file) +{ + include $file; +} diff --git a/vendor/composer/LICENSE b/vendor/composer/LICENSE new file mode 100644 index 0000000..f27399a --- /dev/null +++ b/vendor/composer/LICENSE @@ -0,0 +1,21 @@ + +Copyright (c) Nils Adermann, Jordi Boggiano + +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. + diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php new file mode 100644 index 0000000..7a91153 --- /dev/null +++ b/vendor/composer/autoload_classmap.php @@ -0,0 +1,9 @@ + array($vendorDir . '/imagine/imagine/src'), +); diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php new file mode 100644 index 0000000..d7f3483 --- /dev/null +++ b/vendor/composer/autoload_real.php @@ -0,0 +1,55 @@ += 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); + if ($useStaticLoader) { + require_once __DIR__ . '/autoload_static.php'; + + call_user_func(\Composer\Autoload\ComposerStaticInitfc8948f56a15b1d34cbda7dcc8cc2710::getInitializer($loader)); + } else { + $map = require __DIR__ . '/autoload_namespaces.php'; + foreach ($map as $namespace => $path) { + $loader->set($namespace, $path); + } + + $map = require __DIR__ . '/autoload_psr4.php'; + foreach ($map as $namespace => $path) { + $loader->setPsr4($namespace, $path); + } + + $classMap = require __DIR__ . '/autoload_classmap.php'; + if ($classMap) { + $loader->addClassMap($classMap); + } + } + + $loader->register(true); + + return $loader; + } +} diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php new file mode 100644 index 0000000..9b3dc5b --- /dev/null +++ b/vendor/composer/autoload_static.php @@ -0,0 +1,31 @@ + + array ( + 'Imagine\\' => 8, + ), + ); + + public static $prefixDirsPsr4 = array ( + 'Imagine\\' => + array ( + 0 => __DIR__ . '/..' . '/imagine/imagine/src', + ), + ); + + public static function getInitializer(ClassLoader $loader) + { + return \Closure::bind(function () use ($loader) { + $loader->prefixLengthsPsr4 = ComposerStaticInitfc8948f56a15b1d34cbda7dcc8cc2710::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInitfc8948f56a15b1d34cbda7dcc8cc2710::$prefixDirsPsr4; + + }, null, ClassLoader::class); + } +} diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json new file mode 100644 index 0000000..3fdd0e4 --- /dev/null +++ b/vendor/composer/installed.json @@ -0,0 +1,62 @@ +[ + { + "name": "imagine/imagine", + "version": "1.2.3", + "version_normalized": "1.2.3.0", + "source": { + "type": "git", + "url": "https://github.com/avalanche123/Imagine.git", + "reference": "cb2361e5bb4410b681462d8e4f912bc5dabf84ab" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/avalanche123/Imagine/zipball/cb2361e5bb4410b681462d8e4f912bc5dabf84ab", + "reference": "cb2361e5bb4410b681462d8e4f912bc5dabf84ab", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "2.2.*", + "phpunit/phpunit": "^4.8 || ^5.7 || ^6.5 || ^7.5 || ^8.4" + }, + "suggest": { + "ext-gd": "to use the GD implementation", + "ext-gmagick": "to use the Gmagick implementation", + "ext-imagick": "to use the Imagick implementation" + }, + "time": "2019-12-04T09:55:33+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-develop": "0.7-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Imagine\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bulat Shakirzyanov", + "email": "mallluhuct@gmail.com", + "homepage": "http://avalanche123.com" + } + ], + "description": "Image processing for PHP 5.3", + "homepage": "http://imagine.readthedocs.org/", + "keywords": [ + "drawing", + "graphics", + "image manipulation", + "image processing" + ] + } +] diff --git a/vendor/imagine/imagine/CHANGELOG.md b/vendor/imagine/imagine/CHANGELOG.md new file mode 100644 index 0000000..8e8e818 --- /dev/null +++ b/vendor/imagine/imagine/CHANGELOG.md @@ -0,0 +1,253 @@ +# CHANGELOG + +### 1.2.3 (2019-12-04) +* Handle jfif extension in GD driver (#727, @sylvain-msl-talkspirit) +* Improve detection of unsupported Exit Metadata Reader (#729, @mlocati, @ausi) + +### 1.2.2 (2019-07-09) +* The GD driver can now load WebP files (#711, #718, @lashus, @ausi) +* Avoid calling `imageantialias` if it's not available (#713, @ahukkanen) + +### 1.2.1 (2019-06-03) +* Silence call to `\Imagick::setImageOpacity()` in order to prevent deprecation error with Imagick 3.4.4 and ImageMagick 6 (#715, @samdark, @mlocati) + +### 1.2.0 (2018-12-07) +* `ExifMetadataReader` now returns all the available metadata, not only EXIF and IFD0 (#701, @mlocati) + +### 1.1.0 (2018-10-25) +* New `ImageInterface::THUMBNAIL_FLAG_NOCLONE` flag for `thumbnail()` to let it modify the original image instance in order to save memory (@mlocati) + +### 1.0.2 (2018-10-24) +* Check that the Imagick PHP extension is not compiled using ImageMagick version 7.0.7-32 because it does not work correctly (@mlocati) + +### 1.0.1 (2018-09-27) +* `Box` now rounds the width/height it receives (previously it discarded the decimal points) (@mlocati) + +### 1.0.0 (2018-09-25) +* New `FontInterface` method: `wrapText` - split a text into multiple lines, so that it fits a specific width (@mlocati) + **BREAKING CHANGE** if you have your own `FontInterface` implementation, it now must implement `wrapText` +* Drawer methods can now accept a thickness of zero (@mlocati) +* Fix drawing unfilled chords with GD driver (@mlocati) +* Fix thickness drawing of unfilled chords with Imagick and Gmagick drivers (@mlocati) +* Fix handling of radius in `circle` method implementations (@mlocati) +* The `dissolve` method of `ColorInterface` normalizes the final value of alpha (@mlocati) + **BREAKING CHANGE** `dissolve` doesn't throw a `Imagine\Exception\InvalidArgumentException` anymore + +### 1.0.0-alpha2 (2018-09-08) +* The `coalesce` method of `LayerInterface` instances now returns the LayerInterface itself (@mlocati) + **BREAKING CHANGE** if you have your own `LayerInterface` implementation, it now must return `$this` +* The `__toString` method has been added to `ColorInterface` since all its implementations have it (@mlocati) + **BREAKING CHANGE** if you have your own `ColorInterface` implementation, it now must implement `__toString` +* New Imagick save option: `optimize` if set, the size of animated GIF files is optimized (@mlocati) + **NOTE** Imagick requires that the image frames have the same size +* The `paste` method now accepts images not fully included in the destination image (@mlocati) + **BREAKING CHANGE** the paste method doesn't throw an OutOfBoundsException anymore +* Fix handling of PNG compression in Imagick `save` method (@mlocati) +* New drawer methods: `rectangle` and `circle` (@mlocati) + **BREAKING CHANGE** if you have your own implementation of `DrawerInterface` you should add these two new methods +* The `getChannelsMaxValue` method has been added to `PaletteInterface` (@mlocati) + **BREAKING CHANGE** if you have your own `PaletteInterface` implementation, it now must implement this new method + +### 1.0.0-alpha1 (2018-08-28) +* Imagine is now tested under Windows too (@mlocati) +* Add support to webp image format (@chregu, @antoligy, @alexander-schranz) +* Add `Imagine\File\LoaderInterface` that allows loading remote images with any imaging driver (@mlocati). + You can use your own `LoaderInterface` implementation so that you can for instance use curl or any other library. +* Fix some phpdoc issues (@mlocati) +* `flipHorizontally` and `flipVertically` methods of GD images is now much faster on PHP 5.5+ (@mlocati) +* Fix loading of PNG indexed images with GD (@mlocati) +* Loading indexed images with GD is now much faster on PHP 5.5+ (@mlocati) +* Add support to grayscale images with Gmagick (@mlocati) +* Add support to alpha channels of Gmagick images (@mlocati) +* Fix `getColorAt` method of Gmagick images (@mlocati) +* Add `getTransformations` to the `Autorotate` filter, so that you can get the list of transformations that should be applied to an image accordingly to the EXIF metadata (@mlocati) +* The metadata reader now doesn't throw exceptions or warnings (@lentex, @mlocati) +* Fix documentation (@ZhangChaoWN, @Mark-H, @mlocati) +* Fix pixel range issue with Gmagick image (@b-viguier) +* Fix `text` drawer method on Windows when using relative font file paths (@mlocati) +* Fix `box` font method on Windows when using relative font file paths (@mlocati) +* Fix crash on Windows when loading an image with Imagick (@mlocati) +* Fix generation of API documentation (@mlocati) +* Add `jpeg_sampling_factors` option when saving JPEG images (Gmagick/Imagick only) (@ausi) +* Add BMP as supported image format (@mlocati) +* Add support to new image type constants of Imagick (@ausi) +* Check that Imagick correctly supports profiles (@ausi) +* Add `setMetadataReader`/`getMetadataReader` to `ImagineInterface` (@mlocati) + **BREAKING CHANGE** if you have your own `ImagineInterface` implementation, it now must implement those two methods +* Fix creating Gmagick images with alpha colors when palette doesn't support alpha (@FractalizeR) +* Fix warning about deprecated clone method in copy method of Imagick images (@mlocati) +* Fix copy methods of Images (the original image and its new copy are now fully detached) (@mlocati) +* It's now possible to use `clone $image` as an alternative to `$image->copy()` (@mlocati) +* Add support to custom classes for `BoxInterface`, `MetadataReaderInterface`, `FontInterface`, `LoaderInterface`, `LayersInterface`, `ImageInterface` (@mlocati) + **BREAKING CHANGE** if you have your own `ImagineInterface` implementation, it now must implement the methods of `ClassFactoryAwareInterface` +* Add support for pasting with alpha for GD and Imagick (@AlloVince, @mlocati) +* Downscaling a `Box` until it reaches a dimension less than 1 returns a box with dimension of 1 instead of throwing an exception (@mlocati) + **BREAKING CHANGE** if you relied on `Box::scale` throwing an exception in this case +* New filters: `BlackWhite`, `BorderDetection`, `Negation`, `Neighborhood` (@rejinka) +* Minor optimization of filters based on `OnPixelBased` (@rejinka, @mlocati) +* Add flag to `thumbnail` to allow upscaling images (@vlakoff) + **BREAKING CHANGE** the `$mode` argument has been renamed to `$settings`, and it's now an integer (but old string values are accepted for backward compatibility). In this case the `ManipulatorInterface` constants `THUMBNAIL_INSET`, `THUMBNAIL_OUTBOUND` were changed from string values to integers. +* New filter: `brightness` (@lenybernard, @mlocati) +* New filter: `colvolve` available for all graphics libraries except gmagick with version prior to 2.0.1RC2 (@armatronic, @mlocati) +* Fix bug in Imagine\Image\Palette\RGB::blend() (@dmolineus, @mlocati) +* Autoload was moved from PSR-0 to PSR-4, and code files moved from `/lib/Imagine` to `/src` (@mlocati) + +### 0.7.1 (2017-05-16) +* Remove Symfony PHPUnit bridge as dependency (@craue) + +### 0.7.0 (2017-05-02) +* Fix memory usage on metadata reading (@Seldaek) +* PHP 7.1 support +* Latest Imagemagick compatibility (@jdewit) + +### 0.6.3 (2015-09-19) +* Fix wrong array_merge when calling Transformation::getFilters without filters +* Add export-ignore git attribute (@Benoth) +* Fix docblocks (@Sm0ke0ut and @norkunas) +* Fix animated gif loop length options (@jygaulier) +* Multiple tweaks for the repository and travis builds (@localheinz, @vrkansagara and @dunzun) +* Fix metadata extraction from streams (@armatronic) +* Fix autorotation (@tarleb) +* Load exifmetadata reader whenever possible +* Add metadata getter + +### 0.6.2 (2014-11-11) +* Stripping image containing an invalid ICC profile fails +* MetadataBag now implements \Countable +* Fix wrong array_merge in MetadataBag giving invalid results with HTTP resources (@javaguirre) +* Fix Imagick merge strategy (@GrahamCampbell) +* Fixed various alpha issues (@RadekDvorak) +* Fix Image cloning on HHVM (@RdeWilde) +* Fix exception on invalid file using GD driver (@vlakoff). +* Fix ImageInterface::getSize on animated GIFs (@sokac) + +### 0.6.1 (2014-06-16) +* Fix invalid namespace usage (#336 @csanquer). + +### 0.6.0 (2014-06-13) +* BC break: Colors are now provided through the PaletteInterface. Any call + to previous Imagine\Image\Color constructor must be removed and use the + palette provided by Imagine\Image\ImageInterface::getPalette to create + colors. +* BC break : Animated GIF default delay is no longer 800ms but null. This + avoids resettings a delay on animated image. +* Add support for ICC profiles +* Add support for CMYK and grayscale colorspace images. +* Add filter argument to ImageInterface::thumbnail method. +* Add priority to filters (@Richtermeister). +* Add blur effect (@Nokrosis). +* Rename "quality" option to "jpeg_quality" and apply it only to JPEG files (@vlakoff). +* Add "png_compression_level" option (@vlakoff). +* Rename "filters" option to "png_compression_filter" (@vlakoff). +* Deprecate `quality` and `filters` ManipulatorInterface::save options, use + `jpeg_quality`, `png_compression_level` and `png_compression_filter` instead. +* Add support for alpha blending in GD drawer (@salem). +* Add width parameter to Drawer::text (@salemgolemugoo). +* Add NotSupportedException when a driver does not support an operation (@rouffj). +* Add support for metadata. +* Fix #158: GD alpha detection + Color::isOpaque are broken. +* Fix color extraction for non-RGB palettes. + +### 0.5.0 (2013-07-10) +* Add `Layers::coalesce`. +* Add filter option to `ImageInterface::resize`. +* Add sharpen effect. +* Add interlace support. +* `LayersInterface` now extends `ArrayAccess`, gives support for animated gifs. +* Remove Imagick and Gmagick flatten after composite. +* Fix pixel opacity reading in `Gmagick::histogram`. +* Deprecate pear channel installation. +* Deprecate phar installation. + +### 0.4.1 (2012-12-13) +* Lazy-load GD layers. + +### 0.4.0 (2012-12-10) +* Add support for image Layers. +* Add Colorize effect. +* Add documentation for the Grayscale effect. +* Port RelativeResize filter from JmikolaImagineBundle. + +### 0.3.1 (2012-11-12) +* Add Grayscale effect. +* `Drawer::text` position fix. + +### 0.3.0 (2012-07-28) +* Add configurable border thickness to drawer interface and implementations. +* Add `ImageInterface`::strip. +* Add Canvas filter. +* Add resolution option on image saving. +* Add Grayscale filter. +* Add sami API documentation. +* Add compression quality to Gmagick. +* Add effects API. +* Add method to get pixel at point in Gmagick. +* Ensure valid background color in rotations. +* Fill lines with color to prevent semi-transparency issues. +* Use `Imagick::resizeImage` instead of `Imagick::thumbnailImage` for resizing. +* Fix PNG transparency on save ; do not flatten if not necessary. + +### 0.2.8 (2011-11-29) +* Add support for Travis CI. + +### 0.2.7 (2011-11-17) +* Use composer for autoloading. + +### 0.2.6 (2011-11-09) +* Documentation enhancements. + +### 0.2.5 (2011-10-29) +* Add PEAR support. +* Documentation enhancements. + +### 0.2.4 (2011-10-17) +* Add imagine.phar, phar and rake tasks. +* Add `ImagineInterface::read` to read from a stream resource. +* Documentation enhancements. +* Fix gifs transparency issues. + +### 0.2.3 (2011-10-16) +* Documentation enhancements. + +### 0.2.2 (2011-10-16) +* Documentation enhancements. + +### 0.2.1 (2011-10-15) +* Add `PointInterface::move`. +* `BoxInterface::scale` can accept floats. +* Set antialias mode for GD images. +* Fix png compression. + +### 0.2.0 (2011-10-06) +* Add `Imagine\Fill\Gradient\Linear::getStart`/`getEnd`. +* Add `Imagine\Image\Color::isOpaque`. +* Add Gmagick transparency exceptions. +* Add support for transparency for gif export. +* Add widen/heighten methods for easy scaling to target width/height. +* Add functionals tests to unit test thumbnails creation. +* Add the ability to use hexadecimal notation for `Imagine\Image\Color` construction. +* Implement fast linear gradient for Imagick. +* Remove lengthy image histogram comparisons. +* Extract `ManipulatorInterface` from `ImageInterface`. +* Switch methods to final. +* New method `ImageInterface::getColorAt`. +* Introduce `ImagineAware` abstract filter class. + +### 0.1.5 (2011-05-18) +* Fix bug in GD rotate. + +### 0.1.4 (2011-03-21) +* Add environment check to gracefuly skip test. + +### 0.1.3 (2011-03-21) +* Improve api docs. +* Extract `FontInterface`. + +### 0.1.2 (2011-03-21) +* Add check for GD. + +### 0.1.1 (2011-03-21) +* Add rounding and fixed thumbnail logic. + +### 0.1.0 (2011-03-14) +* First tagged version. diff --git a/vendor/imagine/imagine/LICENSE b/vendor/imagine/imagine/LICENSE new file mode 100644 index 0000000..8de9133 --- /dev/null +++ b/vendor/imagine/imagine/LICENSE @@ -0,0 +1,25 @@ +Copyright (c) 2004-2012 Bulat Shakirzyanov + +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. + +This software embeds Adobe ICC Profiles, see license at +http://www.adobe.com/support/downloads/iccprofiles/icc_eula_mac_dist.html . + +This software also embeds ICC Profile from colormanagement.org. Please +find information about their license at http://colormanagement.org/ . diff --git a/vendor/imagine/imagine/README.md b/vendor/imagine/imagine/README.md new file mode 100644 index 0000000..7b36e9a --- /dev/null +++ b/vendor/imagine/imagine/README.md @@ -0,0 +1,58 @@ +# Imagine +[![Travis CI Build Status](https://travis-ci.org/avalanche123/Imagine.svg?branch=develop)](https://travis-ci.org/avalanche123/Imagine) [![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/avalanche123/Imagine?branch=develop&svg=true)](https://ci.appveyor.com/project/avalanche123/Imagine) + +Tweet about it using the [#php_imagine](https://twitter.com/search?q=%23php_imagine) hashtag. + +Image manipulation library for PHP 5.3 inspired by Python's PIL and other image +libraries. + +## Requirements + +The Imagine library has the following requirements: + + - PHP 5.3+ + +Depending on the chosen Image implementation, you may need one of the following PHP extensions: + + - GD2 + - Imagick (with ImageMagick version 6.2.9 or later, except version 7.0.7-32) + - Gmagick + +### Installation using composer +`php composer.phar require imagine/imagine` + +## Basic Principles + +The main purpose of Imagine is to provide all the necessary functionality to bring all native low level image processing libraries in PHP to the same simple and intuitive OO API. + +Several things are necessary to accomplish that: + +* Image manipulation tools, such as resize, crop, etc. +* Drawing API - to create basic shapes and advanced charts, write text on the image +* Masking functionality - ability to apply black&white or grayscale images as masks, leading to semi-transparency or absolute transparency of the image the mask is being applied to + +The above tools should be the basic foundation for a more powerful set of tools that are called ``Filters`` in Imagine. + +Some of the ideas for upcoming filters: + +* Charting and graphing filters - pie and bar charts, linear graphs with annotations +* Reflection - apple style +* Rounded corners - web 2.0 + +## Documentation ## + + - [Hosted by Read The Docs](http://imagine.readthedocs.org/) + +## Presentations ## + + - [Introduction to Imagine](http://www.slideshare.net/avalanche123/introduction-toimagine) + - [How to Take Over the World with Lithium](http://speakerdeck.com/u/nateabele/p/how-to-take-over-the-world-with-lithium?slide=33) + +## Articles ## + + - [Image Processing with Imagine](http://www.phparch.com/2011/03/image-processing-with-imagine) + +## Contributing ## + +New pull requests should be based on the `develop` branch. +The `master` branch is the stable branch: it usually matches the latest a release but in can be a bit ahead. diff --git a/vendor/imagine/imagine/composer.json b/vendor/imagine/imagine/composer.json new file mode 100644 index 0000000..25b3a7d --- /dev/null +++ b/vendor/imagine/imagine/composer.json @@ -0,0 +1,62 @@ +{ + "name": "imagine/imagine", + "description": "Image processing for PHP 5.3", + "keywords": [ + "image manipulation", + "image processing", + "drawing", + "graphics" + ], + "homepage": "http://imagine.readthedocs.org/", + "license": "MIT", + "authors": [ + { + "name": "Bulat Shakirzyanov", + "email": "mallluhuct@gmail.com", + "homepage": "http://avalanche123.com" + } + ], + "require": { + "php": ">=5.3.2" + }, + "require-dev": { + "phpunit/phpunit": "^4.8 || ^5.7 || ^6.5 || ^7.5 || ^8.4", + "friendsofphp/php-cs-fixer": "2.2.*" + }, + "suggest": { + "ext-gd": "to use the GD implementation", + "ext-imagick": "to use the Imagick implementation", + "ext-gmagick": "to use the Gmagick implementation" + }, + "autoload": { + "psr-4": { + "Imagine\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "Imagine\\Test\\": "tests/tests/" + } + }, + "extra": { + "branch-alias": { + "dev-develop": "0.7-dev" + } + }, + "archive": { + "exclude": [ + "/.*", + "/tests", + "/vendor", + "/bin", + "docs/_build", + "Imagine-*.tgz", + "imagine-*.phar", + "composer.phar" + ] + }, + "scripts": { + "test": "phpunit --verbose", + "codestyle": "php-cs-fixer fix --path-mode=intersection --config=.php_cs.dist" + } +} diff --git a/vendor/imagine/imagine/src/Draw/DrawerInterface.php b/vendor/imagine/imagine/src/Draw/DrawerInterface.php new file mode 100644 index 0000000..bf1e5ff --- /dev/null +++ b/vendor/imagine/imagine/src/Draw/DrawerInterface.php @@ -0,0 +1,175 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Draw; + +use Imagine\Image\AbstractFont; +use Imagine\Image\BoxInterface; +use Imagine\Image\Palette\Color\ColorInterface; +use Imagine\Image\PointInterface; + +/** + * Interface for the drawer. + */ +interface DrawerInterface +{ + /** + * Draws an arc on a starting at a given x, y coordinates under a given + * start and end angles. + * + * @param \Imagine\Image\PointInterface $center + * @param \Imagine\Image\BoxInterface $size + * @param int $start + * @param int $end + * @param \Imagine\Image\Palette\Color\ColorInterface $color + * @param int $thickness + * + * @throws \Imagine\Exception\RuntimeException + * + * @return $this + */ + public function arc(PointInterface $center, BoxInterface $size, $start, $end, ColorInterface $color, $thickness = 1); + + /** + * Same as arc, but also connects end points with a straight line. + * + * @param \Imagine\Image\PointInterface $center + * @param \Imagine\Image\BoxInterface $size + * @param int $start + * @param int $end + * @param \Imagine\Image\Palette\Color\ColorInterface $color + * @param bool $fill + * @param int $thickness + * + * @throws \Imagine\Exception\RuntimeException + * + * @return $this + */ + public function chord(PointInterface $center, BoxInterface $size, $start, $end, ColorInterface $color, $fill = false, $thickness = 1); + + /** + * Draws and circle with center at the given x, y coordinates, and given radius. + * + * @param \Imagine\Image\PointInterface $center + * @param int $radius + * @param \Imagine\Image\Palette\Color\ColorInterface $color + * @param bool $fill + * @param int $thickness + * + * @throws \Imagine\Exception\RuntimeException + * + * @return $this + */ + public function circle(PointInterface $center, $radius, ColorInterface $color, $fill = false, $thickness = 1); + + /** + * Draws and ellipse with center at the given x, y coordinates, and given width and height. + * + * @param \Imagine\Image\PointInterface $center + * @param \Imagine\Image\BoxInterface $size + * @param \Imagine\Image\Palette\Color\ColorInterface $color + * @param bool $fill + * @param int $thickness + * + * @throws \Imagine\Exception\RuntimeException + * + * @return $this + */ + public function ellipse(PointInterface $center, BoxInterface $size, ColorInterface $color, $fill = false, $thickness = 1); + + /** + * Draws a line from start(x, y) to end(x, y) coordinates. + * + * @param \Imagine\Image\PointInterface $start + * @param \Imagine\Image\PointInterface $end + * @param \Imagine\Image\Palette\Color\ColorInterface $outline + * @param int $thickness + * + * @return $this + */ + public function line(PointInterface $start, PointInterface $end, ColorInterface $outline, $thickness = 1); + + /** + * Same as arc, but connects end points and the center. + * + * @param \Imagine\Image\PointInterface $center + * @param \Imagine\Image\BoxInterface $size + * @param int $start + * @param int $end + * @param \Imagine\Image\Palette\Color\ColorInterface $color + * @param bool $fill + * @param int $thickness + * + * @throws \Imagine\Exception\RuntimeException + * + * @return $this + */ + public function pieSlice(PointInterface $center, BoxInterface $size, $start, $end, ColorInterface $color, $fill = false, $thickness = 1); + + /** + * Places a one pixel point at specific coordinates and fills it with + * specified color. + * + * @param \Imagine\Image\PointInterface $position + * @param \Imagine\Image\Palette\Color\ColorInterface $color + * + * @throws \Imagine\Exception\RuntimeException + * + * @return $this + */ + public function dot(PointInterface $position, ColorInterface $color); + + /** + * Draws a rectangle from left, top(x, y) to right, bottom(x, y) coordinates. + * + * @param \Imagine\Image\PointInterface $leftTop + * @param \Imagine\Image\PointInterface $rightBottom + * @param \Imagine\Image\Palette\Color\ColorInterface $color + * @param bool $fill + * @param int $thickness + * + * @throws \Imagine\Exception\RuntimeException + * + * @return $this + */ + public function rectangle(PointInterface $leftTop, PointInterface $rightBottom, ColorInterface $color, $fill = false, $thickness = 1); + + /** + * Draws a polygon using array of x, y coordinates. Must contain at least three coordinates. + * + * @param \Imagine\Image\PointInterface[] $coordinates + * @param \Imagine\Image\Palette\Color\ColorInterface $color + * @param bool $fill + * @param int $thickness + * + * @throws \Imagine\Exception\RuntimeException + * + * @return $this + */ + public function polygon(array $coordinates, ColorInterface $color, $fill = false, $thickness = 1); + + /** + * Annotates image with specified text at a given position starting on the top left of the final text box. + * + * The rotation is done CW + * + * @param string $string + * @param \Imagine\Image\AbstractFont $font + * @param \Imagine\Image\PointInterface $position + * @param int $angle + * @param int $width + * + * @throws \Imagine\Exception\RuntimeException + * + * @return $this + */ + public function text($string, AbstractFont $font, PointInterface $position, $angle = 0, $width = null); +} diff --git a/vendor/imagine/imagine/src/Effects/EffectsInterface.php b/vendor/imagine/imagine/src/Effects/EffectsInterface.php new file mode 100644 index 0000000..2bdcf96 --- /dev/null +++ b/vendor/imagine/imagine/src/Effects/EffectsInterface.php @@ -0,0 +1,103 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Effects; + +use Imagine\Image\Palette\Color\ColorInterface; +use Imagine\Utils\Matrix; + +/** + * Interface for the effects. + */ +interface EffectsInterface +{ + /** + * Apply gamma correction. + * + * @param float $correction + * + * @throws \Imagine\Exception\RuntimeException + * + * @return $this + */ + public function gamma($correction); + + /** + * Invert the colors of the image. + * + * @throws \Imagine\Exception\RuntimeException + * + * @return $this + */ + public function negative(); + + /** + * Grayscale the image. + * + * @throws \Imagine\Exception\RuntimeException + * + * @return $this + */ + public function grayscale(); + + /** + * Colorize the image. + * + * @param \Imagine\Image\Palette\Color\ColorInterface $color + * + * @throws \Imagine\Exception\RuntimeException + * + * @return $this + */ + public function colorize(ColorInterface $color); + + /** + * Sharpens the image. + * + * @throws \Imagine\Exception\RuntimeException + * + * @return $this + */ + public function sharpen(); + + /** + * Blur the image. + * + * @param float|int $sigma + * + * @throws \Imagine\Exception\RuntimeException + * + * @return $this + */ + public function blur($sigma); + + /** + * Changes the brightness of the image. + * + * @param int $brightness The level of brightness (-100 (black) to 100 (white)) + * + * @throws \Imagine\Exception\RuntimeException + * + * @return $this + */ + public function brightness($brightness); + + /** + * Convolves the image. + * + * @param \Imagine\Utils\Matrix $matrix The matrix from which derive the convolution kernel + * + * @throws \Imagine\Exception\RuntimeException + * + * @return $this + */ + public function convolve(Matrix $matrix); +} diff --git a/vendor/imagine/imagine/src/Exception/Exception.php b/vendor/imagine/imagine/src/Exception/Exception.php new file mode 100644 index 0000000..f38f140 --- /dev/null +++ b/vendor/imagine/imagine/src/Exception/Exception.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Exception; + +/** + * Imagine-specific exception. + */ +interface Exception +{ +} diff --git a/vendor/imagine/imagine/src/Exception/InvalidArgumentException.php b/vendor/imagine/imagine/src/Exception/InvalidArgumentException.php new file mode 100644 index 0000000..3a5de8c --- /dev/null +++ b/vendor/imagine/imagine/src/Exception/InvalidArgumentException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Exception; + +/** + * Imagine-specific invalid argument exception. + */ +class InvalidArgumentException extends \InvalidArgumentException implements Exception +{ +} diff --git a/vendor/imagine/imagine/src/Exception/NotSupportedException.php b/vendor/imagine/imagine/src/Exception/NotSupportedException.php new file mode 100644 index 0000000..fd68ce7 --- /dev/null +++ b/vendor/imagine/imagine/src/Exception/NotSupportedException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Exception; + +/** + * Should be used when a driver does not support an operation. + */ +class NotSupportedException extends RuntimeException implements Exception +{ +} diff --git a/vendor/imagine/imagine/src/Exception/OutOfBoundsException.php b/vendor/imagine/imagine/src/Exception/OutOfBoundsException.php new file mode 100644 index 0000000..dbd794b --- /dev/null +++ b/vendor/imagine/imagine/src/Exception/OutOfBoundsException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Exception; + +/** + * Imagine-specific out of bounds exception. + */ +class OutOfBoundsException extends \OutOfBoundsException implements Exception +{ +} diff --git a/vendor/imagine/imagine/src/Exception/RuntimeException.php b/vendor/imagine/imagine/src/Exception/RuntimeException.php new file mode 100644 index 0000000..2c07bff --- /dev/null +++ b/vendor/imagine/imagine/src/Exception/RuntimeException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Exception; + +/** + * Imagine-specific runtime exception. + */ +class RuntimeException extends \RuntimeException implements Exception +{ +} diff --git a/vendor/imagine/imagine/src/Factory/ClassFactory.php b/vendor/imagine/imagine/src/Factory/ClassFactory.php new file mode 100644 index 0000000..eba7b31 --- /dev/null +++ b/vendor/imagine/imagine/src/Factory/ClassFactory.php @@ -0,0 +1,189 @@ +finalize(ExifMetadataReader::isSupported() ? new ExifMetadataReader() : new DefaultMetadataReader()); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Factory\ClassFactoryInterface::createBox() + */ + public function createBox($width, $height) + { + return $this->finalize(new Box($width, $height)); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Factory\ClassFactoryInterface::createFileLoader() + */ + public function createFileLoader($path) + { + return $this->finalize(new Loader($path)); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Factory\ClassFactoryInterface::createDrawer() + */ + public function createDrawer($handle, $resource) + { + switch ($handle) { + case self::HANDLE_GD: + return $this->finalize(new \Imagine\Gd\Drawer($resource)); + case self::HANDLE_GMAGICK: + return $this->finalize(new \Imagine\Gmagick\Drawer($resource)); + case self::HANDLE_IMAGICK: + return $this->finalize(new \Imagine\Imagick\Drawer($resource)); + default: + throw new InvalidArgumentException(sprintf('Unrecognized handle %s in %s', $handle, __FUNCTION__)); + } + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Factory\ClassFactoryInterface::createLayers() + */ + public function createLayers($handle, ImageInterface $image, $initialKey = null) + { + switch ($handle) { + case self::HANDLE_GD: + return $this->finalize(new \Imagine\Gd\Layers($image, $image->palette(), $image->getGdResource(), (int) $initialKey)); + case self::HANDLE_GMAGICK: + return $this->finalize(new \Imagine\Gmagick\Layers($image, $image->palette(), $image->getGmagick(), (int) $initialKey)); + case self::HANDLE_IMAGICK: + return $this->finalize(new \Imagine\Imagick\Layers($image, $image->palette(), $image->getImagick(), (int) $initialKey)); + default: + throw new InvalidArgumentException(sprintf('Unrecognized handle %s in %s', $handle, __FUNCTION__)); + } + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Factory\ClassFactoryInterface::createEffects() + */ + public function createEffects($handle, $resource) + { + switch ($handle) { + case self::HANDLE_GD: + return $this->finalize(new \Imagine\Gd\Effects($resource)); + case self::HANDLE_GMAGICK: + return $this->finalize(new \Imagine\Gmagick\Effects($resource)); + case self::HANDLE_IMAGICK: + return $this->finalize(new \Imagine\Imagick\Effects($resource)); + default: + throw new InvalidArgumentException(sprintf('Unrecognized handle %s in %s', $handle, __FUNCTION__)); + } + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Factory\ClassFactoryInterface::createImage() + */ + public function createImage($handle, $resource, PaletteInterface $palette, MetadataBag $metadata) + { + switch ($handle) { + case self::HANDLE_GD: + return $this->finalize(new \Imagine\Gd\Image($resource, $palette, $metadata)); + case self::HANDLE_GMAGICK: + return $this->finalize(new \Imagine\Gmagick\Image($resource, $palette, $metadata)); + case self::HANDLE_IMAGICK: + return $this->finalize(new \Imagine\Imagick\Image($resource, $palette, $metadata)); + default: + throw new InvalidArgumentException(sprintf('Unrecognized handle %s in %s', $handle, __FUNCTION__)); + } + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Factory\ClassFactoryInterface::createFont() + */ + public function createFont($handle, $file, $size, ColorInterface $color) + { + switch ($handle) { + case self::HANDLE_GD: + $gdInfo = static::getGDInfo(); + if (!$gdInfo['FreeType Support']) { + throw new RuntimeException('GD is not compiled with FreeType support'); + } + + return $this->finalize(new \Imagine\Gd\Font($file, $size, $color)); + case self::HANDLE_GMAGICK: + $gmagick = new \Gmagick(); + $gmagick->newimage(1, 1, 'transparent'); + + return $this->finalize(new \Imagine\Gmagick\Font($gmagick, $file, $size, $color)); + case self::HANDLE_IMAGICK: + return $this->finalize(new \Imagine\Imagick\Font(new \Imagick(), $file, $size, $color)); + default: + throw new InvalidArgumentException(sprintf('Unrecognized handle %s in %s', $handle, __FUNCTION__)); + } + } + + /** + * Finalize the newly created object. + * + * @param object $object + * + * @return object + */ + protected function finalize($object) + { + if ($object instanceof ClassFactoryAwareInterface) { + $object->setClassFactory($this); + } + + return $object; + } + + /** + * @return array + */ + protected static function getGDInfo() + { + if (self::$gdInfo === null) { + if (!function_exists('gd_info')) { + throw new RuntimeException('GD is not installed'); + } + self::$gdInfo = gd_info(); + } + + return self::$gdInfo; + } +} diff --git a/vendor/imagine/imagine/src/Factory/ClassFactoryAwareInterface.php b/vendor/imagine/imagine/src/Factory/ClassFactoryAwareInterface.php new file mode 100644 index 0000000..8bb74f3 --- /dev/null +++ b/vendor/imagine/imagine/src/Factory/ClassFactoryAwareInterface.php @@ -0,0 +1,25 @@ +path = (string) $path; + if ($this->path === '') { + throw new InvalidArgumentException('$path is empty'); + } + $this->isUrl = filter_var($this->path, FILTER_VALIDATE_URL) !== false; + if (!$this->isUrl) { + $this->checkLocalFile(); + } + } + + /** + * {@inheritdoc} + * + * @see \Imagine\File\LoaderInterface::isLocalFile() + */ + public function isLocalFile() + { + return !$this->isUrl; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\File\LoaderInterface::getPath() + */ + public function getPath() + { + return $this->path; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\File\LoaderInterface::hasReadData() + */ + public function hasReadData() + { + return $this->data !== null; + } + + /** + * {@inheritdoc} + * + * @throws \Imagine\Exception\InvalidArgumentException + * @throws \Imagine\Exception\RuntimeException + * + * @see \Imagine\File\LoaderInterface::getData() + */ + public function getData() + { + if (!$this->hasReadData()) { + if ($this->isLocalFile()) { + $this->data = $this->readLocalFile(); + } else { + $this->data = $this->readRemoteFile(); + } + } + + return $this->data; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\File\LoaderInterface::__toString() + */ + public function __toString() + { + return $this->getPath(); + } + + /** + * Read a local file. + * + * @throws \Imagine\Exception\InvalidArgumentException + * + * @return string + */ + protected function readLocalFile() + { + $this->checkLocalFile(); + $data = @file_get_contents($this->path); + if ($data === false) { + throw new InvalidArgumentException(sprintf('Failed to read from file %s.', $this->path)); + } + + return $data; + } + + /** + * Check that the file exists and it's readable. + * + * @throws \Imagine\Exception\InvalidArgumentException + */ + protected function checkLocalFile() + { + if (!is_file($this->path)) { + throw new InvalidArgumentException(sprintf('File %s does not exist.', $this->path)); + } + if (!is_readable($this->path)) { + throw new InvalidArgumentException(sprintf('File %s is not readable.', $this->path)); + } + } + + /** + * Read a remote file. + * + * @throws \Imagine\Exception\InvalidArgumentException + * @throws \Imagine\Exception\RuntimeException + * + * @return string + */ + protected function readRemoteFile() + { + if ($this->isCurlSupported()) { + return $this->readRemoteFileWithCurl(); + } + + return $this->readRemoteFileWithFileGetContents(); + } + + /** + * Check if curl is available and it's a decent version. + * + * @return bool + */ + protected function isCurlSupported() + { + if ($this->isCurlSupported === null) { + $isCurlSupported = false; + if (function_exists('curl_init') && function_exists('curl_version')) { + $curlVersion = curl_version(); + if (is_array($curlVersion) && !empty($curlVersion['version'])) { + if (version_compare($curlVersion['version'], static::MINIMUM_CURL_VERSION) >= 0) { + $isCurlSupported = true; + } + } + } + $this->isCurlSupported = $isCurlSupported; + } + + return $this->isCurlSupported; + } + + /** + * Read a remote file using the cURL extension. + * + * @throws \Imagine\Exception\InvalidArgumentException + * + * @return string + */ + protected function readRemoteFileWithCurl() + { + $curl = @curl_init($this->path); + if ($curl === false) { + throw new RuntimeException('curl_init() failed.'); + } + if (!@curl_setopt($curl, CURLOPT_RETURNTRANSFER, true)) { + throw new RuntimeException('curl_setopt(CURLOPT_RETURNTRANSFER) failed.'); + } + $this->setCurlOptions($curl); + + $response = @curl_exec($curl); + if ($response === false) { + $errorMessage = curl_error($curl); + if ($errorMessage === '') { + $errorMessage = 'curl_exec() failed.'; + } + $errorCode = curl_errno($curl); + curl_close($curl); + throw new RuntimeException($errorMessage, $errorCode); + } + $responseInfo = curl_getinfo($curl); + curl_close($curl); + if ($responseInfo['http_code'] == 404) { + throw new InvalidArgumentException(sprintf('File %s does not exist.', $this->path)); + } + if ($responseInfo['http_code'] < 200 || $responseInfo['http_code'] >= 300) { + throw new InvalidArgumentException(sprintf('Failed to download "%s": %s', $this->path, $responseInfo['http_code'])); + } + + return $response; + } + + /** + * Set curl options. + * + * + * @param resource $curl + * + * @throws \Imagine\Exception\RuntimeException + */ + protected function setCurlOptions($curl) + { + if (!@curl_setopt($curl, CURLOPT_HTTPHEADER, array('Accept-Encoding: identity'))) { + throw new RuntimeException('curl_setopt(CURLOPT_HTTPHEADER) failed.'); + } + if (!@curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true)) { + throw new RuntimeException('curl_setopt(CURLOPT_FOLLOWLOCATION) failed.'); + } + if (defined('CURL_SSLVERSION_TLSv1_1')) { + if (!@curl_setopt($curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_1)) { + throw new RuntimeException('curl_setopt(CURLOPT_SSLVERSION) failed.'); + } + } else { + // Manually checked that CURL_SSLVERSION_TLSv1_1 is 5 for any version of curl from 7.34.0 to 7.61.0 + // See for example https://github.com/curl/curl/blob/curl-7_34_0/include/curl/curl.h#L1668 + if (!@curl_setopt($curl, CURLOPT_SSLVERSION, 5)) { + throw new RuntimeException('curl_setopt(CURLOPT_SSLVERSION) failed.'); + } + } + } + + /** + * Read a remote file using the file_get_contents. + * + * @throws \Imagine\Exception\InvalidArgumentException + * + * @return string + */ + protected function readRemoteFileWithFileGetContents() + { + $http_response_header = null; + $data = @file_get_contents($this->path); + if ($data === false) { + if (is_array($http_response_header) && isset($http_response_header[0]) && preg_match('/^HTTP\/\d+(?:\.\d+)*\s+(\d+\s+\w.*)/i', $http_response_header[0], $matches)) { + throw new InvalidArgumentException(sprintf('Failed to read from URL %s: %s', $this->path, $matches[1])); + } + throw new InvalidArgumentException(sprintf('Failed to read from URL %s', $this->path)); + } + + return $data; + } +} diff --git a/vendor/imagine/imagine/src/File/LoaderInterface.php b/vendor/imagine/imagine/src/File/LoaderInterface.php new file mode 100644 index 0000000..c3dddd9 --- /dev/null +++ b/vendor/imagine/imagine/src/File/LoaderInterface.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Filter\Advanced; + +use Imagine\Exception\InvalidArgumentException; +use Imagine\Filter\FilterInterface; +use Imagine\Image\ImageInterface; +use Imagine\Image\Palette\Color\ColorInterface; +use Imagine\Image\Palette\RGB; +use Imagine\Image\Point; + +/** + * This filter calculates, for each pixel of an image, whether it is ligher or darker than a threshold. + * If the pixel is lighter than the thresold it will be black, otherwise it will be light. + * The result is an image with only black and white pixels (black pixels for ligher colors, white pixels for darker colors). + */ +class BlackWhite extends OnPixelBased implements FilterInterface +{ + /** + * @var \Imagine\Filter\Advanced\Grayscale + */ + protected $grayScaleFilter; + + /** + * Initialize this filter. + * + * @param int $threshold the dask/light threshold, from 0 (all black) to 255 (all white) + * + * @throws \Imagine\Exception\InvalidArgumentException + */ + public function __construct($threshold) + { + if (!(0 <= $threshold && $threshold <= 255)) { + throw new InvalidArgumentException('$threshold has to be between 0 and 255'); + } + + $this->grayScaleFilter = new Grayscale(); + + $rgb = new RGB(); + parent::__construct( + function (ImageInterface $image, Point $point) use ($threshold, $rgb) { + $newRedValue = $image->getColorAt($point)->getValue(ColorInterface::COLOR_RED) < $threshold ? 255 : 0; + $image->draw()->dot($point, $rgb->color(array($newRedValue, $newRedValue, $newRedValue))); + } + ); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Filter\Advanced\OnPixelBased::apply() + */ + public function apply(ImageInterface $image) + { + $grayScaledImage = $this->grayScaleFilter->apply($image); + + return parent::apply($grayScaledImage); + } +} diff --git a/vendor/imagine/imagine/src/Filter/Advanced/Border.php b/vendor/imagine/imagine/src/Filter/Advanced/Border.php new file mode 100644 index 0000000..7e58fe3 --- /dev/null +++ b/vendor/imagine/imagine/src/Filter/Advanced/Border.php @@ -0,0 +1,100 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Filter\Advanced; + +use Imagine\Filter\FilterInterface; +use Imagine\Image\ImageInterface; +use Imagine\Image\Palette\Color\ColorInterface; +use Imagine\Image\Point; + +/** + * A border filter. + */ +class Border implements FilterInterface +{ + /** + * @var \Imagine\Image\Palette\Color\ColorInterface + */ + private $color; + + /** + * @var int + */ + private $width; + + /** + * @var int + */ + private $height; + + /** + * Constructs Border filter with given color, width and height. + * + * @param \Imagine\Image\Palette\Color\ColorInterface $color + * @param int $width Width of the border on the left and right sides of the image + * @param int $height Height of the border on the top and bottom sides of the image + */ + public function __construct(ColorInterface $color, $width = 1, $height = 1) + { + $this->color = $color; + $this->width = $width; + $this->height = $height; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Filter\FilterInterface::apply() + */ + public function apply(ImageInterface $image) + { + $size = $image->getSize(); + $width = $size->getWidth(); + $height = $size->getHeight(); + + $draw = $image->draw(); + + // Draw top and bottom lines + $draw + ->line( + new Point(0, 0), + new Point($width - 1, 0), + $this->color, + $this->height + ) + ->line( + new Point($width - 1, $height - 1), + new Point(0, $height - 1), + $this->color, + $this->height + ) + ; + + // Draw sides + $draw + ->line( + new Point(0, 0), + new Point(0, $height - 1), + $this->color, + $this->width + ) + ->line( + new Point($width - 1, 0), + new Point($width - 1, $height - 1), + $this->color, + $this->width + ) + ; + + return $image; + } +} diff --git a/vendor/imagine/imagine/src/Filter/Advanced/BorderDetection.php b/vendor/imagine/imagine/src/Filter/Advanced/BorderDetection.php new file mode 100644 index 0000000..cc692f5 --- /dev/null +++ b/vendor/imagine/imagine/src/Filter/Advanced/BorderDetection.php @@ -0,0 +1,91 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Filter\Advanced; + +use Imagine\Exception\InvalidArgumentException; +use Imagine\Filter\FilterInterface; +use Imagine\Utils\Matrix; + +/** + * BorderDetection based on Laplace-Operator. Three different variants are offered:. + *
+ *   First          Second            Third
+ *  0,  1, 0       1,  1, 1,       -1,  2, -1,
+ *  1, -4, 1  and  1, -8, 1,  and   2, -4,  2,
+ *  0,  1, 0       1,  1, 1        -1,  2, -1
+ * 
. + * + * Consider to apply this filter on a grayscaled image. + */ +class BorderDetection extends Neighborhood implements FilterInterface +{ + /** + * First variant of the detection matrix. + * + * @var int + */ + const VARIANT_ONE = 0; + + /** + * Second variant of the detection matrix. + * + * @var int + */ + const VARIANT_TWO = 1; + + /** + * Third variant of the detection matrix. + * + * @var int + */ + const VARIANT_THREE = 2; + + /** + * Initialize this filter. + * + * @param int $variant One of the BorderDetection::VARIANT_... constants. + * + * @throws \Imagine\Exception\InvalidArgumentException throws an InvalidArgumentException if $variant is not valid + */ + public function __construct($variant = self::VARIANT_ONE) + { + $matrix = null; + + switch ($variant) { + case self::VARIANT_ONE: + $matrix = new Matrix(3, 3, array( + 0, 1, 0, + 1, -4, 1, + 0, 1, 0, + )); + break; + case self::VARIANT_TWO: + $matrix = new Matrix(3, 3, array( + 1, 1, 1, + 1, -8, 1, + 1, 1, 1, + )); + break; + case self::VARIANT_THREE: + $matrix = new Matrix(3, 3, array( + -1, 2, -1, + 2, -4, 2, + -1, 2, -1, + )); + break; + default: + throw new InvalidArgumentException('Unknown variant ' . $variant); + } + + parent::__construct($matrix); + } +} diff --git a/vendor/imagine/imagine/src/Filter/Advanced/Canvas.php b/vendor/imagine/imagine/src/Filter/Advanced/Canvas.php new file mode 100644 index 0000000..f8a9861 --- /dev/null +++ b/vendor/imagine/imagine/src/Filter/Advanced/Canvas.php @@ -0,0 +1,75 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Filter\Advanced; + +use Imagine\Filter\FilterInterface; +use Imagine\Image\BoxInterface; +use Imagine\Image\ImageInterface; +use Imagine\Image\ImagineInterface; +use Imagine\Image\Palette\Color\ColorInterface; +use Imagine\Image\Point; +use Imagine\Image\PointInterface; + +/** + * A canvas filter. + */ +class Canvas implements FilterInterface +{ + /** + * @var \Imagine\Image\BoxInterface + */ + private $size; + + /** + * @var \Imagine\Image\PointInterface + */ + private $placement; + + /** + * @var \Imagine\Image\Palette\Color\ColorInterface + */ + private $background; + + /** + * @var \Imagine\Image\ImagineInterface + */ + private $imagine; + + /** + * Constructs Canvas filter with given width and height and the placement of the current image inside the new canvas. + * + * @param \Imagine\Image\ImagineInterface $imagine + * @param \Imagine\Image\BoxInterface $size + * @param \Imagine\Image\PointInterface $placement + * @param \Imagine\Image\Palette\Color\ColorInterface $background + */ + public function __construct(ImagineInterface $imagine, BoxInterface $size, PointInterface $placement = null, ColorInterface $background = null) + { + $this->imagine = $imagine; + $this->size = $size; + $this->placement = $placement ?: new Point(0, 0); + $this->background = $background; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Filter\FilterInterface::apply() + */ + public function apply(ImageInterface $image) + { + $canvas = $this->imagine->create($this->size, $this->background); + $canvas->paste($image, $this->placement); + + return $canvas; + } +} diff --git a/vendor/imagine/imagine/src/Filter/Advanced/Grayscale.php b/vendor/imagine/imagine/src/Filter/Advanced/Grayscale.php new file mode 100644 index 0000000..b3a08b4 --- /dev/null +++ b/vendor/imagine/imagine/src/Filter/Advanced/Grayscale.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Filter\Advanced; + +use Imagine\Filter\FilterInterface; +use Imagine\Image\ImageInterface; +use Imagine\Image\Point; + +/** + * The Grayscale filter calculates the gray-value based on RGB. + */ +class Grayscale extends OnPixelBased implements FilterInterface +{ + public function __construct() + { + parent::__construct(function (ImageInterface $image, Point $point) { + $color = $image->getColorAt($point); + $image->draw()->dot($point, $color->grayscale()); + }); + } +} diff --git a/vendor/imagine/imagine/src/Filter/Advanced/Negation.php b/vendor/imagine/imagine/src/Filter/Advanced/Negation.php new file mode 100644 index 0000000..edf4d4b --- /dev/null +++ b/vendor/imagine/imagine/src/Filter/Advanced/Negation.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Filter\Advanced; + +use Imagine\Filter\FilterInterface; +use Imagine\Image\ImageInterface; + +/** + * This filter negates every color of every pixel of an image. + */ +class Negation implements FilterInterface +{ + /** + * {@inheritdoc} + * + * @see \Imagine\Filter\FilterInterface::apply() + */ + public function apply(ImageInterface $image) + { + $image->effects()->negative(); + + return $image; + } +} diff --git a/vendor/imagine/imagine/src/Filter/Advanced/Neighborhood.php b/vendor/imagine/imagine/src/Filter/Advanced/Neighborhood.php new file mode 100644 index 0000000..5b4129f --- /dev/null +++ b/vendor/imagine/imagine/src/Filter/Advanced/Neighborhood.php @@ -0,0 +1,100 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Filter\Advanced; + +use Imagine\Filter\FilterInterface; +use Imagine\Image\ImageInterface; +use Imagine\Image\Point; +use Imagine\Utils\Matrix; + +/** + * The Neighborhood filter takes a matrix and calculates the color current pixel based on its neighborhood. + * + * @example + *
+ *           a, b, c
+ * Matrix =  d, e, f
+ *           g, h, i
+ * 
+ * + * and color{i, j} the color of the pixel at position (i, j). It calculates the color of pixel (x, y) like that: + * + *
+ * color (x, y) =   a * color(x - 1, y - 1) + b * color(x, y - 1) + c * color(x + 1, y - 1)
+ *                + d * color(x - 1, y)     + e * color(x, y)     + f * color(x + 1, y)
+ *                + g * color(x - 1, y + 1) + h * color(x, y + 1) + i * color(x + 1, y + 1)
+ * 
+ */ +class Neighborhood implements FilterInterface +{ + /** + * @var \Imagine\Utils\Matrix + */ + protected $matrix; + + /** + * Initialize the instance. + * + * @param \Imagine\Utils\Matrix $matrix + */ + public function __construct(Matrix $matrix) + { + $this->matrix = $matrix; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Filter\FilterInterface::apply() + */ + public function apply(ImageInterface $image) + { + // We reduce the usage of methods on the image to dramatically increase the performance of this algorithm. + // Really... We need that performance... + // Therefore we first build a matrix, that holds the colors of the image. + $width = $image->getSize()->getWidth(); + $height = $image->getSize()->getHeight(); + $byteData = new Matrix($width, $height); + + for ($y = 0; $y < $height; $y++) { + for ($x = 0; $x < $width; $x++) { + $byteData->setElementAt($x, $y, $image->getColorAt(new Point($x, $y))); + } + } + + $dWidth = (int) (($this->matrix->getWidth() - 1) / 2); + $dHeight = (int) (($this->matrix->getHeight() - 1) / 2); + + // foreach point, which has a big enough neighborhood + for ($y = $dHeight; $y < $height - $dHeight; $y++) { + for ($x = $dWidth; $x < $width - $dWidth; $x++) { + $currentColor = array_fill(0, count($image->palette()->pixelDefinition()), 0); + + // calculate the new color based on the neighborhood + for ($boxY = $y - $dHeight, $matrixY = 0; $boxY <= $y + $dHeight; $boxY++, $matrixY++) { + for ($boxX = $x - $dWidth, $matrixX = 0; $boxX <= $x + $dWidth; $boxX++, $matrixX++) { + foreach ($image->palette()->pixelDefinition() as $index => $stream) { + $currentColor[$index] += + $byteData->getElementAt($boxX, $boxY)->getValue($stream) * + $this->matrix->getElementAt($matrixX, $matrixY) + ; + } + } + } + + $image->draw()->dot(new Point($x, $y), $image->palette()->color($currentColor)); + } + } + + return $image; + } +} diff --git a/vendor/imagine/imagine/src/Filter/Advanced/OnPixelBased.php b/vendor/imagine/imagine/src/Filter/Advanced/OnPixelBased.php new file mode 100644 index 0000000..3f7f705 --- /dev/null +++ b/vendor/imagine/imagine/src/Filter/Advanced/OnPixelBased.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Filter\Advanced; + +use Imagine\Exception\InvalidArgumentException; +use Imagine\Filter\FilterInterface; +use Imagine\Image\ImageInterface; +use Imagine\Image\Point; + +/** + * The OnPixelBased takes a callable, and for each pixel, this callable is called with the + * image (\Imagine\Image\ImageInterface) and the current point (\Imagine\Image\Point). + */ +class OnPixelBased implements FilterInterface +{ + /** + * @var callable + */ + protected $callback; + + /** + * Initialize the instance. + * + * @param callable $callback + * + * @throws \Imagine\Exception\InvalidArgumentException + */ + public function __construct($callback) + { + if (!is_callable($callback)) { + throw new InvalidArgumentException('$callback has to be callable'); + } + + $this->callback = $callback; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Filter\FilterInterface::apply() + */ + public function apply(ImageInterface $image) + { + $size = $image->getSize(); + $w = $size->getWidth(); + $h = $size->getHeight(); + for ($y = 0; $y < $h; $y++) { + for ($x = 0; $x < $w; $x++) { + call_user_func($this->callback, $image, new Point($x, $y)); + } + } + + return $image; + } +} diff --git a/vendor/imagine/imagine/src/Filter/Advanced/RelativeResize.php b/vendor/imagine/imagine/src/Filter/Advanced/RelativeResize.php new file mode 100644 index 0000000..2a19fd4 --- /dev/null +++ b/vendor/imagine/imagine/src/Filter/Advanced/RelativeResize.php @@ -0,0 +1,58 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Filter\Advanced; + +use Imagine\Exception\InvalidArgumentException; +use Imagine\Filter\FilterInterface; +use Imagine\Image\ImageInterface; + +/** + * The RelativeResize filter allows images to be resized relative to their existing dimensions. + */ +class RelativeResize implements FilterInterface +{ + /** + * @var string + */ + private $method; + + /** + * @var mixed + */ + private $parameter; + + /** + * Constructs a RelativeResize filter with the given method and argument. + * + * @param string $method BoxInterface method + * @param mixed $parameter Parameter for BoxInterface method + */ + public function __construct($method, $parameter) + { + if (!in_array($method, array('heighten', 'increase', 'scale', 'widen'))) { + throw new InvalidArgumentException(sprintf('Unsupported method: ', $method)); + } + + $this->method = $method; + $this->parameter = $parameter; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Filter\FilterInterface::apply() + */ + public function apply(ImageInterface $image) + { + return $image->resize(call_user_func(array($image->getSize(), $this->method), $this->parameter)); + } +} diff --git a/vendor/imagine/imagine/src/Filter/Basic/ApplyMask.php b/vendor/imagine/imagine/src/Filter/Basic/ApplyMask.php new file mode 100644 index 0000000..e93f358 --- /dev/null +++ b/vendor/imagine/imagine/src/Filter/Basic/ApplyMask.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Filter\Basic; + +use Imagine\Filter\FilterInterface; +use Imagine\Image\ImageInterface; + +/** + * An apply mask filter. + */ +class ApplyMask implements FilterInterface +{ + /** + * @var \Imagine\Image\ImageInterface + */ + private $mask; + + /** + * Initialize the instance. + * + * @param \Imagine\Image\ImageInterface $mask + */ + public function __construct(ImageInterface $mask) + { + $this->mask = $mask; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Filter\FilterInterface::apply() + */ + public function apply(ImageInterface $image) + { + return $image->applyMask($this->mask); + } +} diff --git a/vendor/imagine/imagine/src/Filter/Basic/Autorotate.php b/vendor/imagine/imagine/src/Filter/Basic/Autorotate.php new file mode 100644 index 0000000..907895b --- /dev/null +++ b/vendor/imagine/imagine/src/Filter/Basic/Autorotate.php @@ -0,0 +1,133 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Filter\Basic; + +use Imagine\Filter\FilterInterface; +use Imagine\Image\ImageInterface; +use Imagine\Image\Palette\Color\ColorInterface; + +/** + * Rotates an image automatically based on exif information. + * + * Your attention please: This filter requires the use of the + * ExifMetadataReader to work. + * + * @see https://imagine.readthedocs.org/en/latest/usage/metadata.html + */ +class Autorotate implements FilterInterface +{ + /** + * Image transformation: flip vertically. + * + * @var string + */ + const FLIP_VERTICALLY = 'V'; + + /** + * Image transformation: flip horizontally. + * + * @var string + */ + const FLIP_HORIZONTALLY = 'H'; + + /** + * @var string|array|\Imagine\Image\Palette\Color\ColorInterface + */ + private $color; + + /** + * @param string|array|\Imagine\Image\Palette\Color\ColorInterface $color A color + */ + public function __construct($color = '000000') + { + $this->color = $color; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Filter\FilterInterface::apply() + */ + public function apply(ImageInterface $image) + { + foreach ($this->getTransformations($image) as $transformation) { + if ($transformation === self::FLIP_HORIZONTALLY) { + $image->flipHorizontally(); + } elseif ($transformation === self::FLIP_VERTICALLY) { + $image->flipVertically(); + } elseif (is_int($transformation)) { + $image->rotate($transformation, $this->getColor($image)); + } + } + + return $image; + } + + /** + * Get the transformations. + * + * @param \Imagine\Image\ImageInterface $image + * + * @return array an array containing Autorotate::FLIP_VERTICALLY, Autorotate::FLIP_HORIZONTALLY, rotation degrees + */ + public function getTransformations(ImageInterface $image) + { + $transformations = array(); + $metadata = $image->metadata(); + switch (isset($metadata['ifd0.Orientation']) ? $metadata['ifd0.Orientation'] : null) { + case 1: // top-left + break; + case 2: // top-right + $transformations[] = self::FLIP_HORIZONTALLY; + break; + case 3: // bottom-right + $transformations[] = 180; + break; + case 4: // bottom-left + $transformations[] = self::FLIP_HORIZONTALLY; + $transformations[] = 180; + break; + case 5: // left-top + $transformations[] = self::FLIP_HORIZONTALLY; + $transformations[] = -90; + break; + case 6: // right-top + $transformations[] = 90; + break; + case 7: // right-bottom + $transformations[] = self::FLIP_HORIZONTALLY; + $transformations[] = 90; + break; + case 8: // left-bottom + $transformations[] = -90; + break; + default: // Invalid orientation + break; + } + + return $transformations; + } + + /** + * @param \Imagine\Image\ImageInterface $image + * + * @return \Imagine\Image\Palette\Color\ColorInterface + */ + private function getColor(ImageInterface $image) + { + if ($this->color instanceof ColorInterface) { + return $this->color; + } + + return $image->palette()->color($this->color); + } +} diff --git a/vendor/imagine/imagine/src/Filter/Basic/Copy.php b/vendor/imagine/imagine/src/Filter/Basic/Copy.php new file mode 100644 index 0000000..7ea17e1 --- /dev/null +++ b/vendor/imagine/imagine/src/Filter/Basic/Copy.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Filter\Basic; + +use Imagine\Filter\FilterInterface; +use Imagine\Image\ImageInterface; + +/** + * A copy filter. + */ +class Copy implements FilterInterface +{ + /** + * {@inheritdoc} + * + * @see \Imagine\Filter\FilterInterface::apply() + */ + public function apply(ImageInterface $image) + { + return $image->copy(); + } +} diff --git a/vendor/imagine/imagine/src/Filter/Basic/Crop.php b/vendor/imagine/imagine/src/Filter/Basic/Crop.php new file mode 100644 index 0000000..3f601d1 --- /dev/null +++ b/vendor/imagine/imagine/src/Filter/Basic/Crop.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Filter\Basic; + +use Imagine\Filter\FilterInterface; +use Imagine\Image\BoxInterface; +use Imagine\Image\ImageInterface; +use Imagine\Image\PointInterface; + +/** + * A crop filter. + */ +class Crop implements FilterInterface +{ + /** + * @var \Imagine\Image\PointInterface + */ + private $start; + + /** + * @var \Imagine\Image\BoxInterface + */ + private $size; + + /** + * Constructs a Crop filter with given x, y, coordinates and crop width and height values. + * + * @param \Imagine\Image\PointInterface $start + * @param \Imagine\Image\BoxInterface $size + */ + public function __construct(PointInterface $start, BoxInterface $size) + { + $this->start = $start; + $this->size = $size; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Filter\FilterInterface::apply() + */ + public function apply(ImageInterface $image) + { + return $image->crop($this->start, $this->size); + } +} diff --git a/vendor/imagine/imagine/src/Filter/Basic/Fill.php b/vendor/imagine/imagine/src/Filter/Basic/Fill.php new file mode 100644 index 0000000..e0974c9 --- /dev/null +++ b/vendor/imagine/imagine/src/Filter/Basic/Fill.php @@ -0,0 +1,45 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Filter\Basic; + +use Imagine\Filter\FilterInterface; +use Imagine\Image\Fill\FillInterface; +use Imagine\Image\ImageInterface; + +/** + * A fill filter. + */ +class Fill implements FilterInterface +{ + /** + * @var \Imagine\Image\Fill\FillInterface + */ + private $fill; + + /** + * @param \Imagine\Image\Fill\FillInterface $fill + */ + public function __construct(FillInterface $fill) + { + $this->fill = $fill; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Filter\FilterInterface::apply() + */ + public function apply(ImageInterface $image) + { + return $image->fill($this->fill); + } +} diff --git a/vendor/imagine/imagine/src/Filter/Basic/FlipHorizontally.php b/vendor/imagine/imagine/src/Filter/Basic/FlipHorizontally.php new file mode 100644 index 0000000..c1058c3 --- /dev/null +++ b/vendor/imagine/imagine/src/Filter/Basic/FlipHorizontally.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Filter\Basic; + +use Imagine\Filter\FilterInterface; +use Imagine\Image\ImageInterface; + +/** + * A "flip horizontally" filter. + */ +class FlipHorizontally implements FilterInterface +{ + /** + * {@inheritdoc} + * + * @see \Imagine\Filter\FilterInterface::apply() + */ + public function apply(ImageInterface $image) + { + return $image->flipHorizontally(); + } +} diff --git a/vendor/imagine/imagine/src/Filter/Basic/FlipVertically.php b/vendor/imagine/imagine/src/Filter/Basic/FlipVertically.php new file mode 100644 index 0000000..3764d26 --- /dev/null +++ b/vendor/imagine/imagine/src/Filter/Basic/FlipVertically.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Filter\Basic; + +use Imagine\Filter\FilterInterface; +use Imagine\Image\ImageInterface; + +/** + * A "flip vertically" filter. + */ +class FlipVertically implements FilterInterface +{ + /** + * {@inheritdoc} + * + * @see \Imagine\Filter\FilterInterface::apply() + */ + public function apply(ImageInterface $image) + { + return $image->flipVertically(); + } +} diff --git a/vendor/imagine/imagine/src/Filter/Basic/Paste.php b/vendor/imagine/imagine/src/Filter/Basic/Paste.php new file mode 100644 index 0000000..ea6ddd0 --- /dev/null +++ b/vendor/imagine/imagine/src/Filter/Basic/Paste.php @@ -0,0 +1,69 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Filter\Basic; + +use Imagine\Exception\InvalidArgumentException; +use Imagine\Filter\FilterInterface; +use Imagine\Image\ImageInterface; +use Imagine\Image\PointInterface; + +/** + * A paste filter. + */ +class Paste implements FilterInterface +{ + /** + * @var \Imagine\Image\ImageInterface + */ + private $image; + + /** + * @var \Imagine\Image\PointInterface + */ + private $start; + + /** + * How to paste the image, from 0 (fully transparent) to 100 (fully opaque). + * + * @var int + */ + private $alpha; + + /** + * Constructs a Paste filter with given ImageInterface to paste and x, y + * coordinates of target position. + * + * @param \Imagine\Image\ImageInterface $image + * @param \Imagine\Image\PointInterface $start + * @param int $alpha how to paste the image, from 0 (fully transparent) to 100 (fully opaque) + */ + public function __construct(ImageInterface $image, PointInterface $start, $alpha = 100) + { + $this->image = $image; + $this->start = $start; + $alpha = (int) round($alpha); + if ($alpha < 0 || $alpha > 100) { + throw new InvalidArgumentException(sprintf('The %1$s argument can range from %2$d to %3$d, but you specified %4$d.', '$alpha', 0, 100, $alpha)); + } + $this->alpha = $alpha; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Filter\FilterInterface::apply() + */ + public function apply(ImageInterface $image) + { + return $image->paste($this->image, $this->start, $this->alpha); + } +} diff --git a/vendor/imagine/imagine/src/Filter/Basic/Resize.php b/vendor/imagine/imagine/src/Filter/Basic/Resize.php new file mode 100644 index 0000000..0e668c1 --- /dev/null +++ b/vendor/imagine/imagine/src/Filter/Basic/Resize.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Filter\Basic; + +use Imagine\Filter\FilterInterface; +use Imagine\Image\BoxInterface; +use Imagine\Image\ImageInterface; + +/** + * A resize filter. + */ +class Resize implements FilterInterface +{ + /** + * @var \Imagine\Image\BoxInterface + */ + private $size; + + /** + * @var string + */ + private $filter; + + /** + * Constructs Resize filter with given width and height. + * + * @param \Imagine\Image\BoxInterface $size + * @param string $filter + */ + public function __construct(BoxInterface $size, $filter = ImageInterface::FILTER_UNDEFINED) + { + $this->size = $size; + $this->filter = $filter; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Filter\FilterInterface::apply() + */ + public function apply(ImageInterface $image) + { + return $image->resize($this->size, $this->filter); + } +} diff --git a/vendor/imagine/imagine/src/Filter/Basic/Rotate.php b/vendor/imagine/imagine/src/Filter/Basic/Rotate.php new file mode 100644 index 0000000..9992a8f --- /dev/null +++ b/vendor/imagine/imagine/src/Filter/Basic/Rotate.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Filter\Basic; + +use Imagine\Filter\FilterInterface; +use Imagine\Image\ImageInterface; +use Imagine\Image\Palette\Color\ColorInterface; + +/** + * A rotate filter. + */ +class Rotate implements FilterInterface +{ + /** + * @var int + */ + private $angle; + + /** + * @var \Imagine\Image\Palette\Color\ColorInterface + */ + private $background; + + /** + * Constructs Rotate filter with given angle and background color. + * + * @param int $angle + * @param \Imagine\Image\Palette\Color\ColorInterface $background + */ + public function __construct($angle, ColorInterface $background = null) + { + $this->angle = $angle; + $this->background = $background; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Filter\FilterInterface::apply() + */ + public function apply(ImageInterface $image) + { + return $image->rotate($this->angle, $this->background); + } +} diff --git a/vendor/imagine/imagine/src/Filter/Basic/Save.php b/vendor/imagine/imagine/src/Filter/Basic/Save.php new file mode 100644 index 0000000..3b8e204 --- /dev/null +++ b/vendor/imagine/imagine/src/Filter/Basic/Save.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Filter\Basic; + +use Imagine\Filter\FilterInterface; +use Imagine\Image\ImageInterface; + +/** + * A save filter. + */ +class Save implements FilterInterface +{ + /** + * @var string + */ + private $path; + + /** + * @var array + */ + private $options; + + /** + * Constructs Save filter with given path and options. + * + * @param string $path + * @param array $options + */ + public function __construct($path = null, array $options = array()) + { + $this->path = $path; + $this->options = $options; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Filter\FilterInterface::apply() + */ + public function apply(ImageInterface $image) + { + return $image->save($this->path, $this->options); + } +} diff --git a/vendor/imagine/imagine/src/Filter/Basic/Show.php b/vendor/imagine/imagine/src/Filter/Basic/Show.php new file mode 100644 index 0000000..feee1cf --- /dev/null +++ b/vendor/imagine/imagine/src/Filter/Basic/Show.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Filter\Basic; + +use Imagine\Filter\FilterInterface; +use Imagine\Image\ImageInterface; + +/** + * A show filter. + */ +class Show implements FilterInterface +{ + /** + * @var string + */ + private $format; + + /** + * @var array + */ + private $options; + + /** + * Constructs the Show filter with given format and options. + * + * @param string $format + * @param array $options + */ + public function __construct($format, array $options = array()) + { + $this->format = $format; + $this->options = $options; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Filter\FilterInterface::apply() + */ + public function apply(ImageInterface $image) + { + return $image->show($this->format, $this->options); + } +} diff --git a/vendor/imagine/imagine/src/Filter/Basic/Strip.php b/vendor/imagine/imagine/src/Filter/Basic/Strip.php new file mode 100644 index 0000000..94a9a3c --- /dev/null +++ b/vendor/imagine/imagine/src/Filter/Basic/Strip.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Filter\Basic; + +use Imagine\Filter\FilterInterface; +use Imagine\Image\ImageInterface; + +/** + * A strip filter. + */ +class Strip implements FilterInterface +{ + /** + * {@inheritdoc} + * + * @see \Imagine\Filter\FilterInterface::apply() + */ + public function apply(ImageInterface $image) + { + return $image->strip(); + } +} diff --git a/vendor/imagine/imagine/src/Filter/Basic/Thumbnail.php b/vendor/imagine/imagine/src/Filter/Basic/Thumbnail.php new file mode 100644 index 0000000..5c34b28 --- /dev/null +++ b/vendor/imagine/imagine/src/Filter/Basic/Thumbnail.php @@ -0,0 +1,61 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Filter\Basic; + +use Imagine\Filter\FilterInterface; +use Imagine\Image\BoxInterface; +use Imagine\Image\ImageInterface; + +/** + * A thumbnail filter. + */ +class Thumbnail implements FilterInterface +{ + /** + * @var \Imagine\Image\BoxInterface + */ + private $size; + + /** + * @var int|string + */ + private $settings; + + /** + * @var string + */ + private $filter; + + /** + * Constructs the Thumbnail filter. + * + * @param \Imagine\Image\BoxInterface $size + * @param int|string $settings One or more of the ManipulatorInterface::THUMBNAIL_ flags (joined with |). It may be a string for backward compatibility with old constant values that were strings. + * @param string $filter See ImageInterface::FILTER_... constants + */ + public function __construct(BoxInterface $size, $settings = ImageInterface::THUMBNAIL_INSET, $filter = ImageInterface::FILTER_UNDEFINED) + { + $this->size = $size; + $this->settings = $settings; + $this->filter = $filter; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Filter\FilterInterface::apply() + */ + public function apply(ImageInterface $image) + { + return $image->thumbnail($this->size, $this->settings, $this->filter); + } +} diff --git a/vendor/imagine/imagine/src/Filter/Basic/WebOptimization.php b/vendor/imagine/imagine/src/Filter/Basic/WebOptimization.php new file mode 100644 index 0000000..2c88871 --- /dev/null +++ b/vendor/imagine/imagine/src/Filter/Basic/WebOptimization.php @@ -0,0 +1,74 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Filter\Basic; + +use Imagine\Filter\FilterInterface; +use Imagine\Image\ImageInterface; +use Imagine\Image\Palette\RGB; + +/** + * A filter to render web-optimized images. + */ +class WebOptimization implements FilterInterface +{ + /** + * @var \Imagine\Image\Palette\RGB + */ + private $palette; + + /** + * @var string|callable|null + */ + private $path; + + /** + * @var array + */ + private $options; + + /** + * @param string|callable|null $path + * @param array $options + */ + public function __construct($path = null, array $options = array()) + { + $this->path = $path; + $this->options = array_replace(array( + 'resolution-units' => ImageInterface::RESOLUTION_PIXELSPERINCH, + 'resolution-y' => 72, + 'resolution-x' => 72, + ), $options); + $this->palette = new RGB(); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Filter\FilterInterface::apply() + */ + public function apply(ImageInterface $image) + { + $image + ->usePalette($this->palette) + ->strip(); + + if (is_callable($this->path)) { + $path = call_user_func($this->path, $image); + } elseif (null !== $this->path) { + $path = $this->path; + } else { + return $image; + } + + return $image->save($path, $this->options); + } +} diff --git a/vendor/imagine/imagine/src/Filter/FilterInterface.php b/vendor/imagine/imagine/src/Filter/FilterInterface.php new file mode 100644 index 0000000..3b61028 --- /dev/null +++ b/vendor/imagine/imagine/src/Filter/FilterInterface.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Filter; + +use Imagine\Image\ImageInterface; + +/** + * Interface for imagine filters. + */ +interface FilterInterface +{ + /** + * Applies scheduled transformation to an ImageInterface instance. + * + * @param \Imagine\Image\ImageInterface $image + * + * @return \Imagine\Image\ImageInterface returns the processed ImageInterface instance + */ + public function apply(ImageInterface $image); +} diff --git a/vendor/imagine/imagine/src/Filter/ImagineAware.php b/vendor/imagine/imagine/src/Filter/ImagineAware.php new file mode 100644 index 0000000..2403b23 --- /dev/null +++ b/vendor/imagine/imagine/src/Filter/ImagineAware.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Filter; + +use Imagine\Exception\InvalidArgumentException; +use Imagine\Image\ImagineInterface; + +/** + * ImagineAware base class. + */ +abstract class ImagineAware implements FilterInterface +{ + /** + * An ImagineInterface instance. + * + * @var \Imagine\Image\ImagineInterface + */ + private $imagine; + + /** + * Set ImagineInterface instance. + * + * @param \Imagine\Image\ImagineInterface $imagine An ImagineInterface instance + */ + public function setImagine(ImagineInterface $imagine) + { + $this->imagine = $imagine; + } + + /** + * Get ImagineInterface instance. + * + * @throws \Imagine\Exception\InvalidArgumentException + * + * @return \Imagine\Image\ImagineInterface + */ + public function getImagine() + { + if (!$this->imagine instanceof ImagineInterface) { + throw new InvalidArgumentException(sprintf('In order to use %s pass an Imagine\Image\ImagineInterface instance to filter constructor', get_class($this))); + } + + return $this->imagine; + } +} diff --git a/vendor/imagine/imagine/src/Filter/Transformation.php b/vendor/imagine/imagine/src/Filter/Transformation.php new file mode 100644 index 0000000..f529c48 --- /dev/null +++ b/vendor/imagine/imagine/src/Filter/Transformation.php @@ -0,0 +1,268 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Filter; + +use Imagine\Exception\InvalidArgumentException; +use Imagine\Filter\Basic\ApplyMask; +use Imagine\Filter\Basic\Copy; +use Imagine\Filter\Basic\Crop; +use Imagine\Filter\Basic\Fill; +use Imagine\Filter\Basic\FlipHorizontally; +use Imagine\Filter\Basic\FlipVertically; +use Imagine\Filter\Basic\Paste; +use Imagine\Filter\Basic\Resize; +use Imagine\Filter\Basic\Rotate; +use Imagine\Filter\Basic\Save; +use Imagine\Filter\Basic\Show; +use Imagine\Filter\Basic\Strip; +use Imagine\Filter\Basic\Thumbnail; +use Imagine\Image\BoxInterface; +use Imagine\Image\Fill\FillInterface; +use Imagine\Image\ImageInterface; +use Imagine\Image\ImagineInterface; +use Imagine\Image\ManipulatorInterface; +use Imagine\Image\Palette\Color\ColorInterface; +use Imagine\Image\PointInterface; + +/** + * A transformation filter. + */ +final class Transformation implements FilterInterface, ManipulatorInterface +{ + /** + * @var array[\Imagine\Filter\FilterInterface[]] + */ + private $filters = array(); + + /** + * @var array[\Imagine\Filter\FilterInterface[]]|null + */ + private $sorted; + + /** + * An ImagineInterface instance. + * + * @var \Imagine\Image\ImageInterface|null + */ + private $imagine; + + /** + * Class constructor. + * + * @param \Imagine\Image\ImageInterface|null $imagine An ImagineInterface instance + */ + public function __construct(ImagineInterface $imagine = null) + { + $this->imagine = $imagine; + } + + /** + * Applies a given FilterInterface onto given ImageInterface and returns modified ImageInterface. + * + * @param \Imagine\Image\ImageInterface $image + * @param \Imagine\Filter\FilterInterface $filter + * + * @throws \Imagine\Exception\InvalidArgumentException + * + * @return \Imagine\Image\ImageInterface + */ + public function applyFilter(ImageInterface $image, FilterInterface $filter) + { + if ($filter instanceof ImagineAware) { + if ($this->imagine === null) { + throw new InvalidArgumentException(sprintf('In order to use %s pass an Imagine\Image\ImagineInterface instance to Transformation constructor', get_class($filter))); + } + $filter->setImagine($this->imagine); + } + + return $filter->apply($image); + } + + /** + * Returns a list of filters sorted by their priority. Filters with same priority will be returned in the order they were added. + * + * @return array + */ + public function getFilters() + { + if (null === $this->sorted) { + if (!empty($this->filters)) { + ksort($this->filters); + $this->sorted = call_user_func_array('array_merge', $this->filters); + } else { + $this->sorted = array(); + } + } + + return $this->sorted; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Filter\FilterInterface::apply() + */ + public function apply(ImageInterface $image) + { + return array_reduce( + $this->getFilters(), + array($this, 'applyFilter'), + $image + ); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ManipulatorInterface::copy() + */ + public function copy() + { + return $this->add(new Copy()); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ManipulatorInterface::crop() + */ + public function crop(PointInterface $start, BoxInterface $size) + { + return $this->add(new Crop($start, $size)); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ManipulatorInterface::flipHorizontally() + */ + public function flipHorizontally() + { + return $this->add(new FlipHorizontally()); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ManipulatorInterface::flipVertically() + */ + public function flipVertically() + { + return $this->add(new FlipVertically()); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ManipulatorInterface::strip() + */ + public function strip() + { + return $this->add(new Strip()); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ManipulatorInterface::paste() + */ + public function paste(ImageInterface $image, PointInterface $start, $alpha = 100) + { + return $this->add(new Paste($image, $start, $alpha)); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ManipulatorInterface::applyMask() + */ + public function applyMask(ImageInterface $mask) + { + return $this->add(new ApplyMask($mask)); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ManipulatorInterface::fill() + */ + public function fill(FillInterface $fill) + { + return $this->add(new Fill($fill)); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ManipulatorInterface::resize() + */ + public function resize(BoxInterface $size, $filter = ImageInterface::FILTER_UNDEFINED) + { + return $this->add(new Resize($size, $filter)); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ManipulatorInterface::rotate() + */ + public function rotate($angle, ColorInterface $background = null) + { + return $this->add(new Rotate($angle, $background)); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ManipulatorInterface::save() + */ + public function save($path = null, array $options = array()) + { + return $this->add(new Save($path, $options)); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ManipulatorInterface::show() + */ + public function show($format, array $options = array()) + { + return $this->add(new Show($format, $options)); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ManipulatorInterface::thumbnail() + */ + public function thumbnail(BoxInterface $size, $settings = ImageInterface::THUMBNAIL_INSET, $filter = ImageInterface::FILTER_UNDEFINED) + { + return $this->add(new Thumbnail($size, $settings, $filter)); + } + + /** + * Registers a given FilterInterface in an internal array of filters for later application to an instance of ImageInterface. + * + * @param \Imagine\Filter\FilterInterface $filter + * @param int $priority + * + * @return $this + */ + public function add(FilterInterface $filter, $priority = 0) + { + $this->filters[$priority][] = $filter; + $this->sorted = null; + + return $this; + } +} diff --git a/vendor/imagine/imagine/src/Gd/Drawer.php b/vendor/imagine/imagine/src/Gd/Drawer.php new file mode 100644 index 0000000..34e670d --- /dev/null +++ b/vendor/imagine/imagine/src/Gd/Drawer.php @@ -0,0 +1,422 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Gd; + +use Imagine\Draw\DrawerInterface; +use Imagine\Exception\InvalidArgumentException; +use Imagine\Exception\RuntimeException; +use Imagine\Image\AbstractFont; +use Imagine\Image\Box; +use Imagine\Image\BoxInterface; +use Imagine\Image\Palette\Color\ColorInterface; +use Imagine\Image\Palette\Color\RGB as RGBColor; +use Imagine\Image\PointInterface; + +/** + * Drawer implementation using the GD PHP extension. + */ +final class Drawer implements DrawerInterface +{ + /** + * @var resource + */ + private $resource; + + /** + * @var array + */ + private $info; + + /** + * Constructs Drawer with a given gd image resource. + * + * @param resource $resource + */ + public function __construct($resource) + { + $this->loadGdInfo(); + $this->resource = $resource; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Draw\DrawerInterface::arc() + */ + public function arc(PointInterface $center, BoxInterface $size, $start, $end, ColorInterface $color, $thickness = 1) + { + $thickness = max(0, (int) round($thickness)); + if ($thickness === 0) { + return $this; + } + imagesetthickness($this->resource, $thickness); + + if (false === imagealphablending($this->resource, true)) { + throw new RuntimeException('Draw arc operation failed'); + } + + if (false === imagearc($this->resource, $center->getX(), $center->getY(), $size->getWidth(), $size->getHeight(), $start, $end, $this->getColor($color))) { + imagealphablending($this->resource, false); + throw new RuntimeException('Draw arc operation failed'); + } + + if (false === imagealphablending($this->resource, false)) { + throw new RuntimeException('Draw arc operation failed'); + } + + return $this; + } + + /** + * This function does not work properly because of a bug in GD. + * + * {@inheritdoc} + * + * @see \Imagine\Draw\DrawerInterface::chord() + */ + public function chord(PointInterface $center, BoxInterface $size, $start, $end, ColorInterface $color, $fill = false, $thickness = 1) + { + $thickness = max(0, (int) round($thickness)); + if ($thickness === 0 && !$fill) { + return $this; + } + imagesetthickness($this->resource, $thickness); + + if (false === imagealphablending($this->resource, true)) { + throw new RuntimeException('Draw chord operation failed'); + } + + if ($fill) { + $style = IMG_ARC_CHORD; + if (false === imagefilledarc($this->resource, $center->getX(), $center->getY(), $size->getWidth(), $size->getHeight(), $start, $end, $this->getColor($color), $style)) { + imagealphablending($this->resource, false); + throw new RuntimeException('Draw chord operation failed'); + } + } else { + foreach (array(IMG_ARC_NOFILL, IMG_ARC_NOFILL | IMG_ARC_CHORD) as $style) { + if (false === imagefilledarc($this->resource, $center->getX(), $center->getY(), $size->getWidth(), $size->getHeight(), $start, $end, $this->getColor($color), $style)) { + imagealphablending($this->resource, false); + throw new RuntimeException('Draw chord operation failed'); + } + } + } + + if (false === imagealphablending($this->resource, false)) { + throw new RuntimeException('Draw chord operation failed'); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Draw\DrawerInterface::circle() + */ + public function circle(PointInterface $center, $radius, ColorInterface $color, $fill = false, $thickness = 1) + { + $diameter = $radius * 2; + + return $this->ellipse($center, new Box($diameter, $diameter), $color, $fill, $thickness); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Draw\DrawerInterface::ellipse() + */ + public function ellipse(PointInterface $center, BoxInterface $size, ColorInterface $color, $fill = false, $thickness = 1) + { + $thickness = max(0, (int) round($thickness)); + if ($thickness === 0 && !$fill) { + return $this; + } + if (function_exists('imageantialias')) { + imageantialias($this->resource, true); + } + imagesetthickness($this->resource, $thickness); + + if ($fill) { + $callback = 'imagefilledellipse'; + } else { + $callback = 'imageellipse'; + } + + if (function_exists('imageantialias')) { + imageantialias($this->resource, true); + } + if (false === imagealphablending($this->resource, true)) { + throw new RuntimeException('Draw ellipse operation failed'); + } + + if (function_exists('imageantialias')) { + imageantialias($this->resource, true); + } + if (false === $callback($this->resource, $center->getX(), $center->getY(), $size->getWidth(), $size->getHeight(), $this->getColor($color))) { + imagealphablending($this->resource, false); + throw new RuntimeException('Draw ellipse operation failed'); + } + + if (false === imagealphablending($this->resource, false)) { + throw new RuntimeException('Draw ellipse operation failed'); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Draw\DrawerInterface::line() + */ + public function line(PointInterface $start, PointInterface $end, ColorInterface $color, $thickness = 1) + { + $thickness = max(0, (int) round($thickness)); + if ($thickness === 0) { + return $this; + } + imagesetthickness($this->resource, $thickness); + + if (false === imagealphablending($this->resource, true)) { + throw new RuntimeException('Draw line operation failed'); + } + + if (false === imageline($this->resource, $start->getX(), $start->getY(), $end->getX(), $end->getY(), $this->getColor($color))) { + imagealphablending($this->resource, false); + throw new RuntimeException('Draw line operation failed'); + } + + if (false === imagealphablending($this->resource, false)) { + throw new RuntimeException('Draw line operation failed'); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Draw\DrawerInterface::pieSlice() + */ + public function pieSlice(PointInterface $center, BoxInterface $size, $start, $end, ColorInterface $color, $fill = false, $thickness = 1) + { + $thickness = max(0, (int) round($thickness)); + if ($thickness === 0 && !$fill) { + return $this; + } + imagesetthickness($this->resource, $thickness); + + if ($fill) { + $style = IMG_ARC_EDGED; + } else { + $style = IMG_ARC_EDGED | IMG_ARC_NOFILL; + } + + if (false === imagealphablending($this->resource, true)) { + throw new RuntimeException('Draw chord operation failed'); + } + + if (false === imagefilledarc($this->resource, $center->getX(), $center->getY(), $size->getWidth(), $size->getHeight(), $start, $end, $this->getColor($color), $style)) { + imagealphablending($this->resource, false); + throw new RuntimeException('Draw chord operation failed'); + } + + if (false === imagealphablending($this->resource, false)) { + throw new RuntimeException('Draw chord operation failed'); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Draw\DrawerInterface::dot() + */ + public function dot(PointInterface $position, ColorInterface $color) + { + if (false === imagealphablending($this->resource, true)) { + throw new RuntimeException('Draw point operation failed'); + } + + if (false === imagesetpixel($this->resource, $position->getX(), $position->getY(), $this->getColor($color))) { + imagealphablending($this->resource, false); + throw new RuntimeException('Draw point operation failed'); + } + + if (false === imagealphablending($this->resource, false)) { + throw new RuntimeException('Draw point operation failed'); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Draw\DrawerInterface::rectangle() + */ + public function rectangle(PointInterface $leftTop, PointInterface $rightBottom, ColorInterface $color, $fill = false, $thickness = 1) + { + $thickness = max(0, (int) round($thickness)); + if ($thickness === 0 && !$fill) { + return $this; + } + imagesetthickness($this->resource, $thickness); + + $minX = min($leftTop->getX(), $rightBottom->getX()); + $maxX = max($leftTop->getX(), $rightBottom->getX()); + $minY = min($leftTop->getY(), $rightBottom->getY()); + $maxY = max($leftTop->getY(), $rightBottom->getY()); + + if ($fill) { + $callback = 'imagefilledrectangle'; + } else { + $callback = 'imagerectangle'; + } + + if (false === imagealphablending($this->resource, true)) { + throw new RuntimeException('Draw polygon operation failed'); + } + + if (false === $callback($this->resource, $minX, $minY, $maxX, $maxY, $this->getColor($color))) { + imagealphablending($this->resource, false); + throw new RuntimeException('Draw polygon operation failed'); + } + + if (false === imagealphablending($this->resource, false)) { + throw new RuntimeException('Draw polygon operation failed'); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Draw\DrawerInterface::polygon() + */ + public function polygon(array $coordinates, ColorInterface $color, $fill = false, $thickness = 1) + { + $thickness = max(0, (int) round($thickness)); + if ($thickness === 0 && !$fill) { + return $this; + } + imagesetthickness($this->resource, $thickness); + + if (count($coordinates) < 3) { + throw new InvalidArgumentException(sprintf('A polygon must consist of at least 3 points, %d given', count($coordinates))); + } + + $points = call_user_func_array('array_merge', array_map(function (PointInterface $p) { + return array($p->getX(), $p->getY()); + }, $coordinates)); + + if ($fill) { + $callback = 'imagefilledpolygon'; + } else { + $callback = 'imagepolygon'; + } + + if (false === imagealphablending($this->resource, true)) { + throw new RuntimeException('Draw polygon operation failed'); + } + + if (false === $callback($this->resource, $points, count($coordinates), $this->getColor($color))) { + imagealphablending($this->resource, false); + throw new RuntimeException('Draw polygon operation failed'); + } + + if (false === imagealphablending($this->resource, false)) { + throw new RuntimeException('Draw polygon operation failed'); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Draw\DrawerInterface::text() + */ + public function text($string, AbstractFont $font, PointInterface $position, $angle = 0, $width = null) + { + if (!$this->info['FreeType Support']) { + throw new RuntimeException('GD is not compiled with FreeType support'); + } + + $angle = -1 * $angle; + $fontsize = $font->getSize(); + $fontfile = $font->getFile(); + $x = $position->getX(); + $y = $position->getY() + $fontsize; + + if ($width !== null) { + $string = $font->wrapText($string, $width, $angle); + } + + if (false === imagealphablending($this->resource, true)) { + throw new RuntimeException('Font mask operation failed'); + } + + if ($fontfile && DIRECTORY_SEPARATOR === '\\') { + // On Windows imagefttext() throws a "Could not find/open font" error if $fontfile is not an absolute path. + $fontfileRealpath = realpath($fontfile); + if ($fontfileRealpath !== false) { + $fontfile = $fontfileRealpath; + } + } + if (false === imagefttext($this->resource, $fontsize, $angle, $x, $y, $this->getColor($font->getColor()), $fontfile, $string)) { + imagealphablending($this->resource, false); + throw new RuntimeException('Font mask operation failed'); + } + + if (false === imagealphablending($this->resource, false)) { + throw new RuntimeException('Font mask operation failed'); + } + + return $this; + } + + /** + * Generates a GD color from Color instance. + * + * @param \Imagine\Image\Palette\Color\ColorInterface $color + * + * @throws \Imagine\Exception\RuntimeException + * @throws \Imagine\Exception\InvalidArgumentException + * + * @return resource + */ + private function getColor(ColorInterface $color) + { + if (!$color instanceof RGBColor) { + throw new InvalidArgumentException('GD driver only supports RGB colors'); + } + + $gdColor = imagecolorallocatealpha($this->resource, $color->getRed(), $color->getGreen(), $color->getBlue(), (100 - $color->getAlpha()) * 127 / 100); + if (false === $gdColor) { + throw new RuntimeException(sprintf('Unable to allocate color "RGB(%s, %s, %s)" with transparency of %d percent', $color->getRed(), $color->getGreen(), $color->getBlue(), $color->getAlpha())); + } + + return $gdColor; + } + + private function loadGdInfo() + { + if (!function_exists('gd_info')) { + throw new RuntimeException('Gd not installed'); + } + + $this->info = gd_info(); + } +} diff --git a/vendor/imagine/imagine/src/Gd/Effects.php b/vendor/imagine/imagine/src/Gd/Effects.php new file mode 100644 index 0000000..ed72f67 --- /dev/null +++ b/vendor/imagine/imagine/src/Gd/Effects.php @@ -0,0 +1,166 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Gd; + +use Imagine\Effects\EffectsInterface; +use Imagine\Exception\InvalidArgumentException; +use Imagine\Exception\RuntimeException; +use Imagine\Image\Palette\Color\ColorInterface; +use Imagine\Image\Palette\Color\RGB as RGBColor; +use Imagine\Utils\Matrix; + +/** + * Effects implementation using the GD PHP extension. + */ +class Effects implements EffectsInterface +{ + /** + * @var resource + */ + private $resource; + + /** + * Initialize the instance. + * + * @param resource $resource + */ + public function __construct($resource) + { + $this->resource = $resource; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Effects\EffectsInterface::gamma() + */ + public function gamma($correction) + { + if (false === imagegammacorrect($this->resource, 1.0, $correction)) { + throw new RuntimeException('Failed to apply gamma correction to the image'); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Effects\EffectsInterface::negative() + */ + public function negative() + { + if (false === imagefilter($this->resource, IMG_FILTER_NEGATE)) { + throw new RuntimeException('Failed to negate the image'); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Effects\EffectsInterface::grayscale() + */ + public function grayscale() + { + if (false === imagefilter($this->resource, IMG_FILTER_GRAYSCALE)) { + throw new RuntimeException('Failed to grayscale the image'); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Effects\EffectsInterface::colorize() + */ + public function colorize(ColorInterface $color) + { + if (!$color instanceof RGBColor) { + throw new RuntimeException('Colorize effects only accepts RGB color in GD context'); + } + + if (false === imagefilter($this->resource, IMG_FILTER_COLORIZE, $color->getRed(), $color->getGreen(), $color->getBlue())) { + throw new RuntimeException('Failed to colorize the image'); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Effects\EffectsInterface::sharpen() + */ + public function sharpen() + { + $sharpenMatrix = array(array(-1, -1, -1), array(-1, 16, -1), array(-1, -1, -1)); + $divisor = array_sum(array_map('array_sum', $sharpenMatrix)); + + if (false === imageconvolution($this->resource, $sharpenMatrix, $divisor, 0)) { + throw new RuntimeException('Failed to sharpen the image'); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Effects\EffectsInterface::blur() + */ + public function blur($sigma = 1) + { + if (false === imagefilter($this->resource, IMG_FILTER_GAUSSIAN_BLUR)) { + throw new RuntimeException('Failed to blur the image'); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Effects\EffectsInterface::brightness() + */ + public function brightness($brightness) + { + $gdBrightness = (int) round($brightness / 100 * 255); + if ($gdBrightness < -255 || $gdBrightness > 255) { + throw new InvalidArgumentException(sprintf('The %1$s argument can range from %2$d to %3$d, but you specified %4$d.', '$brightness', -100, 100, $brightness)); + } + if (false === imagefilter($this->resource, IMG_FILTER_BRIGHTNESS, $gdBrightness)) { + throw new RuntimeException('Failed to brightness the image'); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Effects\EffectsInterface::convolve() + */ + public function convolve(Matrix $matrix) + { + if ($matrix->getWidth() !== 3 || $matrix->getHeight() !== 3) { + throw new InvalidArgumentException(sprintf('A convolution matrix must be 3x3 (%dx%d provided).', $matrix->getWidth(), $matrix->getHeight())); + } + if (false === imageconvolution($this->resource, $matrix->getMatrix(), 1, 0)) { + throw new RuntimeException('Failed to convolve the image'); + } + + return $this; + } +} diff --git a/vendor/imagine/imagine/src/Gd/Font.php b/vendor/imagine/imagine/src/Gd/Font.php new file mode 100644 index 0000000..d5e395f --- /dev/null +++ b/vendor/imagine/imagine/src/Gd/Font.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Gd; + +use Imagine\Exception\RuntimeException; +use Imagine\Image\AbstractFont; + +/** + * Font implementation using the GD library. + */ +final class Font extends AbstractFont +{ + /** + * {@inheritdoc} + * + * @see \Imagine\Image\FontInterface::box() + */ + public function box($string, $angle = 0) + { + if (!function_exists('imageftbbox')) { + throw new RuntimeException('GD must have been compiled with `--with-freetype-dir` option to use the Font feature.'); + } + $fontfile = $this->file; + if ($fontfile && DIRECTORY_SEPARATOR === '\\') { + // On Windows imageftbbox() throws a "Could not find/open font" error if $fontfile is not an absolute path. + $fontfileRealpath = realpath($fontfile); + if ($fontfileRealpath !== false) { + $fontfile = $fontfileRealpath; + } + } + + $angle = -1 * $angle; + $info = imageftbbox($this->size, $angle, $fontfile, $string); + $xs = array($info[0], $info[2], $info[4], $info[6]); + $ys = array($info[1], $info[3], $info[5], $info[7]); + $width = abs(max($xs) - min($xs)); + $height = abs(max($ys) - min($ys)); + + return $this->getClassFactory()->createBox($width, $height); + } +} diff --git a/vendor/imagine/imagine/src/Gd/Image.php b/vendor/imagine/imagine/src/Gd/Image.php new file mode 100644 index 0000000..ccd65ba --- /dev/null +++ b/vendor/imagine/imagine/src/Gd/Image.php @@ -0,0 +1,818 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Gd; + +use Imagine\Exception\InvalidArgumentException; +use Imagine\Exception\OutOfBoundsException; +use Imagine\Exception\RuntimeException; +use Imagine\Factory\ClassFactoryInterface; +use Imagine\Image\AbstractImage; +use Imagine\Image\BoxInterface; +use Imagine\Image\Fill\FillInterface; +use Imagine\Image\ImageInterface; +use Imagine\Image\Metadata\MetadataBag; +use Imagine\Image\Palette\Color\ColorInterface; +use Imagine\Image\Palette\Color\RGB as RGBColor; +use Imagine\Image\Palette\PaletteInterface; +use Imagine\Image\Palette\RGB; +use Imagine\Image\Point; +use Imagine\Image\PointInterface; +use Imagine\Image\ProfileInterface; +use Imagine\Utils\ErrorHandling; + +/** + * Image implementation using the GD library. + */ +final class Image extends AbstractImage +{ + /** + * @var resource + */ + private $resource; + + /** + * @var \Imagine\Gd\Layers|null + */ + private $layers; + + /** + * @var \Imagine\Image\Palette\PaletteInterface + */ + private $palette; + + /** + * Constructs a new Image instance. + * + * @param resource $resource + * @param \Imagine\Image\Palette\PaletteInterface $palette + * @param \Imagine\Image\Metadata\MetadataBag $metadata + */ + public function __construct($resource, PaletteInterface $palette, MetadataBag $metadata) + { + $this->metadata = $metadata; + $this->palette = $palette; + $this->resource = $resource; + } + + /** + * Makes sure the current image resource is destroyed. + */ + public function __destruct() + { + if (is_resource($this->resource) && 'gd' === get_resource_type($this->resource)) { + imagedestroy($this->resource); + } + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\AbstractImage::__clone() + */ + public function __clone() + { + parent::__clone(); + $size = $this->getSize(); + $copy = $this->createImage($size, 'copy'); + if (false === imagecopy($copy, $this->resource, 0, 0, 0, 0, $size->getWidth(), $size->getHeight())) { + imagedestroy($copy); + throw new RuntimeException('Image copy operation failed'); + } + $this->resource = $copy; + $this->palette = clone $this->palette; + if ($this->layers !== null) { + $this->layers = $this->getClassFactory()->createLayers(ClassFactoryInterface::HANDLE_GD, $this, $this->layers->key()); + } + } + + /** + * Returns Gd resource. + * + * @return resource + */ + public function getGdResource() + { + return $this->resource; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ManipulatorInterface::copy() + */ + final public function copy() + { + return clone $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ManipulatorInterface::crop() + */ + final public function crop(PointInterface $start, BoxInterface $size) + { + if (!$start->in($this->getSize())) { + throw new OutOfBoundsException('Crop coordinates must start at minimum 0, 0 position from top left corner, crop height and width must be positive integers and must not exceed the current image borders'); + } + + $width = $size->getWidth(); + $height = $size->getHeight(); + + $dest = $this->createImage($size, 'crop'); + + if (false === imagecopy($dest, $this->resource, 0, 0, $start->getX(), $start->getY(), $width, $height)) { + imagedestroy($dest); + throw new RuntimeException('Image crop operation failed'); + } + + imagedestroy($this->resource); + + $this->resource = $dest; + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ManipulatorInterface::paste() + */ + final public function paste(ImageInterface $image, PointInterface $start, $alpha = 100) + { + if (!$image instanceof self) { + throw new InvalidArgumentException(sprintf('Gd\Image can only paste() Gd\Image instances, %s given', get_class($image))); + } + + $alpha = (int) round($alpha); + if ($alpha < 0 || $alpha > 100) { + throw new InvalidArgumentException(sprintf('The %1$s argument can range from %2$d to %3$d, but you specified %4$d.', '$alpha', 0, 100, $alpha)); + } + + $size = $image->getSize(); + + if ($alpha === 100) { + imagealphablending($this->resource, true); + imagealphablending($image->resource, true); + + $success = imagecopy($this->resource, $image->resource, $start->getX(), $start->getY(), 0, 0, $size->getWidth(), $size->getHeight()); + + imagealphablending($this->resource, false); + imagealphablending($image->resource, false); + + if ($success === false) { + throw new RuntimeException('Image paste operation failed'); + } + } elseif ($alpha > 0) { + if (false === imagecopymerge(/*dst_im*/$this->resource, /*src_im*/$image->resource, /*dst_x*/$start->getX(), /*dst_y*/$start->getY(), /*src_x*/0, /*src_y*/0, /*src_w*/$size->getWidth(), /*src_h*/$size->getHeight(), /*pct*/$alpha)) { + throw new RuntimeException('Image paste operation failed'); + } + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ManipulatorInterface::resize() + */ + final public function resize(BoxInterface $size, $filter = ImageInterface::FILTER_UNDEFINED) + { + if (ImageInterface::FILTER_UNDEFINED !== $filter) { + throw new InvalidArgumentException('Unsupported filter type, GD only supports ImageInterface::FILTER_UNDEFINED filter'); + } + + $width = $size->getWidth(); + $height = $size->getHeight(); + + $dest = $this->createImage($size, 'resize'); + + imagealphablending($this->resource, true); + imagealphablending($dest, true); + + $success = imagecopyresampled($dest, $this->resource, 0, 0, 0, 0, $width, $height, imagesx($this->resource), imagesy($this->resource)); + + imagealphablending($this->resource, false); + imagealphablending($dest, false); + + if ($success === false) { + imagedestroy($dest); + throw new RuntimeException('Image resize operation failed'); + } + + imagedestroy($this->resource); + + $this->resource = $dest; + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ManipulatorInterface::rotate() + */ + final public function rotate($angle, ColorInterface $background = null) + { + if ($background === null) { + $background = $this->palette->color('fff'); + } + $color = $this->getColor($background); + $resource = imagerotate($this->resource, -1 * $angle, $color); + + if (false === $resource) { + throw new RuntimeException('Image rotate operation failed'); + } + + imagedestroy($this->resource); + $this->resource = $resource; + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ManipulatorInterface::save() + */ + final public function save($path = null, array $options = array()) + { + $path = null === $path ? (isset($this->metadata['filepath']) ? $this->metadata['filepath'] : $path) : $path; + + if (null === $path) { + throw new RuntimeException('You can omit save path only if image has been open from a file'); + } + + if (isset($options['format'])) { + $format = $options['format']; + } elseif ('' !== $extension = pathinfo($path, \PATHINFO_EXTENSION)) { + $format = $extension; + } else { + $originalPath = isset($this->metadata['filepath']) ? $this->metadata['filepath'] : null; + $format = pathinfo($originalPath, \PATHINFO_EXTENSION); + } + + $this->saveOrOutput($format, $options, $path); + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ManipulatorInterface::show() + */ + public function show($format, array $options = array()) + { + header('Content-type: ' . $this->getMimeType($format)); + + $this->saveOrOutput($format, $options); + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImageInterface::get() + */ + public function get($format, array $options = array()) + { + ob_start(); + $this->saveOrOutput($format, $options); + + return ob_get_clean(); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImageInterface::__toString() + */ + public function __toString() + { + return $this->get('png'); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ManipulatorInterface::flipHorizontally() + */ + final public function flipHorizontally() + { + if (function_exists('imageflip')) { + imageflip($this->resource, IMG_FLIP_HORIZONTAL); + } else { + $size = $this->getSize(); + $width = $size->getWidth(); + $height = $size->getHeight(); + $dest = $this->createImage($size, 'flip'); + + for ($i = 0; $i < $width; $i++) { + if (false === imagecopy($dest, $this->resource, $i, 0, ($width - 1) - $i, 0, 1, $height)) { + imagedestroy($dest); + throw new RuntimeException('Horizontal flip operation failed'); + } + } + + imagedestroy($this->resource); + + $this->resource = $dest; + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ManipulatorInterface::flipVertically() + */ + final public function flipVertically() + { + if (function_exists('imageflip')) { + imageflip($this->resource, IMG_FLIP_VERTICAL); + } else { + $size = $this->getSize(); + $width = $size->getWidth(); + $height = $size->getHeight(); + $dest = $this->createImage($size, 'flip'); + + for ($i = 0; $i < $height; $i++) { + if (false === imagecopy($dest, $this->resource, 0, $i, 0, ($height - 1) - $i, $width, 1)) { + imagedestroy($dest); + throw new RuntimeException('Vertical flip operation failed'); + } + } + + imagedestroy($this->resource); + + $this->resource = $dest; + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ManipulatorInterface::strip() + */ + final public function strip() + { + // GD strips profiles and comment, so there's nothing to do here + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImageInterface::draw() + */ + public function draw() + { + return $this->getClassFactory()->createDrawer(ClassFactoryInterface::HANDLE_GD, $this->resource); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImageInterface::effects() + */ + public function effects() + { + return $this->getClassFactory()->createEffects(ClassFactoryInterface::HANDLE_GD, $this->resource); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImageInterface::getSize() + */ + public function getSize() + { + return $this->getClassFactory()->createBox(imagesx($this->resource), imagesy($this->resource)); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ManipulatorInterface::applyMask() + */ + public function applyMask(ImageInterface $mask) + { + if (!$mask instanceof self) { + throw new InvalidArgumentException('Cannot mask non-gd images'); + } + + $size = $this->getSize(); + $maskSize = $mask->getSize(); + + if ($size != $maskSize) { + throw new InvalidArgumentException(sprintf('The given mask doesn\'t match current image\'s size, Current mask\'s dimensions are %s, while image\'s dimensions are %s', $maskSize, $size)); + } + + for ($x = 0, $width = $size->getWidth(); $x < $width; $x++) { + for ($y = 0, $height = $size->getHeight(); $y < $height; $y++) { + $position = new Point($x, $y); + $color = $this->getColorAt($position); + $maskColor = $mask->getColorAt($position); + $round = (int) round(max($color->getAlpha(), (100 - $color->getAlpha()) * $maskColor->getRed() / 255)); + + if (false === imagesetpixel($this->resource, $x, $y, $this->getColor($color->dissolve($round - $color->getAlpha())))) { + throw new RuntimeException('Apply mask operation failed'); + } + } + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ManipulatorInterface::fill() + */ + public function fill(FillInterface $fill) + { + $size = $this->getSize(); + + for ($x = 0, $width = $size->getWidth(); $x < $width; $x++) { + for ($y = 0, $height = $size->getHeight(); $y < $height; $y++) { + if (false === imagesetpixel($this->resource, $x, $y, $this->getColor($fill->getColor(new Point($x, $y))))) { + throw new RuntimeException('Fill operation failed'); + } + } + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImageInterface::mask() + */ + public function mask() + { + $mask = $this->copy(); + + if (false === imagefilter($mask->resource, IMG_FILTER_GRAYSCALE)) { + throw new RuntimeException('Mask operation failed'); + } + + return $mask; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImageInterface::histogram() + */ + public function histogram() + { + $size = $this->getSize(); + $colors = array(); + + for ($x = 0, $width = $size->getWidth(); $x < $width; $x++) { + for ($y = 0, $height = $size->getHeight(); $y < $height; $y++) { + $colors[] = $this->getColorAt(new Point($x, $y)); + } + } + + return array_unique($colors); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImageInterface::getColorAt() + */ + public function getColorAt(PointInterface $point) + { + if (!$point->in($this->getSize())) { + throw new RuntimeException(sprintf('Error getting color at point [%s,%s]. The point must be inside the image of size [%s,%s]', $point->getX(), $point->getY(), $this->getSize()->getWidth(), $this->getSize()->getHeight())); + } + + $index = imagecolorat($this->resource, $point->getX(), $point->getY()); + $info = imagecolorsforindex($this->resource, $index); + + return $this->palette->color(array($info['red'], $info['green'], $info['blue']), max(min(100 - (int) round($info['alpha'] / 127 * 100), 100), 0)); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImageInterface::layers() + */ + public function layers() + { + if (null === $this->layers) { + $this->layers = $this->getClassFactory()->createLayers(ClassFactoryInterface::HANDLE_GD, $this); + } + + return $this->layers; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImageInterface::interlace() + */ + public function interlace($scheme) + { + static $supportedInterlaceSchemes = array( + ImageInterface::INTERLACE_NONE => 0, + ImageInterface::INTERLACE_LINE => 1, + ImageInterface::INTERLACE_PLANE => 1, + ImageInterface::INTERLACE_PARTITION => 1, + ); + + if (!array_key_exists($scheme, $supportedInterlaceSchemes)) { + throw new InvalidArgumentException('Unsupported interlace type'); + } + + imageinterlace($this->resource, $supportedInterlaceSchemes[$scheme]); + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImageInterface::palette() + */ + public function palette() + { + return $this->palette; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImageInterface::profile() + */ + public function profile(ProfileInterface $profile) + { + throw new RuntimeException('GD driver does not support color profiles'); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImageInterface::usePalette() + */ + public function usePalette(PaletteInterface $palette) + { + if (!$palette instanceof RGB) { + throw new RuntimeException('GD driver only supports RGB palette'); + } + + $this->palette = $palette; + + return $this; + } + + /** + * Performs save or show operation using one of GD's image... functions. + * + * @param string $format + * @param array $options + * @param string $filename + * + * @throws \Imagine\Exception\InvalidArgumentException + * @throws \Imagine\Exception\RuntimeException + */ + private function saveOrOutput($format, array $options, $filename = null) + { + $format = $this->normalizeFormat($format); + + if (!$this->supported($format)) { + throw new InvalidArgumentException(sprintf('Saving image in "%s" format is not supported, please use one of the following extensions: "%s"', $format, implode('", "', $this->supported()))); + } + + $save = 'image' . $format; + $args = array(&$this->resource, $filename); + + switch ($format) { + case 'bmp': + if (isset($options['compressed'])) { + $args[] = (bool) $options['compressed']; + } + break; + case 'jpeg': + if (!isset($options['jpeg_quality'])) { + if (isset($options['quality'])) { + $options['jpeg_quality'] = $options['quality']; + } + } + if (isset($options['jpeg_quality'])) { + $args[] = $options['jpeg_quality']; + } + break; + case 'png': + if (!isset($options['png_compression_level'])) { + if (isset($options['quality'])) { + $options['png_compression_level'] = round((100 - $options['quality']) * 9 / 100); + } + } + if (isset($options['png_compression_level'])) { + if ($options['png_compression_level'] < 0 || $options['png_compression_level'] > 9) { + throw new InvalidArgumentException('png_compression_level option should be an integer from 0 to 9'); + } + $args[] = $options['png_compression_level']; + } else { + $args[] = -1; // use default level + } + if (!isset($options['png_compression_filter'])) { + if (isset($options['filters'])) { + $options['png_compression_filter'] = $options['filters']; + } + } + if (isset($options['png_compression_filter'])) { + if (~PNG_ALL_FILTERS & $options['png_compression_filter']) { + throw new InvalidArgumentException('png_compression_filter option should be a combination of the PNG_FILTER_XXX constants'); + } + $args[] = $options['png_compression_filter']; + } + break; + case 'wbmp': + case 'xbm': + if (isset($options['foreground'])) { + $args[] = $options['foreground']; + } + break; + case 'webp': + if (!isset($options['webp_quality'])) { + if (isset($options['quality'])) { + $options['webp_quality'] = $options['quality']; + } + } + if (isset($options['webp_quality'])) { + if ($options['webp_quality'] < 0 || $options['webp_quality'] > 100) { + throw new InvalidArgumentException('webp_quality option should be an integer from 0 to 100'); + } + $args[] = $options['webp_quality']; + } + break; + } + + ErrorHandling::throwingRuntimeException(E_WARNING | E_NOTICE, function () use ($save, $args) { + if (false === call_user_func_array($save, $args)) { + throw new RuntimeException('Save operation failed'); + } + }); + } + + /** + * Generates a GD image. + * + * @param \Imagine\Image\BoxInterface $size + * @param string $operation the operation initiating the creation + * + * @throws \Imagine\Exception\RuntimeException + * + * @return resource + */ + private function createImage(BoxInterface $size, $operation) + { + $resource = imagecreatetruecolor($size->getWidth(), $size->getHeight()); + + if (false === $resource) { + throw new RuntimeException('Image ' . $operation . ' failed'); + } + + if (false === imagealphablending($resource, false) || false === imagesavealpha($resource, true)) { + throw new RuntimeException('Image ' . $operation . ' failed'); + } + + if (function_exists('imageantialias')) { + imageantialias($resource, true); + } + + $transparent = imagecolorallocatealpha($resource, 255, 255, 255, 127); + imagefill($resource, 0, 0, $transparent); + imagecolortransparent($resource, $transparent); + + return $resource; + } + + /** + * Generates a GD color from Color instance. + * + * @param \Imagine\Image\Palette\Color\ColorInterface $color + * + * @throws \Imagine\Exception\RuntimeException + * @throws \Imagine\Exception\InvalidArgumentException + * + * @return int A color identifier + */ + private function getColor(ColorInterface $color) + { + if (!$color instanceof RGBColor) { + throw new InvalidArgumentException('GD driver only supports RGB colors'); + } + + $index = imagecolorallocatealpha($this->resource, $color->getRed(), $color->getGreen(), $color->getBlue(), round(127 * (100 - $color->getAlpha()) / 100)); + + if (false === $index) { + throw new RuntimeException(sprintf('Unable to allocate color "RGB(%s, %s, %s)" with transparency of %d percent', $color->getRed(), $color->getGreen(), $color->getBlue(), $color->getAlpha())); + } + + return $index; + } + + /** + * Normalizes a given format name. + * + * @param string $format + * + * @return string + */ + private function normalizeFormat($format) + { + $format = strtolower($format); + + if ('jpg' === $format || 'pjpeg' === $format || 'jfif' === $format) { + $format = 'jpeg'; + } + + return $format; + } + + /** + * Checks whether a given format is supported by GD library. + * + * @param string $format + * + * @return bool + */ + private function supported($format = null) + { + $formats = self::getSupportedFormats(); + + if (null === $format) { + return array_keys($formats); + } + + return is_string($format) && isset($formats[$format]); + } + + /** + * Get the mime type based on format. + * + * @param string $format + * + * @throws \Imagine\Exception\RuntimeException + * + * @return string mime-type + */ + private function getMimeType($format) + { + $format = $this->normalizeFormat($format); + $formats = self::getSupportedFormats(); + + if (!isset($formats[$format])) { + throw new RuntimeException('Invalid format'); + } + + return $formats[$format]['mimeType']; + } + + /** + * @return array + */ + private static function getSupportedFormats() + { + static $supportedFormats; + if (!isset($supportedFormats)) { + $supportedFormats = array( + 'gif' => array('mimeType' => 'image/gif'), + 'jpeg' => array('mimeType' => 'image/jpeg'), + 'png' => array('mimeType' => 'image/png'), + 'wbmp' => array('mimeType' => 'image/vnd.wap.wbmp'), + 'xbm' => array('mimeType' => 'image/xbm'), + ); + if (function_exists('imagebmp')) { + $supportedFormats['bmp'] = array('mimeType' => 'image/bmp'); + } + if (function_exists('imagewebp')) { + $supportedFormats['webp'] = array('mimeType' => 'image/webp'); + } + ksort($supportedFormats); + } + + return $supportedFormats; + } +} diff --git a/vendor/imagine/imagine/src/Gd/Imagine.php b/vendor/imagine/imagine/src/Gd/Imagine.php new file mode 100644 index 0000000..cc870dc --- /dev/null +++ b/vendor/imagine/imagine/src/Gd/Imagine.php @@ -0,0 +1,250 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Gd; + +use Imagine\Exception\InvalidArgumentException; +use Imagine\Exception\RuntimeException; +use Imagine\Factory\ClassFactoryInterface; +use Imagine\File\LoaderInterface; +use Imagine\Image\AbstractImagine; +use Imagine\Image\BoxInterface; +use Imagine\Image\Metadata\MetadataBag; +use Imagine\Image\Palette\Color\ColorInterface; +use Imagine\Image\Palette\Color\RGB as RGBColor; +use Imagine\Image\Palette\PaletteInterface; +use Imagine\Image\Palette\RGB; +use Imagine\Utils\ErrorHandling; + +/** + * Imagine implementation using the GD library. + */ +final class Imagine extends AbstractImagine +{ + /** + * Initialize the class. + */ + public function __construct() + { + $this->requireGdVersion('2.0.1'); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImagineInterface::create() + */ + public function create(BoxInterface $size, ColorInterface $color = null) + { + $width = $size->getWidth(); + $height = $size->getHeight(); + + $resource = imagecreatetruecolor($width, $height); + + if (false === $resource) { + throw new RuntimeException('Create operation failed'); + } + + $palette = null !== $color ? $color->getPalette() : new RGB(); + $color = $color ? $color : $palette->color('fff'); + + if (!$color instanceof RGBColor) { + throw new InvalidArgumentException('GD driver only supports RGB colors'); + } + + $index = imagecolorallocatealpha($resource, $color->getRed(), $color->getGreen(), $color->getBlue(), round(127 * (100 - $color->getAlpha()) / 100)); + + if (false === $index) { + throw new RuntimeException('Unable to allocate color'); + } + + if (false === imagefill($resource, 0, 0, $index)) { + throw new RuntimeException('Could not set background color fill'); + } + + if ($color->getAlpha() <= 5) { + imagecolortransparent($resource, $index); + } + + return $this->wrap($resource, $palette, new MetadataBag()); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImagineInterface::open() + */ + public function open($path) + { + $loader = $path instanceof LoaderInterface ? $path : $this->getClassFactory()->createFileLoader($path); + $path = $loader->getPath(); + + $data = $loader->getData(); + + $resource = $this->createImageFromString($data); + + if (!\is_resource($resource)) { + throw new RuntimeException(sprintf('Unable to open image %s', $path)); + } + + return $this->wrap($resource, new RGB(), $this->getMetadataReader()->readFile($loader)); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImagineInterface::load() + */ + public function load($string) + { + return $this->doLoad($string, $this->getMetadataReader()->readData($string)); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImagineInterface::read() + */ + public function read($resource) + { + if (!\is_resource($resource)) { + throw new InvalidArgumentException('Variable does not contain a stream resource'); + } + + $content = stream_get_contents($resource); + + if (false === $content) { + throw new InvalidArgumentException('Cannot read resource content'); + } + + return $this->doLoad($content, $this->getMetadataReader()->readData($content, $resource)); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImagineInterface::font() + */ + public function font($file, $size, ColorInterface $color) + { + return $this->getClassFactory()->createFont(ClassFactoryInterface::HANDLE_GD, $file, $size, $color); + } + + /** + * @param resource $resource + * @param \Imagine\Image\Palette\PaletteInterface $palette + * @param \Imagine\Image\Metadata\MetadataBag $metadata + * + * @throws \Imagine\Exception\RuntimeException + * + * @return \Imagine\Image\ImageInterface + */ + private function wrap($resource, PaletteInterface $palette, MetadataBag $metadata) + { + if (!imageistruecolor($resource)) { + if (\function_exists('imagepalettetotruecolor')) { + if (false === imagepalettetotruecolor($resource)) { + throw new RuntimeException('Could not convert a palette based image to true color'); + } + } else { + list($width, $height) = array(imagesx($resource), imagesy($resource)); + + // create transparent truecolor canvas + $truecolor = imagecreatetruecolor($width, $height); + $transparent = imagecolorallocatealpha($truecolor, 255, 255, 255, 127); + + imagealphablending($truecolor, false); + imagefilledrectangle($truecolor, 0, 0, $width, $height, $transparent); + imagealphablending($truecolor, false); + + imagecopy($truecolor, $resource, 0, 0, 0, 0, $width, $height); + + imagedestroy($resource); + $resource = $truecolor; + } + } + + if (false === imagealphablending($resource, false) || false === imagesavealpha($resource, true)) { + throw new RuntimeException('Could not set alphablending, savealpha and antialias values'); + } + + if (\function_exists('imageantialias')) { + imageantialias($resource, true); + } + + return $this->getClassFactory()->createImage(ClassFactoryInterface::HANDLE_GD, $resource, $palette, $metadata); + } + + /** + * @param string $version + * + * @throws \Imagine\Exception\RuntimeException + */ + private function requireGdVersion($version) + { + if (!\function_exists('gd_info')) { + throw new RuntimeException('Gd not installed'); + } + if (version_compare(GD_VERSION, $version, '<')) { + throw new RuntimeException(sprintf('GD2 version %s or higher is required, %s provided', $version, GD_VERSION)); + } + } + + /** + * @param string $string + * @param \Imagine\Image\Metadata\MetadataBag $metadata + * + * @throws \Imagine\Exception\RuntimeException + * + * @return \Imagine\Image\ImageInterface + */ + private function doLoad($string, MetadataBag $metadata) + { + $resource = $this->createImageFromString($string); + + if (!\is_resource($resource)) { + throw new RuntimeException('An image could not be created from the given input'); + } + + return $this->wrap($resource, new RGB(), $metadata); + } + + /** + * Check if the raw image data represents an image in WebP format. + * + * @param string $data + * + * @return bool + */ + private function isWebP(&$data) + { + return substr($data, 8, 7) === 'WEBPVP8'; + } + + /** + * Create an image resource starting from its raw daa. + * + * @param string $string + * + * @return resource|false + */ + private function createImageFromString(&$string) + { + return ErrorHandling::ignoring(-1, function () use (&$string) { + // imagecreatefromstring() does not support webp images before PHP 7.3.0 + if (PHP_VERSION_ID < 70300 && function_exists('imagecreatefromwebp') && $this->isWebP($string)) { + return @imagecreatefromwebp('data:image/webp;base64,' . base64_encode($string)); + } + + return @imagecreatefromstring($string); + }); + } +} diff --git a/vendor/imagine/imagine/src/Gd/Layers.php b/vendor/imagine/imagine/src/Gd/Layers.php new file mode 100644 index 0000000..6c67bab --- /dev/null +++ b/vendor/imagine/imagine/src/Gd/Layers.php @@ -0,0 +1,195 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Gd; + +use Imagine\Exception\NotSupportedException; +use Imagine\Exception\RuntimeException; +use Imagine\Factory\ClassFactoryInterface; +use Imagine\Image\AbstractLayers; +use Imagine\Image\Metadata\MetadataBag; +use Imagine\Image\Palette\PaletteInterface; + +class Layers extends AbstractLayers +{ + /** + * @var \Imagine\Gd\Image + */ + private $image; + + /** + * @var int + */ + private $offset; + + /** + * @var resource + */ + private $resource; + + /** + * @var \Imagine\Image\Palette\PaletteInterface + */ + private $palette; + + /** + * @param \Imagine\Gd\Image $image + * @param \Imagine\Image\Palette\PaletteInterface $palette + * @param resource $resource + * @param int $initialOffset + * + * @throws \Imagine\Exception\RuntimeException + */ + public function __construct(Image $image, PaletteInterface $palette, $resource, $initialOffset = 0) + { + if (!is_resource($resource)) { + throw new RuntimeException('Invalid Gd resource provided'); + } + + $this->image = $image; + $this->resource = $resource; + $this->offset = (int) $initialOffset; + $this->palette = $palette; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\LayersInterface::merge() + */ + public function merge() + { + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\LayersInterface::coalesce() + */ + public function coalesce() + { + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\LayersInterface::animate() + */ + public function animate($format, $delay, $loops) + { + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Iterator::current() + */ + public function current() + { + return $this->getClassFactory()->createImage(ClassFactoryInterface::HANDLE_GD, $this->resource, $this->palette, new MetadataBag()); + } + + /** + * {@inheritdoc} + * + * @see \Iterator::key() + */ + public function key() + { + return $this->offset; + } + + /** + * {@inheritdoc} + * + * @see \Iterator::next() + */ + public function next() + { + ++$this->offset; + } + + /** + * {@inheritdoc} + * + * @see \Iterator::rewind() + */ + public function rewind() + { + $this->offset = 0; + } + + /** + * {@inheritdoc} + * + * @see \Iterator::valid() + */ + public function valid() + { + return $this->offset < 1; + } + + /** + * {@inheritdoc} + * + * @see \Countable::count() + */ + public function count() + { + return 1; + } + + /** + * {@inheritdoc} + * + * @see \ArrayAccess::offsetExists() + */ + public function offsetExists($offset) + { + return 0 === $offset; + } + + /** + * {@inheritdoc} + * + * @see \ArrayAccess::offsetGet() + */ + public function offsetGet($offset) + { + if (0 === $offset) { + return $this->getClassFactory()->createImage(ClassFactoryInterface::HANDLE_GD, $this->resource, $this->palette, new MetadataBag()); + } + + throw new RuntimeException('GD only supports one layer at offset 0'); + } + + /** + * {@inheritdoc} + * + * @see \ArrayAccess::offsetSet() + */ + public function offsetSet($offset, $value) + { + throw new NotSupportedException('GD does not support layer set'); + } + + /** + * {@inheritdoc} + * + * @see \ArrayAccess::offsetUnset() + */ + public function offsetUnset($offset) + { + throw new NotSupportedException('GD does not support layer unset'); + } +} diff --git a/vendor/imagine/imagine/src/Gmagick/Drawer.php b/vendor/imagine/imagine/src/Gmagick/Drawer.php new file mode 100644 index 0000000..cc7bccb --- /dev/null +++ b/vendor/imagine/imagine/src/Gmagick/Drawer.php @@ -0,0 +1,445 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Gmagick; + +use Imagine\Draw\DrawerInterface; +use Imagine\Exception\InvalidArgumentException; +use Imagine\Exception\RuntimeException; +use Imagine\Image\AbstractFont; +use Imagine\Image\Box; +use Imagine\Image\BoxInterface; +use Imagine\Image\Palette\Color\ColorInterface; +use Imagine\Image\Point; +use Imagine\Image\PointInterface; + +/** + * Drawer implementation using the Gmagick PHP extension. + */ +final class Drawer implements DrawerInterface +{ + /** + * @var \Gmagick + */ + private $gmagick; + + /** + * @param \Gmagick $gmagick + */ + public function __construct(\Gmagick $gmagick) + { + $this->gmagick = $gmagick; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Draw\DrawerInterface::arc() + */ + public function arc(PointInterface $center, BoxInterface $size, $start, $end, ColorInterface $color, $thickness = 1) + { + $thickness = max(0, (int) round($thickness)); + if ($thickness === 0) { + return $this; + } + $x = $center->getX(); + $y = $center->getY(); + $width = $size->getWidth(); + $height = $size->getHeight(); + + try { + $pixel = $this->getColor($color); + $arc = new \GmagickDraw(); + + $arc->setstrokecolor($pixel); + $arc->setstrokewidth($thickness); + $arc->setfillcolor('transparent'); + $arc->arc( + $x - $width / 2, + $y - $height / 2, + $x + $width / 2, + $y + $height / 2, + $start, + $end + ); + + $this->gmagick->drawImage($arc); + + $pixel = null; + + $arc = null; + } catch (\GmagickException $e) { + throw new RuntimeException('Draw arc operation failed', $e->getCode(), $e); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Draw\DrawerInterface::chord() + */ + public function chord(PointInterface $center, BoxInterface $size, $start, $end, ColorInterface $color, $fill = false, $thickness = 1) + { + $thickness = max(0, (int) round($thickness)); + if ($thickness === 0 && !$fill) { + return $this; + } + $x = $center->getX(); + $y = $center->getY(); + $width = $size->getWidth(); + $height = $size->getHeight(); + + try { + $pixel = $this->getColor($color); + $chord = new \GmagickDraw(); + + $chord->setstrokecolor($pixel); + $chord->setstrokewidth($thickness); + + if ($fill) { + $chord->setfillcolor($pixel); + } else { + $x1 = round($x + $width / 2 * cos(deg2rad($start))); + $y1 = round($y + $height / 2 * sin(deg2rad($start))); + $x2 = round($x + $width / 2 * cos(deg2rad($end))); + $y2 = round($y + $height / 2 * sin(deg2rad($end))); + + $this->line(new Point($x1, $y1), new Point($x2, $y2), $color, $thickness); + + $chord->setfillcolor('transparent'); + } + + $chord->arc($x - $width / 2, $y - $height / 2, $x + $width / 2, $y + $height / 2, $start, $end); + + $this->gmagick->drawImage($chord); + + $pixel = null; + + $chord = null; + } catch (\GmagickException $e) { + throw new RuntimeException('Draw chord operation failed', $e->getCode(), $e); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Draw\DrawerInterface::circle() + */ + public function circle(PointInterface $center, $radius, ColorInterface $color, $fill = false, $thickness = 1) + { + $diameter = $radius * 2; + + return $this->ellipse($center, new Box($diameter, $diameter), $color, $fill, $thickness); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Draw\DrawerInterface::ellipse() + */ + public function ellipse(PointInterface $center, BoxInterface $size, ColorInterface $color, $fill = false, $thickness = 1) + { + $thickness = max(0, (int) round($thickness)); + if ($thickness === 0 && !$fill) { + return $this; + } + $width = $size->getWidth(); + $height = $size->getHeight(); + + try { + $pixel = $this->getColor($color); + $ellipse = new \GmagickDraw(); + + $ellipse->setstrokecolor($pixel); + $ellipse->setstrokewidth($thickness); + + if ($fill) { + $ellipse->setfillcolor($pixel); + } else { + $ellipse->setfillcolor('transparent'); + } + + $ellipse->ellipse( + $center->getX(), + $center->getY(), + $width / 2, + $height / 2, + 0, 360 + ); + + $this->gmagick->drawImage($ellipse); + + $pixel = null; + + $ellipse = null; + } catch (\GmagickException $e) { + throw new RuntimeException('Draw ellipse operation failed', $e->getCode(), $e); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Draw\DrawerInterface::line() + */ + public function line(PointInterface $start, PointInterface $end, ColorInterface $color, $thickness = 1) + { + $thickness = max(0, (int) round($thickness)); + if ($thickness === 0) { + return $this; + } + try { + $pixel = $this->getColor($color); + $line = new \GmagickDraw(); + + $line->setstrokecolor($pixel); + $line->setstrokewidth($thickness); + $line->setfillcolor($pixel); + $line->line( + $start->getX(), + $start->getY(), + $end->getX(), + $end->getY() + ); + + $this->gmagick->drawImage($line); + + $pixel = null; + + $line = null; + } catch (\GmagickException $e) { + throw new RuntimeException('Draw line operation failed', $e->getCode(), $e); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Draw\DrawerInterface::pieSlice() + */ + public function pieSlice(PointInterface $center, BoxInterface $size, $start, $end, ColorInterface $color, $fill = false, $thickness = 1) + { + $thickness = max(0, (int) round($thickness)); + if ($thickness === 0 && !$fill) { + return $this; + } + $width = $size->getWidth(); + $height = $size->getHeight(); + + $x1 = round($center->getX() + $width / 2 * cos(deg2rad($start))); + $y1 = round($center->getY() + $height / 2 * sin(deg2rad($start))); + $x2 = round($center->getX() + $width / 2 * cos(deg2rad($end))); + $y2 = round($center->getY() + $height / 2 * sin(deg2rad($end))); + + if ($fill) { + $this->chord($center, $size, $start, $end, $color, true, $thickness); + $this->polygon( + array( + $center, + new Point($x1, $y1), + new Point($x2, $y2), + ), + $color, + true, + $thickness + ); + } else { + $this->arc($center, $size, $start, $end, $color, $thickness); + $this->line($center, new Point($x1, $y1), $color, $thickness); + $this->line($center, new Point($x2, $y2), $color, $thickness); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Draw\DrawerInterface::dot() + */ + public function dot(PointInterface $position, ColorInterface $color) + { + $x = $position->getX(); + $y = $position->getY(); + + try { + $pixel = $this->getColor($color); + $point = new \GmagickDraw(); + + $point->setfillcolor($pixel); + $point->point($x, $y); + + $this->gmagick->drawimage($point); + + $pixel = null; + $point = null; + } catch (\GmagickException $e) { + throw new RuntimeException('Draw point operation failed', $e->getCode(), $e); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Draw\DrawerInterface::rectangle() + */ + public function rectangle(PointInterface $leftTop, PointInterface $rightBottom, ColorInterface $color, $fill = false, $thickness = 1) + { + $thickness = max(0, (int) round($thickness)); + if ($thickness === 0 && !$fill) { + return $this; + } + $minX = min($leftTop->getX(), $rightBottom->getX()); + $maxX = max($leftTop->getX(), $rightBottom->getX()); + $minY = min($leftTop->getY(), $rightBottom->getY()); + $maxY = max($leftTop->getY(), $rightBottom->getY()); + + try { + $pixel = $this->getColor($color); + $rectangle = new \GmagickDraw(); + + $rectangle->setstrokecolor($pixel); + $rectangle->setstrokewidth($thickness); + + if ($fill) { + $rectangle->setfillcolor($pixel); + } else { + $rectangle->setfillcolor('transparent'); + } + $rectangle->rectangle($minX, $minY, $maxX, $maxY); + $this->gmagick->drawImage($rectangle); + } catch (\GmagickException $e) { + throw new RuntimeException('Draw polygon operation failed', $e->getCode(), $e); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Draw\DrawerInterface::polygon() + */ + public function polygon(array $coordinates, ColorInterface $color, $fill = false, $thickness = 1) + { + if (count($coordinates) < 3) { + throw new InvalidArgumentException(sprintf('Polygon must consist of at least 3 coordinates, %d given', count($coordinates))); + } + $thickness = max(0, (int) round($thickness)); + if ($thickness === 0 && !$fill) { + return $this; + } + + $points = array_map(function (PointInterface $p) { + return array('x' => $p->getX(), 'y' => $p->getY()); + }, $coordinates); + + try { + $pixel = $this->getColor($color); + $polygon = new \GmagickDraw(); + + $polygon->setstrokecolor($pixel); + $polygon->setstrokewidth($thickness); + + if ($fill) { + $polygon->setfillcolor($pixel); + } else { + $polygon->setfillcolor('transparent'); + } + + $polygon->polygon($points); + + $this->gmagick->drawImage($polygon); + + unset($pixel, $polygon); + } catch (\GmagickException $e) { + throw new RuntimeException('Draw polygon operation failed', $e->getCode(), $e); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Draw\DrawerInterface::text() + */ + public function text($string, AbstractFont $font, PointInterface $position, $angle = 0, $width = null) + { + try { + $pixel = $this->getColor($font->getColor()); + $text = new \GmagickDraw(); + + $text->setfont($font->getFile()); + /* + * @see http://www.php.net/manual/en/imagick.queryfontmetrics.php#101027 + * + * ensure font resolution is the same as GD's hard-coded 96 + */ + $text->setfontsize((int) ($font->getSize() * (96 / 72))); + $text->setfillcolor($pixel); + + if ($width !== null) { + $string = $font->wrapText($string, $width, $angle); + } + + $info = $this->gmagick->queryfontmetrics($text, $string); + $rad = deg2rad($angle); + $cos = cos($rad); + $sin = sin($rad); + + $x1 = round(0 * $cos - 0 * $sin); + $x2 = round($info['textWidth'] * $cos - $info['textHeight'] * $sin); + $y1 = round(0 * $sin + 0 * $cos); + $y2 = round($info['textWidth'] * $sin + $info['textHeight'] * $cos); + + $xdiff = 0 - min($x1, $x2); + $ydiff = 0 - min($y1, $y2); + + $this->gmagick->annotateimage($text, $position->getX() + $x1 + $xdiff, $position->getY() + $y2 + $ydiff, $angle, $string); + + unset($pixel, $text); + } catch (\GmagickException $e) { + throw new RuntimeException('Draw text operation failed', $e->getCode(), $e); + } + + return $this; + } + + /** + * Gets specifically formatted color string from Color instance. + * + * @param \Imagine\Image\Palette\Color\ColorInterface $color + * + * @throws \Imagine\Exception\InvalidArgumentException In case a non-opaque color is passed + * + * @return \GmagickPixel + */ + private function getColor(ColorInterface $color) + { + if (!$color->isOpaque()) { + throw new InvalidArgumentException('Gmagick doesn\'t support transparency'); + } + + return new \GmagickPixel((string) $color); + } +} diff --git a/vendor/imagine/imagine/src/Gmagick/Effects.php b/vendor/imagine/imagine/src/Gmagick/Effects.php new file mode 100644 index 0000000..f62cc42 --- /dev/null +++ b/vendor/imagine/imagine/src/Gmagick/Effects.php @@ -0,0 +1,177 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Gmagick; + +use Imagine\Effects\EffectsInterface; +use Imagine\Exception\InvalidArgumentException; +use Imagine\Exception\NotSupportedException; +use Imagine\Exception\RuntimeException; +use Imagine\Image\Palette\Color\ColorInterface; +use Imagine\Utils\Matrix; + +/** + * Effects implementation using the Gmagick PHP extension. + */ +class Effects implements EffectsInterface +{ + /** + * @var \Gmagick + */ + private $gmagick; + + /** + * Initialize the instance. + * + * @param \Gmagick $gmagick + */ + public function __construct(\Gmagick $gmagick) + { + $this->gmagick = $gmagick; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Effects\EffectsInterface::gamma() + */ + public function gamma($correction) + { + try { + $this->gmagick->gammaimage($correction); + } catch (\GmagickException $e) { + throw new RuntimeException('Failed to apply gamma correction to the image', $e->getCode(), $e); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Effects\EffectsInterface::negative() + */ + public function negative() + { + if (!method_exists($this->gmagick, 'negateimage')) { + throw new NotSupportedException('Gmagick version 1.1.0 RC3 is required for negative effect'); + } + + try { + $this->gmagick->negateimage(false, \Gmagick::CHANNEL_ALL); + } catch (\GmagickException $e) { + throw new RuntimeException('Failed to negate the image', $e->getCode(), $e); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Effects\EffectsInterface::grayscale() + */ + public function grayscale() + { + try { + $this->gmagick->setImageType(2); + } catch (\GmagickException $e) { + throw new RuntimeException('Failed to grayscale the image', $e->getCode(), $e); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Effects\EffectsInterface::colorize() + */ + public function colorize(ColorInterface $color) + { + throw new NotSupportedException('Gmagick does not support colorize'); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Effects\EffectsInterface::sharpen() + */ + public function sharpen() + { + throw new NotSupportedException('Gmagick does not support sharpen yet'); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Effects\EffectsInterface::blur() + */ + public function blur($sigma = 1) + { + try { + $this->gmagick->blurImage(0, $sigma); + } catch (\GmagickException $e) { + throw new RuntimeException('Failed to blur the image', $e->getCode(), $e); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Effects\EffectsInterface::brightness() + */ + public function brightness($brightness) + { + $brightness = (int) round($brightness); + if ($brightness < -100 || $brightness > 100) { + throw new InvalidArgumentException(sprintf('The %1$s argument can range from %2$d to %3$d, but you specified %4$d.', '$brightness', -100, 100, $brightness)); + } + try { + // This *emulates* setting the brightness + $sign = $brightness < 0 ? -1 : 1; + $v = abs($brightness) / 100; + if ($sign > 0) { + $v = (2 / (sin(($v * .99999 * M_PI_2) + M_PI_2))) - 2; + } + $this->gmagick->modulateimage(100 + $sign * $v * 100, 100, 100); + } catch (\GmagickException $e) { + throw new RuntimeException('Failed to brightness the image'); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Effects\EffectsInterface::convolve() + */ + public function convolve(Matrix $matrix) + { + if (!method_exists($this->gmagick, 'convolveimage')) { + // convolveimage has been added in gmagick 2.0.1RC2 + throw new NotSupportedException('The version of Gmagick extension is too old: it does not support convolve.'); + } + if ($matrix->getWidth() !== 3 || $matrix->getHeight() !== 3) { + throw new InvalidArgumentException(sprintf('A convolution matrix must be 3x3 (%dx%d provided).', $matrix->getWidth(), $matrix->getHeight())); + } + try { + $this->gmagick->convolveimage($matrix->getValueList()); + } catch (\ImagickException $e) { + throw new RuntimeException('Failed to convolve the image'); + } + + return $this; + } +} diff --git a/vendor/imagine/imagine/src/Gmagick/Font.php b/vendor/imagine/imagine/src/Gmagick/Font.php new file mode 100644 index 0000000..d1b1215 --- /dev/null +++ b/vendor/imagine/imagine/src/Gmagick/Font.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Gmagick; + +use Imagine\Image\AbstractFont; +use Imagine\Image\Palette\Color\ColorInterface; + +/** + * Font implementation using the Gmagick PHP extension. + */ +final class Font extends AbstractFont +{ + /** + * @var \Gmagick + */ + private $gmagick; + + /** + * @param \Gmagick $gmagick + * @param string $file + * @param int $size + * @param \Imagine\Image\Palette\Color\ColorInterface $color + */ + public function __construct(\Gmagick $gmagick, $file, $size, ColorInterface $color) + { + $this->gmagick = $gmagick; + + parent::__construct($file, $size, $color); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\FontInterface::box() + */ + public function box($string, $angle = 0) + { + $text = new \GmagickDraw(); + + $text->setfont($this->file); + /* + * @see http://www.php.net/manual/en/imagick.queryfontmetrics.php#101027 + * + * ensure font resolution is the same as GD's hard-coded 96 + */ + $text->setfontsize((int) ($this->size * (96 / 72))); + $text->setfontstyle(\Gmagick::STYLE_OBLIQUE); + + $info = $this->gmagick->queryfontmetrics($text, $string); + + $box = $this->getClassFactory()->createBox($info['textWidth'], $info['textHeight']); + + return $box; + } +} diff --git a/vendor/imagine/imagine/src/Gmagick/Image.php b/vendor/imagine/imagine/src/Gmagick/Image.php new file mode 100644 index 0000000..9fc85b6 --- /dev/null +++ b/vendor/imagine/imagine/src/Gmagick/Image.php @@ -0,0 +1,890 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Gmagick; + +use Imagine\Exception\InvalidArgumentException; +use Imagine\Exception\NotSupportedException; +use Imagine\Exception\OutOfBoundsException; +use Imagine\Exception\RuntimeException; +use Imagine\Factory\ClassFactoryInterface; +use Imagine\Image\AbstractImage; +use Imagine\Image\BoxInterface; +use Imagine\Image\Fill\FillInterface; +use Imagine\Image\ImageInterface; +use Imagine\Image\Metadata\MetadataBag; +use Imagine\Image\Palette\Color\ColorInterface; +use Imagine\Image\Palette\PaletteInterface; +use Imagine\Image\Point; +use Imagine\Image\PointInterface; +use Imagine\Image\ProfileInterface; + +/** + * Image implementation using the Gmagick PHP extension. + */ +final class Image extends AbstractImage +{ + /** + * @var \Gmagick + */ + private $gmagick; + + /** + * @var \Imagine\Gmagick\Layers|null + */ + private $layers; + + /** + * @var \Imagine\Image\Palette\PaletteInterface + */ + private $palette; + + /** + * @var array|null + */ + private static $colorspaceMapping = null; + + /** + * Constructs a new Image instance. + * + * @param \Gmagick $gmagick + * @param \Imagine\Image\Palette\PaletteInterface $palette + * @param \Imagine\Image\Metadata\MetadataBag $metadata + */ + public function __construct(\Gmagick $gmagick, PaletteInterface $palette, MetadataBag $metadata) + { + $this->metadata = $metadata; + $this->gmagick = $gmagick; + $this->setColorspace($palette); + } + + /** + * Destroys allocated gmagick resources. + */ + public function __destruct() + { + if ($this->gmagick instanceof \Gmagick) { + $this->gmagick->clear(); + $this->gmagick->destroy(); + } + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\AbstractImage::__clone() + */ + public function __clone() + { + parent::__clone(); + $this->gmagick = clone $this->gmagick; + $this->palette = clone $this->palette; + if ($this->layers !== null) { + $this->layers = $this->getClassFactory()->createLayers(ClassFactoryInterface::HANDLE_GMAGICK, $this, $this->layers->key()); + } + } + + /** + * Returns gmagick instance. + * + * @return \Gmagick + */ + public function getGmagick() + { + return $this->gmagick; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ManipulatorInterface::copy() + */ + public function copy() + { + return clone $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ManipulatorInterface::crop() + */ + public function crop(PointInterface $start, BoxInterface $size) + { + if (!$start->in($this->getSize())) { + throw new OutOfBoundsException('Crop coordinates must start at minimum 0, 0 position from top left corner, crop height and width must be positive integers and must not exceed the current image borders'); + } + + try { + $this->gmagick->cropimage($size->getWidth(), $size->getHeight(), $start->getX(), $start->getY()); + } catch (\GmagickException $e) { + throw new RuntimeException('Crop operation failed', $e->getCode(), $e); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ManipulatorInterface::flipHorizontally() + */ + public function flipHorizontally() + { + try { + $this->gmagick->flopimage(); + } catch (\GmagickException $e) { + throw new RuntimeException('Horizontal flip operation failed', $e->getCode(), $e); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ManipulatorInterface::flipVertically() + */ + public function flipVertically() + { + try { + $this->gmagick->flipimage(); + } catch (\GmagickException $e) { + throw new RuntimeException('Vertical flip operation failed', $e->getCode(), $e); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ManipulatorInterface::strip() + */ + public function strip() + { + try { + try { + $this->profile($this->palette->profile()); + } catch (\Exception $e) { + // here we discard setting the profile as the previous incorporated profile + // is corrupted, let's now strip the image + } + $this->gmagick->stripimage(); + } catch (\GmagickException $e) { + throw new RuntimeException('Strip operation failed', $e->getCode(), $e); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ManipulatorInterface::paste() + */ + public function paste(ImageInterface $image, PointInterface $start, $alpha = 100) + { + if (!$image instanceof self) { + throw new InvalidArgumentException(sprintf('Gmagick\Image can only paste() Gmagick\Image instances, %s given', get_class($image))); + } + + $alpha = (int) round($alpha); + if ($alpha < 0 || $alpha > 100) { + throw new InvalidArgumentException(sprintf('The %1$s argument can range from %2$d to %3$d, but you specified %4$d.', '$alpha', 0, 100, $alpha)); + } + + if ($alpha === 100) { + try { + $this->gmagick->compositeimage($image->gmagick, \Gmagick::COMPOSITE_DEFAULT, $start->getX(), $start->getY()); + } catch (\GmagickException $e) { + throw new RuntimeException('Paste operation failed', $e->getCode(), $e); + } + } elseif ($alpha > 0) { + throw new NotSupportedException('Gmagick doesn\'t support paste with alpha.', 1); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ManipulatorInterface::resize() + */ + public function resize(BoxInterface $size, $filter = ImageInterface::FILTER_UNDEFINED) + { + static $supportedFilters = array( + ImageInterface::FILTER_UNDEFINED => \Gmagick::FILTER_UNDEFINED, + ImageInterface::FILTER_BESSEL => \Gmagick::FILTER_BESSEL, + ImageInterface::FILTER_BLACKMAN => \Gmagick::FILTER_BLACKMAN, + ImageInterface::FILTER_BOX => \Gmagick::FILTER_BOX, + ImageInterface::FILTER_CATROM => \Gmagick::FILTER_CATROM, + ImageInterface::FILTER_CUBIC => \Gmagick::FILTER_CUBIC, + ImageInterface::FILTER_GAUSSIAN => \Gmagick::FILTER_GAUSSIAN, + ImageInterface::FILTER_HANNING => \Gmagick::FILTER_HANNING, + ImageInterface::FILTER_HAMMING => \Gmagick::FILTER_HAMMING, + ImageInterface::FILTER_HERMITE => \Gmagick::FILTER_HERMITE, + ImageInterface::FILTER_LANCZOS => \Gmagick::FILTER_LANCZOS, + ImageInterface::FILTER_MITCHELL => \Gmagick::FILTER_MITCHELL, + ImageInterface::FILTER_POINT => \Gmagick::FILTER_POINT, + ImageInterface::FILTER_QUADRATIC => \Gmagick::FILTER_QUADRATIC, + ImageInterface::FILTER_SINC => \Gmagick::FILTER_SINC, + ImageInterface::FILTER_TRIANGLE => \Gmagick::FILTER_TRIANGLE, + ); + + if (!array_key_exists($filter, $supportedFilters)) { + throw new InvalidArgumentException('Unsupported filter type'); + } + + try { + $this->gmagick->resizeimage($size->getWidth(), $size->getHeight(), $supportedFilters[$filter], 1); + } catch (\GmagickException $e) { + throw new RuntimeException('Resize operation failed', $e->getCode(), $e); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ManipulatorInterface::rotate() + */ + public function rotate($angle, ColorInterface $background = null) + { + try { + if ($background === null) { + $background = $this->palette->color('fff'); + } + $pixel = $this->getColor($background); + + $this->gmagick->rotateimage($pixel, $angle); + + unset($pixel); + } catch (\GmagickException $e) { + throw new RuntimeException('Rotate operation failed', $e->getCode(), $e); + } + + return $this; + } + + /** + * Applies options before save or output. + * + * @param \Gmagick $image + * @param array $options + * @param string $path + * + * @throws \Imagine\Exception\InvalidArgumentException + */ + private function applyImageOptions(\Gmagick $image, array $options, $path) + { + if (isset($options['format'])) { + $format = $options['format']; + } elseif ('' !== $extension = pathinfo($path, \PATHINFO_EXTENSION)) { + $format = $extension; + } else { + $format = pathinfo($image->getImageFilename(), \PATHINFO_EXTENSION); + } + + $format = strtolower($format); + + switch ($format) { + case 'jpeg': + case 'jpg': + case 'pjpeg': + if (!isset($options['jpeg_quality'])) { + if (isset($options['quality'])) { + $options['jpeg_quality'] = $options['quality']; + } + } + if (isset($options['jpeg_quality'])) { + $image->setCompressionQuality($options['jpeg_quality']); + } + if (isset($options['jpeg_sampling_factors'])) { + if (!is_array($options['jpeg_sampling_factors']) || \count($options['jpeg_sampling_factors']) < 1) { + throw new InvalidArgumentException('jpeg_sampling_factors option should be an array of integers'); + } + $image->setSamplingFactors(array_map(function ($factor) { + return (int) $factor; + }, $options['jpeg_sampling_factors'])); + } + break; + case 'png': + if (!isset($options['png_compression_level'])) { + if (isset($options['quality'])) { + $options['png_compression_level'] = round((100 - $options['quality']) * 9 / 100); + } + } + if (isset($options['png_compression_level'])) { + if ($options['png_compression_level'] < 0 || $options['png_compression_level'] > 9) { + throw new InvalidArgumentException('png_compression_level option should be an integer from 0 to 9'); + } + } + if (isset($options['png_compression_filter'])) { + if ($options['png_compression_filter'] < 0 || $options['png_compression_filter'] > 9) { + throw new InvalidArgumentException('png_compression_filter option should be an integer from 0 to 9'); + } + } + if (isset($options['png_compression_level']) || isset($options['png_compression_filter'])) { + // first digit: compression level (default: 7) + $compression = isset($options['png_compression_level']) ? $options['png_compression_level'] * 10 : 70; + // second digit: compression filter (default: 5) + $compression += isset($options['png_compression_filter']) ? $options['png_compression_filter'] : 5; + $image->setCompressionQuality($compression); + } + break; + case 'webp': + if (!isset($options['webp_quality'])) { + if (isset($options['quality'])) { + $options['webp_quality'] = $options['quality']; + } + } + if (isset($options['webp_quality'])) { + $image->setCompressionQuality($options['webp_quality']); + } + break; + } + if (isset($options['resolution-units']) && isset($options['resolution-x']) && isset($options['resolution-y'])) { + switch ($options['resolution-units']) { + case ImageInterface::RESOLUTION_PIXELSPERCENTIMETER: + $image->setimageunits(\Gmagick::RESOLUTION_PIXELSPERCENTIMETER); + break; + case ImageInterface::RESOLUTION_PIXELSPERINCH: + $image->setimageunits(\Gmagick::RESOLUTION_PIXELSPERINCH); + break; + default: + throw new InvalidArgumentException('Unsupported image unit format'); + } + $image->setimageresolution($options['resolution-x'], $options['resolution-y']); + } + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ManipulatorInterface::save() + */ + public function save($path = null, array $options = array()) + { + $path = null === $path ? $this->gmagick->getImageFilename() : $path; + + if ('' === trim($path)) { + throw new RuntimeException('You can omit save path only if image has been open from a file'); + } + + try { + $this->prepareOutput($options, $path); + $allFrames = !isset($options['animated']) || false === $options['animated']; + $this->gmagick->writeimage($path, $allFrames); + } catch (\GmagickException $e) { + throw new RuntimeException('Save operation failed', $e->getCode(), $e); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ManipulatorInterface::show() + */ + public function show($format, array $options = array()) + { + header('Content-type: ' . $this->getMimeType($format)); + echo $this->get($format, $options); + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImageInterface::get() + */ + public function get($format, array $options = array()) + { + try { + $options['format'] = $format; + $this->prepareOutput($options); + } catch (\GmagickException $e) { + throw new RuntimeException('Get operation failed', $e->getCode(), $e); + } + + return $this->gmagick->getimagesblob(); + } + + /** + * @param array $options + * @param string $path + */ + private function prepareOutput(array $options, $path = null) + { + if (isset($options['format'])) { + $this->gmagick->setimageformat($options['format']); + } + + if (isset($options['animated']) && true === $options['animated']) { + $format = isset($options['format']) ? $options['format'] : 'gif'; + $delay = isset($options['animated.delay']) ? $options['animated.delay'] : null; + $loops = isset($options['animated.loops']) ? $options['animated.loops'] : 0; + + $options['flatten'] = false; + + $this->layers()->animate($format, $delay, $loops); + } else { + $this->layers()->merge(); + } + $this->applyImageOptions($this->gmagick, $options, $path); + + // flatten only if image has multiple layers + if ((!isset($options['flatten']) || $options['flatten'] === true) && $this->layers()->count() > 1) { + $this->flatten(); + } + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImageInterface::__toString() + */ + public function __toString() + { + return $this->get('png'); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImageInterface::draw() + */ + public function draw() + { + return $this->getClassFactory()->createDrawer(ClassFactoryInterface::HANDLE_GMAGICK, $this->gmagick); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImageInterface::effects() + */ + public function effects() + { + return $this->getClassFactory()->createEffects(ClassFactoryInterface::HANDLE_GMAGICK, $this->gmagick); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImageInterface::getSize() + */ + public function getSize() + { + try { + $i = $this->gmagick->getimageindex(); + $this->gmagick->setimageindex(0); //rewind + $width = $this->gmagick->getimagewidth(); + $height = $this->gmagick->getimageheight(); + $this->gmagick->setimageindex($i); + } catch (\GmagickException $e) { + throw new RuntimeException('Get size operation failed', $e->getCode(), $e); + } + + return $this->getClassFactory()->createBox($width, $height); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ManipulatorInterface::applyMask() + */ + public function applyMask(ImageInterface $mask) + { + if (!$mask instanceof self) { + throw new InvalidArgumentException('Can only apply instances of Imagine\Gmagick\Image as masks'); + } + + $size = $this->getSize(); + $maskSize = $mask->getSize(); + + if ($size != $maskSize) { + throw new InvalidArgumentException(sprintf('The given mask doesn\'t match current image\'s size, current mask\'s dimensions are %s, while image\'s dimensions are %s', $maskSize, $size)); + } + + try { + $mask = $mask->copy(); + $this->gmagick->compositeimage($mask->gmagick, \Gmagick::COMPOSITE_DEFAULT, 0, 0); + } catch (\GmagickException $e) { + throw new RuntimeException('Apply mask operation failed', $e->getCode(), $e); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImageInterface::mask() + */ + public function mask() + { + $mask = $this->copy(); + + try { + $mask->gmagick->modulateimage(100, 0, 100); + } catch (\GmagickException $e) { + throw new RuntimeException('Mask operation failed', $e->getCode(), $e); + } + + return $mask; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ManipulatorInterface::fill() + */ + public function fill(FillInterface $fill) + { + try { + $draw = new \GmagickDraw(); + $size = $this->getSize(); + + $w = $size->getWidth(); + $h = $size->getHeight(); + + for ($x = 0; $x < $w; $x++) { + for ($y = 0; $y < $h; $y++) { + $pixel = $this->getColor($fill->getColor(new Point($x, $y))); + + $draw->setfillcolor($pixel); + $draw->point($x, $y); + + $pixel = null; + } + } + + $this->gmagick->drawimage($draw); + + $draw = null; + } catch (\GmagickException $e) { + throw new RuntimeException('Fill operation failed', $e->getCode(), $e); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImageInterface::histogram() + */ + public function histogram() + { + try { + $pixels = $this->gmagick->getimagehistogram(); + } catch (\GmagickException $e) { + throw new RuntimeException('Error while fetching histogram', $e->getCode(), $e); + } + + $image = $this; + + return array_map(function (\GmagickPixel $pixel) use ($image) { + return $image->pixelToColor($pixel); + }, $pixels); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImageInterface::getColorAt() + */ + public function getColorAt(PointInterface $point) + { + if (!$point->in($this->getSize())) { + throw new InvalidArgumentException(sprintf('Error getting color at point [%s,%s]. The point must be inside the image of size [%s,%s]', $point->getX(), $point->getY(), $this->getSize()->getWidth(), $this->getSize()->getHeight())); + } + + try { + $cropped = clone $this->gmagick; + $histogram = $cropped + ->rollimage(-$point->getX(), -$point->getY()) + ->cropImage(1, 1, 0, 0) + ->getImageHistogram(); + } catch (\GmagickException $e) { + throw new RuntimeException('Unable to get the pixel', $e->getCode(), $e); + } + + $pixel = array_shift($histogram); + + unset($histogram, $cropped); + + return $this->pixelToColor($pixel); + } + + /** + * Returns a color given a pixel, depending the Palette context. + * + * Note : this method is public for PHP 5.3 compatibility + * + * @param \GmagickPixel $pixel + * + * @throws \Imagine\Exception\InvalidArgumentException In case a unknown color is requested + * + * @return \Imagine\Image\Palette\Color\ColorInterface + */ + public function pixelToColor(\GmagickPixel $pixel) + { + static $colorMapping = array( + ColorInterface::COLOR_RED => \Gmagick::COLOR_RED, + ColorInterface::COLOR_GREEN => \Gmagick::COLOR_GREEN, + ColorInterface::COLOR_BLUE => \Gmagick::COLOR_BLUE, + ColorInterface::COLOR_CYAN => \Gmagick::COLOR_CYAN, + ColorInterface::COLOR_MAGENTA => \Gmagick::COLOR_MAGENTA, + ColorInterface::COLOR_YELLOW => \Gmagick::COLOR_YELLOW, + ColorInterface::COLOR_KEYLINE => \Gmagick::COLOR_BLACK, + // There is no gray component in \Gmagick, let's use one of the RGB comp + ColorInterface::COLOR_GRAY => \Gmagick::COLOR_RED, + ); + + $alpha = null; + if ($this->palette->supportsAlpha()) { + if ($alpha === null && defined('Gmagick::COLOR_ALPHA')) { + try { + $alpha = (int) round($pixel->getcolorvalue(\Gmagick::COLOR_ALPHA) * 100); + } catch (\GmagickPixelException $e) { + } + } + if ($alpha === null && defined('Gmagick::COLOR_OPACITY')) { + try { + $alpha = (int) round(100 - $pixel->getcolorvalue(\Gmagick::COLOR_OPACITY) * 100); + } catch (\GmagickPixelException $e) { + } + } + } + + $multiplier = $this->palette()->getChannelsMaxValue(); + + return $this->palette->color(array_map(function ($color) use ($multiplier, $pixel, $colorMapping) { + if (!isset($colorMapping[$color])) { + throw new InvalidArgumentException(sprintf('Color %s is not mapped in Gmagick', $color)); + } + + return $pixel->getcolorvalue($colorMapping[$color]) * $multiplier; + }, $this->palette->pixelDefinition()), $alpha); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImageInterface::layers() + */ + public function layers() + { + if ($this->layers === null) { + $this->layers = $this->getClassFactory()->createLayers(ClassFactoryInterface::HANDLE_GMAGICK, $this); + } + + return $this->layers; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImageInterface::interlace() + */ + public function interlace($scheme) + { + static $supportedInterlaceSchemes = array( + ImageInterface::INTERLACE_NONE => \Gmagick::INTERLACE_NO, + ImageInterface::INTERLACE_LINE => \Gmagick::INTERLACE_LINE, + ImageInterface::INTERLACE_PLANE => \Gmagick::INTERLACE_PLANE, + ImageInterface::INTERLACE_PARTITION => \Gmagick::INTERLACE_PARTITION, + ); + + if (!array_key_exists($scheme, $supportedInterlaceSchemes)) { + throw new InvalidArgumentException('Unsupported interlace type'); + } + + $this->gmagick->setInterlaceScheme($supportedInterlaceSchemes[$scheme]); + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImageInterface::usePalette() + */ + public function usePalette(PaletteInterface $palette) + { + $colorspaceMapping = self::getColorspaceMapping(); + if (!isset($colorspaceMapping[$palette->name()])) { + throw new InvalidArgumentException(sprintf('The palette %s is not supported by Gmagick driver', $palette->name())); + } + + if ($this->palette->name() === $palette->name()) { + return $this; + } + + try { + try { + $hasICCProfile = (bool) $this->gmagick->getimageprofile('ICM'); + } catch (\GmagickException $e) { + $hasICCProfile = false; + } + + if (!$hasICCProfile) { + $this->profile($this->palette->profile()); + } + + $this->profile($palette->profile()); + + $this->setColorspace($palette); + } catch (\GmagickException $e) { + throw new RuntimeException('Failed to set colorspace', $e->getCode(), $e); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImageInterface::palette() + */ + public function palette() + { + return $this->palette; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImageInterface::profile() + */ + public function profile(ProfileInterface $profile) + { + try { + $this->gmagick->profileimage('ICM', $profile->data()); + } catch (\GmagickException $e) { + if (false !== strpos($e->getMessage(), 'LCMS encoding not enabled')) { + throw new RuntimeException(sprintf('Unable to add profile %s to image, be sue to compile graphicsmagick with `--with-lcms2` option', $profile->name()), $e->getCode(), $e); + } + + throw new RuntimeException(sprintf('Unable to add profile %s to image', $profile->name()), $e->getCode(), $e); + } + + return $this; + } + + /** + * Flatten the image. + */ + private function flatten() + { + /* + * @see http://pecl.php.net/bugs/bug.php?id=22435 + */ + if (method_exists($this->gmagick, 'flattenImages')) { + try { + $this->gmagick = $this->gmagick->flattenImages(); + } catch (\GmagickException $e) { + throw new RuntimeException('Flatten operation failed', $e->getCode(), $e); + } + } + } + + /** + * Gets specifically formatted color string from Color instance. + * + * @param \Imagine\Image\Palette\Color\ColorInterface $color + * + * @throws \Imagine\Exception\InvalidArgumentException + * + * @return \GmagickPixel + */ + private function getColor(ColorInterface $color) + { + if (!$color->isOpaque()) { + throw new InvalidArgumentException('Gmagick doesn\'t support transparency'); + } + + return new \GmagickPixel((string) $color); + } + + /** + * Get the mime type based on format. + * + * @param string $format + * + * @throws \Imagine\Exception\InvalidArgumentException + * + * @return string mime-type + */ + private function getMimeType($format) + { + static $mimeTypes = array( + 'jpeg' => 'image/jpeg', + 'jpg' => 'image/jpeg', + 'gif' => 'image/gif', + 'png' => 'image/png', + 'webp' => 'image/webp', + 'wbmp' => 'image/vnd.wap.wbmp', + 'xbm' => 'image/xbm', + 'bmp' => 'image/bmp', + ); + + if (!isset($mimeTypes[$format])) { + throw new InvalidArgumentException(sprintf('Unsupported format given. Only %s are supported, %s given', implode(', ', array_keys($mimeTypes)), $format)); + } + + return $mimeTypes[$format]; + } + + /** + * Sets colorspace and image type, assigns the palette. + * + * @param \Imagine\Image\Palette\PaletteInterface $palette + * + * @throws \Imagine\Exception\InvalidArgumentException + */ + private function setColorspace(PaletteInterface $palette) + { + $colorspaceMapping = self::getColorspaceMapping(); + if (!isset($colorspaceMapping[$palette->name()])) { + throw new InvalidArgumentException(sprintf('The palette %s is not supported by Gmagick driver', $palette->name())); + } + + $this->gmagick->setimagecolorspace($colorspaceMapping[$palette->name()]); + $this->palette = $palette; + } + + /** + * @return array + */ + private static function getColorspaceMapping() + { + if (self::$colorspaceMapping === null) { + $csm = array( + PaletteInterface::PALETTE_CMYK => \Gmagick::COLORSPACE_CMYK, + PaletteInterface::PALETTE_RGB => \Gmagick::COLORSPACE_RGB, + ); + if (defined('Gmagick::COLORSPACE_GRAY')) { + $csm[PaletteInterface::PALETTE_GRAYSCALE] = \Gmagick::COLORSPACE_GRAY; + } + self::$colorspaceMapping = $csm; + } + + return self::$colorspaceMapping; + } +} diff --git a/vendor/imagine/imagine/src/Gmagick/Imagine.php b/vendor/imagine/imagine/src/Gmagick/Imagine.php new file mode 100644 index 0000000..3ab11fa --- /dev/null +++ b/vendor/imagine/imagine/src/Gmagick/Imagine.php @@ -0,0 +1,194 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Gmagick; + +use Imagine\Exception\InvalidArgumentException; +use Imagine\Exception\NotSupportedException; +use Imagine\Exception\RuntimeException; +use Imagine\Factory\ClassFactoryInterface; +use Imagine\File\LoaderInterface; +use Imagine\Image\AbstractImagine; +use Imagine\Image\BoxInterface; +use Imagine\Image\Metadata\MetadataBag; +use Imagine\Image\Palette\CMYK; +use Imagine\Image\Palette\Color\CMYK as CMYKColor; +use Imagine\Image\Palette\Color\ColorInterface; +use Imagine\Image\Palette\Grayscale; +use Imagine\Image\Palette\RGB; + +/** + * Imagine implementation using the Gmagick PHP extension. + */ +class Imagine extends AbstractImagine +{ + /** + * @throws \Imagine\Exception\RuntimeException + */ + public function __construct() + { + if (!class_exists('Gmagick')) { + throw new RuntimeException('Gmagick not installed'); + } + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImagineInterface::open() + */ + public function open($path) + { + $loader = $path instanceof LoaderInterface ? $path : $this->getClassFactory()->createFileLoader($path); + $path = $loader->getPath(); + + try { + if ($loader->isLocalFile()) { + $gmagick = new \Gmagick($path); + $image = $this->getClassFactory()->createImage(ClassFactoryInterface::HANDLE_GMAGICK, $gmagick, $this->createPalette($gmagick), $this->getMetadataReader()->readFile($loader)); + } else { + $image = $this->doLoad($loader->getData(), $this->getMetadataReader()->readFile($loader)); + } + } catch (\GmagickException $e) { + throw new RuntimeException(sprintf('Unable to open image %s', $path), $e->getCode(), $e); + } + + return $image; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImagineInterface::create() + */ + public function create(BoxInterface $size, ColorInterface $color = null) + { + $width = $size->getWidth(); + $height = $size->getHeight(); + + $palette = null !== $color ? $color->getPalette() : new RGB(); + $color = null !== $color ? $color : $palette->color('fff'); + + try { + $gmagick = new \Gmagick(); + // Gmagick does not support creation of CMYK GmagickPixel + // see https://bugs.php.net/bug.php?id=64466 + if ($color instanceof CMYKColor) { + $switchPalette = $palette; + $palette = new RGB(); + $pixel = new \GmagickPixel($palette->color((string) $color)); + } else { + $switchPalette = null; + $pixel = new \GmagickPixel((string) $color); + } + + if (!$color->getPalette()->supportsAlpha() && $color->getAlpha() !== null && $color->getAlpha() < 100) { + throw new NotSupportedException('alpha transparency is not supported'); + } + + $gmagick->newimage($width, $height, $pixel->getcolor(false)); + $gmagick->setimagecolorspace(\Gmagick::COLORSPACE_TRANSPARENT); + $gmagick->setimagebackgroundcolor($pixel); + + $image = $this->getClassFactory()->createImage(ClassFactoryInterface::HANDLE_GMAGICK, $gmagick, $palette, new MetadataBag()); + + if ($switchPalette) { + $image->usePalette($switchPalette); + } + + return $image; + } catch (\GmagickException $e) { + throw new RuntimeException('Could not create empty image', $e->getCode(), $e); + } + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImagineInterface::load() + */ + public function load($string) + { + return $this->doLoad($string, $this->getMetadataReader()->readData($string)); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImagineInterface::read() + */ + public function read($resource) + { + if (!is_resource($resource)) { + throw new InvalidArgumentException('Variable does not contain a stream resource'); + } + + $content = stream_get_contents($resource); + + if (false === $content) { + throw new InvalidArgumentException('Couldn\'t read given resource'); + } + + return $this->doLoad($content, $this->getMetadataReader()->readData($content, $resource)); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImagineInterface::font() + */ + public function font($file, $size, ColorInterface $color) + { + return $this->getClassFactory()->createFont(ClassFactoryInterface::HANDLE_GMAGICK, $file, $size, $color); + } + + /** + * @param \Gmagick $gmagick + * + * @throws \Imagine\Exception\NotSupportedException + * + * @return \Imagine\Image\Palette\PaletteInterface + */ + private function createPalette(\Gmagick $gmagick) + { + switch ($gmagick->getimagecolorspace()) { + case \Gmagick::COLORSPACE_SRGB: + case \Gmagick::COLORSPACE_RGB: + return new RGB(); + case \Gmagick::COLORSPACE_CMYK: + return new CMYK(); + case \Gmagick::COLORSPACE_GRAY: + return new Grayscale(); + default: + throw new NotSupportedException('Only RGB and CMYK colorspace are currently supported'); + } + } + + /** + * @param string $content + * @param \Imagine\Image\Metadata\MetadataBag $metadata + * + * @throws \Imagine\Exception\RuntimeException + * + * @return \Imagine\Image\ImageInterface + */ + private function doLoad($content, MetadataBag $metadata) + { + try { + $gmagick = new \Gmagick(); + $gmagick->readimageblob($content); + } catch (\GmagickException $e) { + throw new RuntimeException('Could not load image from string', $e->getCode(), $e); + } + + return $this->getClassFactory()->createImage(ClassFactoryInterface::HANDLE_GMAGICK, $gmagick, $this->createPalette($gmagick), $metadata); + } +} diff --git a/vendor/imagine/imagine/src/Gmagick/Layers.php b/vendor/imagine/imagine/src/Gmagick/Layers.php new file mode 100644 index 0000000..ffa130b --- /dev/null +++ b/vendor/imagine/imagine/src/Gmagick/Layers.php @@ -0,0 +1,308 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Gmagick; + +use Imagine\Exception\InvalidArgumentException; +use Imagine\Exception\NotSupportedException; +use Imagine\Exception\OutOfBoundsException; +use Imagine\Exception\RuntimeException; +use Imagine\Factory\ClassFactoryInterface; +use Imagine\Image\AbstractLayers; +use Imagine\Image\Metadata\MetadataBag; +use Imagine\Image\Palette\PaletteInterface; + +class Layers extends AbstractLayers +{ + /** + * @var \Imagine\Gmagick\Image + */ + private $image; + + /** + * @var \Gmagick + */ + private $resource; + + /** + * @var int + */ + private $offset; + + /** + * @var \Imagine\Gmagick\Image[] + */ + private $layers = array(); + + /** + * @var \Imagine\Image\Palette\PaletteInterface + */ + private $palette; + + /** + * @param \Imagine\Gmagick\Image $image + * @param \Imagine\Image\Palette\PaletteInterface $palette + * @param \Gmagick $resource + * @param int $initialOffset + */ + public function __construct(Image $image, PaletteInterface $palette, \Gmagick $resource, $initialOffset = 0) + { + $this->image = $image; + $this->resource = $resource; + $this->palette = $palette; + $this->offset = (int) $initialOffset; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\LayersInterface::merge() + */ + public function merge() + { + foreach ($this->layers as $offset => $image) { + try { + $this->resource->setimageindex($offset); + $this->resource->setimage($image->getGmagick()); + } catch (\GmagickException $e) { + throw new RuntimeException('Failed to substitute layer', $e->getCode(), $e); + } + } + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\LayersInterface::coalesce() + */ + public function coalesce() + { + throw new NotSupportedException('Gmagick does not support coalescing'); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\LayersInterface::animate() + */ + public function animate($format, $delay, $loops) + { + if ('gif' !== strtolower($format)) { + throw new NotSupportedException('Animated picture is currently only supported on gif'); + } + + if (!is_int($loops) || $loops < 0) { + throw new InvalidArgumentException('Loops must be a positive integer.'); + } + + if (null !== $delay && (!is_int($delay) || $delay < 0)) { + throw new InvalidArgumentException('Delay must be either null or a positive integer.'); + } + + try { + foreach ($this as $offset => $layer) { + $this->resource->setimageindex($offset); + $this->resource->setimageformat($format); + + if (null !== $delay) { + $this->resource->setimagedelay($delay / 10); + } + + $this->resource->setimageiterations($loops); + } + } catch (\GmagickException $e) { + throw new RuntimeException('Failed to animate layers', $e->getCode(), $e); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Iterator::current() + */ + public function current() + { + return $this->extractAt($this->offset); + } + + /** + * Tries to extract layer at given offset. + * + * @param int $offset + * + * @throws \Imagine\Exception\RuntimeException + * + * @return \Imagine\Gmagick\Image + */ + private function extractAt($offset) + { + if (!isset($this->layers[$offset])) { + try { + $this->resource->setimageindex($offset); + $this->layers[$offset] = $this->getClassFactory()->createImage(ClassFactoryInterface::HANDLE_GMAGICK, $this->resource->getimage(), $this->palette, new MetadataBag()); + } catch (\GmagickException $e) { + throw new RuntimeException(sprintf('Failed to extract layer %d', $offset), $e->getCode(), $e); + } + } + + return $this->layers[$offset]; + } + + /** + * {@inheritdoc} + * + * @see \Iterator::key() + */ + public function key() + { + return $this->offset; + } + + /** + * {@inheritdoc} + * + * @see \Iterator::next() + */ + public function next() + { + ++$this->offset; + } + + /** + * {@inheritdoc} + * + * @see \Iterator::rewind() + */ + public function rewind() + { + $this->offset = 0; + } + + /** + * {@inheritdoc} + * + * @see \Iterator::valid() + */ + public function valid() + { + return $this->offset < count($this); + } + + /** + * {@inheritdoc} + * + * @see \Countable::count() + */ + public function count() + { + try { + return $this->resource->getnumberimages(); + } catch (\GmagickException $e) { + throw new RuntimeException('Failed to count the number of layers', $e->getCode(), $e); + } + } + + /** + * {@inheritdoc} + * + * @see \ArrayAccess::offsetExists() + */ + public function offsetExists($offset) + { + return is_int($offset) && $offset >= 0 && $offset < count($this); + } + + /** + * {@inheritdoc} + * + * @see \ArrayAccess::offsetGet() + */ + public function offsetGet($offset) + { + return $this->extractAt($offset); + } + + /** + * {@inheritdoc} + * + * @see \ArrayAccess::offsetSet() + */ + public function offsetSet($offset, $image) + { + if (!$image instanceof Image) { + throw new InvalidArgumentException('Only a Gmagick Image can be used as layer'); + } + + if (null === $offset) { + $offset = count($this) - 1; + } else { + if (!is_int($offset)) { + throw new InvalidArgumentException('Invalid offset for layer, it must be an integer'); + } + + if (count($this) < $offset || 0 > $offset) { + throw new OutOfBoundsException(sprintf('Invalid offset for layer, it must be a value between 0 and %d, %d given', count($this), $offset)); + } + + if (isset($this[$offset])) { + unset($this[$offset]); + $offset = $offset - 1; + } + } + + $frame = $image->getGmagick(); + + try { + if (count($this) > 0) { + $this->resource->setimageindex($offset); + $this->resource->nextimage(); + } + $this->resource->addimage($frame); + + /* + * ugly hack to bypass issue https://bugs.php.net/bug.php?id=64623 + */ + if (count($this) == 2) { + $this->resource->setimageindex($offset + 1); + $this->resource->nextimage(); + $this->resource->addimage($frame); + unset($this[0]); + } + } catch (\GmagickException $e) { + throw new RuntimeException('Unable to set the layer', $e->getCode(), $e); + } + + $this->layers = array(); + } + + /** + * {@inheritdoc} + * + * @see \ArrayAccess::offsetUnset() + */ + public function offsetUnset($offset) + { + try { + $this->extractAt($offset); + } catch (RuntimeException $e) { + return; + } + + try { + $this->resource->setimageindex($offset); + $this->resource->removeimage(); + } catch (\GmagickException $e) { + throw new RuntimeException('Unable to remove layer', $e->getCode(), $e); + } + } +} diff --git a/vendor/imagine/imagine/src/Image/AbstractFont.php b/vendor/imagine/imagine/src/Image/AbstractFont.php new file mode 100644 index 0000000..4c22c1a --- /dev/null +++ b/vendor/imagine/imagine/src/Image/AbstractFont.php @@ -0,0 +1,155 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Image; + +use Imagine\Exception\InvalidArgumentException; +use Imagine\Factory\ClassFactory; +use Imagine\Factory\ClassFactoryAwareInterface; +use Imagine\Factory\ClassFactoryInterface; +use Imagine\Image\Palette\Color\ColorInterface; + +/** + * Abstract font base class. + */ +abstract class AbstractFont implements FontInterface, ClassFactoryAwareInterface +{ + /** + * @var \Imagine\Factory\ClassFactoryInterface|null + */ + private $classFactory; + + /** + * @var string + */ + protected $file; + + /** + * @var int + */ + protected $size; + + /** + * @var \Imagine\Image\Palette\Color\ColorInterface + */ + protected $color; + + /** + * Constructs a font with specified $file, $size and $color. + * + * The font size is to be specified in points (e.g. 10pt means 10) + * + * @param string $file + * @param int $size + * @param \Imagine\Image\Palette\Color\ColorInterface $color + */ + public function __construct($file, $size, ColorInterface $color) + { + $this->file = $file; + $this->size = $size; + $this->color = $color; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\FontInterface::getFile() + */ + final public function getFile() + { + return $this->file; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\FontInterface::getSize() + */ + final public function getSize() + { + return $this->size; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\FontInterface::getColor() + */ + final public function getColor() + { + return $this->color; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\FontInterface::wrapText() + */ + public function wrapText($string, $maxWidth, $angle = 0) + { + $string = (string) $string; + if ($string === '') { + return $string; + } + $maxWidth = (int) round($maxWidth); + if ($maxWidth < 1) { + throw new InvalidArgumentException(sprintf('The $maxWidth parameter of wrapText must be greater than 0.')); + } + $words = explode(' ', $string); + $lines = array(); + $currentLine = null; + foreach ($words as $word) { + if ($currentLine === null) { + $currentLine = $word; + } else { + $testLine = $currentLine . ' ' . $word; + $testbox = $this->box($testLine, $angle); + if ($testbox->getWidth() <= $maxWidth) { + $currentLine = $testLine; + } else { + $lines[] = $currentLine; + $currentLine = $word; + } + } + } + if ($currentLine !== null) { + $lines[] = $currentLine; + } + + return implode("\n", $lines); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Factory\ClassFactoryAwareInterface::getClassFactory() + */ + public function getClassFactory() + { + if ($this->classFactory === null) { + $this->classFactory = new ClassFactory(); + } + + return $this->classFactory; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Factory\ClassFactoryAwareInterface::setClassFactory() + */ + public function setClassFactory(ClassFactoryInterface $classFactory) + { + $this->classFactory = $classFactory; + + return $this; + } +} diff --git a/vendor/imagine/imagine/src/Image/AbstractImage.php b/vendor/imagine/imagine/src/Image/AbstractImage.php new file mode 100644 index 0000000..4aa92e2 --- /dev/null +++ b/vendor/imagine/imagine/src/Image/AbstractImage.php @@ -0,0 +1,216 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Image; + +use Imagine\Exception\InvalidArgumentException; +use Imagine\Factory\ClassFactory; +use Imagine\Factory\ClassFactoryAwareInterface; +use Imagine\Factory\ClassFactoryInterface; + +abstract class AbstractImage implements ImageInterface, ClassFactoryAwareInterface +{ + /** + * @var \Imagine\Image\Metadata\MetadataBag + */ + protected $metadata; + + /** + * @var \Imagine\Factory\ClassFactoryInterface|null + */ + private $classFactory; + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ManipulatorInterface::thumbnail() + */ + public function thumbnail(BoxInterface $size, $settings = ImageInterface::THUMBNAIL_INSET, $filter = ImageInterface::FILTER_UNDEFINED) + { + $settings = $this->checkThumbnailSettings($settings); + + $mode = $settings & 0xffff; + + $allowUpscale = (bool) ($settings & ImageInterface::THUMBNAIL_FLAG_UPSCALE); + $noClone = (bool) ($settings & ImageInterface::THUMBNAIL_FLAG_NOCLONE); + + $imageSize = $this->getSize(); + $palette = $this->palette(); + + $thumbnail = $noClone ? $this : $this->copy(); + + $thumbnail->usePalette($palette); + $thumbnail->strip(); + + if ($size->getWidth() === $imageSize->getWidth() && $size->getHeight() === $imageSize->getHeight()) { + // The thumbnail size is the same as the wanted size. + return $thumbnail; + } + if (!$allowUpscale && $size->contains($imageSize)) { + // Thumbnail is smaller than the image and we are not upscaling + return $thumbnail; + } + + $ratios = array( + $size->getWidth() / $imageSize->getWidth(), + $size->getHeight() / $imageSize->getHeight(), + ); + switch ($mode) { + case ImageInterface::THUMBNAIL_OUTBOUND: + // Crop the image so that it fits the wanted size + $ratio = max($ratios); + if ($imageSize->contains($size)) { + // Downscale the image + $imageSize = $imageSize->scale($ratio); + $thumbnail->resize($imageSize, $filter); + $thumbnailSize = $size; + } else { + if ($allowUpscale) { + // Upscale the image so that the max dimension will be the wanted one + $imageSize = $imageSize->scale($ratio); + $thumbnail->resize($imageSize, $filter); + } + $thumbnailSize = new Box( + min($imageSize->getWidth(), $size->getWidth()), + min($imageSize->getHeight(), $size->getHeight()) + ); + } + $thumbnail->crop( + new Point( + max(0, round(($imageSize->getWidth() - $size->getWidth()) / 2)), + max(0, round(($imageSize->getHeight() - $size->getHeight()) / 2)) + ), + $thumbnailSize + ); + break; + case ImageInterface::THUMBNAIL_INSET: + default: + // Scale the image so that it fits the wanted size + $ratio = min($ratios); + $thumbnailSize = $imageSize->scale($ratio); + $thumbnail->resize($thumbnailSize, $filter); + break; + } + + return $thumbnail; + } + + /** + * Check the settings argument in thumbnail() method. + * + * @param int $settings + */ + private function checkThumbnailSettings($settings) + { + // Preserve BC until version 1.0 + if (is_string($settings)) { + if ($settings === 'inset') { + $settings = ImageInterface::THUMBNAIL_INSET; + } elseif ($settings === 'outbound') { + $settings = ImageInterface::THUMBNAIL_OUTBOUND; + } elseif (is_numeric($settings)) { + $settings = (int) $settings; + } + } + if (!is_int($settings)) { + throw new InvalidArgumentException('Invalid setting specified'); + } + $mode = $settings & 0xffff; + if ($mode === 0) { + $settings |= ImageInterface::THUMBNAIL_INSET; + } else { + if (!in_array($mode, $this->getAllThumbnailModes())) { + if (strlen(str_replace('0', '', decbin($mode))) === 1) { + throw new InvalidArgumentException('Invalid setting specified'); + } + throw new InvalidArgumentException('Only one mode should be specified'); + } + } + + return $settings; + } + + /** + * Get all the available thumbnail modes. + * + * @return int[] + */ + protected function getAllThumbnailModes() + { + return array( + ImageInterface::THUMBNAIL_INSET, + ImageInterface::THUMBNAIL_OUTBOUND, + ); + } + + /** + * Updates a given array of save options for backward compatibility with legacy names. + * + * @param array $options + * + * @return array + */ + protected function updateSaveOptions(array $options) + { + // Preserve BC until version 1.0 + if (isset($options['quality']) && !isset($options['jpeg_quality'])) { + $options['jpeg_quality'] = $options['quality']; + } + + return $options; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImageInterface::metadata() + */ + public function metadata() + { + return $this->metadata; + } + + /** + * Clones all the resources associated to this instance. + */ + public function __clone() + { + if ($this->metadata !== null) { + $this->metadata = clone $this->metadata; + } + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Factory\ClassFactoryAwareInterface::getClassFactory() + */ + public function getClassFactory() + { + if ($this->classFactory === null) { + $this->classFactory = new ClassFactory(); + } + + return $this->classFactory; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Factory\ClassFactoryAwareInterface::setClassFactory() + */ + public function setClassFactory(ClassFactoryInterface $classFactory) + { + $this->classFactory = $classFactory; + + return $this; + } +} diff --git a/vendor/imagine/imagine/src/Image/AbstractImagine.php b/vendor/imagine/imagine/src/Image/AbstractImagine.php new file mode 100644 index 0000000..d35cd6d --- /dev/null +++ b/vendor/imagine/imagine/src/Image/AbstractImagine.php @@ -0,0 +1,110 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Image; + +use Imagine\Exception\InvalidArgumentException; +use Imagine\Factory\ClassFactory; +use Imagine\Factory\ClassFactoryInterface; +use Imagine\Image\Metadata\MetadataReaderInterface; + +abstract class AbstractImagine implements ImagineInterface +{ + /** + * @var \Imagine\Image\Metadata\MetadataReaderInterface|null + */ + private $metadataReader; + + /** + * @var \Imagine\Factory\ClassFactoryInterface + */ + private $classFactory; + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImagineInterface::setMetadataReader() + */ + public function setMetadataReader(MetadataReaderInterface $metadataReader) + { + $this->metadataReader = $metadataReader; + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImagineInterface::getMetadataReader() + */ + public function getMetadataReader() + { + if (null === $this->metadataReader) { + $this->metadataReader = $this->getClassFactory()->createMetadataReader(); + } + + return $this->metadataReader; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Factory\ClassFactoryAwareInterface::setClassFactory() + */ + public function setClassFactory(ClassFactoryInterface $classFactory) + { + $this->classFactory = $classFactory; + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Factory\ClassFactoryAwareInterface::getClassFactory() + */ + public function getClassFactory() + { + if ($this->classFactory === null) { + $this->classFactory = new ClassFactory(); + } + + return $this->classFactory; + } + + /** + * Checks a path that could be used with ImagineInterface::open and returns + * a proper string. + * + * @param string|object $path + * + * @throws \Imagine\Exception\InvalidArgumentException in case the given path is invalid + * + * @return string + */ + protected function checkPath($path) + { + // provide compatibility with objects such as \SplFileInfo + if (is_object($path) && method_exists($path, '__toString')) { + $path = (string) $path; + } + + $handle = @fopen($path, 'r'); + + if (false === $handle) { + throw new InvalidArgumentException(sprintf('File %s does not exist.', $path)); + } + + fclose($handle); + + return $path; + } +} diff --git a/vendor/imagine/imagine/src/Image/AbstractLayers.php b/vendor/imagine/imagine/src/Image/AbstractLayers.php new file mode 100644 index 0000000..55845ed --- /dev/null +++ b/vendor/imagine/imagine/src/Image/AbstractLayers.php @@ -0,0 +1,106 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Image; + +use Imagine\Factory\ClassFactory; +use Imagine\Factory\ClassFactoryAwareInterface; +use Imagine\Factory\ClassFactoryInterface; + +abstract class AbstractLayers implements LayersInterface, ClassFactoryAwareInterface +{ + /** + * @var \Imagine\Factory\ClassFactoryInterface|null + */ + private $classFactory; + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\LayersInterface::add() + */ + public function add(ImageInterface $image) + { + $this[] = $image; + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\LayersInterface::set() + */ + public function set($offset, ImageInterface $image) + { + $this[$offset] = $image; + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\LayersInterface::remove() + */ + public function remove($offset) + { + unset($this[$offset]); + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\LayersInterface::get() + */ + public function get($offset) + { + return $this[$offset]; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\LayersInterface::has() + */ + public function has($offset) + { + return isset($this[$offset]); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Factory\ClassFactoryAwareInterface::setClassFactory() + */ + public function setClassFactory(ClassFactoryInterface $classFactory) + { + $this->classFactory = $classFactory; + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Factory\ClassFactoryAwareInterface::getClassFactory() + */ + public function getClassFactory() + { + if ($this->classFactory === null) { + $this->classFactory = new ClassFactory(); + } + + return $this->classFactory; + } +} diff --git a/vendor/imagine/imagine/src/Image/Box.php b/vendor/imagine/imagine/src/Image/Box.php new file mode 100644 index 0000000..fee2fde --- /dev/null +++ b/vendor/imagine/imagine/src/Image/Box.php @@ -0,0 +1,148 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Image; + +use Imagine\Exception\InvalidArgumentException; + +/** + * A box implementation. + */ +final class Box implements BoxInterface +{ + /** + * @var int + */ + private $width; + + /** + * @var int + */ + private $height; + + /** + * Constructs the Size with given width and height. + * + * @param int $width + * @param int $height + * + * @throws \Imagine\Exception\InvalidArgumentException + */ + public function __construct($width, $height) + { + if (!\is_int($width)) { + $width = (int) round($width); + } + if (!\is_int($height)) { + $height = (int) round($height); + } + $this->width = $width; + $this->height = $height; + if ($this->width < 1 || $this->height < 1) { + throw new InvalidArgumentException(sprintf('Length of either side cannot be 0 or negative, current size is %sx%s', $width, $height)); + } + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\BoxInterface::getWidth() + */ + public function getWidth() + { + return $this->width; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\BoxInterface::getHeight() + */ + public function getHeight() + { + return $this->height; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\BoxInterface::scale() + */ + public function scale($ratio) + { + $width = max(1, round($ratio * $this->width)); + $height = max(1, round($ratio * $this->height)); + + return new self($width, $height); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\BoxInterface::increase() + */ + public function increase($size) + { + return new self((int) $size + $this->width, (int) $size + $this->height); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\BoxInterface::contains() + */ + public function contains(BoxInterface $box, PointInterface $start = null) + { + $start = $start ? $start : new Point(0, 0); + + return $start->in($this) && $this->width >= $box->getWidth() + $start->getX() && $this->height >= $box->getHeight() + $start->getY(); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\BoxInterface::square() + */ + public function square() + { + return $this->width * $this->height; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\BoxInterface::__toString() + */ + public function __toString() + { + return sprintf('%dx%d px', $this->width, $this->height); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\BoxInterface::widen() + */ + public function widen($width) + { + return $this->scale($width / $this->width); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\BoxInterface::heighten() + */ + public function heighten($height) + { + return $this->scale($height / $this->height); + } +} diff --git a/vendor/imagine/imagine/src/Image/BoxInterface.php b/vendor/imagine/imagine/src/Image/BoxInterface.php new file mode 100644 index 0000000..b963777 --- /dev/null +++ b/vendor/imagine/imagine/src/Image/BoxInterface.php @@ -0,0 +1,94 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Image; + +/** + * Interface for a box. + */ +interface BoxInterface +{ + /** + * Gets box height. + * + * @return int + */ + public function getHeight(); + + /** + * Gets box width. + * + * @return int + */ + public function getWidth(); + + /** + * Creates new BoxInterface instance with ratios applied to both sides. + * + * @param float $ratio + * + * @return static + */ + public function scale($ratio); + + /** + * Creates new BoxInterface, adding given size to both sides. + * + * @param int $size + * + * @return static + */ + public function increase($size); + + /** + * Checks whether current box can fit given box at a given start position, + * start position defaults to top left corner xy(0,0). + * + * @param \Imagine\Image\BoxInterface $box + * @param \Imagine\Image\PointInterface $start + * + * @return bool + */ + public function contains(BoxInterface $box, PointInterface $start = null); + + /** + * Gets current box square, useful for getting total number of pixels in a + * given box. + * + * @return int + */ + public function square(); + + /** + * Returns a string representation of the current box. + * + * @return string + */ + public function __toString(); + + /** + * Resizes box to given width, constraining proportions and returns the new box. + * + * @param int $width + * + * @return static + */ + public function widen($width); + + /** + * Resizes box to given height, constraining proportions and returns the new box. + * + * @param int $height + * + * @return static + */ + public function heighten($height); +} diff --git a/vendor/imagine/imagine/src/Image/Fill/FillInterface.php b/vendor/imagine/imagine/src/Image/Fill/FillInterface.php new file mode 100644 index 0000000..48c2735 --- /dev/null +++ b/vendor/imagine/imagine/src/Image/Fill/FillInterface.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Image\Fill; + +use Imagine\Image\PointInterface; + +/** + * Interface for the fill. + */ +interface FillInterface +{ + /** + * Gets color of the fill for the given position. + * + * @param \Imagine\Image\PointInterface $position + * + * @return \Imagine\Image\Palette\Color\ColorInterface + */ + public function getColor(PointInterface $position); +} diff --git a/vendor/imagine/imagine/src/Image/Fill/Gradient/Horizontal.php b/vendor/imagine/imagine/src/Image/Fill/Gradient/Horizontal.php new file mode 100644 index 0000000..f5142b3 --- /dev/null +++ b/vendor/imagine/imagine/src/Image/Fill/Gradient/Horizontal.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Image\Fill\Gradient; + +use Imagine\Image\PointInterface; + +/** + * Horizontal gradient fill. + */ +final class Horizontal extends Linear +{ + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Fill\Gradient\Linear::getDistance() + */ + public function getDistance(PointInterface $position) + { + return $position->getX(); + } +} diff --git a/vendor/imagine/imagine/src/Image/Fill/Gradient/Linear.php b/vendor/imagine/imagine/src/Image/Fill/Gradient/Linear.php new file mode 100644 index 0000000..dfe4b64 --- /dev/null +++ b/vendor/imagine/imagine/src/Image/Fill/Gradient/Linear.php @@ -0,0 +1,97 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Image\Fill\Gradient; + +use Imagine\Image\Fill\FillInterface; +use Imagine\Image\Palette\Color\ColorInterface; +use Imagine\Image\PointInterface; + +/** + * Linear gradient fill. + */ +abstract class Linear implements FillInterface +{ + /** + * @var int + */ + private $length; + + /** + * @var \Imagine\Image\Palette\Color\ColorInterface + */ + private $start; + + /** + * @var \Imagine\Image\Palette\Color\ColorInterface + */ + private $end; + + /** + * Constructs a linear gradient with overall gradient length, and start and + * end shades, which default to 0 and 255 accordingly. + * + * @param int $length + * @param \Imagine\Image\Palette\Color\ColorInterface $start + * @param \Imagine\Image\Palette\Color\ColorInterface $end + */ + final public function __construct($length, ColorInterface $start, ColorInterface $end) + { + $this->length = $length; + $this->start = $start; + $this->end = $end; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Fill\FillInterface::getColor() + */ + final public function getColor(PointInterface $position) + { + $l = $this->getDistance($position); + + if ($l >= $this->length) { + return $this->end; + } + + if ($l < 0) { + return $this->start; + } + + return $this->start->getPalette()->blend($this->start, $this->end, $l / $this->length); + } + + /** + * @return \Imagine\Image\Palette\Color\ColorInterface + */ + final public function getStart() + { + return $this->start; + } + + /** + * @return \Imagine\Image\Palette\Color\ColorInterface + */ + final public function getEnd() + { + return $this->end; + } + + /** + * Get the distance of the position relative to the beginning of the gradient. + * + * @param \Imagine\Image\PointInterface $position + * + * @return int + */ + abstract protected function getDistance(PointInterface $position); +} diff --git a/vendor/imagine/imagine/src/Image/Fill/Gradient/Vertical.php b/vendor/imagine/imagine/src/Image/Fill/Gradient/Vertical.php new file mode 100644 index 0000000..a794fbf --- /dev/null +++ b/vendor/imagine/imagine/src/Image/Fill/Gradient/Vertical.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Image\Fill\Gradient; + +use Imagine\Image\PointInterface; + +/** + * Vertical gradient fill. + */ +final class Vertical extends Linear +{ + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Fill\Gradient\Linear::getDistance() + */ + public function getDistance(PointInterface $position) + { + return $position->getY(); + } +} diff --git a/vendor/imagine/imagine/src/Image/FontInterface.php b/vendor/imagine/imagine/src/Image/FontInterface.php new file mode 100644 index 0000000..be47c02 --- /dev/null +++ b/vendor/imagine/imagine/src/Image/FontInterface.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Image; + +/** + * The font interface. + */ +interface FontInterface +{ + /** + * Gets the fontfile for current font. + * + * @return string + */ + public function getFile(); + + /** + * Gets font's integer point size. + * + * @return int + */ + public function getSize(); + + /** + * Gets font's color. + * + * @return \Imagine\Image\Palette\Color\ColorInterface + */ + public function getColor(); + + /** + * Gets BoxInterface of font size on the image based on string and angle. + * + * @param string $string + * @param int $angle + * + * @return \Imagine\Image\BoxInterface + */ + public function box($string, $angle = 0); + + /** + * Split a string into multiple lines so that it fits a specific width. + * + * @param string $string The text to be wrapped + * @param int $maxWidth The maximum width of the text + * @param int $angle + * + * @return string + */ + public function wrapText($string, $maxWidth, $angle = 0); +} diff --git a/vendor/imagine/imagine/src/Image/Histogram/Bucket.php b/vendor/imagine/imagine/src/Image/Histogram/Bucket.php new file mode 100644 index 0000000..3c411ab --- /dev/null +++ b/vendor/imagine/imagine/src/Image/Histogram/Bucket.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Image\Histogram; + +/** + * Bucket histogram. + */ +final class Bucket implements \Countable +{ + /** + * @var \Imagine\Image\Histogram\Range + */ + private $range; + + /** + * @var int + */ + private $count; + + /** + * @param \Imagine\Image\Histogram\Range $range + * @param int $count + */ + public function __construct(Range $range, $count = 0) + { + $this->range = $range; + $this->count = $count; + } + + /** + * @param int $value + * + * @return $this + */ + public function add($value) + { + if ($this->range->contains($value)) { + $this->count++; + } + + return $this; + } + + /** + * @return int the number of elements in the bucket + */ + public function count() + { + return $this->count; + } +} diff --git a/vendor/imagine/imagine/src/Image/Histogram/Range.php b/vendor/imagine/imagine/src/Image/Histogram/Range.php new file mode 100644 index 0000000..e2ba05d --- /dev/null +++ b/vendor/imagine/imagine/src/Image/Histogram/Range.php @@ -0,0 +1,56 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Image\Histogram; + +use Imagine\Exception\OutOfBoundsException; + +/** + * Range histogram. + */ +final class Range +{ + /** + * @var int + */ + private $start; + + /** + * @var int + */ + private $end; + + /** + * @param int $start + * @param int $end + * + * @throws \Imagine\Exception\OutOfBoundsException + */ + public function __construct($start, $end) + { + if ($end <= $start) { + throw new OutOfBoundsException(sprintf('Range end cannot be bigger than start, %d %d given accordingly', $this->start, $this->end)); + } + + $this->start = $start; + $this->end = $end; + } + + /** + * @param int $value + * + * @return bool + */ + public function contains($value) + { + return $value >= $this->start && $value < $this->end; + } +} diff --git a/vendor/imagine/imagine/src/Image/ImageInterface.php b/vendor/imagine/imagine/src/Image/ImageInterface.php new file mode 100644 index 0000000..8f0370b --- /dev/null +++ b/vendor/imagine/imagine/src/Image/ImageInterface.php @@ -0,0 +1,297 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Image; + +use Imagine\Image\Palette\PaletteInterface; + +/** + * The image interface. + */ +interface ImageInterface extends ManipulatorInterface +{ + /** + * Resolution units: pixels per inch. + * + * @var string + */ + const RESOLUTION_PIXELSPERINCH = 'ppi'; + + /** + * Resolution units: pixels per centimeter. + * + * @var string + */ + const RESOLUTION_PIXELSPERCENTIMETER = 'ppc'; + + /** + * Image interlacing: none. + * + * @var string + */ + const INTERLACE_NONE = 'none'; + + /** + * Image interlacing: scanline. + * + * @var string + */ + const INTERLACE_LINE = 'line'; + + /** + * Image interlacing: plane. + * + * @var string + */ + const INTERLACE_PLANE = 'plane'; + + /** + * Image interlacing: like plane interlacing except the different planes are saved to individual files. + * + * @var string + */ + const INTERLACE_PARTITION = 'partition'; + + /** + * Image filter: none/undefined. + * + * @var string + */ + const FILTER_UNDEFINED = 'undefined'; + + /** + * Resampling filter: point (interpolated). + * + * @var string + */ + const FILTER_POINT = 'point'; + + /** + * Resampling filter: box. + * + * @var string + */ + const FILTER_BOX = 'box'; + + /** + * Resampling filter: triangle. + * + * @var string + */ + const FILTER_TRIANGLE = 'triangle'; + + /** + * Resampling filter: hermite. + * + * @var string + */ + const FILTER_HERMITE = 'hermite'; + + /** + * Resampling filter: hanning. + * + * @var string + */ + const FILTER_HANNING = 'hanning'; + + /** + * Resampling filter: hamming. + * + * @var string + */ + const FILTER_HAMMING = 'hamming'; + + /** + * Resampling filter: blackman. + * + * @var string + */ + const FILTER_BLACKMAN = 'blackman'; + + /** + * Resampling filter: gaussian. + * + * @var string + */ + const FILTER_GAUSSIAN = 'gaussian'; + + /** + * Resampling filter: quadratic. + * + * @var string + */ + const FILTER_QUADRATIC = 'quadratic'; + + /** + * Resampling filter: cubic. + * + * @var string + */ + const FILTER_CUBIC = 'cubic'; + + /** + * Resampling filter: catrom. + * + * @var string + */ + const FILTER_CATROM = 'catrom'; + + /** + * Resampling filter: mitchell. + * + * @var string + */ + const FILTER_MITCHELL = 'mitchell'; + + /** + * Resampling filter: lanczos. + * + * @var string + */ + const FILTER_LANCZOS = 'lanczos'; + + /** + * Resampling filter: bessel. + * + * @var string + */ + const FILTER_BESSEL = 'bessel'; + + /** + * Resampling filter: sinc. + * + * @var string + */ + const FILTER_SINC = 'sinc'; + + /** + * Returns the image content as a binary string. + * + * @param string $format + * @param array $options + * + * @throws \Imagine\Exception\RuntimeException + * + * @return string binary + */ + public function get($format, array $options = array()); + + /** + * Returns the image content as a PNG binary string. + * + * @throws \Imagine\Exception\RuntimeException + * + * @return string binary + */ + public function __toString(); + + /** + * Instantiates and returns a DrawerInterface instance for image drawing. + * + * @return \Imagine\Draw\DrawerInterface + */ + public function draw(); + + /** + * @return \Imagine\Effects\EffectsInterface + */ + public function effects(); + + /** + * Returns current image size. + * + * @return \Imagine\Image\BoxInterface + */ + public function getSize(); + + /** + * Transforms creates a grayscale mask from current image, returns a new + * image, while keeping the existing image unmodified. + * + * @return static + */ + public function mask(); + + /** + * Returns array of image colors as Imagine\Image\Palette\Color\ColorInterface instances. + * + * @return \Imagine\Image\Palette\Color\ColorInterface[] + */ + public function histogram(); + + /** + * Returns color at specified positions of current image. + * + * @param \Imagine\Image\PointInterface $point + * + * @throws \Imagine\Exception\RuntimeException + * + * @return \Imagine\Image\Palette\Color\ColorInterface + */ + public function getColorAt(PointInterface $point); + + /** + * Returns the image layers when applicable. + * + * @throws \Imagine\Exception\RuntimeException In case the layer can not be returned + * @throws \Imagine\Exception\OutOfBoundsException In case the index is not a valid value + * + * @return \Imagine\Image\LayersInterface + */ + public function layers(); + + /** + * Enables or disables interlacing. + * + * @param string $scheme + * + * @throws \Imagine\Exception\InvalidArgumentException When an unsupported Interface type is supplied + * + * @return $this + */ + public function interlace($scheme); + + /** + * Return the current color palette. + * + * @return \Imagine\Image\Palette\PaletteInterface + */ + public function palette(); + + /** + * Set a palette for the image. Useful to change colorspace. + * + * @param \Imagine\Image\Palette\PaletteInterface $palette + * + * @throws \Imagine\Exception\RuntimeException + * + * @return $this + */ + public function usePalette(PaletteInterface $palette); + + /** + * Applies a color profile on the Image. + * + * @param \Imagine\Image\ProfileInterface $profile + * + * @throws \Imagine\Exception\RuntimeException + * + * @return $this + */ + public function profile(ProfileInterface $profile); + + /** + * Returns the Image's meta data. + * + * @return \Imagine\Image\Metadata\MetadataBag + */ + public function metadata(); +} diff --git a/vendor/imagine/imagine/src/Image/ImagineInterface.php b/vendor/imagine/imagine/src/Image/ImagineInterface.php new file mode 100644 index 0000000..62d2eef --- /dev/null +++ b/vendor/imagine/imagine/src/Image/ImagineInterface.php @@ -0,0 +1,99 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Image; + +use Imagine\Factory\ClassFactoryAwareInterface; +use Imagine\Image\Metadata\MetadataReaderInterface; +use Imagine\Image\Palette\Color\ColorInterface; + +/** + * The imagine interface. + */ +interface ImagineInterface extends ClassFactoryAwareInterface +{ + const VERSION = '1.2.3'; + + /** + * Creates a new empty image with an optional background color. + * + * @param \Imagine\Image\BoxInterface $size + * @param \Imagine\Image\Palette\Color\ColorInterface $color + * + * @throws \Imagine\Exception\InvalidArgumentException + * @throws \Imagine\Exception\RuntimeException + * + * @return \Imagine\Image\ImageInterface + */ + public function create(BoxInterface $size, ColorInterface $color = null); + + /** + * Opens an existing image from $path. + * + * @param string|\Imagine\File\LoaderInterface|mixed $path the file path, a LoaderInterface instance, or an object whose string representation is the image path + * + * @throws \Imagine\Exception\RuntimeException + * + * @return \Imagine\Image\ImageInterface + */ + public function open($path); + + /** + * Loads an image from a binary $string. + * + * @param string $string + * + * @throws \Imagine\Exception\RuntimeException + * + * @return \Imagine\Image\ImageInterface + */ + public function load($string); + + /** + * Loads an image from a resource $resource. + * + * @param resource $resource + * + * @throws \Imagine\Exception\RuntimeException + * + * @return \Imagine\Image\ImageInterface + */ + public function read($resource); + + /** + * Constructs a font with specified $file, $size and $color. + * + * The font size is to be specified in points (e.g. 10pt means 10) + * + * @param string $file + * @param int $size + * @param \Imagine\Image\Palette\Color\ColorInterface $color + * + * @return \Imagine\Image\FontInterface + */ + public function font($file, $size, ColorInterface $color); + + /** + * Set the object to be used to read image metadata. + * + * @param \Imagine\Image\Metadata\MetadataReaderInterface $metadataReader + * + * @return $this + */ + public function setMetadataReader(MetadataReaderInterface $metadataReader); + + /** + * Get the object to be used to read image metadata. + * + * @return \Imagine\Image\Metadata\MetadataReaderInterface + */ + public function getMetadataReader(); +} diff --git a/vendor/imagine/imagine/src/Image/LayersInterface.php b/vendor/imagine/imagine/src/Image/LayersInterface.php new file mode 100644 index 0000000..631f4ab --- /dev/null +++ b/vendor/imagine/imagine/src/Image/LayersInterface.php @@ -0,0 +1,107 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Image; + +/** + * The layers interface. + */ +interface LayersInterface extends \Iterator, \Countable, \ArrayAccess +{ + /** + * Merge layers into the original objects. + * + * @throws \Imagine\Exception\RuntimeException + */ + public function merge(); + + /** + * Animates layers. + * + * @param string $format The output output format + * @param int $delay The delay in milliseconds between two frames + * @param int $loops The number of loops, 0 means infinite + * + * @throws \Imagine\Exception\InvalidArgumentException In case an invalid argument is provided + * @throws \Imagine\Exception\RuntimeException In case the driver fails to animate + * + * @return $this + */ + public function animate($format, $delay, $loops); + + /** + * Coalesce layers. Each layer in the sequence is the same size as the first and composited with the next layer in + * the sequence. + * + * @throws \Imagine\Exception\NotSupportedException + * + * @return $this + */ + public function coalesce(); + + /** + * Adds an image at the end of the layers stack. + * + * @param \Imagine\Image\ImageInterface $image + * + * @throws \Imagine\Exception\RuntimeException + * + * @return $this + */ + public function add(ImageInterface $image); + + /** + * Set an image at offset. + * + * @param int $offset + * @param \Imagine\Image\ImageInterface $image + * + * @throws \Imagine\Exception\RuntimeException + * @throws \Imagine\Exception\InvalidArgumentException + * @throws \Imagine\Exception\OutOfBoundsException + * + * @return $this + */ + public function set($offset, ImageInterface $image); + + /** + * Removes the image at offset. + * + * @param int $offset + * + * @throws \Imagine\Exception\RuntimeException + * @throws \Imagine\Exception\InvalidArgumentException + * + * @return $this + */ + public function remove($offset); + + /** + * Returns the image at offset. + * + * @param int $offset + * + * @throws \Imagine\Exception\RuntimeException + * @throws \Imagine\Exception\InvalidArgumentException + * + * @return \Imagine\Image\ImageInterface + */ + public function get($offset); + + /** + * Returns true if a layer at offset is preset. + * + * @param int $offset + * + * @return bool + */ + public function has($offset); +} diff --git a/vendor/imagine/imagine/src/Image/ManipulatorInterface.php b/vendor/imagine/imagine/src/Image/ManipulatorInterface.php new file mode 100644 index 0000000..23f033f --- /dev/null +++ b/vendor/imagine/imagine/src/Image/ManipulatorInterface.php @@ -0,0 +1,204 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Image; + +use Imagine\Image\Fill\FillInterface; +use Imagine\Image\Palette\Color\ColorInterface; + +/** + * The manipulator interface. + */ +interface ManipulatorInterface +{ + /** + * The original image is scaled so it is fully contained within the thumbnail dimensions (the image width/height ratio doesn't change). + * + * @var int + */ + const THUMBNAIL_INSET = 0x00000001; + + /** + * The thumbnail is scaled so that its smallest side equals the length of the corresponding side in the original image (the width or the height are cropped). + * + * @var int + */ + const THUMBNAIL_OUTBOUND = 0x00000002; + + /** + * Allow upscaling the image if it's smaller than the wanted thumbnail size. + * + * @var int + */ + const THUMBNAIL_FLAG_UPSCALE = 0x00010000; + + /** + * Instead of creating a new image instance, the thumbnail method modifies the original image (saving memory. + * + * @var int + */ + const THUMBNAIL_FLAG_NOCLONE = 0x00020000; + + /** + * Copies current source image into a new ImageInterface instance. + * + * @throws \Imagine\Exception\RuntimeException + * + * @return static + */ + public function copy(); + + /** + * Crops a specified box out of the source image (modifies the source image) + * Returns cropped self. + * + * @param \Imagine\Image\PointInterface $start + * @param \Imagine\Image\BoxInterface $size + * + * @throws \Imagine\Exception\OutOfBoundsException + * @throws \Imagine\Exception\RuntimeException + * + * @return $this + */ + public function crop(PointInterface $start, BoxInterface $size); + + /** + * Resizes current image and returns self. + * + * @param \Imagine\Image\BoxInterface $size + * @param string $filter + * + * @throws \Imagine\Exception\RuntimeException + * + * @return $this + */ + public function resize(BoxInterface $size, $filter = ImageInterface::FILTER_UNDEFINED); + + /** + * Rotates an image at the given angle. + * Optional $background can be used to specify the fill color of the empty + * area of rotated image. + * + * @param int $angle + * @param \Imagine\Image\Palette\Color\ColorInterface $background + * + * @throws \Imagine\Exception\RuntimeException + * + * @return $this + */ + public function rotate($angle, ColorInterface $background = null); + + /** + * Pastes an image into a parent image + * Throws exceptions if image exceeds parent image borders or if paste + * operation fails. + * + * Returns source image + * + * @param \Imagine\Image\ImageInterface $image + * @param \Imagine\Image\PointInterface $start + * @param int $alpha How to paste the image, from 0 (fully transparent) to 100 (fully opaque) + * + * @throws \Imagine\Exception\InvalidArgumentException + * @throws \Imagine\Exception\RuntimeException + * + * @return $this + */ + public function paste(ImageInterface $image, PointInterface $start, $alpha = 100); + + /** + * Saves the image at a specified path, the target file extension is used + * to determine file format, only jpg, jpeg, gif, png, wbmp, xbm, webp and bmp are + * supported. + * Please remark that bmp is supported by the GD driver only since PHP 7.2. + * + * @param string $path + * @param array $options + * + * @throws \Imagine\Exception\RuntimeException + * + * @return $this + */ + public function save($path = null, array $options = array()); + + /** + * Outputs the image content. + * + * @param string $format + * @param array $options + * + * @throws \Imagine\Exception\RuntimeException + * + * @return $this + */ + public function show($format, array $options = array()); + + /** + * Flips current image using vertical axis. + * + * @throws \Imagine\Exception\RuntimeException + * + * @return $this + */ + public function flipHorizontally(); + + /** + * Flips current image using horizontal axis. + * + * @throws \Imagine\Exception\RuntimeException + * + * @return $this + */ + public function flipVertically(); + + /** + * Remove all profiles and comments. + * + * @throws \Imagine\Exception\RuntimeException + * + * @return $this + */ + public function strip(); + + /** + * Generates a thumbnail from a current image + * Returns it as a new image without modifying the current image unless the THUMBNAIL_FLAG_NOCLONE flag is specified. + * + * @param \Imagine\Image\BoxInterface $size + * @param int|string $settings One or more of the ManipulatorInterface::THUMBNAIL_ flags (joined with |). It may be a string for backward compatibility with old constant values that were strings. + * @param string $filter The filter to use for resizing, one of ImageInterface::FILTER_* + * + * @throws \Imagine\Exception\RuntimeException + * + * @return static + */ + public function thumbnail(BoxInterface $size, $settings = self::THUMBNAIL_INSET, $filter = ImageInterface::FILTER_UNDEFINED); + + /** + * Applies a given mask to current image's alpha channel. + * + * @param \Imagine\Image\ImageInterface $mask + * + * @return $this + */ + public function applyMask(ImageInterface $mask); + + /** + * Fills image with provided filling, by replacing each pixel's color in + * the current image with corresponding color from FillInterface, and + * returns modified image. + * + * @param \Imagine\Image\Fill\FillInterface $fill + * + * @return $this + */ + public function fill(FillInterface $fill); +} diff --git a/vendor/imagine/imagine/src/Image/Metadata/AbstractMetadataReader.php b/vendor/imagine/imagine/src/Image/Metadata/AbstractMetadataReader.php new file mode 100644 index 0000000..4dd7024 --- /dev/null +++ b/vendor/imagine/imagine/src/Image/Metadata/AbstractMetadataReader.php @@ -0,0 +1,117 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Image\Metadata; + +use Imagine\Exception\InvalidArgumentException; +use Imagine\File\Loader; +use Imagine\File\LoaderInterface; + +/** + * Base class for the default metadata readers. + */ +abstract class AbstractMetadataReader implements MetadataReaderInterface +{ + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Metadata\MetadataReaderInterface::readFile() + */ + public function readFile($file) + { + $loader = $file instanceof LoaderInterface ? $file : new Loader($file); + + return new MetadataBag(array_merge($this->getStreamMetadata($loader), $this->extractFromFile($loader))); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Metadata\MetadataReaderInterface::readData() + */ + public function readData($data, $originalResource = null) + { + if (null !== $originalResource) { + return new MetadataBag(array_merge($this->getStreamMetadata($originalResource), $this->extractFromData($data))); + } + + return new MetadataBag($this->extractFromData($data)); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Metadata\MetadataReaderInterface::readStream() + */ + public function readStream($resource) + { + if (!is_resource($resource)) { + throw new InvalidArgumentException('Invalid resource provided.'); + } + + return new MetadataBag(array_merge($this->getStreamMetadata($resource), $this->extractFromStream($resource))); + } + + /** + * Gets the URI from a stream resource. + * + * @param resource|\Imagine\File\LoaderInterface $resource + * + * @return array + */ + private function getStreamMetadata($resource) + { + $metadata = array(); + + if ($resource instanceof LoaderInterface) { + $metadata['uri'] = $resource->getPath(); + if ($resource->isLocalFile()) { + $metadata['filepath'] = realpath($resource->getPath()); + } + } elseif (false !== $data = @stream_get_meta_data($resource)) { + if (isset($data['uri'])) { + $metadata['uri'] = $data['uri']; + if (stream_is_local($resource)) { + $metadata['filepath'] = realpath($data['uri']); + } + } + } + + return $metadata; + } + + /** + * Extracts metadata from a file. + * + * @param string|\Imagine\File\LoaderInterface $file + * + * @return array An associative array of metadata + */ + abstract protected function extractFromFile($file); + + /** + * Extracts metadata from raw data. + * + * @param $data + * + * @return array An associative array of metadata + */ + abstract protected function extractFromData($data); + + /** + * Extracts metadata from a stream. + * + * @param $resource + * + * @return array An associative array of metadata + */ + abstract protected function extractFromStream($resource); +} diff --git a/vendor/imagine/imagine/src/Image/Metadata/DefaultMetadataReader.php b/vendor/imagine/imagine/src/Image/Metadata/DefaultMetadataReader.php new file mode 100644 index 0000000..17d6232 --- /dev/null +++ b/vendor/imagine/imagine/src/Image/Metadata/DefaultMetadataReader.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Image\Metadata; + +/** + * A metadata reader that actually doesn't try to extract metadata. + */ +class DefaultMetadataReader extends AbstractMetadataReader +{ + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Metadata\AbstractMetadataReader::extractFromFile() + */ + protected function extractFromFile($file) + { + return array(); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Metadata\AbstractMetadataReader::extractFromData() + */ + protected function extractFromData($data) + { + return array(); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Metadata\AbstractMetadataReader::extractFromStream() + */ + protected function extractFromStream($resource) + { + return array(); + } +} diff --git a/vendor/imagine/imagine/src/Image/Metadata/ExifMetadataReader.php b/vendor/imagine/imagine/src/Image/Metadata/ExifMetadataReader.php new file mode 100644 index 0000000..8f55b10 --- /dev/null +++ b/vendor/imagine/imagine/src/Image/Metadata/ExifMetadataReader.php @@ -0,0 +1,149 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Image\Metadata; + +use Imagine\Exception\NotSupportedException; +use Imagine\File\Loader; +use Imagine\File\LoaderInterface; +use Imagine\Utils\ErrorHandling; + +/** + * Metadata driven by Exif information. + */ +class ExifMetadataReader extends AbstractMetadataReader +{ + /** + * @throws \Imagine\Exception\NotSupportedException + */ + public function __construct() + { + $whyNot = static::getUnsupportedReason(); + if ($whyNot !== '') { + throw new NotSupportedException($whyNot); + } + } + + /** + * Get the reason why this metadata reader is not supported. + * + * @return string empty string if the reader is available + */ + public static function getUnsupportedReason() + { + if (!function_exists('exif_read_data')) { + return 'The PHP EXIF extension is required to use the ExifMetadataReader'; + } + if (!in_array('data', stream_get_wrappers(), true)) { + return 'The data:// stream wrapper must be enabled'; + } + if (in_array(ini_get('allow_url_fopen'), array('', '0', 0), true)) { + return 'The allow_url_fopen php.ini configuration key must be set to 1'; + } + + return ''; + } + + /** + * Is this metadata reader supported? + * + * @return bool + */ + public static function isSupported() + { + return static::getUnsupportedReason() === ''; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Metadata\AbstractMetadataReader::extractFromFile() + */ + protected function extractFromFile($file) + { + $loader = $file instanceof LoaderInterface ? $file : new Loader($file); + + return $this->doReadData($loader->getData()); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Metadata\AbstractMetadataReader::extractFromData() + */ + protected function extractFromData($data) + { + return $this->doReadData($data); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Metadata\AbstractMetadataReader::extractFromStream() + */ + protected function extractFromStream($resource) + { + return $this->doReadData(stream_get_contents($resource)); + } + + /** + * Extracts metadata from raw data, merges with existing metadata. + * + * @param string $data + * + * @return array + */ + private function doReadData($data) + { + if (substr($data, 0, 2) === 'II') { + $mime = 'image/tiff'; + } else { + $mime = 'image/jpeg'; + } + + return $this->extract('data://' . $mime . ';base64,' . base64_encode($data)); + } + + /** + * Performs the exif data extraction given a path or data-URI representation. + * + * @param string $path the path to the file or the data-URI representation + * + * @return array + */ + private function extract($path) + { + try { + $exifData = ErrorHandling::ignoring(-1, function () use ($path) { + return @exif_read_data($path, null, true, false); + }); + } catch (\Exception $e) { + $exifData = false; + } catch (\Throwable $e) { + $exifData = false; + } + if (!is_array($exifData)) { + return array(); + } + + $metadata = array(); + foreach ($exifData as $prefix => $values) { + if (is_array($values)) { + $prefix = strtolower($prefix); + foreach ($values as $prop => $value) { + $metadata[$prefix . '.' . $prop] = $value; + } + } + } + + return $metadata; + } +} diff --git a/vendor/imagine/imagine/src/Image/Metadata/MetadataBag.php b/vendor/imagine/imagine/src/Image/Metadata/MetadataBag.php new file mode 100644 index 0000000..92e9a00 --- /dev/null +++ b/vendor/imagine/imagine/src/Image/Metadata/MetadataBag.php @@ -0,0 +1,114 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Image\Metadata; + +/** + * The container of the data extracted from metadata. + */ +class MetadataBag implements \ArrayAccess, \IteratorAggregate, \Countable +{ + /** + * @var array + */ + private $data; + + /** + * @param array $data + */ + public function __construct(array $data = array()) + { + $this->data = $data; + } + + /** + * Returns the metadata key, default value if it does not exist. + * + * @param string $key + * @param mixed|null $default + * + * @return mixed + */ + public function get($key, $default = null) + { + return array_key_exists($key, $this->data) ? $this->data[$key] : $default; + } + + /** + * {@inheritdoc} + * + * @see \Countable::count() + */ + public function count() + { + return count($this->data); + } + + /** + * {@inheritdoc} + * + * @see \IteratorAggregate::getIterator() + */ + public function getIterator() + { + return new \ArrayIterator($this->data); + } + + /** + * {@inheritdoc} + * + * @see \ArrayAccess::offsetExists() + */ + public function offsetExists($offset) + { + return array_key_exists($offset, $this->data); + } + + /** + * {@inheritdoc} + * + * @see \ArrayAccess::offsetSet() + */ + public function offsetSet($offset, $value) + { + $this->data[$offset] = $value; + } + + /** + * {@inheritdoc} + * + * @see \ArrayAccess::offsetUnset() + */ + public function offsetUnset($offset) + { + unset($this->data[$offset]); + } + + /** + * {@inheritdoc} + * + * @see \ArrayAccess::offsetGet() + */ + public function offsetGet($offset) + { + return $this->get($offset); + } + + /** + * Returns metadata as an associative array. + * + * @return array + */ + public function toArray() + { + return $this->data; + } +} diff --git a/vendor/imagine/imagine/src/Image/Metadata/MetadataReaderInterface.php b/vendor/imagine/imagine/src/Image/Metadata/MetadataReaderInterface.php new file mode 100644 index 0000000..6d4ea5a --- /dev/null +++ b/vendor/imagine/imagine/src/Image/Metadata/MetadataReaderInterface.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Image\Metadata; + +/** + * Interface that metadata readers must implement. + */ +interface MetadataReaderInterface +{ + /** + * Reads metadata from a file. + * + * @param string|\Imagine\File\LoaderInterface $file the path to the file where to read metadata + * + * @throws \Imagine\Exception\InvalidArgumentException in case the file does not exist + * + * @return \Imagine\Image\Metadata\MetadataBag + */ + public function readFile($file); + + /** + * Reads metadata from a binary string. + * + * @param string $data the binary string to read + * @param resource $originalResource an optional resource to gather stream metadata + * + * @return \Imagine\Image\Metadata\MetadataBag + */ + public function readData($data, $originalResource = null); + + /** + * Reads metadata from a stream. + * + * @param resource $resource the stream to read + * + * @throws \Imagine\Exception\InvalidArgumentException in case the resource is not valid + * + * @return \Imagine\Image\Metadata\MetadataBag + */ + public function readStream($resource); +} diff --git a/vendor/imagine/imagine/src/Image/Palette/CMYK.php b/vendor/imagine/imagine/src/Image/Palette/CMYK.php new file mode 100644 index 0000000..c0126ac --- /dev/null +++ b/vendor/imagine/imagine/src/Image/Palette/CMYK.php @@ -0,0 +1,157 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Image\Palette; + +use Imagine\Exception\InvalidArgumentException; +use Imagine\Exception\RuntimeException; +use Imagine\Image\Palette\Color\CMYK as CMYKColor; +use Imagine\Image\Palette\Color\ColorInterface; +use Imagine\Image\Profile; +use Imagine\Image\ProfileInterface; + +/** + * The CMYK palette. + */ +class CMYK implements PaletteInterface +{ + /** + * @var \Imagine\Image\Palette\ColorParser + */ + private $parser; + + /** + * @var \Imagine\Image\ProfileInterface|null + */ + private $profile; + + /** + * @var \Imagine\Image\Palette\Color\CMYK[] + */ + private static $colors = array(); + + public function __construct() + { + $this->parser = new ColorParser(); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Palette\PaletteInterface::name() + */ + public function name() + { + return PaletteInterface::PALETTE_CMYK; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Palette\PaletteInterface::pixelDefinition() + */ + public function pixelDefinition() + { + return array( + ColorInterface::COLOR_CYAN, + ColorInterface::COLOR_MAGENTA, + ColorInterface::COLOR_YELLOW, + ColorInterface::COLOR_KEYLINE, + ); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Palette\PaletteInterface::supportsAlpha() + */ + public function supportsAlpha() + { + return false; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Palette\PaletteInterface::getChannelsMaxValue() + */ + public function getChannelsMaxValue() + { + return 100; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Palette\PaletteInterface::color() + */ + public function color($color, $alpha = null) + { + if (null !== $alpha && $alpha !== 100) { + throw new InvalidArgumentException('CMYK palette does not support alpha'); + } + + $color = $this->parser->parseToCMYK($color); + $index = sprintf('cmyk(%d, %d, %d, %d)', $color[0], $color[1], $color[2], $color[3]); + + if (false === array_key_exists($index, self::$colors)) { + self::$colors[$index] = new CMYKColor($this, $color); + } + + return self::$colors[$index]; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Palette\PaletteInterface::blend() + */ + public function blend(ColorInterface $color1, ColorInterface $color2, $amount) + { + if (!$color1 instanceof CMYKColor || !$color2 instanceof CMYKColor) { + throw new RuntimeException('CMYK palette can only blend CMYK colors'); + } + $max = $this->getChannelsMaxValue(); + + return $this->color(array( + min($max, $color1->getCyan() + $color2->getCyan() * $amount), + min($max, $color1->getMagenta() + $color2->getMagenta() * $amount), + min($max, $color1->getYellow() + $color2->getYellow() * $amount), + min($max, $color1->getKeyline() + $color2->getKeyline() * $amount), + )); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Palette\PaletteInterface::useProfile() + */ + public function useProfile(ProfileInterface $profile) + { + $this->profile = $profile; + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Palette\PaletteInterface::profile() + */ + public function profile() + { + if (!$this->profile) { + $this->profile = Profile::fromPath(__DIR__ . '/../../resources/Adobe/CMYK/USWebUncoated.icc'); + } + + return $this->profile; + } +} diff --git a/vendor/imagine/imagine/src/Image/Palette/Color/CMYK.php b/vendor/imagine/imagine/src/Image/Palette/Color/CMYK.php new file mode 100644 index 0000000..4d5a990 --- /dev/null +++ b/vendor/imagine/imagine/src/Image/Palette/Color/CMYK.php @@ -0,0 +1,238 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Image\Palette\Color; + +use Imagine\Exception\InvalidArgumentException; +use Imagine\Exception\RuntimeException; +use Imagine\Image\Palette\CMYK as CMYKPalette; + +final class CMYK implements ColorInterface +{ + /** + * @var int + */ + private $c; + + /** + * @var int + */ + private $m; + + /** + * @var int + */ + private $y; + + /** + * @var int + */ + private $k; + + /** + * @var \Imagine\Image\Palette\CMYK + */ + private $palette; + + /** + * @param \Imagine\Image\Palette\CMYK $palette + * @param int[] $color + */ + public function __construct(CMYKPalette $palette, array $color) + { + $this->palette = $palette; + $this->setColor($color); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Palette\Color\ColorInterface::getValue() + */ + public function getValue($component) + { + switch ($component) { + case ColorInterface::COLOR_CYAN: + return $this->getCyan(); + case ColorInterface::COLOR_MAGENTA: + return $this->getMagenta(); + case ColorInterface::COLOR_YELLOW: + return $this->getYellow(); + case ColorInterface::COLOR_KEYLINE: + return $this->getKeyline(); + default: + throw new InvalidArgumentException(sprintf('Color component %s is not valid', $component)); + } + } + + /** + * Returns Cyan value of the color (from 0 to 100). + * + * @return int + */ + public function getCyan() + { + return $this->c; + } + + /** + * Returns Magenta value of the color (from 0 to 100). + * + * @return int + */ + public function getMagenta() + { + return $this->m; + } + + /** + * Returns Yellow value of the color (from 0 to 100). + * + * @return int + */ + public function getYellow() + { + return $this->y; + } + + /** + * Returns Key value of the color (from 0 to 100). + * + * @return int + */ + public function getKeyline() + { + return $this->k; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Palette\Color\ColorInterface::getPalette() + */ + public function getPalette() + { + return $this->palette; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Palette\Color\ColorInterface::getAlpha() + */ + public function getAlpha() + { + return null; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Palette\Color\ColorInterface::dissolve() + */ + public function dissolve($alpha) + { + throw new RuntimeException('CMYK does not support dissolution'); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Palette\Color\ColorInterface::lighten() + */ + public function lighten($shade) + { + return $this->palette->color( + array( + $this->c, + $this->m, + $this->y, + max(0, $this->k - $shade), + ) + ); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Palette\Color\ColorInterface::darken() + */ + public function darken($shade) + { + return $this->palette->color( + array( + $this->c, + $this->m, + $this->y, + min(100, $this->k + $shade), + ) + ); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Palette\Color\ColorInterface::grayscale() + */ + public function grayscale() + { + $color = array( + $this->c * (1 - $this->k / 100) + $this->k, + $this->m * (1 - $this->k / 100) + $this->k, + $this->y * (1 - $this->k / 100) + $this->k, + ); + + $gray = min(100, round(0.299 * $color[0] + 0.587 * $color[1] + 0.114 * $color[2])); + + return $this->palette->color(array($gray, $gray, $gray, $this->k)); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Palette\Color\ColorInterface::isOpaque() + */ + public function isOpaque() + { + return true; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Palette\Color\ColorInterface::__toString() + */ + public function __toString() + { + return sprintf('cmyk(%d%%, %d%%, %d%%, %d%%)', $this->c, $this->m, $this->y, $this->k); + } + + /** + * Internal, Performs checks for color validity (an of array(C, M, Y, K)). + * + * @param int[] $color + * + * @throws \Imagine\Exception\InvalidArgumentException + */ + private function setColor(array $color) + { + if (count($color) !== 4) { + throw new InvalidArgumentException('Color argument must look like array(C, M, Y, K), where C, M, Y, K are the integer values between 0 and 100 for cyan, magenta, yellow and black color indexes accordingly'); + } + + $colors = array_values($color); + array_walk($colors, function (&$color) { + $color = max(0, min(100, $color)); + }); + + list($this->c, $this->m, $this->y, $this->k) = $colors; + } +} diff --git a/vendor/imagine/imagine/src/Image/Palette/Color/ColorInterface.php b/vendor/imagine/imagine/src/Image/Palette/Color/ColorInterface.php new file mode 100644 index 0000000..1f410b5 --- /dev/null +++ b/vendor/imagine/imagine/src/Image/Palette/Color/ColorInterface.php @@ -0,0 +1,146 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Image\Palette\Color; + +interface ColorInterface +{ + /** + * Channel name: red. + * + * @var string + */ + const COLOR_RED = 'red'; + + /** + * Channel name: green. + * + * @var string + */ + const COLOR_GREEN = 'green'; + + /** + * Channel name: blue. + * + * @var string + */ + const COLOR_BLUE = 'blue'; + + /** + * Channel name: cyan. + * + * @var string + */ + const COLOR_CYAN = 'cyan'; + + /** + * Channel name: magenta. + * + * @var string + */ + const COLOR_MAGENTA = 'magenta'; + + /** + * Channel name: yellow. + * + * @var string + */ + const COLOR_YELLOW = 'yellow'; + + /** + * Channel name: key (black). + * + * @var string + */ + const COLOR_KEYLINE = 'keyline'; + + /** + * Channel name: gray. + * + * @var string + */ + const COLOR_GRAY = 'gray'; + + /** + * Return the value of one of the component. + * + * @param string $component One of the ColorInterface::COLOR_* component + * + * @throws \Imagine\Exception\InvalidArgumentException if $component is not valid + * + * @return int|null + */ + public function getValue($component); + + /** + * Returns percentage of transparency of the color (from 0 - fully transparent, to 100 - fully opaque). + * + * @return int|null return NULL if the color type does not support transparency + */ + public function getAlpha(); + + /** + * Returns the palette attached to the current color. + * + * @return \Imagine\Image\Palette\PaletteInterface + */ + public function getPalette(); + + /** + * Returns a copy of current color, incrementing the alpha channel by the given amount. + * + * @param int $alpha + * + * @throws \Imagine\Exception\RuntimeException if the color type does not support transparency + * + * @return static + */ + public function dissolve($alpha); + + /** + * Returns a copy of the current color, lightened by the specified number of shades. + * + * @param int $shade + * + * @return static + */ + public function lighten($shade); + + /** + * Returns a copy of the current color, darkened by the specified number of shades. + * + * @param int $shade + * + * @return static + */ + public function darken($shade); + + /** + * Returns a gray related to the current color. + * + * @return static + */ + public function grayscale(); + + /** + * Checks if the current color is opaque. + * + * @return bool + */ + public function isOpaque(); + + /** + * Returns hex representation of the color. + * + * @return string + */ + public function __toString(); +} diff --git a/vendor/imagine/imagine/src/Image/Palette/Color/Gray.php b/vendor/imagine/imagine/src/Image/Palette/Color/Gray.php new file mode 100644 index 0000000..17c587d --- /dev/null +++ b/vendor/imagine/imagine/src/Image/Palette/Color/Gray.php @@ -0,0 +1,188 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Image\Palette\Color; + +use Imagine\Exception\InvalidArgumentException; +use Imagine\Image\Palette\Grayscale; + +final class Gray implements ColorInterface +{ + /** + * @var int + */ + private $gray; + + /** + * @var int + */ + private $alpha; + + /** + * @var \Imagine\Image\Palette\Grayscale + */ + private $palette; + + /** + * @param \Imagine\Image\Palette\Grayscale $palette + * @param int[] $color + * @param int $alpha + */ + public function __construct(Grayscale $palette, array $color, $alpha) + { + $this->palette = $palette; + $this->setColor($color); + $this->setAlpha($alpha); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Palette\Color\ColorInterface::getValue() + */ + public function getValue($component) + { + switch ($component) { + case ColorInterface::COLOR_GRAY: + return $this->getGray(); + default: + throw new InvalidArgumentException(sprintf('Color component %s is not valid', $component)); + } + } + + /** + * Returns Gray value of the color (from 0 to 255). + * + * @return int + */ + public function getGray() + { + return $this->gray; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Palette\Color\ColorInterface::getPalette() + */ + public function getPalette() + { + return $this->palette; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Palette\Color\ColorInterface::getAlpha() + */ + public function getAlpha() + { + return $this->alpha; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Palette\Color\ColorInterface::dissolve() + */ + public function dissolve($alpha) + { + return $this->palette->color( + array($this->gray), + min(max((int) round($this->alpha + $alpha), 0), 100) + ); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Palette\Color\ColorInterface::lighten() + */ + public function lighten($shade) + { + return $this->palette->color(array(min(255, $this->gray + $shade)), $this->alpha); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Palette\Color\ColorInterface::darken() + */ + public function darken($shade) + { + return $this->palette->color(array(max(0, $this->gray - $shade)), $this->alpha); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Palette\Color\ColorInterface::grayscale() + */ + public function grayscale() + { + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Palette\Color\ColorInterface::isOpaque() + */ + public function isOpaque() + { + return 100 === $this->alpha; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Palette\Color\ColorInterface::__toString() + */ + public function __toString() + { + return sprintf('#%02x%02x%02x', $this->gray, $this->gray, $this->gray); + } + + /** + * Performs checks for validity of given alpha value and sets it. + * + * @param int $alpha + * + * @throws \Imagine\Exception\InvalidArgumentException + */ + private function setAlpha($alpha) + { + if (!is_int($alpha) || $alpha < 0 || $alpha > 100) { + throw new InvalidArgumentException(sprintf('Alpha must be an integer between 0 and 100, %s given', $alpha)); + } + + $this->alpha = $alpha; + } + + /** + * Performs checks for color validity (array of array(gray)). + * + * @param int[] $color + * + * @throws \Imagine\Exception\InvalidArgumentException + */ + private function setColor(array $color) + { + if (count($color) !== 1) { + throw new InvalidArgumentException('Color argument must look like array(gray), where gray is the integer value between 0 and 255 for the grayscale'); + } + + $color = array_values($color); + $color[0] = max(0, min(255, $color[0])); + + list($this->gray) = $color; + } +} diff --git a/vendor/imagine/imagine/src/Image/Palette/Color/RGB.php b/vendor/imagine/imagine/src/Image/Palette/Color/RGB.php new file mode 100644 index 0000000..242deb7 --- /dev/null +++ b/vendor/imagine/imagine/src/Image/Palette/Color/RGB.php @@ -0,0 +1,242 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Image\Palette\Color; + +use Imagine\Exception\InvalidArgumentException; +use Imagine\Image\Palette\RGB as RGBPalette; + +final class RGB implements ColorInterface +{ + /** + * @var int + */ + private $r; + + /** + * @var int + */ + private $g; + + /** + * @var int + */ + private $b; + + /** + * @var int + */ + private $alpha; + + /** + * @var \Imagine\Image\Palette\RGB + */ + private $palette; + + /** + * @param \Imagine\Image\Palette\RGB $palette + * @param int[] $color + * @param int $alpha + */ + public function __construct(RGBPalette $palette, array $color, $alpha) + { + $this->palette = $palette; + $this->setColor($color); + $this->setAlpha($alpha); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Palette\Color\ColorInterface::getValue() + */ + public function getValue($component) + { + switch ($component) { + case ColorInterface::COLOR_RED: + return $this->getRed(); + case ColorInterface::COLOR_GREEN: + return $this->getGreen(); + case ColorInterface::COLOR_BLUE: + return $this->getBlue(); + default: + throw new InvalidArgumentException(sprintf('Color component %s is not valid', $component)); + } + } + + /** + * Returns RED value of the color (from 0 to 255). + * + * @return int + */ + public function getRed() + { + return $this->r; + } + + /** + * Returns GREEN value of the color (from 0 to 255). + * + * @return int + */ + public function getGreen() + { + return $this->g; + } + + /** + * Returns BLUE value of the color (from 0 to 255). + * + * @return int + */ + public function getBlue() + { + return $this->b; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Palette\Color\ColorInterface::getPalette() + */ + public function getPalette() + { + return $this->palette; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Palette\Color\ColorInterface::getAlpha() + */ + public function getAlpha() + { + return $this->alpha; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Palette\Color\ColorInterface::dissolve() + */ + public function dissolve($alpha) + { + return $this->palette->color( + array($this->r, $this->g, $this->b), + min(max((int) round($this->alpha + $alpha), 0), 100) + ); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Palette\Color\ColorInterface::lighten() + */ + public function lighten($shade) + { + return $this->palette->color( + array( + min(255, $this->r + $shade), + min(255, $this->g + $shade), + min(255, $this->b + $shade), + ), $this->alpha + ); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Palette\Color\ColorInterface::darken() + */ + public function darken($shade) + { + return $this->palette->color( + array( + max(0, $this->r - $shade), + max(0, $this->g - $shade), + max(0, $this->b - $shade), + ), $this->alpha + ); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Palette\Color\ColorInterface::grayscale() + */ + public function grayscale() + { + $gray = min(255, round(0.299 * $this->getRed() + 0.114 * $this->getBlue() + 0.587 * $this->getGreen())); + + return $this->palette->color(array($gray, $gray, $gray), $this->alpha); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Palette\Color\ColorInterface::isOpaque() + */ + public function isOpaque() + { + return 100 === $this->alpha; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Palette\Color\ColorInterface::__toString() + */ + public function __toString() + { + return sprintf('#%02x%02x%02x', $this->r, $this->g, $this->b); + } + + /** + * Internal. + * + * Performs checks for validity of given alpha value and sets it + * + * @param int $alpha + * + * @throws \Imagine\Exception\InvalidArgumentException + */ + private function setAlpha($alpha) + { + if (!is_int($alpha) || $alpha < 0 || $alpha > 100) { + throw new InvalidArgumentException(sprintf('Alpha must be an integer between 0 and 100, %s given', $alpha)); + } + + $this->alpha = $alpha; + } + + /** + * Internal. + * + * Performs checks for color validity (array of array(R, G, B)) + * + * @param array $color + * + * @throws \Imagine\Exception\InvalidArgumentException + */ + private function setColor(array $color) + { + if (count($color) !== 3) { + throw new InvalidArgumentException('Color argument must look like array(R, G, B), where R, G, B are the integer values between 0 and 255 for red, green and blue color indexes accordingly'); + } + + $colors = array_values($color); + array_walk($colors, function (&$color) { + $color = max(0, min(255, $color)); + }); + + list($this->r, $this->g, $this->b) = $colors; + } +} diff --git a/vendor/imagine/imagine/src/Image/Palette/ColorParser.php b/vendor/imagine/imagine/src/Image/Palette/ColorParser.php new file mode 100644 index 0000000..2dfbeb4 --- /dev/null +++ b/vendor/imagine/imagine/src/Image/Palette/ColorParser.php @@ -0,0 +1,157 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Image\Palette; + +use Imagine\Exception\InvalidArgumentException; + +class ColorParser +{ + /** + * Parses a color to a RGB tuple. + * + * @param string|array|int $color + * + * @throws \Imagine\Exception\InvalidArgumentException + * + * @return array + */ + public function parseToRGB($color) + { + $color = $this->parse($color); + + if (4 === count($color)) { + $color = array( + 255 * (1 - $color[0] / 100) * (1 - $color[3] / 100), + 255 * (1 - $color[1] / 100) * (1 - $color[3] / 100), + 255 * (1 - $color[2] / 100) * (1 - $color[3] / 100), + ); + } + + return $color; + } + + /** + * Parses a color to a CMYK tuple. + * + * @param string|array|int $color + * + * @throws \Imagine\Exception\InvalidArgumentException + * + * @return array + */ + public function parseToCMYK($color) + { + $color = $this->parse($color); + + if (3 === count($color)) { + $r = $color[0] / 255; + $g = $color[1] / 255; + $b = $color[2] / 255; + + $k = 1 - max($r, $g, $b); + + $color = array( + 1 === $k ? 0 : round((1 - $r - $k) / (1 - $k) * 100), + 1 === $k ? 0 : round((1 - $g - $k) / (1 - $k) * 100), + 1 === $k ? 0 : round((1 - $b - $k) / (1 - $k) * 100), + round($k * 100), + ); + } + + return $color; + } + + /** + * Parses a color to a grayscale value. + * + * @param string|array|int $color + * + * @throws \Imagine\Exception\InvalidArgumentException + * + * @return int[] + */ + public function parseToGrayscale($color) + { + if (is_array($color) && 1 === count($color)) { + return array((int) round(array_pop($color))); + } + + $color = array_unique($this->parse($color)); + + if (1 !== count($color)) { + throw new InvalidArgumentException('The provided color has different values of red, green and blue components. Grayscale colors must have the same values for these.'); + } + + return $color; + } + + /** + * Parses a color. + * + * @param string|array|int $color + * + * @throws \Imagine\Exception\InvalidArgumentException + * + * @return int[] + */ + private function parse($color) + { + if (!is_string($color) && !is_array($color) && !is_int($color)) { + throw new InvalidArgumentException(sprintf('Color must be specified as a hexadecimal string, array or integer, %s given', gettype($color))); + } + + if (is_array($color)) { + if (3 === count($color) || 4 === count($color)) { + return array_map( + function ($component) { + return (int) round($component); + }, + array_values($color) + ); + } + throw new InvalidArgumentException('Color argument if array, must look like array(R, G, B), or array(C, M, Y, K) where R, G, B are the integer values between 0 and 255 for red, green and blue or cyan, magenta, yellow and black color indexes accordingly'); + } + if (is_string($color)) { + if (0 === strpos($color, 'cmyk(')) { + $substrColor = substr($color, 5, strlen($color) - 6); + + $components = array_map(function ($component) { + return (int) round(trim($component, ' %')); + }, explode(',', $substrColor)); + + if (count($components) !== 4) { + throw new InvalidArgumentException(sprintf('Unable to parse color %s', $color)); + } + + return $components; + } else { + $color = ltrim($color, '#'); + + if (strlen($color) !== 3 && strlen($color) !== 6) { + throw new InvalidArgumentException(sprintf('Color must be a hex value in regular (6 characters) or short (3 characters) notation, "%s" given', $color)); + } + + if (strlen($color) === 3) { + $color = $color[0] . $color[0] . $color[1] . $color[1] . $color[2] . $color[2]; + } + + $color = array_map('hexdec', str_split($color, 2)); + } + } + + if (is_int($color)) { + $color = array(255 & ($color >> 16), 255 & ($color >> 8), 255 & $color); + } + + return $color; + } +} diff --git a/vendor/imagine/imagine/src/Image/Palette/Grayscale.php b/vendor/imagine/imagine/src/Image/Palette/Grayscale.php new file mode 100644 index 0000000..5f91898 --- /dev/null +++ b/vendor/imagine/imagine/src/Image/Palette/Grayscale.php @@ -0,0 +1,151 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Image\Palette; + +use Imagine\Exception\RuntimeException; +use Imagine\Image\Palette\Color\ColorInterface; +use Imagine\Image\Palette\Color\Gray as GrayColor; +use Imagine\Image\Profile; +use Imagine\Image\ProfileInterface; + +/** + * The grayscale palette. + */ +class Grayscale implements PaletteInterface +{ + /** + * @var \Imagine\Image\Palette\ColorParser + */ + private $parser; + + /** + * @var \Imagine\Image\ProfileInterface|null + */ + private $profile; + + /** + * @var \Imagine\Image\Palette\Color\Gray[] + */ + protected static $colors = array(); + + public function __construct() + { + $this->parser = new ColorParser(); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Palette\PaletteInterface::name() + */ + public function name() + { + return PaletteInterface::PALETTE_GRAYSCALE; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Palette\PaletteInterface::pixelDefinition() + */ + public function pixelDefinition() + { + return array(ColorInterface::COLOR_GRAY); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Palette\PaletteInterface::supportsAlpha() + */ + public function supportsAlpha() + { + return true; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Palette\PaletteInterface::getChannelsMaxValue() + */ + public function getChannelsMaxValue() + { + return 255; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Palette\PaletteInterface::useProfile() + */ + public function useProfile(ProfileInterface $profile) + { + $this->profile = $profile; + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Palette\PaletteInterface::profile() + */ + public function profile() + { + if (!$this->profile) { + $this->profile = Profile::fromPath(__DIR__ . '/../../resources/colormanagement.org/ISOcoated_v2_grey1c_bas.ICC'); + } + + return $this->profile; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Palette\PaletteInterface::color() + */ + public function color($color, $alpha = null) + { + if (null === $alpha) { + $alpha = 0; + } + + $color = $this->parser->parseToGrayscale($color); + $index = sprintf('#%02x%02x%02x-%d', $color[0], $color[0], $color[0], $alpha); + + if (false === array_key_exists($index, static::$colors)) { + static::$colors[$index] = new GrayColor($this, $color, $alpha); + } + + return static::$colors[$index]; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Palette\PaletteInterface::blend() + */ + public function blend(ColorInterface $color1, ColorInterface $color2, $amount) + { + if (!$color1 instanceof GrayColor || !$color2 instanceof GrayColor) { + throw new RuntimeException('Grayscale palette can only blend Grayscale colors'); + } + $max = $this->getChannelsMaxValue(); + + return $this->color( + array( + (int) min($max, min($color1->getGray(), $color2->getGray()) + round(abs($color2->getGray() - $color1->getGray()) * $amount)), + ), + (int) min(100, min($color1->getAlpha(), $color2->getAlpha()) + round(abs($color2->getAlpha() - $color1->getAlpha()) * $amount)) + ); + } +} diff --git a/vendor/imagine/imagine/src/Image/Palette/PaletteInterface.php b/vendor/imagine/imagine/src/Image/Palette/PaletteInterface.php new file mode 100644 index 0000000..adcb5dd --- /dev/null +++ b/vendor/imagine/imagine/src/Image/Palette/PaletteInterface.php @@ -0,0 +1,112 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Image\Palette; + +use Imagine\Image\Palette\Color\ColorInterface; +use Imagine\Image\ProfileInterface; + +/** + * Interface that any palette must implement. + */ +interface PaletteInterface +{ + /** + * Palette name: grayscale. + * + * @var string + */ + const PALETTE_GRAYSCALE = 'gray'; + + /** + * Palette name: RGB. + * + * @var string + */ + const PALETTE_RGB = 'rgb'; + + /** + * Palette name: CMYK. + * + * @var string + */ + const PALETTE_CMYK = 'cmyk'; + + /** + * Returns a color given some values. + * + * @param string|int[]|int $color A color + * @param int|null $alpha Set alpha to null to disable it + * + * @throws \Imagine\Exception\InvalidArgumentException In case you pass an alpha value to a Palette that does not support alpha + * + * @return \Imagine\Image\Palette\Color\ColorInterface + */ + public function color($color, $alpha = null); + + /** + * Blend two colors given an amount. + * + * @param \Imagine\Image\Palette\Color\ColorInterface $color1 + * @param \Imagine\Image\Palette\Color\ColorInterface $color2 + * @param float $amount The amount of color2 in color1 + * + * @return \Imagine\Image\Palette\Color\ColorInterface + */ + public function blend(ColorInterface $color1, ColorInterface $color2, $amount); + + /** + * Attachs an ICC profile to this Palette. + * + * (A default profile is provided by default) + * + * @param \Imagine\Image\ProfileInterface $profile + * + * @return $this + */ + public function useProfile(ProfileInterface $profile); + + /** + * Returns the ICC profile attached to this Palette. + * + * @return \Imagine\Image\ProfileInterface + */ + public function profile(); + + /** + * Returns the name of this Palette, one of PaletteInterface::PALETTE_ constants. + * + * @return string + */ + public function name(); + + /** + * Returns an array containing ColorInterface::COLOR_* constants that + * define the structure of colors for a pixel. + * + * @return string[] + */ + public function pixelDefinition(); + + /** + * Tells if alpha channel is supported in this palette. + * + * @return bool + */ + public function supportsAlpha(); + + /** + * Get the max value of palette components (255 for RGB and Grayscale, 100 for CMYK). + * + * @return int + */ + public function getChannelsMaxValue(); +} diff --git a/vendor/imagine/imagine/src/Image/Palette/RGB.php b/vendor/imagine/imagine/src/Image/Palette/RGB.php new file mode 100644 index 0000000..c853dab --- /dev/null +++ b/vendor/imagine/imagine/src/Image/Palette/RGB.php @@ -0,0 +1,159 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Image\Palette; + +use Imagine\Exception\RuntimeException; +use Imagine\Image\Palette\Color\ColorInterface; +use Imagine\Image\Palette\Color\RGB as RGBColor; +use Imagine\Image\Profile; +use Imagine\Image\ProfileInterface; + +/** + * The RGB palette. + */ +class RGB implements PaletteInterface +{ + /** + * @var \Imagine\Image\Palette\ColorParser + */ + private $parser; + + /** + * @var \Imagine\Image\ProfileInterface|null + */ + private $profile; + + /** + * @var \Imagine\Image\Palette\Color\RGB[] + */ + protected static $colors = array(); + + public function __construct() + { + $this->parser = new ColorParser(); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Palette\PaletteInterface::name() + */ + public function name() + { + return PaletteInterface::PALETTE_RGB; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Palette\PaletteInterface::pixelDefinition() + */ + public function pixelDefinition() + { + return array( + ColorInterface::COLOR_RED, + ColorInterface::COLOR_GREEN, + ColorInterface::COLOR_BLUE, + ); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Palette\PaletteInterface::supportsAlpha() + */ + public function supportsAlpha() + { + return true; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Palette\PaletteInterface::getChannelsMaxValue() + */ + public function getChannelsMaxValue() + { + return 255; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Palette\PaletteInterface::useProfile() + */ + public function useProfile(ProfileInterface $profile) + { + $this->profile = $profile; + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Palette\PaletteInterface::profile() + */ + public function profile() + { + if (!$this->profile) { + $this->profile = Profile::fromPath(__DIR__ . '/../../resources/color.org/sRGB_IEC61966-2-1_black_scaled.icc'); + } + + return $this->profile; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Palette\PaletteInterface::color() + */ + public function color($color, $alpha = null) + { + if (null === $alpha) { + $alpha = 100; + } + + $color = $this->parser->parseToRGB($color); + $index = sprintf('#%02x%02x%02x-%d', $color[0], $color[1], $color[2], $alpha); + + if (false === array_key_exists($index, static::$colors)) { + static::$colors[$index] = new RGBColor($this, $color, $alpha); + } + + return static::$colors[$index]; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\Palette\PaletteInterface::blend() + */ + public function blend(ColorInterface $color1, ColorInterface $color2, $amount) + { + if (!$color1 instanceof RGBColor || !$color2 instanceof RGBColor) { + throw new RuntimeException('RGB palette can only blend RGB colors'); + } + $amount = (float) $amount; + $amountComplement = 1 - $amount; + $max = $this->getChannelsMaxValue(); + + return $this->color( + array( + min(max((int) round($color2->getRed() * $amount + $color1->getRed() * $amountComplement), 0), $max), + min(max((int) round($color2->getGreen() * $amount + $color1->getGreen() * $amountComplement), 0), $max), + min(max((int) round($color2->getBlue() * $amount + $color1->getBlue() * $amountComplement), 0), $max), + ), + min(max((int) round($color2->getAlpha() * $amount + $color1->getAlpha() * $amountComplement), 0), 100) + ); + } +} diff --git a/vendor/imagine/imagine/src/Image/Point.php b/vendor/imagine/imagine/src/Image/Point.php new file mode 100644 index 0000000..6119b0e --- /dev/null +++ b/vendor/imagine/imagine/src/Image/Point.php @@ -0,0 +1,98 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Image; + +use Imagine\Exception\InvalidArgumentException; + +/** + * The point class. + */ +final class Point implements PointInterface +{ + /** + * @var int + */ + private $x; + + /** + * @var int + */ + private $y; + + /** + * Constructs a point of coordinates. + * + * @param int $x + * @param int $y + * + * @throws \Imagine\Exception\InvalidArgumentException + */ + public function __construct($x, $y) + { + if ($x < 0 || $y < 0) { + throw new InvalidArgumentException(sprintf('A coordinate cannot be positioned outside of a bounding box (x: %s, y: %s given)', $x, $y)); + } + + $this->x = $x; + $this->y = $y; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\PointInterface::getX() + */ + public function getX() + { + return $this->x; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\PointInterface::getY() + */ + public function getY() + { + return $this->y; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\PointInterface::in() + */ + public function in(BoxInterface $box) + { + return $this->x < $box->getWidth() && $this->y < $box->getHeight(); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\PointInterface::move() + */ + public function move($amount) + { + return new self($this->x + $amount, $this->y + $amount); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\PointInterface::__toString() + */ + public function __toString() + { + return sprintf('(%d, %d)', $this->x, $this->y); + } +} diff --git a/vendor/imagine/imagine/src/Image/Point/Center.php b/vendor/imagine/imagine/src/Image/Point/Center.php new file mode 100644 index 0000000..044bd36 --- /dev/null +++ b/vendor/imagine/imagine/src/Image/Point/Center.php @@ -0,0 +1,87 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Image\Point; + +use Imagine\Image\BoxInterface; +use Imagine\Image\Point as OriginalPoint; +use Imagine\Image\PointInterface; + +/** + * Center point of a box. + */ +final class Center implements PointInterface +{ + /** + * @var \Imagine\Image\BoxInterface + */ + private $box; + + /** + * Constructs coordinate with size instance, it needs to be relative to. + * + * @param \Imagine\Image\BoxInterface $box + */ + public function __construct(BoxInterface $box) + { + $this->box = $box; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\PointInterface::getX() + */ + public function getX() + { + return ceil($this->box->getWidth() / 2); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\PointInterface::getY() + */ + public function getY() + { + return ceil($this->box->getHeight() / 2); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\PointInterface::in() + */ + public function in(BoxInterface $box) + { + return $this->getX() < $box->getWidth() && $this->getY() < $box->getHeight(); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\PointInterface::move() + */ + public function move($amount) + { + return new OriginalPoint($this->getX() + $amount, $this->getY() + $amount); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\PointInterface::__toString() + */ + public function __toString() + { + return sprintf('(%d, %d)', $this->getX(), $this->getY()); + } +} diff --git a/vendor/imagine/imagine/src/Image/PointInterface.php b/vendor/imagine/imagine/src/Image/PointInterface.php new file mode 100644 index 0000000..9a62c22 --- /dev/null +++ b/vendor/imagine/imagine/src/Image/PointInterface.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Image; + +/** + * The point interface. + */ +interface PointInterface +{ + /** + * Gets points x coordinate. + * + * @return int + */ + public function getX(); + + /** + * Gets points y coordinate. + * + * @return int + */ + public function getY(); + + /** + * Checks if current coordinate is inside a given box. + * + * @param \Imagine\Image\BoxInterface $box + * + * @return bool + */ + public function in(BoxInterface $box); + + /** + * Returns another point, moved by a given amount from current coordinates. + * + * @param int $amount + * + * @return \Imagine\Image\PointInterface + */ + public function move($amount); + + /** + * Gets a string representation for the current point. + * + * @return string + */ + public function __toString(); +} diff --git a/vendor/imagine/imagine/src/Image/PointSigned.php b/vendor/imagine/imagine/src/Image/PointSigned.php new file mode 100644 index 0000000..f8ef8f3 --- /dev/null +++ b/vendor/imagine/imagine/src/Image/PointSigned.php @@ -0,0 +1,92 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Image; + +/** + * A point class that allows negative values of coordinates. + */ +final class PointSigned implements PointInterface +{ + /** + * @var int + */ + private $x; + + /** + * @var int + */ + private $y; + + /** + * Constructs a point of coordinates. + * + * @param int $x + * @param int $y + * + * @throws \Imagine\Exception\InvalidArgumentException + */ + public function __construct($x, $y) + { + $this->x = $x; + $this->y = $y; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\PointInterface::getX() + */ + public function getX() + { + return $this->x; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\PointInterface::getY() + */ + public function getY() + { + return $this->y; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\PointInterface::in() + */ + public function in(BoxInterface $box) + { + return 0 <= $this->x && $this->x < $box->getWidth() && 0 <= $this->y && $this->y < $box->getHeight(); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\PointInterface::move() + */ + public function move($amount) + { + return new self($this->x + $amount, $this->y + $amount); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\PointInterface::__toString() + */ + public function __toString() + { + return sprintf('(%d, %d)', $this->x, $this->y); + } +} diff --git a/vendor/imagine/imagine/src/Image/Profile.php b/vendor/imagine/imagine/src/Image/Profile.php new file mode 100644 index 0000000..a57ff3f --- /dev/null +++ b/vendor/imagine/imagine/src/Image/Profile.php @@ -0,0 +1,78 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Image; + +use Imagine\Exception\InvalidArgumentException; + +/** + * The default implementation of ProfileInterface. + */ +class Profile implements ProfileInterface +{ + /** + * @var string + */ + private $data; + + /** + * @var string + */ + private $name; + + /** + * @param string $name + * @param string $data + */ + public function __construct($name, $data) + { + $this->name = $name; + $this->data = $data; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ProfileInterface::name() + */ + public function name() + { + return $this->name; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ProfileInterface::data() + */ + public function data() + { + return $this->data; + } + + /** + * Creates a profile from a path to a file. + * + * @param string $path + * + * @throws \Imagine\Exception\InvalidArgumentException In case the provided path is not valid + * + * @return static + */ + public static function fromPath($path) + { + if (!file_exists($path) || !is_file($path) || !is_readable($path)) { + throw new InvalidArgumentException(sprintf('Path %s is an invalid profile file or is not readable', $path)); + } + + return new static(basename($path), file_get_contents($path)); + } +} diff --git a/vendor/imagine/imagine/src/Image/ProfileInterface.php b/vendor/imagine/imagine/src/Image/ProfileInterface.php new file mode 100644 index 0000000..f96141c --- /dev/null +++ b/vendor/imagine/imagine/src/Image/ProfileInterface.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Image; + +interface ProfileInterface +{ + /** + * Returns the name of the profile. + * + * @return string + */ + public function name(); + + /** + * Returns the profile data. + * + * @return string + */ + public function data(); +} diff --git a/vendor/imagine/imagine/src/Imagick/Drawer.php b/vendor/imagine/imagine/src/Imagick/Drawer.php new file mode 100644 index 0000000..c972d3b --- /dev/null +++ b/vendor/imagine/imagine/src/Imagick/Drawer.php @@ -0,0 +1,474 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Imagick; + +use Imagine\Draw\DrawerInterface; +use Imagine\Exception\InvalidArgumentException; +use Imagine\Exception\RuntimeException; +use Imagine\Image\AbstractFont; +use Imagine\Image\Box; +use Imagine\Image\BoxInterface; +use Imagine\Image\Palette\Color\ColorInterface; +use Imagine\Image\Point; +use Imagine\Image\PointInterface; + +/** + * Drawer implementation using the Imagick PHP extension. + */ +final class Drawer implements DrawerInterface +{ + /** + * @var \Imagick + */ + private $imagick; + + /** + * @param \Imagick $imagick + */ + public function __construct(\Imagick $imagick) + { + $this->imagick = $imagick; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Draw\DrawerInterface::arc() + */ + public function arc(PointInterface $center, BoxInterface $size, $start, $end, ColorInterface $color, $thickness = 1) + { + $thickness = max(0, (int) round($thickness)); + if ($thickness === 0) { + return $this; + } + $x = $center->getX(); + $y = $center->getY(); + $width = $size->getWidth(); + $height = $size->getHeight(); + + try { + $pixel = $this->getColor($color); + $arc = new \ImagickDraw(); + + $arc->setStrokeColor($pixel); + $arc->setStrokeWidth($thickness); + $arc->setFillColor('transparent'); + $arc->arc($x - $width / 2, $y - $height / 2, $x + $width / 2, $y + $height / 2, $start, $end); + + $this->imagick->drawImage($arc); + + $pixel->clear(); + $pixel->destroy(); + + $arc->clear(); + $arc->destroy(); + } catch (\ImagickException $e) { + throw new RuntimeException('Draw arc operation failed', $e->getCode(), $e); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Draw\DrawerInterface::chord() + */ + public function chord(PointInterface $center, BoxInterface $size, $start, $end, ColorInterface $color, $fill = false, $thickness = 1) + { + $thickness = max(0, (int) round($thickness)); + if ($thickness === 0 && !$fill) { + return $this; + } + $x = $center->getX(); + $y = $center->getY(); + $width = $size->getWidth(); + $height = $size->getHeight(); + + try { + $pixel = $this->getColor($color); + $chord = new \ImagickDraw(); + + $chord->setStrokeColor($pixel); + $chord->setStrokeWidth($thickness); + + if ($fill) { + $chord->setFillColor($pixel); + } else { + $from = new Point(round($x + $width / 2 * cos(deg2rad($start))), round($y + $height / 2 * sin(deg2rad($start)))); + $to = new Point(round($x + $width / 2 * cos(deg2rad($end))), round($y + $height / 2 * sin(deg2rad($end)))); + $this->line($from, $to, $color, $thickness); + $chord->setFillColor('transparent'); + } + + $chord->arc( + $x - $width / 2, + $y - $height / 2, + $x + $width / 2, + $y + $height / 2, + $start, + $end + ); + + $this->imagick->drawImage($chord); + + $pixel->clear(); + $pixel->destroy(); + + $chord->clear(); + $chord->destroy(); + } catch (\ImagickException $e) { + throw new RuntimeException('Draw chord operation failed', $e->getCode(), $e); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Draw\DrawerInterface::circle() + */ + public function circle(PointInterface $center, $radius, ColorInterface $color, $fill = false, $thickness = 1) + { + $diameter = $radius * 2; + + return $this->ellipse($center, new Box($diameter, $diameter), $color, $fill, $thickness); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Draw\DrawerInterface::ellipse() + */ + public function ellipse(PointInterface $center, BoxInterface $size, ColorInterface $color, $fill = false, $thickness = 1) + { + $thickness = max(0, (int) round($thickness)); + if ($thickness === 0 && !$fill) { + return $this; + } + $width = $size->getWidth(); + $height = $size->getHeight(); + try { + $pixel = $this->getColor($color); + $ellipse = new \ImagickDraw(); + + $ellipse->setStrokeColor($pixel); + $ellipse->setStrokeWidth($thickness); + + if ($fill) { + $ellipse->setFillColor($pixel); + } else { + $ellipse->setFillColor('transparent'); + } + + $ellipse->ellipse( + $center->getX(), + $center->getY(), + $width / 2, + $height / 2, + 0, 360 + ); + + if (false === $this->imagick->drawImage($ellipse)) { + throw new RuntimeException('Ellipse operation failed'); + } + + $pixel->clear(); + $pixel->destroy(); + + $ellipse->clear(); + $ellipse->destroy(); + } catch (\ImagickException $e) { + throw new RuntimeException('Draw ellipse operation failed', $e->getCode(), $e); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Draw\DrawerInterface::line() + */ + public function line(PointInterface $start, PointInterface $end, ColorInterface $color, $thickness = 1) + { + $thickness = max(0, (int) round($thickness)); + if ($thickness === 0) { + return $this; + } + try { + $pixel = $this->getColor($color); + $line = new \ImagickDraw(); + + $line->setStrokeColor($pixel); + $line->setStrokeWidth($thickness); + $line->setFillColor($pixel); + $line->line( + $start->getX(), + $start->getY(), + $end->getX(), + $end->getY() + ); + + $this->imagick->drawImage($line); + + $pixel->clear(); + $pixel->destroy(); + + $line->clear(); + $line->destroy(); + } catch (\ImagickException $e) { + throw new RuntimeException('Draw line operation failed', $e->getCode(), $e); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Draw\DrawerInterface::pieSlice() + */ + public function pieSlice(PointInterface $center, BoxInterface $size, $start, $end, ColorInterface $color, $fill = false, $thickness = 1) + { + $thickness = max(0, (int) round($thickness)); + if ($thickness === 0 && !$fill) { + return $this; + } + $width = $size->getWidth(); + $height = $size->getHeight(); + + $x1 = round($center->getX() + $width / 2 * cos(deg2rad($start))); + $y1 = round($center->getY() + $height / 2 * sin(deg2rad($start))); + $x2 = round($center->getX() + $width / 2 * cos(deg2rad($end))); + $y2 = round($center->getY() + $height / 2 * sin(deg2rad($end))); + + if ($fill) { + $this->chord($center, $size, $start, $end, $color, true, $thickness); + $this->polygon( + array( + $center, + new Point($x1, $y1), + new Point($x2, $y2), + ), + $color, + true, + $thickness + ); + } else { + $this->arc($center, $size, $start, $end, $color, $thickness); + $this->line($center, new Point($x1, $y1), $color, $thickness); + $this->line($center, new Point($x2, $y2), $color, $thickness); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Draw\DrawerInterface::dot() + */ + public function dot(PointInterface $position, ColorInterface $color) + { + $x = $position->getX(); + $y = $position->getY(); + + try { + $pixel = $this->getColor($color); + $point = new \ImagickDraw(); + + $point->setFillColor($pixel); + $point->point($x, $y); + + $this->imagick->drawimage($point); + + $pixel->clear(); + $pixel->destroy(); + + $point->clear(); + $point->destroy(); + } catch (\ImagickException $e) { + throw new RuntimeException('Draw point operation failed', $e->getCode(), $e); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Draw\DrawerInterface::rectangle() + */ + public function rectangle(PointInterface $leftTop, PointInterface $rightBottom, ColorInterface $color, $fill = false, $thickness = 1) + { + $thickness = max(0, (int) round($thickness)); + if ($thickness === 0 && !$fill) { + return $this; + } + $minX = min($leftTop->getX(), $rightBottom->getX()); + $maxX = max($leftTop->getX(), $rightBottom->getX()); + $minY = min($leftTop->getY(), $rightBottom->getY()); + $maxY = max($leftTop->getY(), $rightBottom->getY()); + + try { + $pixel = $this->getColor($color); + $rectangle = new \ImagickDraw(); + $rectangle->setStrokeColor($pixel); + $rectangle->setStrokeWidth($thickness); + + if ($fill) { + $rectangle->setFillColor($pixel); + } else { + $rectangle->setFillColor('transparent'); + } + + $rectangle->rectangle($minX, $minY, $maxX, $maxY); + $this->imagick->drawImage($rectangle); + + $pixel->clear(); + $pixel->destroy(); + + $rectangle->clear(); + $rectangle->destroy(); + } catch (\ImagickException $e) { + throw new RuntimeException('Draw rectangle operation failed', $e->getCode(), $e); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Draw\DrawerInterface::polygon() + */ + public function polygon(array $coordinates, ColorInterface $color, $fill = false, $thickness = 1) + { + if (count($coordinates) < 3) { + throw new InvalidArgumentException(sprintf('Polygon must consist of at least 3 coordinates, %d given', count($coordinates))); + } + + $thickness = max(0, (int) round($thickness)); + if ($thickness === 0 && !$fill) { + return $this; + } + $points = array_map(function (PointInterface $p) { + return array('x' => $p->getX(), 'y' => $p->getY()); + }, $coordinates); + + try { + $pixel = $this->getColor($color); + $polygon = new \ImagickDraw(); + + $polygon->setStrokeColor($pixel); + $polygon->setStrokeWidth($thickness); + + if ($fill) { + $polygon->setFillColor($pixel); + } else { + $polygon->setFillColor('transparent'); + } + + $polygon->polygon($points); + $this->imagick->drawImage($polygon); + + $pixel->clear(); + $pixel->destroy(); + + $polygon->clear(); + $polygon->destroy(); + } catch (\ImagickException $e) { + throw new RuntimeException('Draw polygon operation failed', $e->getCode(), $e); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Draw\DrawerInterface::text() + */ + public function text($string, AbstractFont $font, PointInterface $position, $angle = 0, $width = null) + { + try { + $pixel = $this->getColor($font->getColor()); + $text = new \ImagickDraw(); + + $text->setFont($font->getFile()); + /* + * @see http://www.php.net/manual/en/imagick.queryfontmetrics.php#101027 + * + * ensure font resolution is the same as GD's hard-coded 96 + */ + if (version_compare(phpversion('imagick'), '3.0.2', '>=')) { + $text->setResolution(96, 96); + $text->setFontSize($font->getSize()); + } else { + $text->setFontSize((int) ($font->getSize() * (96 / 72))); + } + $text->setFillColor($pixel); + $text->setTextAntialias(true); + + if ($width !== null) { + $string = $font->wrapText($string, $width, $angle); + } + + $info = $this->imagick->queryFontMetrics($text, $string); + $rad = deg2rad($angle); + $cos = cos($rad); + $sin = sin($rad); + + // round(0 * $cos - 0 * $sin) + $x1 = 0; + $x2 = round($info['characterWidth'] * $cos - $info['characterHeight'] * $sin); + // round(0 * $sin + 0 * $cos) + $y1 = 0; + $y2 = round($info['characterWidth'] * $sin + $info['characterHeight'] * $cos); + + $xdiff = 0 - min($x1, $x2); + $ydiff = 0 - min($y1, $y2); + + $this->imagick->annotateImage( + $text, $position->getX() + $x1 + $xdiff, + $position->getY() + $y2 + $ydiff, $angle, $string + ); + + $pixel->clear(); + $pixel->destroy(); + + $text->clear(); + $text->destroy(); + } catch (\ImagickException $e) { + throw new RuntimeException('Draw text operation failed', $e->getCode(), $e); + } + + return $this; + } + + /** + * Gets specifically formatted color string from ColorInterface instance. + * + * @param \Imagine\Image\Palette\Color\ColorInterface $color + * + * @return string + */ + private function getColor(ColorInterface $color) + { + $pixel = new \ImagickPixel((string) $color); + $pixel->setColorValue(\Imagick::COLOR_ALPHA, $color->getAlpha() / 100); + + return $pixel; + } +} diff --git a/vendor/imagine/imagine/src/Imagick/Effects.php b/vendor/imagine/imagine/src/Imagick/Effects.php new file mode 100644 index 0000000..8a72628 --- /dev/null +++ b/vendor/imagine/imagine/src/Imagick/Effects.php @@ -0,0 +1,189 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Imagick; + +use Imagine\Effects\EffectsInterface; +use Imagine\Exception\InvalidArgumentException; +use Imagine\Exception\NotSupportedException; +use Imagine\Exception\RuntimeException; +use Imagine\Image\Palette\Color\ColorInterface; +use Imagine\Image\Palette\Color\RGB; +use Imagine\Utils\Matrix; + +/** + * Effects implementation using the Imagick PHP extension. + */ +class Effects implements EffectsInterface +{ + /** + * @var \Imagick + */ + private $imagick; + + /** + * Initialize the instance. + * + * @param \Imagick $imagick + */ + public function __construct(\Imagick $imagick) + { + $this->imagick = $imagick; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Effects\EffectsInterface::gamma() + */ + public function gamma($correction) + { + try { + $this->imagick->gammaImage($correction, \Imagick::CHANNEL_ALL); + } catch (\ImagickException $e) { + throw new RuntimeException('Failed to apply gamma correction to the image', $e->getCode(), $e); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Effects\EffectsInterface::negative() + */ + public function negative() + { + try { + $this->imagick->negateImage(false, \Imagick::CHANNEL_ALL); + } catch (\ImagickException $e) { + throw new RuntimeException('Failed to negate the image', $e->getCode(), $e); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Effects\EffectsInterface::grayscale() + */ + public function grayscale() + { + try { + $this->imagick->setImageType(\Imagick::IMGTYPE_GRAYSCALE); + } catch (\ImagickException $e) { + throw new RuntimeException('Failed to grayscale the image', $e->getCode(), $e); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Effects\EffectsInterface::colorize() + */ + public function colorize(ColorInterface $color) + { + if (!$color instanceof RGB) { + throw new NotSupportedException('Colorize with non-rgb color is not supported'); + } + + try { + $this->imagick->colorizeImage((string) $color, new \ImagickPixel(sprintf('rgba(%d, %d, %d, 1)', $color->getRed(), $color->getGreen(), $color->getBlue()))); + } catch (\ImagickException $e) { + throw new RuntimeException('Failed to colorize the image', $e->getCode(), $e); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Effects\EffectsInterface::sharpen() + */ + public function sharpen() + { + try { + $this->imagick->sharpenImage(2, 1); + } catch (\ImagickException $e) { + throw new RuntimeException('Failed to sharpen the image', $e->getCode(), $e); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Effects\EffectsInterface::blur() + */ + public function blur($sigma = 1) + { + try { + $this->imagick->gaussianBlurImage(0, $sigma); + } catch (\ImagickException $e) { + throw new RuntimeException('Failed to blur the image', $e->getCode(), $e); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Effects\EffectsInterface::brightness() + */ + public function brightness($brightness) + { + $brightness = (int) round($brightness); + if ($brightness < -100 || $brightness > 100) { + throw new InvalidArgumentException(sprintf('The %1$s argument can range from %2$d to %3$d, but you specified %4$d.', '$brightness', -100, 100, $brightness)); + } + try { + if (method_exists($this->imagick, 'brightnesscontrastimage')) { + // Available since Imagick 3.3.0 + $this->imagick->brightnesscontrastimage($brightness, 0); + } else { + // This *emulates* brightnesscontrastimage + $sign = $brightness < 0 ? -1 : 1; + $v = abs($brightness) / 100; + $v = (1 / (sin(($v * .99999 * M_PI_2) + M_PI_2))) - 1; + $this->imagick->modulateimage(100 + $sign * $v * 100, 100, 100); + } + } catch (\ImagickException $e) { + throw new RuntimeException('Failed to brightness the image'); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Effects\EffectsInterface::convolve() + */ + public function convolve(Matrix $matrix) + { + if ($matrix->getWidth() !== 3 || $matrix->getHeight() !== 3) { + throw new InvalidArgumentException(sprintf('A convolution matrix must be 3x3 (%dx%d provided).', $matrix->getWidth(), $matrix->getHeight())); + } + try { + $this->imagick->convolveImage($matrix->getValueList()); + } catch (\ImagickException $e) { + throw new RuntimeException('Failed to convolve the image'); + } + + return $this; + } +} diff --git a/vendor/imagine/imagine/src/Imagick/Font.php b/vendor/imagine/imagine/src/Imagick/Font.php new file mode 100644 index 0000000..3edd261 --- /dev/null +++ b/vendor/imagine/imagine/src/Imagick/Font.php @@ -0,0 +1,69 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Imagick; + +use Imagine\Image\AbstractFont; +use Imagine\Image\Palette\Color\ColorInterface; + +/** + * Font implementation using the Imagick PHP extension. + */ +final class Font extends AbstractFont +{ + /** + * @var \Imagick + */ + private $imagick; + + /** + * @param \Imagick $imagick + * @param string $file + * @param int $size + * @param \Imagine\Image\Palette\Color\ColorInterface $color + */ + public function __construct(\Imagick $imagick, $file, $size, ColorInterface $color) + { + $this->imagick = $imagick; + + parent::__construct($file, $size, $color); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\FontInterface::box() + */ + public function box($string, $angle = 0) + { + $text = new \ImagickDraw(); + + $text->setFont($this->file); + + /* + * @see http://www.php.net/manual/en/imagick.queryfontmetrics.php#101027 + * + * ensure font resolution is the same as GD's hard-coded 96 + */ + if (version_compare(phpversion('imagick'), '3.0.2', '>=')) { + $text->setResolution(96, 96); + $text->setFontSize($this->size); + } else { + $text->setFontSize((int) ($this->size * (96 / 72))); + } + + $info = $this->imagick->queryFontMetrics($text, $string); + + $box = $this->getClassFactory()->createBox($info['textWidth'], $info['textHeight']); + + return $box; + } +} diff --git a/vendor/imagine/imagine/src/Imagick/Image.php b/vendor/imagine/imagine/src/Imagick/Image.php new file mode 100644 index 0000000..f991a89 --- /dev/null +++ b/vendor/imagine/imagine/src/Imagick/Image.php @@ -0,0 +1,1081 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Imagick; + +use Imagine\Exception\InvalidArgumentException; +use Imagine\Exception\OutOfBoundsException; +use Imagine\Exception\RuntimeException; +use Imagine\Factory\ClassFactoryInterface; +use Imagine\Image\AbstractImage; +use Imagine\Image\BoxInterface; +use Imagine\Image\Fill\FillInterface; +use Imagine\Image\Fill\Gradient\Horizontal; +use Imagine\Image\Fill\Gradient\Linear; +use Imagine\Image\ImageInterface; +use Imagine\Image\Metadata\MetadataBag; +use Imagine\Image\Palette\Color\ColorInterface; +use Imagine\Image\Palette\PaletteInterface; +use Imagine\Image\Point; +use Imagine\Image\PointInterface; +use Imagine\Image\ProfileInterface; +use Imagine\Utils\ErrorHandling; + +/** + * Image implementation using the Imagick PHP extension. + */ +final class Image extends AbstractImage +{ + /** + * @var \Imagick + */ + private $imagick; + + /** + * @var \Imagine\Imagick\Layers|null + */ + private $layers; + + /** + * @var \Imagine\Image\Palette\PaletteInterface + */ + private $palette; + + /** + * @var bool + */ + private static $supportsColorspaceConversion; + + /** + * @var bool + */ + private static $supportsProfiles; + + /** + * @var array + */ + private static $colorspaceMapping = array( + PaletteInterface::PALETTE_CMYK => \Imagick::COLORSPACE_CMYK, + PaletteInterface::PALETTE_RGB => \Imagick::COLORSPACE_RGB, + PaletteInterface::PALETTE_GRAYSCALE => \Imagick::COLORSPACE_GRAY, + ); + + /** + * Constructs a new Image instance. + * + * @param \Imagick $imagick + * @param \Imagine\Image\Palette\PaletteInterface $palette + * @param \Imagine\Image\Metadata\MetadataBag $metadata + */ + public function __construct(\Imagick $imagick, PaletteInterface $palette, MetadataBag $metadata) + { + $this->metadata = $metadata; + $this->detectColorspaceConversionSupport(); + $this->imagick = $imagick; + if (static::$supportsColorspaceConversion) { + $this->setColorspace($palette); + } + $this->palette = $palette; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\AbstractImage::__clone() + */ + public function __clone() + { + parent::__clone(); + if ($this->imagick instanceof \Imagick) { + $this->imagick = $this->cloneImagick(); + } + $this->palette = clone $this->palette; + if ($this->layers !== null) { + $this->layers = $this->getClassFactory()->createLayers(ClassFactoryInterface::HANDLE_IMAGICK, $this, $this->layers->key()); + } + } + + /** + * Destroys allocated imagick resources. + */ + public function __destruct() + { + if ($this->imagick instanceof \Imagick) { + $this->imagick->clear(); + $this->imagick->destroy(); + } + } + + /** + * Returns the underlying \Imagick instance. + * + * @return \Imagick + */ + public function getImagick() + { + return $this->imagick; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ManipulatorInterface::copy() + */ + public function copy() + { + try { + return clone $this; + } catch (\ImagickException $e) { + throw new RuntimeException('Copy operation failed', $e->getCode(), $e); + } + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ManipulatorInterface::crop() + */ + public function crop(PointInterface $start, BoxInterface $size) + { + if (!$start->in($this->getSize())) { + throw new OutOfBoundsException('Crop coordinates must start at minimum 0, 0 position from top left corner, crop height and width must be positive integers and must not exceed the current image borders'); + } + try { + if ($this->layers()->count() > 1) { + // Crop each layer separately + $this->imagick = $this->imagick->coalesceImages(); + foreach ($this->imagick as $frame) { + $frame->cropImage($size->getWidth(), $size->getHeight(), $start->getX(), $start->getY()); + // Reset canvas for gif format + $frame->setImagePage(0, 0, 0, 0); + } + $this->imagick = $this->imagick->deconstructImages(); + } else { + $this->imagick->cropImage($size->getWidth(), $size->getHeight(), $start->getX(), $start->getY()); + // Reset canvas for gif format + $this->imagick->setImagePage(0, 0, 0, 0); + } + } catch (\ImagickException $e) { + throw new RuntimeException('Crop operation failed', $e->getCode(), $e); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ManipulatorInterface::flipHorizontally() + */ + public function flipHorizontally() + { + try { + $this->imagick->flopImage(); + } catch (\ImagickException $e) { + throw new RuntimeException('Horizontal Flip operation failed', $e->getCode(), $e); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ManipulatorInterface::flipVertically() + */ + public function flipVertically() + { + try { + $this->imagick->flipImage(); + } catch (\ImagickException $e) { + throw new RuntimeException('Vertical flip operation failed', $e->getCode(), $e); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ManipulatorInterface::strip() + */ + public function strip() + { + try { + try { + $this->profile($this->palette->profile()); + } catch (\Exception $e) { + // here we discard setting the profile as the previous incorporated profile + // is corrupted, let's now strip the image + } + $this->imagick->stripImage(); + } catch (\ImagickException $e) { + throw new RuntimeException('Strip operation failed', $e->getCode(), $e); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ManipulatorInterface::paste() + */ + public function paste(ImageInterface $image, PointInterface $start, $alpha = 100) + { + if (!$image instanceof self) { + throw new InvalidArgumentException(sprintf('Imagick\Image can only paste() Imagick\Image instances, %s given', get_class($image))); + } + + $alpha = (int) round($alpha); + if ($alpha < 0 || $alpha > 100) { + throw new InvalidArgumentException(sprintf('The %1$s argument can range from %2$d to %3$d, but you specified %4$d.', '$alpha', 0, 100, $alpha)); + } + + if ($alpha === 100) { + $pasteMe = $image->imagick; + } elseif ($alpha > 0) { + $pasteMe = $image->cloneImagick(); + // setImageOpacity was replaced with setImageAlpha in php-imagick v3.4.3 + if (method_exists($pasteMe, 'setImageAlpha')) { + $pasteMe->setImageAlpha($alpha / 100); + } else { + ErrorHandling::ignoring(E_DEPRECATED, function () use ($pasteMe, $alpha) { + $pasteMe->setImageOpacity($alpha / 100); + }); + } + } else { + $pasteMe = null; + } + if ($pasteMe !== null) { + try { + $this->imagick->compositeImage($pasteMe, \Imagick::COMPOSITE_DEFAULT, $start->getX(), $start->getY()); + $error = null; + } catch (\ImagickException $e) { + $error = $e; + } + if ($pasteMe !== $image->imagick) { + $pasteMe->clear(); + $pasteMe->destroy(); + } + if ($error !== null) { + throw new RuntimeException('Paste operation failed', $error->getCode(), $error); + } + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ManipulatorInterface::resize() + */ + public function resize(BoxInterface $size, $filter = ImageInterface::FILTER_UNDEFINED) + { + try { + if ($this->layers()->count() > 1) { + $this->imagick = $this->imagick->coalesceImages(); + foreach ($this->imagick as $frame) { + $frame->resizeImage($size->getWidth(), $size->getHeight(), $this->getFilter($filter), 1); + } + $this->imagick = $this->imagick->deconstructImages(); + } else { + $this->imagick->resizeImage($size->getWidth(), $size->getHeight(), $this->getFilter($filter), 1); + } + } catch (\ImagickException $e) { + throw new RuntimeException('Resize operation failed', $e->getCode(), $e); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ManipulatorInterface::rotate() + */ + public function rotate($angle, ColorInterface $background = null) + { + if ($background === null) { + $background = $this->palette->color('fff'); + } + + try { + $pixel = $this->getColor($background); + + $this->imagick->rotateimage($pixel, $angle); + + $pixel->clear(); + $pixel->destroy(); + } catch (\ImagickException $e) { + throw new RuntimeException('Rotate operation failed', $e->getCode(), $e); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ManipulatorInterface::save() + */ + public function save($path = null, array $options = array()) + { + $path = null === $path ? $this->imagick->getImageFilename() : $path; + if (null === $path) { + throw new RuntimeException('You can omit save path only if image has been open from a file'); + } + + try { + $this->prepareOutput($options, $path); + $this->imagick->writeImages($path, true); + } catch (\ImagickException $e) { + throw new RuntimeException('Save operation failed', $e->getCode(), $e); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ManipulatorInterface::show() + */ + public function show($format, array $options = array()) + { + header('Content-type: ' . $this->getMimeType($format)); + echo $this->get($format, $options); + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImageInterface::get() + */ + public function get($format, array $options = array()) + { + try { + $options['format'] = $format; + $this->prepareOutput($options); + } catch (\ImagickException $e) { + throw new RuntimeException('Get operation failed', $e->getCode(), $e); + } + + return $this->imagick->getImagesBlob(); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImageInterface::interlace() + */ + public function interlace($scheme) + { + static $supportedInterlaceSchemes = array( + ImageInterface::INTERLACE_NONE => \Imagick::INTERLACE_NO, + ImageInterface::INTERLACE_LINE => \Imagick::INTERLACE_LINE, + ImageInterface::INTERLACE_PLANE => \Imagick::INTERLACE_PLANE, + ImageInterface::INTERLACE_PARTITION => \Imagick::INTERLACE_PARTITION, + ); + + if (!array_key_exists($scheme, $supportedInterlaceSchemes)) { + throw new InvalidArgumentException('Unsupported interlace type'); + } + + $this->imagick->setInterlaceScheme($supportedInterlaceSchemes[$scheme]); + + return $this; + } + + /** + * @param array $options + * @param string $path + */ + private function prepareOutput(array $options, $path = null) + { + if (isset($options['format'])) { + $this->imagick->setImageFormat($options['format']); + } + + if (isset($options['animated']) && true === $options['animated']) { + $format = isset($options['format']) ? $options['format'] : 'gif'; + $delay = isset($options['animated.delay']) ? $options['animated.delay'] : null; + $loops = isset($options['animated.loops']) ? $options['animated.loops'] : 0; + + $options['flatten'] = false; + + $this->layers()->animate($format, $delay, $loops); + } else { + $this->layers()->merge(); + } + $this->imagick = $this->applyImageOptions($this->imagick, $options, $path); + + // flatten only if image has multiple layers + if ((!isset($options['flatten']) || $options['flatten'] === true) && $this->layers()->count() > 1) { + $this->flatten(); + } + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImageInterface::__toString() + */ + public function __toString() + { + return $this->get('png'); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImageInterface::draw() + */ + public function draw() + { + return $this->getClassFactory()->createDrawer(ClassFactoryInterface::HANDLE_IMAGICK, $this->imagick); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImageInterface::effects() + */ + public function effects() + { + return $this->getClassFactory()->createEffects(ClassFactoryInterface::HANDLE_IMAGICK, $this->imagick); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImageInterface::getSize() + */ + public function getSize() + { + try { + $i = $this->imagick->getIteratorIndex(); + $this->imagick->rewind(); + $width = $this->imagick->getImageWidth(); + $height = $this->imagick->getImageHeight(); + $this->imagick->setIteratorIndex($i); + } catch (\ImagickException $e) { + throw new RuntimeException('Could not get size', $e->getCode(), $e); + } + + return $this->getClassFactory()->createBox($width, $height); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ManipulatorInterface::applyMask() + */ + public function applyMask(ImageInterface $mask) + { + if (!$mask instanceof self) { + throw new InvalidArgumentException('Can only apply instances of Imagine\Imagick\Image as masks'); + } + + $size = $this->getSize(); + $maskSize = $mask->getSize(); + + if ($size != $maskSize) { + throw new InvalidArgumentException(sprintf('The given mask doesn\'t match current image\'s size, Current mask\'s dimensions are %s, while image\'s dimensions are %s', $maskSize, $size)); + } + + $mask = $mask->mask(); + $mask->imagick->negateImage(true); + + try { + // remove transparent areas of the original from the mask + $mask->imagick->compositeImage($this->imagick, \Imagick::COMPOSITE_DSTIN, 0, 0); + $this->imagick->compositeImage($mask->imagick, \Imagick::COMPOSITE_COPYOPACITY, 0, 0); + + $mask->imagick->clear(); + $mask->imagick->destroy(); + } catch (\ImagickException $e) { + throw new RuntimeException('Apply mask operation failed', $e->getCode(), $e); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImageInterface::mask() + */ + public function mask() + { + $mask = $this->copy(); + + try { + $mask->imagick->modulateImage(100, 0, 100); + $mask->imagick->setImageMatte(false); + } catch (\ImagickException $e) { + throw new RuntimeException('Mask operation failed', $e->getCode(), $e); + } + + return $mask; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ManipulatorInterface::fill() + */ + public function fill(FillInterface $fill) + { + try { + if ($this->isLinearOpaque($fill)) { + $this->applyFastLinear($fill); + } else { + $iterator = $this->imagick->getPixelIterator(); + + foreach ($iterator as $y => $pixels) { + foreach ($pixels as $x => $pixel) { + $color = $fill->getColor(new Point($x, $y)); + + $pixel->setColor((string) $color); + $pixel->setColorValue(\Imagick::COLOR_ALPHA, $color->getAlpha() / 100); + } + + $iterator->syncIterator(); + } + } + } catch (\ImagickException $e) { + throw new RuntimeException('Fill operation failed', $e->getCode(), $e); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImageInterface::histogram() + */ + public function histogram() + { + try { + $pixels = $this->imagick->getImageHistogram(); + } catch (\ImagickException $e) { + throw new RuntimeException('Error while fetching histogram', $e->getCode(), $e); + } + + $image = $this; + + return array_map(function (\ImagickPixel $pixel) use ($image) { + return $image->pixelToColor($pixel); + }, $pixels); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImageInterface::getColorAt() + */ + public function getColorAt(PointInterface $point) + { + if (!$point->in($this->getSize())) { + throw new RuntimeException(sprintf('Error getting color at point [%s,%s]. The point must be inside the image of size [%s,%s]', $point->getX(), $point->getY(), $this->getSize()->getWidth(), $this->getSize()->getHeight())); + } + + try { + $pixel = $this->imagick->getImagePixelColor($point->getX(), $point->getY()); + } catch (\ImagickException $e) { + throw new RuntimeException('Error while getting image pixel color', $e->getCode(), $e); + } + + return $this->pixelToColor($pixel); + } + + /** + * Returns a color given a pixel, depending the Palette context. + * + * Note : this method is public for PHP 5.3 compatibility + * + * @param \ImagickPixel $pixel + * + * @throws \Imagine\Exception\InvalidArgumentException In case a unknown color is requested + * + * @return \Imagine\Image\Palette\Color\ColorInterface + */ + public function pixelToColor(\ImagickPixel $pixel) + { + static $colorMapping = array( + ColorInterface::COLOR_RED => \Imagick::COLOR_RED, + ColorInterface::COLOR_GREEN => \Imagick::COLOR_GREEN, + ColorInterface::COLOR_BLUE => \Imagick::COLOR_BLUE, + ColorInterface::COLOR_CYAN => \Imagick::COLOR_CYAN, + ColorInterface::COLOR_MAGENTA => \Imagick::COLOR_MAGENTA, + ColorInterface::COLOR_YELLOW => \Imagick::COLOR_YELLOW, + ColorInterface::COLOR_KEYLINE => \Imagick::COLOR_BLACK, + // There is no gray component in \Imagick, let's use one of the RGB comp + ColorInterface::COLOR_GRAY => \Imagick::COLOR_RED, + ); + + $alpha = $this->palette->supportsAlpha() ? (int) round($pixel->getColorValue(\Imagick::COLOR_ALPHA) * 100) : null; + if ($alpha) { + $alpha = min(max($alpha, 0), 100); + } + + $multiplier = $this->palette()->getChannelsMaxValue(); + + return $this->palette->color(array_map(function ($color) use ($multiplier, $pixel, $colorMapping) { + if (!isset($colorMapping[$color])) { + throw new InvalidArgumentException(sprintf('Color %s is not mapped in Imagick', $color)); + } + + return $pixel->getColorValue($colorMapping[$color]) * $multiplier; + }, $this->palette->pixelDefinition()), $alpha); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImageInterface::layers() + */ + public function layers() + { + if ($this->layers === null) { + $this->layers = $this->getClassFactory()->createLayers(ClassFactoryInterface::HANDLE_IMAGICK, $this); + } + + return $this->layers; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImageInterface::usePalette() + */ + public function usePalette(PaletteInterface $palette) + { + if (!isset(static::$colorspaceMapping[$palette->name()])) { + throw new InvalidArgumentException(sprintf('The palette %s is not supported by Imagick driver', $palette->name())); + } + + if ($this->palette->name() === $palette->name()) { + return $this; + } + + if (!static::$supportsColorspaceConversion) { + throw new RuntimeException('Your version of Imagick does not support colorspace conversions.'); + } + + try { + try { + $hasICCProfile = (bool) $this->imagick->getImageProfile('icc'); + } catch (\ImagickException $e) { + $hasICCProfile = false; + } + + if (!$hasICCProfile) { + $this->profile($this->palette->profile()); + } + + $this->profile($palette->profile()); + $this->setColorspace($palette); + } catch (\ImagickException $e) { + throw new RuntimeException('Failed to set colorspace', $e->getCode(), $e); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImageInterface::palette() + */ + public function palette() + { + return $this->palette; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImageInterface::profile() + */ + public function profile(ProfileInterface $profile) + { + if (!$this->detectProfilesSupport()) { + throw new RuntimeException(sprintf('Unable to add profile %s to image, be sure to compile imagemagick with `--with-lcms2` option', $profile->name())); + } + + try { + $this->imagick->profileImage('icc', $profile->data()); + } catch (\ImagickException $e) { + throw new RuntimeException(sprintf('Unable to add profile %s to image', $profile->name()), $e->getCode(), $e); + } + + return $this; + } + + /** + * Flatten the image. + */ + private function flatten() + { + /* + * @see https://github.com/mkoppanen/imagick/issues/45 + */ + try { + if (method_exists($this->imagick, 'mergeImageLayers') && defined('Imagick::LAYERMETHOD_UNDEFINED')) { + $this->imagick = $this->imagick->mergeImageLayers(\Imagick::LAYERMETHOD_UNDEFINED); + } elseif (method_exists($this->imagick, 'flattenImages')) { + $this->imagick = $this->imagick->flattenImages(); + } + } catch (\ImagickException $e) { + throw new RuntimeException('Flatten operation failed', $e->getCode(), $e); + } + } + + /** + * Applies options before save or output. + * + * @param \Imagick $image + * @param array $options + * @param string $path + * + * @throws \Imagine\Exception\InvalidArgumentException + * @throws \Imagine\Exception\RuntimeException + * + * @return \Imagick + */ + private function applyImageOptions(\Imagick $image, array $options, $path) + { + if (isset($options['format'])) { + $format = $options['format']; + } elseif ('' !== $extension = pathinfo($path, \PATHINFO_EXTENSION)) { + $format = $extension; + } else { + $format = pathinfo($image->getImageFilename(), \PATHINFO_EXTENSION); + } + + $format = strtolower($format); + + switch ($format) { + case 'jpeg': + case 'jpg': + case 'pjpeg': + if (!isset($options['jpeg_quality'])) { + if (isset($options['quality'])) { + $options['jpeg_quality'] = $options['quality']; + } + } + if (isset($options['jpeg_quality'])) { + $image->setimagecompressionquality($options['jpeg_quality']); + $image->setcompressionquality($options['jpeg_quality']); + } + if (isset($options['jpeg_sampling_factors'])) { + if (!is_array($options['jpeg_sampling_factors']) || \count($options['jpeg_sampling_factors']) < 1) { + throw new InvalidArgumentException('jpeg_sampling_factors option should be an array of integers'); + } + $image->setSamplingFactors(array_map(function ($factor) { + return (int) $factor; + }, $options['jpeg_sampling_factors'])); + } + break; + case 'png': + if (!isset($options['png_compression_level'])) { + if (isset($options['quality'])) { + $options['png_compression_level'] = round((100 - $options['quality']) * 9 / 100); + } + } + if (isset($options['png_compression_level'])) { + if ($options['png_compression_level'] < 0 || $options['png_compression_level'] > 9) { + throw new InvalidArgumentException('png_compression_level option should be an integer from 0 to 9'); + } + } + if (isset($options['png_compression_filter'])) { + if ($options['png_compression_filter'] < 0 || $options['png_compression_filter'] > 9) { + throw new InvalidArgumentException('png_compression_filter option should be an integer from 0 to 9'); + } + } + if (isset($options['png_compression_level']) || isset($options['png_compression_filter'])) { + // first digit: compression level (default: 7) + $compression = isset($options['png_compression_level']) ? $options['png_compression_level'] * 10 : 70; + // second digit: compression filter (default: 5) + $compression += isset($options['png_compression_filter']) ? $options['png_compression_filter'] : 5; + $image->setimagecompressionquality($compression); + $image->setcompressionquality($compression); + } + break; + case 'webp': + if (!isset($options['webp_quality'])) { + if (isset($options['quality'])) { + $options['webp_quality'] = $options['quality']; + } + } + if (isset($options['webp_quality'])) { + $image->setImageCompressionQuality($options['webp_quality']); + } + if (isset($options['webp_lossless'])) { + $image->setOption('webp:lossless', $options['webp_lossless']); + } + break; + } + if (isset($options['resolution-units']) && isset($options['resolution-x']) && isset($options['resolution-y'])) { + if (empty($options['resampling-filter'])) { + $filterName = ImageInterface::FILTER_UNDEFINED; + } else { + $filterName = $options['resampling-filter']; + } + $filter = $this->getFilter($filterName); + switch ($options['resolution-units']) { + case ImageInterface::RESOLUTION_PIXELSPERCENTIMETER: + $image->setImageUnits(\Imagick::RESOLUTION_PIXELSPERCENTIMETER); + break; + case ImageInterface::RESOLUTION_PIXELSPERINCH: + $image->setImageUnits(\Imagick::RESOLUTION_PIXELSPERINCH); + break; + default: + throw new RuntimeException('Unsupported image unit format'); + } + $image->setImageResolution($options['resolution-x'], $options['resolution-y']); + $image->resampleImage($options['resolution-x'], $options['resolution-y'], $filter, 0); + } + if (!empty($options['optimize'])) { + try { + $image = $image->coalesceImages(); + $optimized = $image->optimizeimagelayers(); + } catch (\ImagickException $e) { + throw new RuntimeException('Image optimization failed', $e->getCode(), $e); + } + if ($optimized === false) { + throw new RuntimeException('Image optimization failed'); + } + if ($optimized instanceof \Imagick) { + $image = $optimized; + } + } + + return $image; + } + + /** + * Gets specifically formatted color string from Color instance. + * + * @param \Imagine\Image\Palette\Color\ColorInterface $color + * + * @return \ImagickPixel + */ + private function getColor(ColorInterface $color) + { + $pixel = new \ImagickPixel((string) $color); + $pixel->setColorValue(\Imagick::COLOR_ALPHA, $color->getAlpha() / 100); + + return $pixel; + } + + /** + * Checks whether given $fill is linear and opaque. + * + * @param \Imagine\Image\Fill\FillInterface $fill + * + * @return bool + */ + private function isLinearOpaque(FillInterface $fill) + { + return $fill instanceof Linear && $fill->getStart()->isOpaque() && $fill->getEnd()->isOpaque(); + } + + /** + * Performs optimized gradient fill for non-opaque linear gradients. + * + * @param \Imagine\Image\Fill\Gradient\Linear $fill + */ + private function applyFastLinear(Linear $fill) + { + $gradient = new \Imagick(); + $size = $this->getSize(); + $color = sprintf('gradient:%s-%s', (string) $fill->getStart(), (string) $fill->getEnd()); + + if ($fill instanceof Horizontal) { + $gradient->newPseudoImage($size->getHeight(), $size->getWidth(), $color); + $gradient->rotateImage(new \ImagickPixel(), 90); + } else { + $gradient->newPseudoImage($size->getWidth(), $size->getHeight(), $color); + } + + $this->imagick->compositeImage($gradient, \Imagick::COMPOSITE_OVER, 0, 0); + $gradient->clear(); + $gradient->destroy(); + } + + /** + * Internal. + * + * Get the mime type based on format. + * + * @param string $format + * + * @throws \Imagine\Exception\RuntimeException + * + * @return string mime-type + */ + private function getMimeType($format) + { + static $mimeTypes = array( + 'jpeg' => 'image/jpeg', + 'jpg' => 'image/jpeg', + 'gif' => 'image/gif', + 'png' => 'image/png', + 'wbmp' => 'image/vnd.wap.wbmp', + 'xbm' => 'image/xbm', + 'webp' => 'image/webp', + 'bmp' => 'image/bmp', + ); + + if (!isset($mimeTypes[$format])) { + throw new RuntimeException(sprintf('Unsupported format given. Only %s are supported, %s given', implode(', ', array_keys($mimeTypes)), $format)); + } + + return $mimeTypes[$format]; + } + + /** + * Sets colorspace and image type, assigns the palette. + * + * @param \Imagine\Image\Palette\PaletteInterface $palette + * + * @throws \Imagine\Exception\InvalidArgumentException + */ + private function setColorspace(PaletteInterface $palette) + { + $typeMapping = array( + // We use Matte variants to preserve alpha + // + // (the IMGTYPE_...ALPHA constants are only available since ImageMagick 7 and Imagick 3.4.3, previously they were named + // IMGTYPE_...MATTE but in some combinations of different Imagick and ImageMagick versions none of them are avaiable at all, + // so we found no other way to fix it as to hard code the values here) + PaletteInterface::PALETTE_CMYK => defined('\Imagick::IMGTYPE_TRUECOLORALPHA') ? \Imagick::IMGTYPE_TRUECOLORALPHA : (defined('\Imagick::IMGTYPE_TRUECOLORMATTE') ? \Imagick::IMGTYPE_TRUECOLORMATTE : 7), + PaletteInterface::PALETTE_RGB => defined('\Imagick::IMGTYPE_TRUECOLORALPHA') ? \Imagick::IMGTYPE_TRUECOLORALPHA : (defined('\Imagick::IMGTYPE_TRUECOLORMATTE') ? \Imagick::IMGTYPE_TRUECOLORMATTE : 7), + PaletteInterface::PALETTE_GRAYSCALE => defined('\Imagick::IMGTYPE_GRAYSCALEALPHA') ? \Imagick::IMGTYPE_GRAYSCALEALPHA : (defined('\Imagick::IMGTYPE_GRAYSCALEMATTE') ? \Imagick::IMGTYPE_GRAYSCALEMATTE : 3), + ); + + if (!isset(static::$colorspaceMapping[$palette->name()])) { + throw new InvalidArgumentException(sprintf('The palette %s is not supported by Imagick driver', $palette->name())); + } + + $this->imagick->setType($typeMapping[$palette->name()]); + $this->imagick->setColorspace(static::$colorspaceMapping[$palette->name()]); + $this->palette = $palette; + } + + /** + * Older imagemagick versions does not support colorspace conversions. + * Let's detect if it is supported. + * + * @return bool + */ + private function detectColorspaceConversionSupport() + { + if (null !== static::$supportsColorspaceConversion) { + return static::$supportsColorspaceConversion; + } + + return static::$supportsColorspaceConversion = method_exists('Imagick', 'setColorspace'); + } + + /** + * ImageMagick without the lcms delegate cannot handle profiles well. + * This detection is needed because there is no way to directly check for lcms. + * + * @return bool + */ + private function detectProfilesSupport() + { + if (null !== self::$supportsProfiles) { + return self::$supportsProfiles; + } + + self::$supportsProfiles = false; + + try { + $image = new \Imagick(); + $image->newImage(1, 1, new \ImagickPixel('#fff')); + $image->profileImage('icc', 'x'); + } catch (\ImagickException $exception) { + // If ImageMagick has support for profiles, + // it detects the invalid profile data 'x' and throws an exception. + self::$supportsProfiles = true; + } + + return self::$supportsProfiles; + } + + /** + * Returns the filter if it's supported. + * + * @param string $filter + * + * @throws \Imagine\Exception\InvalidArgumentException if the filter is unsupported + * + * @return string + */ + private function getFilter($filter = ImageInterface::FILTER_UNDEFINED) + { + static $supportedFilters = array( + ImageInterface::FILTER_UNDEFINED => \Imagick::FILTER_UNDEFINED, + ImageInterface::FILTER_BESSEL => \Imagick::FILTER_BESSEL, + ImageInterface::FILTER_BLACKMAN => \Imagick::FILTER_BLACKMAN, + ImageInterface::FILTER_BOX => \Imagick::FILTER_BOX, + ImageInterface::FILTER_CATROM => \Imagick::FILTER_CATROM, + ImageInterface::FILTER_CUBIC => \Imagick::FILTER_CUBIC, + ImageInterface::FILTER_GAUSSIAN => \Imagick::FILTER_GAUSSIAN, + ImageInterface::FILTER_HANNING => \Imagick::FILTER_HANNING, + ImageInterface::FILTER_HAMMING => \Imagick::FILTER_HAMMING, + ImageInterface::FILTER_HERMITE => \Imagick::FILTER_HERMITE, + ImageInterface::FILTER_LANCZOS => \Imagick::FILTER_LANCZOS, + ImageInterface::FILTER_MITCHELL => \Imagick::FILTER_MITCHELL, + ImageInterface::FILTER_POINT => \Imagick::FILTER_POINT, + ImageInterface::FILTER_QUADRATIC => \Imagick::FILTER_QUADRATIC, + ImageInterface::FILTER_SINC => \Imagick::FILTER_SINC, + ImageInterface::FILTER_TRIANGLE => \Imagick::FILTER_TRIANGLE, + ); + + if (!array_key_exists($filter, $supportedFilters)) { + throw new InvalidArgumentException(sprintf( + 'The resampling filter "%s" is not supported by Imagick driver.', + $filter + )); + } + + return $supportedFilters[$filter]; + } + + /** + * Clone the Imagick resource of this instance. + * + * @throws \ImagickException + * + * @return \Imagick + */ + protected function cloneImagick() + { + // the clone method has been deprecated in imagick 3.1.0b1. + // we can't use phpversion('imagick') because it may return `@PACKAGE_VERSION@` + // so, let's check if ImagickDraw has the setResolution method, which has been introduced in the same version 3.1.0b1 + if (method_exists('ImagickDraw', 'setResolution')) { + return clone $this->imagick; + } + + return $this->imagick->clone(); + } +} diff --git a/vendor/imagine/imagine/src/Imagick/Imagine.php b/vendor/imagine/imagine/src/Imagick/Imagine.php new file mode 100644 index 0000000..daad633 --- /dev/null +++ b/vendor/imagine/imagine/src/Imagick/Imagine.php @@ -0,0 +1,215 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Imagick; + +use Imagine\Exception\InvalidArgumentException; +use Imagine\Exception\NotSupportedException; +use Imagine\Exception\RuntimeException; +use Imagine\Factory\ClassFactoryInterface; +use Imagine\File\LoaderInterface; +use Imagine\Image\AbstractImagine; +use Imagine\Image\BoxInterface; +use Imagine\Image\Metadata\MetadataBag; +use Imagine\Image\Palette\CMYK; +use Imagine\Image\Palette\Color\ColorInterface; +use Imagine\Image\Palette\Grayscale; +use Imagine\Image\Palette\RGB; +use Imagine\Utils\ErrorHandling; + +/** + * Imagine implementation using the Imagick PHP extension. + */ +final class Imagine extends AbstractImagine +{ + /** + * @throws \Imagine\Exception\RuntimeException + */ + public function __construct() + { + if (!class_exists('Imagick')) { + throw new RuntimeException('Imagick not installed'); + } + + $version = $this->getVersion(new \Imagick()); + + if (version_compare('6.2.9', $version) > 0) { + throw new RuntimeException(sprintf('ImageMagick version 6.2.9 or higher is required, %s provided', $version)); + } + if ($version === '7.0.7-32') { // https://github.com/avalanche123/Imagine/issues/689 + throw new RuntimeException(sprintf('ImageMagick version %s has known bugs that prevent it from working', $version)); + } + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImagineInterface::open() + */ + public function open($path) + { + $loader = $path instanceof LoaderInterface ? $path : $this->getClassFactory()->createFileLoader($path); + $path = $loader->getPath(); + + try { + if ($loader->isLocalFile()) { + if (DIRECTORY_SEPARATOR === '\\' && PHP_INT_SIZE === 8 && PHP_VERSION_ID >= 70100 && PHP_VERSION_ID < 70200) { + $imagick = new \Imagick(); + // PHP 7.1 64 bit on Windows: don't pass the file name to the constructor: it may break PHP - see https://github.com/mkoppanen/imagick/issues/252 + $imagick->readImageBlob($loader->getData(), $path); + } else { + $imagick = new \Imagick($loader->getPath()); + } + } else { + $imagick = new \Imagick(); + $imagick->readImageBlob($loader->getData()); + } + $image = $this->getClassFactory()->createImage(ClassFactoryInterface::HANDLE_IMAGICK, $imagick, $this->createPalette($imagick), $this->getMetadataReader()->readFile($loader)); + } catch (\ImagickException $e) { + throw new RuntimeException(sprintf('Unable to open image %s', $path), $e->getCode(), $e); + } + + return $image; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImagineInterface::create() + */ + public function create(BoxInterface $size, ColorInterface $color = null) + { + $width = $size->getWidth(); + $height = $size->getHeight(); + + $palette = null !== $color ? $color->getPalette() : new RGB(); + $color = null !== $color ? $color : $palette->color('fff'); + + try { + $pixel = new \ImagickPixel((string) $color); + $pixel->setColorValue(\Imagick::COLOR_ALPHA, $color->getAlpha() / 100); + + $imagick = new \Imagick(); + $imagick->newImage($width, $height, $pixel); + $imagick->setImageMatte(true); + $imagick->setImageBackgroundColor($pixel); + + if (version_compare('6.3.1', $this->getVersion($imagick)) < 0) { + // setImageOpacity was replaced with setImageAlpha in php-imagick v3.4.3 + if (method_exists($imagick, 'setImageAlpha')) { + $imagick->setImageAlpha($pixel->getColorValue(\Imagick::COLOR_ALPHA)); + } else { + ErrorHandling::ignoring(E_DEPRECATED, function () use ($imagick, $pixel) { + $imagick->setImageOpacity($pixel->getColorValue(\Imagick::COLOR_ALPHA)); + }); + } + } + + $pixel->clear(); + $pixel->destroy(); + + return $this->getClassFactory()->createImage(ClassFactoryInterface::HANDLE_IMAGICK, $imagick, $palette, new MetadataBag()); + } catch (\ImagickException $e) { + throw new RuntimeException('Could not create empty image', $e->getCode(), $e); + } + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImagineInterface::load() + */ + public function load($string) + { + try { + $imagick = new \Imagick(); + + $imagick->readImageBlob($string); + $imagick->setImageMatte(true); + + return $this->getClassFactory()->createImage(ClassFactoryInterface::HANDLE_IMAGICK, $imagick, $this->createPalette($imagick), $this->getMetadataReader()->readData($string)); + } catch (\ImagickException $e) { + throw new RuntimeException('Could not load image from string', $e->getCode(), $e); + } + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImagineInterface::read() + */ + public function read($resource) + { + if (!is_resource($resource)) { + throw new InvalidArgumentException('Variable does not contain a stream resource'); + } + + $content = stream_get_contents($resource); + + try { + $imagick = new \Imagick(); + $imagick->readImageBlob($content); + } catch (\ImagickException $e) { + throw new RuntimeException('Could not read image from resource', $e->getCode(), $e); + } + + return $this->getClassFactory()->createImage(ClassFactoryInterface::HANDLE_IMAGICK, $imagick, $this->createPalette($imagick), $this->getMetadataReader()->readData($content, $resource)); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\ImagineInterface::font() + */ + public function font($file, $size, ColorInterface $color) + { + return $this->getClassFactory()->createFont(ClassFactoryInterface::HANDLE_IMAGICK, $file, $size, $color); + } + + /** + * Returns the palette corresponding to an \Imagick resource colorspace. + * + * @param \Imagick $imagick + * + * @throws \Imagine\Exception\NotSupportedException + * + * @return \Imagine\Image\Palette\CMYK|\Imagine\Image\Palette\Grayscale|\Imagine\Image\Palette\RGB + */ + private function createPalette(\Imagick $imagick) + { + switch ($imagick->getImageColorspace()) { + case \Imagick::COLORSPACE_RGB: + case \Imagick::COLORSPACE_SRGB: + return new RGB(); + case \Imagick::COLORSPACE_CMYK: + return new CMYK(); + case \Imagick::COLORSPACE_GRAY: + return new Grayscale(); + default: + throw new NotSupportedException('Only RGB and CMYK colorspace are currently supported'); + } + } + + /** + * Returns ImageMagick version. + * + * @param \Imagick $imagick + * + * @return string + */ + private function getVersion(\Imagick $imagick) + { + $v = $imagick->getVersion(); + list($version) = sscanf($v['versionString'], 'ImageMagick %s %04d-%02d-%02d %s %s'); + + return $version; + } +} diff --git a/vendor/imagine/imagine/src/Imagick/Layers.php b/vendor/imagine/imagine/src/Imagick/Layers.php new file mode 100644 index 0000000..826cf90 --- /dev/null +++ b/vendor/imagine/imagine/src/Imagick/Layers.php @@ -0,0 +1,308 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Imagick; + +use Imagine\Exception\InvalidArgumentException; +use Imagine\Exception\OutOfBoundsException; +use Imagine\Exception\RuntimeException; +use Imagine\Factory\ClassFactoryInterface; +use Imagine\Image\AbstractLayers; +use Imagine\Image\Metadata\MetadataBag; +use Imagine\Image\Palette\PaletteInterface; + +class Layers extends AbstractLayers +{ + /** + * @var \Imagine\Imagick\Image + */ + private $image; + + /** + * @var \Imagick + */ + private $resource; + + /** + * @var int + */ + private $offset; + + /** + * @var \Imagine\Imagick\Image[] + */ + private $layers = array(); + + /** + * @var \Imagine\Image\Palette\PaletteInterface + */ + private $palette; + + public function __construct(Image $image, PaletteInterface $palette, \Imagick $resource, $initialOffset = 0) + { + $this->image = $image; + $this->resource = $resource; + $this->palette = $palette; + $this->offset = (int) $initialOffset; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\LayersInterface::merge() + */ + public function merge() + { + foreach ($this->layers as $offset => $image) { + try { + $this->resource->setIteratorIndex($offset); + $this->resource->setImage($image->getImagick()); + } catch (\ImagickException $e) { + throw new RuntimeException('Failed to substitute layer', $e->getCode(), $e); + } + } + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\LayersInterface::animate() + */ + public function animate($format, $delay, $loops) + { + if ('gif' !== strtolower($format)) { + throw new InvalidArgumentException('Animated picture is currently only supported on gif'); + } + + if (!is_int($loops) || $loops < 0) { + throw new InvalidArgumentException('Loops must be a positive integer.'); + } + + if (null !== $delay && (!is_int($delay) || $delay < 0)) { + throw new InvalidArgumentException('Delay must be either null or a positive integer.'); + } + + try { + foreach ($this as $offset => $layer) { + $this->resource->setIteratorIndex($offset); + $this->resource->setFormat($format); + + if (null !== $delay) { + $layer->getImagick()->setImageDelay($delay / 10); + $layer->getImagick()->setImageTicksPerSecond(100); + } + $layer->getImagick()->setImageIterations($loops); + + $this->resource->setImage($layer->getImagick()); + } + } catch (\ImagickException $e) { + throw new RuntimeException('Failed to animate layers', $e->getCode(), $e); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Image\LayersInterface::coalesce() + */ + public function coalesce() + { + try { + $coalescedResource = $this->resource->coalesceImages(); + } catch (\ImagickException $e) { + throw new RuntimeException('Failed to coalesce layers', $e->getCode(), $e); + } + + $count = $coalescedResource->getNumberImages(); + for ($offset = 0; $offset < $count; $offset++) { + try { + $coalescedResource->setIteratorIndex($offset); + $this->layers[$offset] = $this->getClassFactory()->createImage(ClassFactoryInterface::HANDLE_IMAGICK, $coalescedResource->getImage(), $this->palette, new MetadataBag()); + } catch (\ImagickException $e) { + throw new RuntimeException('Failed to retrieve layer', $e->getCode(), $e); + } + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @see \Iterator::current() + */ + public function current() + { + return $this->extractAt($this->offset); + } + + /** + * Tries to extract layer at given offset. + * + * @param int $offset + * + * @throws \Imagine\Exception\RuntimeException + * + * @return \Imagine\Imagick\Image + */ + private function extractAt($offset) + { + if (!isset($this->layers[$offset])) { + try { + $this->resource->setIteratorIndex($offset); + $this->layers[$offset] = $this->getClassFactory()->createImage(ClassFactoryInterface::HANDLE_IMAGICK, $this->resource->getImage(), $this->palette, new MetadataBag()); + } catch (\ImagickException $e) { + throw new RuntimeException(sprintf('Failed to extract layer %d', $offset), $e->getCode(), $e); + } + } + + return $this->layers[$offset]; + } + + /** + * {@inheritdoc} + * + * @see \Iterator::key() + */ + public function key() + { + return $this->offset; + } + + /** + * {@inheritdoc} + * + * @see \Iterator::next() + */ + public function next() + { + ++$this->offset; + } + + /** + * {@inheritdoc} + * + * @see \Iterator::rewind() + */ + public function rewind() + { + $this->offset = 0; + } + + /** + * {@inheritdoc} + * + * @see \Iterator::valid() + */ + public function valid() + { + return $this->offset < count($this); + } + + /** + * {@inheritdoc} + * + * @see \Countable::count() + */ + public function count() + { + try { + return $this->resource->getNumberImages(); + } catch (\ImagickException $e) { + throw new RuntimeException('Failed to count the number of layers', $e->getCode(), $e); + } + } + + /** + * {@inheritdoc} + * + * @see \ArrayAccess::offsetExists() + */ + public function offsetExists($offset) + { + return is_int($offset) && $offset >= 0 && $offset < count($this); + } + + /** + * {@inheritdoc} + * + * @see \ArrayAccess::offsetGet() + */ + public function offsetGet($offset) + { + return $this->extractAt($offset); + } + + /** + * {@inheritdoc} + * + * @see \ArrayAccess::offsetSet() + */ + public function offsetSet($offset, $image) + { + if (!$image instanceof Image) { + throw new InvalidArgumentException('Only an Imagick Image can be used as layer'); + } + + if (null === $offset) { + $offset = count($this) - 1; + } else { + if (!is_int($offset)) { + throw new InvalidArgumentException('Invalid offset for layer, it must be an integer'); + } + + if (count($this) < $offset || 0 > $offset) { + throw new OutOfBoundsException(sprintf('Invalid offset for layer, it must be a value between 0 and %d, %d given', count($this), $offset)); + } + + if (isset($this[$offset])) { + unset($this[$offset]); + $offset = $offset - 1; + } + } + + $frame = $image->getImagick(); + + try { + if (count($this) > 0) { + $this->resource->setIteratorIndex($offset); + } + $this->resource->addImage($frame); + } catch (\ImagickException $e) { + throw new RuntimeException('Unable to set the layer', $e->getCode(), $e); + } + + $this->layers = array(); + } + + /** + * {@inheritdoc} + * + * @see \ArrayAccess::offsetUnset() + */ + public function offsetUnset($offset) + { + try { + $this->extractAt($offset); + } catch (RuntimeException $e) { + return; + } + + try { + $this->resource->setIteratorIndex($offset); + $this->resource->removeImage(); + } catch (\ImagickException $e) { + throw new RuntimeException('Unable to remove layer', $e->getCode(), $e); + } + } +} diff --git a/vendor/imagine/imagine/src/Utils/ErrorHandling.php b/vendor/imagine/imagine/src/Utils/ErrorHandling.php new file mode 100644 index 0000000..28905a8 --- /dev/null +++ b/vendor/imagine/imagine/src/Utils/ErrorHandling.php @@ -0,0 +1,93 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Utils; + +use ErrorException; +use Exception; +use Imagine\Exception\RuntimeException; +use Throwable; + +class ErrorHandling +{ + /** + * Call a callback ignoring $flags warnings. + * + * @param int $flags The flags to be ignored (eg E_WARNING | E_NOTICE) + * @param callable $callback The callable to be called + * + * @throws \Exception Throws an Exception if $callback throws an Exception + * @throws \Throwable Throws an Throwable if $callback throws an Throwable + * + * @return mixed Returns the result of $callback + */ + public static function ignoring($flags, $callback) + { + set_error_handler( + function () { + }, + $flags + ); + try { + $result = $callback(); + $exception = null; + } catch (Exception $x) { + $exception = $x; + } catch (Throwable $x) { + $exception = $x; + } + restore_error_handler(); + if ($exception !== null) { + throw $exception; + } + + return $result; + } + + /** + * Call a callback and throws a RuntimeException if a $flags warning is thrown. + * + * @param int $flags The flags to be intercepted (eg E_WARNING | E_NOTICE) + * @param callable $callback The callable to be called + * + * @throws RuntimeException + * @throws \Imagine\Exception\RuntimeException + * @throws \Exception + * @throws \Throwable + * + * @return mixed Returns the result of $callback + */ + public static function throwingRuntimeException($flags, $callback) + { + set_error_handler( + function ($errno, $errstr, $errfile, $errline) { + if (error_reporting() !== 0) { + throw new RuntimeException($errstr, $errno, new ErrorException($errstr, 0, $errno, $errfile, $errline)); + } + }, + $flags + ); + try { + $result = $callback(); + $exception = null; + } catch (Exception $x) { + $exception = $x; + } catch (Throwable $x) { + $exception = $x; + } + restore_error_handler(); + if ($exception !== null) { + throw $exception; + } + + return $result; + } +} diff --git a/vendor/imagine/imagine/src/Utils/Matrix.php b/vendor/imagine/imagine/src/Utils/Matrix.php new file mode 100644 index 0000000..c6e9910 --- /dev/null +++ b/vendor/imagine/imagine/src/Utils/Matrix.php @@ -0,0 +1,177 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Imagine\Utils; + +use Imagine\Exception\InvalidArgumentException; +use Imagine\Exception\OutOfBoundsException; + +class Matrix +{ + /** + * The array of elements. + * + * @var int[]|float[] + */ + protected $elements = array(); + + /** + * The matrix width. + * + * @var int + */ + protected $width; + + /** + * The matrix height. + * + * @var int + */ + protected $height; + + /** + * The given $elements get arranged as follows: The elements will be set from left to right in a row until the + * row is full. Then, the next line begins alike and so on. + * + * @param int $width the matrix width + * @param int $height he matrix height + * @param int[]|float[] $elements the matrix elements + * + * @throws \Imagine\Exception\InvalidArgumentException + */ + public function __construct($width, $height, $elements = array()) + { + $this->width = (int) round($width); + if ($this->width < 1) { + throw new InvalidArgumentException('width has to be > 0'); + } + $this->height = (int) round($height); + if ($this->height < 1) { + throw new InvalidArgumentException('height has to be > 0'); + } + $expectedElements = $width * $height; + $providedElements = count($elements); + if ($providedElements > $expectedElements) { + throw new InvalidArgumentException('there are more provided elements than space in the matrix'); + } + $this->elements = array_values($elements); + if ($providedElements < $expectedElements) { + $this->elements = array_merge( + $this->elements, + array_fill($providedElements, $expectedElements - $providedElements, 0) + ); + } + } + + /** + * Get the matrix width. + * + * @return int + */ + public function getWidth() + { + return $this->width; + } + + /** + * Get the matrix height. + * + * @return int + */ + public function getHeight() + { + return $this->height; + } + + /** + * Set the value of a cell. + * + * @param int $x + * @param int $y + * @param int|float $value + */ + public function setElementAt($x, $y, $value) + { + $this->elements[$this->calculatePosition($x, $y)] = $value; + } + + /** + * Get the value of a cell. + * + * @param int $x + * @param int $y + * + * @return int|float + */ + public function getElementAt($x, $y) + { + return $this->elements[$this->calculatePosition($x, $y)]; + } + + /** + * Return all the matrix values, as a monodimensional array. + * + * @return int[]|float[] + */ + public function getValueList() + { + return $this->elements; + } + + /** + * Return all the matrix values, as a bidimensional array (every array item contains the values of a row). + * + * @return int[]|float[] + */ + public function getMatrix() + { + return array_chunk($this->elements, $this->getWidth()); + } + + /** + * Returns a new Matrix instance, representing the normalized value of this matrix. + * + * @return static + */ + public function normalize() + { + $values = $this->getValueList(); + $divisor = array_sum($values); + if ($divisor == 0 || $divisor == 1) { + return clone $this; + } + $normalizedElements = array(); + foreach ($values as $value) { + $normalizedElements[] = $value / $divisor; + } + + return new static($this->getWidth(), $this->getHeight(), $normalizedElements); + } + + /** + * Calculate the offset position of a cell. + * + * @param int $x + * @param int $y + * + * @throws \Imagine\Exception\OutOfBoundsException + * + * @return int + */ + protected function calculatePosition($x, $y) + { + if (0 > $x || 0 > $y || $this->width <= $x || $this->height <= $y) { + throw new OutOfBoundsException(sprintf('There is no position (%s, %s) in this matrix', $x, $y)); + } + + return $y * $this->height + $x; + } +} diff --git a/vendor/imagine/imagine/src/resources/Adobe/CMYK/CoatedFOGRA27.icc b/vendor/imagine/imagine/src/resources/Adobe/CMYK/CoatedFOGRA27.icc new file mode 100644 index 0000000..086ac9d Binary files /dev/null and b/vendor/imagine/imagine/src/resources/Adobe/CMYK/CoatedFOGRA27.icc differ diff --git a/vendor/imagine/imagine/src/resources/Adobe/CMYK/CoatedFOGRA39.icc b/vendor/imagine/imagine/src/resources/Adobe/CMYK/CoatedFOGRA39.icc new file mode 100644 index 0000000..61cb86a Binary files /dev/null and b/vendor/imagine/imagine/src/resources/Adobe/CMYK/CoatedFOGRA39.icc differ diff --git a/vendor/imagine/imagine/src/resources/Adobe/CMYK/CoatedGRACoL2006.icc b/vendor/imagine/imagine/src/resources/Adobe/CMYK/CoatedGRACoL2006.icc new file mode 100644 index 0000000..1f360b7 Binary files /dev/null and b/vendor/imagine/imagine/src/resources/Adobe/CMYK/CoatedGRACoL2006.icc differ diff --git a/vendor/imagine/imagine/src/resources/Adobe/CMYK/JapanColor2001Coated.icc b/vendor/imagine/imagine/src/resources/Adobe/CMYK/JapanColor2001Coated.icc new file mode 100644 index 0000000..5841b46 Binary files /dev/null and b/vendor/imagine/imagine/src/resources/Adobe/CMYK/JapanColor2001Coated.icc differ diff --git a/vendor/imagine/imagine/src/resources/Adobe/CMYK/JapanColor2001Uncoated.icc b/vendor/imagine/imagine/src/resources/Adobe/CMYK/JapanColor2001Uncoated.icc new file mode 100644 index 0000000..8ade70d Binary files /dev/null and b/vendor/imagine/imagine/src/resources/Adobe/CMYK/JapanColor2001Uncoated.icc differ diff --git a/vendor/imagine/imagine/src/resources/Adobe/CMYK/JapanColor2002Newspaper.icc b/vendor/imagine/imagine/src/resources/Adobe/CMYK/JapanColor2002Newspaper.icc new file mode 100644 index 0000000..18307e2 Binary files /dev/null and b/vendor/imagine/imagine/src/resources/Adobe/CMYK/JapanColor2002Newspaper.icc differ diff --git a/vendor/imagine/imagine/src/resources/Adobe/CMYK/JapanColor2003WebCoated.icc b/vendor/imagine/imagine/src/resources/Adobe/CMYK/JapanColor2003WebCoated.icc new file mode 100644 index 0000000..733dc1d Binary files /dev/null and b/vendor/imagine/imagine/src/resources/Adobe/CMYK/JapanColor2003WebCoated.icc differ diff --git a/vendor/imagine/imagine/src/resources/Adobe/CMYK/JapanWebCoated.icc b/vendor/imagine/imagine/src/resources/Adobe/CMYK/JapanWebCoated.icc new file mode 100644 index 0000000..004b8b9 Binary files /dev/null and b/vendor/imagine/imagine/src/resources/Adobe/CMYK/JapanWebCoated.icc differ diff --git a/vendor/imagine/imagine/src/resources/Adobe/CMYK/USWebCoatedSWOP.icc b/vendor/imagine/imagine/src/resources/Adobe/CMYK/USWebCoatedSWOP.icc new file mode 100644 index 0000000..078a644 Binary files /dev/null and b/vendor/imagine/imagine/src/resources/Adobe/CMYK/USWebCoatedSWOP.icc differ diff --git a/vendor/imagine/imagine/src/resources/Adobe/CMYK/USWebUncoated.icc b/vendor/imagine/imagine/src/resources/Adobe/CMYK/USWebUncoated.icc new file mode 100644 index 0000000..75efcb2 Binary files /dev/null and b/vendor/imagine/imagine/src/resources/Adobe/CMYK/USWebUncoated.icc differ diff --git a/vendor/imagine/imagine/src/resources/Adobe/CMYK/UncoatedFOGRA29.icc b/vendor/imagine/imagine/src/resources/Adobe/CMYK/UncoatedFOGRA29.icc new file mode 100644 index 0000000..70e13f5 Binary files /dev/null and b/vendor/imagine/imagine/src/resources/Adobe/CMYK/UncoatedFOGRA29.icc differ diff --git a/vendor/imagine/imagine/src/resources/Adobe/CMYK/WebCoatedFOGRA28.icc b/vendor/imagine/imagine/src/resources/Adobe/CMYK/WebCoatedFOGRA28.icc new file mode 100644 index 0000000..06bf0e6 Binary files /dev/null and b/vendor/imagine/imagine/src/resources/Adobe/CMYK/WebCoatedFOGRA28.icc differ diff --git a/vendor/imagine/imagine/src/resources/Adobe/CMYK/WebCoatedSWOP2006Grade3.icc b/vendor/imagine/imagine/src/resources/Adobe/CMYK/WebCoatedSWOP2006Grade3.icc new file mode 100644 index 0000000..ad24acb Binary files /dev/null and b/vendor/imagine/imagine/src/resources/Adobe/CMYK/WebCoatedSWOP2006Grade3.icc differ diff --git a/vendor/imagine/imagine/src/resources/Adobe/CMYK/WebCoatedSWOP2006Grade5.icc b/vendor/imagine/imagine/src/resources/Adobe/CMYK/WebCoatedSWOP2006Grade5.icc new file mode 100644 index 0000000..11a82c8 Binary files /dev/null and b/vendor/imagine/imagine/src/resources/Adobe/CMYK/WebCoatedSWOP2006Grade5.icc differ diff --git a/vendor/imagine/imagine/src/resources/Adobe/Color Profile Bundling License_10.15.08.md b/vendor/imagine/imagine/src/resources/Adobe/Color Profile Bundling License_10.15.08.md new file mode 100644 index 0000000..09469ad --- /dev/null +++ b/vendor/imagine/imagine/src/resources/Adobe/Color Profile Bundling License_10.15.08.md @@ -0,0 +1,76 @@ +### ADOBE SYSTEMS INCORPORATED + +# COLOR PROFILE BUNDLING AGREEMENT + +NOTICE TO USER: PLEASE READ THIS CONTRACT CAREFULLY. BY USING ALL OR ANY PORTION OF THE SOFTWARE YOU ACCEPT ALL THE TERMS AND CONDITIONS OF THIS AGREEMENT. YOU AGREE THAT THIS AGREEMENT IS ENFORCEABLE LIKE ANY WRITTEN NEGOTIATED AGREEMENT SIGNED BY YOU. IF YOU DO NOT AGREE WITH THE TERMS OF THIS AGREEMENT, DO NOT USE THE SOFTWARE. + +1. DEFINITIONS. In this Agreement, "Adobe" means Adobe Systems Incorporated, a Delaware corporation, located at 345 Park Avenue, San Jose, California 95110. "Software" means the software and related items with which this Agreement is provided, as listed in Exhibit A. +2. LICENSE. Subject to the terms of this Agreement, Adobe hereby grants you the worldwide, non-exclusive, nontransferable, royalty-free license to use, reproduce and publicly display the Software. Adobe also grants you the rights to distribute the Software: +(a) on a standalone basis, +(b) as embedded within digital image files. +(c) as embedded within hardware products that author digital images, where there is no End User access to the Software, and +(d) as bundled with your own application software, +provided that you comply with all the distribution requirements in Section 3 below. No other distribution of the Software is allowed. All individual profiles must be referenced by their ICC Profile description string. YOU MAY NOT MODIFY THE SOFTWARE. Adobe is under no obligation to provide any support under this Agreement, including upgrades or future versions of the Software or other items. No title to the intellectual property in the Software is transferred to you under the terms of this Agreement. You do not acquire any rights to the Software except as expressly set forth in this Agreement. Notwithstanding the above, if you are bundling with Linux or Unix software products, you may (a) add shortcut or menu items within your software that point to the Software, but may not change the name or iconography of the Software, (b) repackage the RPM or Gzip versions of the Software for distribution purposes, and (c) create a graphical user interface as otherwise specifically allowed by instructions found at [www.adobe.com](http://www.adobe.com) or [http://partners.adobe.com](http://partners.adobe.com) (e.g., installation of additional plug-in and help files) but may not add, delete, or modify any components of the Software without the explicit written permission of Adobe. +3. DISTRIBUTION. If you choose to distribute the Software, you do so with the understanding that you agree to defend, indemnify and hold harmless Adobe against any losses, damages or costs arising from any claims, lawsuits or other legal actions arising out of such distribution, including, without limitation, product liability and other claims by consumers and your failure to comply with this Section 3. If you distribute the Software on a standalone or bundled basis, you will do so by first obtaining the agreement of the end user under the terms of either the Adobe End User License Agreement (“Adobe EULA”), attached as **Exhibit B**, or your own license agreement which (a) complies with the terms and conditions of this Agreement; (b) effectively disclaims all warranties and conditions, express or implied, on behalf of Adobe; (c) effectively excludes all liability for damages on behalf of Adobe; (d) substantially states that any provisions that differ from this Agreement are offered by you alone and not Adobe; and (e) substantially states that the Software is available from you or Adobe and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange. Any distributed Software will include the Adobe copyright notices as included in the Software provided to you by Adobe. +4. DISCLAIMER OF WARRANTY. Adobe licenses the Software to you on an "AS IS" basis. Adobe makes no representation as to the adequacy of the Software for any particular purpose or to produce any particular result. Adobe shall not be liable for loss or damage arising out of this Agreement or from the distribution or use of the Software or any other materials. ADOBE AND ITS SUPPLIERS DO NOT AND CANNOT WARRANT THE PERFORMANCE OR RESULTS YOU MAY OBTAIN BY USING THE SOFTWARE, EXCEPT FOR ANY WARRANTY, CONDITION, REPRESENTATION OR TERM TO THE EXTENT TO WHICH THE SAME CANNOT OR MAY NOT BE EXCLUDED OR LIMITED BY LAW APPLICABLE TO YOU IN YOUR JURISDICTION, ADOBE AND ITS SUPPLIERS MAKE NO WARRANTIES, CONDITIONS, REPRESENTATIONS OR TERMS, EXPRESS OR IMPLIED, WHETHER BY STATUTE, COMMON LAW, CUSTOM, USAGE OR OTHERWISE AS TO ANY OTHER MATTERS, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT OF THIRD PARTY RIGHTS, INTEGRATION, SATISFACTORY QUALITY OR FITNESS FOR ANY PARTICULAR PURPOSE. YOU MAY HAVE ADDITIONAL RIGHTS WHICH VARY FROM JURISDICTION TO JURISDICTION. The provisions of Sections 4 and 5 shall survive the termination of this Agreement, howsoever caused, but this shall not imply or create any continued right to use the Software after termination of this Agreement. +5. LIMITATION OF LIABILITY. IN NO EVENT WILL ADOBE OR ITS SUPPLIERS BE LIABLE TO YOU FOR ANY DAMAGES, CLAIMS OR COSTS WHATSOEVER OR ANY CONSEQUENTIAL, INDIRECT, INCIDENTAL DAMAGES, OR ANY LOST PROFITS OR LOST SAVINGS, EVEN IF AN ADOBE REPRESENTATIVE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH LOSS, DAMAGES, CLAIMS OR COSTS OR FOR ANY CLAIM BY ANY THIRD PARTY. THE FOREGOING LIMITATIONS AND EXCLUSIONS APPLY TO THE EXTENT PERMITTED BY APPLICABLE LAW IN YOUR JURISDICTION. ADOBE'S AGGREGATE LIABILITY AND THAT OF ITS SUPPLIERS UNDER OR IN CONNECTION WITH THIS AGREEMENT SHALL BE LIMITED TO THE AMOUNT PAID FOR THE SOFTWARE. Nothing contained in this Agreement limits Adobe's liability to you in the event of death or personal injury resulting from Adobe's negligence or for the tort of deceit (fraud). Adobe is acting on behalf of its suppliers for the purpose of disclaiming, excluding and/or limiting obligations, warranties and liability as provided in this Agreement, but in no other respects and for no other purpose. +6. TRADEMARKS. Adobe grants you a worldwide, nonexclusive, nontransferable, personal right to use the “Adobe” word trademark (the “Trademark”) solely to identify Adobe as the source of the Adobe RGB (1998) product or Adobe RGB technology, so long as such use complies with the terms of this Agreement, the trademark guidelines available at the “Permissions and trademarks” pages of the Adobe web site ([www.adobe.com](http://www.adobe.com)) and the “Adobe Trademark Guidelines for third parties who license, use or refer to Adobe trademarks,” also available from the Adobe web site. You acknowledge the validity of the Trademark and Adobe’s ownership of the Trademark. Nothing in this Agreement shall give you any right, title or interest in the Trademark, other than the license rights granted in this Agreement. You recognize the value of the goodwill associated with the Trademark and acknowledge that such goodwill exclusively inures to the benefit of and belongs to Adobe. Adobe and the Adobe logo are either registered trademarks or trademarks of Adobe in the United States and/or other countries. With the exception of referential use and the rights granted in this Agreement, you will not use such trademarks or any other Adobe trademark or logo without separate prior written permission from Adobe. +7. TERM. This Agreement is effective until terminated. Adobe has the right to terminate this Agreement immediately if you fail to comply with any term hereof. Upon any such termination, you must return to Adobe all full and partial copies of the Software in your possession or control. +8. GOVERNMENT REGULATIONS. If any part of the Software is identified as an export controlled item under the United States Export Administration Act or any other export law, restriction or regulation (the "Export Laws"), you represent and warrant that you are not a citizen, or otherwise located within, an embargoed nation (including without limitation Iran, Iraq, Syria, Sudan, Libya, Cuba, North Korea, and Serbia) and that you are not otherwise prohibited under the Export Laws from receiving the Software. All rights to use the Software are granted on condition that such rights are forfeited if you fail to comply with the terms of this Agreement. +9. GOVERNING LAW. This Agreement will be governed by and construed in accordance with the substantive laws in force in the State of California as such laws are applied to agreements entered into and to be performed entirely within California between California residents. This Agreement will not be governed by the conflict of law rules of any jurisdiction or the United Nations Convention on Contracts for the International Sale of Goods, the application of which is expressly excluded. All disputes arising out of, under or related to this Agreement will be brought exclusively in the state Santa Clara County, California, USA. +10. GENERAL. You may not assign your rights or obligations granted under this Agreement without the prior written consent of Adobe. None of the provisions of this Agreement shall be deemed to have been waived by any act or acquiescence on the part of Adobe, its agents, or employees, but only by an instrument in writing signed by an authorized signatory of Adobe. When conflicting language exists between this Agreement and any other agreement included in the Software, the terms of such included agreement shall apply. If either you or Adobe employs attorneys to enforce any rights arising out of or relating to this Agreement, the prevailing party shall be entitled to recover reasonable attorneys’ fees. You acknowledge that you have read this Agreement, understand it, and that it is the complete and exclusive statement of your agreement with Adobe which supersedes any prior agreement, oral or written, between Adobe and you with respect to the licensing to you of the Software. No variation of the terms of this Agreement will be enforceable against Adobe unless Adobe gives its express consent, in writing, signed by an authorized signatory of Adobe. + +## Exhibit A + +The “Software” for the purposes of this Agreement and which Licensee is permitted to distribute subject to the terms and conditions of this Agreement, shall consist of one or more of the following color profiles: + +### 8 RGB profiles + +- Adobe RGB (1998) +- Apple RGB +- ColorMatch RGB +- SMPTE-C +- PAL/SECAM +- HDTV (Rec. 709) +- SDTV NTSC +- SDTV PAL + +### 14 CMYK profiles + +- Coated FOGRA27 (ISO 12647-2:2004) +- Web Coated FOGRA28 (ISO 12647-2:2004) +- Uncoated FOGRA29 (ISO 12647-2:2004) +- Coated FOGRA39 (ISO 12647-2:2004) +- Japan Color 2001 Coated +- Japan Color 2001 Uncoated +- Japan Color 2002 Newspaper +- Japan Color 2003 Web Coated +- Japan Web Coated (Ad) +- U.S. Web Coated (SWOP) v2 +- U.S. Web Uncoated v2 +- Coated GRACol 2006 (ISO 12647-2:2004) +- Web Coated SWOP Grade 3 Paper +- Web Coated SWOP Grade 5 Paper + +## EXHIBIT B + +ADOBE SYSTEMS INCORPORATED + +COLOR PROFILE LICENSE AGREEMENT + +NOTICE TO USER: PLEASE READ THIS CONTRACT CAREFULLY. BY USING ALL OR ANY PORTION OF THE SOFTWARE YOU ACCEPT ALL THE TERMS AND CONDITIONS OF THIS AGREEMENT. YOU AGREE THAT THIS AGREEMENT IS ENFORCEABLE LIKE ANY WRITTEN NEGOTIATED AGREEMENT SIGNED BY YOU. IF YOU DO NOT AGREE WITH THE TERMS OF THIS AGREEMENT, DO NOT USE THE SOFTWARE. + +1. DEFINITIONS In this Agreement, "Adobe" means Adobe Systems Incorporated, a Delaware corporation, located at 345 Park Avenue, San Jose, California 95110. "Software" means the software and related items with which this Agreement is provided. +2. LICENSE Subject to the terms of this Agreement, Adobe hereby grants you the worldwide, non-exclusive, nontransferable, royalty-free license to use, reproduce and publicly display the Software. Adobe also grants you the rights to distribute the Software only (a) as embedded within digital image files and (b) on a standalone basis. No other distribution of the Software is allowed; including, without limitation, distribution of the Software when incorporated into or bundled with any application software. All individual profiles must be referenced by their ICC Profile description string. You may not modify the Software. Adobe is under no obligation to provide any support under this Agreement, including upgrades or future versions of the Software or other items. No title to the intellectual property in the Software is transferred to you under the terms of this Agreement. You do not acquire any rights to the Software except as expressly set forth in this Agreement. +3. DISTRIBUTION If you choose to distribute the Software, you do so with the understanding that you agree to defend, indemnify and hold harmless Adobe against any losses, damages or costs arising from any claims, lawsuits or other legal actions arising out of such distribution, including without limitation, your failure to comply with this Section 3. If you distribute the Software on a standalone basis, you will do so under the terms of this Agreement or your own license agreement which (a) complies with the terms and conditions of this Agreement; (b) effectively disclaims all warranties and conditions, express or implied, on behalf of Adobe; (c) effectively excludes all liability for damages on behalf of Adobe; (d) substantially states that any provisions that differ from this Agreement are offered by you alone and not Adobe and (e) substantially states that the Software is available from you or Adobe and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange. Any distributed Software will include the Adobe copyright notices as included in the Software provided to you by Adobe. +4. DISCLAIMER OF WARRANTY Adobe licenses the Software to you on an "AS IS" basis. Adobe makes no representation as to the adequacy of the Software for any particular purpose or to produce any particular result. Adobe shall not be liable for loss or damage arising out of this Agreement or from the distribution or use of the Software or any other materials. ADOBE AND ITS SUPPLIERS DO NOT AND CANNOT WARRANT THE PERFORMANCE OR RESULTS YOU MAY OBTAIN BY USING THE SOFTWARE, EXCEPT FOR ANY WARRANTY, CONDITION, REPRESENTATION OR TERM TO THE EXTENT TO WHICH THE SAME CANNOT OR MAY NOT BE EXCLUDED OR LIMITED BY LAW APPLICABLE TO YOU IN YOUR JURISDICTION, ADOBE AND ITS SUPPLIERS MAKE NO WARRANTIES, CONDITIONS, REPRESENTATIONS OR TERMS, EXPRESS OR IMPLIED, WHETHER BY STATUTE, COMMON LAW, CUSTOM, USAGE OR OTHERWISE AS TO ANY OTHER MATTERS, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT OF THIRD PARTY RIGHTS, INTEGRATION, SATISFACTORY QUALITY OR FITNESS FOR ANY PARTICULAR PURPOSE. YOU MAY HAVE ADDITIONAL RIGHTS WHICH VARY FROM JURISDICTION TO JURISDICTION. The provisions of Sections 4 and 5 shall survive the termination of this Agreement, howsoever caused, but this shall not imply or create any continued right to use the Software after termination of this Agreement. +5. LIMITATION OF LIABILITY IN NO EVENT WILL ADOBE OR ITS SUPPLIERS BE LIABLE TO YOU FOR ANY DAMAGES, CLAIMS OR COSTS WHATSOEVER OR ANY CONSEQUENTIAL, INDIRECT, INCIDENTAL DAMAGES, OR ANY LOST PROFITS OR LOST SAVINGS, EVEN IF AN ADOBE REPRESENTATIVE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH LOSS, DAMAGES, CLAIMS OR COSTS OR FOR ANY CLAIM BY ANY THIRD PARTY. THE FOREGOING LIMITATIONS AND EXCLUSIONS APPLY TO THE EXTENT PERMITTED BY APPLICABLE LAW IN YOUR JURISDICTION. ADOBE'S AGGREGATE LIABILITY AND THAT OF ITS SUPPLIERS UNDER OR IN CONNECTION WITH THIS AGREEMENT SHALL BE LIMITED TO THE AMOUNT PAID FOR THE SOFTWARE. Nothing contained in this Agreement limits Adobe's liability to you in the event of death or personal injury resulting from Adobe's negligence or for the tort of deceit (fraud). Adobe is acting on behalf of its suppliers for the purpose of disclaiming, excluding and/or limiting obligations, warranties and liability as provided in this Agreement, but in no other respects and for no other purpose. +6. TRADEMARKS Adobe grants you a worldwide, nonexclusive, nontransferable, personal right to use the “Adobe” word trademark (the “Trademark”) solely to identify Adobe as the source of the Adobe RGB (1998) product or Adobe RGB technology, so long as such use complies with the terms of this Agreement, the trademark guidelines available at the “Permissions and trademarks” pages of the Adobe web site (www.adobe.com) and the “Adobe Trademark Guidelines for third parties who license, use or refer to Adobe trademarks,” also available from the Adobe web site. You acknowledge the validity of the Trademark and Adobe’s ownership of the Trademark. Nothing in this Agreement shall give you any right, title or interest in the Trademark, other than the license rights granted in this Agreement. You recognize the value of the goodwill associated with the Trademark and acknowledge that such goodwill exclusively inures to the benefit of and belongs to Adobe. Adobe and the Adobe logo are either registered trademarks or trademarks of Adobe in the United States and/or other countries. With the exception of referential use and the rights granted in this Agreement, you will not use such trademarks or any other Adobe trademark or logo without separate prior written permission granted by Adobe. +7. TERM This Agreement is effective until terminated. Adobe has the right to terminate this Agreement immediately if you fail to comply with any term hereof. Upon any such termination, you must return to Adobe all full and partial copies of the Software in your possession or control. +8. GOVERNMENT REGULATIONS If any part of the Software is identified as an export controlled item under the United States Export Administration Act or any other export law, restriction or regulation (the "Export Laws"), you represent and warrant that you are not a citizen, or otherwise located within, an embargoed nation (including without limitation Iran, Iraq, Syria, Sudan, Libya, Cuba, North Korea, and Serbia) and that you are not otherwise prohibited under the Export Laws from receiving the Software. All rights to use the Software are granted on condition that such rights are forfeited if you fail to comply with the terms of this Agreement. +9. GOVERNING LAW This Agreement will be governed by and construed in accordance with the substantive laws in force in the State of California as such laws are applied to agreements entered into and to be performed entirely within California between California residents. This Agreement will not be governed by the conflict of law rules of any jurisdiction or the United Nations Convention on Contracts for the International Sale of Goods, the application of which is expressly excluded. All disputes arising out of, under or related to this Agreement will be brought exclusively in the state Santa Clara County, California, USA. +10. GENERAL You may not assign your rights or obligations granted under this Agreement without the prior written consent of Adobe. None of the provisions of this Agreement shall be deemed to have been waived by any act or acquiescence on the part of Adobe, its agents, or employees, but only by an instrument in writing signed by an authorized signatory of Adobe. When conflicting language exists between this Agreement and any other agreement included in the Software, the terms of such included agreement shall apply. If either you or Adobe employs attorneys to enforce any rights arising out of or relating to this Agreement, the prevailing party shall be entitled to recover reasonable attorneys’ fees. You acknowledge that you have read this Agreement, understand it, and that it is the complete and exclusive statement of your agreement with Adobe which supersedes any prior agreement, oral or written, between Adobe and you with respect to the licensing to you of the Software. No variation of the terms of this Agreement will be enforceable against Adobe unless Adobe gives its express consent, in writing, signed by an authorized signatory of Adobe. + +--- + +*10/20/2008_dhk/jmr rev. ICCProfileLic_Bdle102008_final.docx* \ No newline at end of file diff --git a/vendor/imagine/imagine/src/resources/Adobe/RGB/AdobeRGB1998.icc b/vendor/imagine/imagine/src/resources/Adobe/RGB/AdobeRGB1998.icc new file mode 100644 index 0000000..a79f576 Binary files /dev/null and b/vendor/imagine/imagine/src/resources/Adobe/RGB/AdobeRGB1998.icc differ diff --git a/vendor/imagine/imagine/src/resources/Adobe/RGB/AppleRGB.icc b/vendor/imagine/imagine/src/resources/Adobe/RGB/AppleRGB.icc new file mode 100644 index 0000000..ff59d23 Binary files /dev/null and b/vendor/imagine/imagine/src/resources/Adobe/RGB/AppleRGB.icc differ diff --git a/vendor/imagine/imagine/src/resources/Adobe/RGB/ColorMatchRGB.icc b/vendor/imagine/imagine/src/resources/Adobe/RGB/ColorMatchRGB.icc new file mode 100644 index 0000000..df927ea Binary files /dev/null and b/vendor/imagine/imagine/src/resources/Adobe/RGB/ColorMatchRGB.icc differ diff --git a/vendor/imagine/imagine/src/resources/Adobe/RGB/PAL_SECAM.icc b/vendor/imagine/imagine/src/resources/Adobe/RGB/PAL_SECAM.icc new file mode 100644 index 0000000..88c1717 Binary files /dev/null and b/vendor/imagine/imagine/src/resources/Adobe/RGB/PAL_SECAM.icc differ diff --git a/vendor/imagine/imagine/src/resources/Adobe/RGB/SMPTE-C.icc b/vendor/imagine/imagine/src/resources/Adobe/RGB/SMPTE-C.icc new file mode 100644 index 0000000..8eeeb30 Binary files /dev/null and b/vendor/imagine/imagine/src/resources/Adobe/RGB/SMPTE-C.icc differ diff --git a/vendor/imagine/imagine/src/resources/Adobe/RGB/VideoHD.icc b/vendor/imagine/imagine/src/resources/Adobe/RGB/VideoHD.icc new file mode 100644 index 0000000..57f121a Binary files /dev/null and b/vendor/imagine/imagine/src/resources/Adobe/RGB/VideoHD.icc differ diff --git a/vendor/imagine/imagine/src/resources/Adobe/RGB/VideoNTSC.icc b/vendor/imagine/imagine/src/resources/Adobe/RGB/VideoNTSC.icc new file mode 100644 index 0000000..78d1ff3 Binary files /dev/null and b/vendor/imagine/imagine/src/resources/Adobe/RGB/VideoNTSC.icc differ diff --git a/vendor/imagine/imagine/src/resources/Adobe/RGB/VideoPAL.icc b/vendor/imagine/imagine/src/resources/Adobe/RGB/VideoPAL.icc new file mode 100644 index 0000000..0b7ed9b Binary files /dev/null and b/vendor/imagine/imagine/src/resources/Adobe/RGB/VideoPAL.icc differ diff --git a/vendor/imagine/imagine/src/resources/Adobe/Trademark Information.md b/vendor/imagine/imagine/src/resources/Adobe/Trademark Information.md new file mode 100644 index 0000000..265bca5 --- /dev/null +++ b/vendor/imagine/imagine/src/resources/Adobe/Trademark Information.md @@ -0,0 +1,11 @@ +*5/10/05* + +# Trademark Information + +Adobe is either a registered trademark or trademark of Adobe Systems Incorporated in the United States and/or other countries. All instances of the name “Adobe RGB” are references to the Adobe RGB (1998) color space and color encodings as defined by Adobe, unless otherwise stated. The name “Adobe RGB (1998)” also is used as a software product trademark for Adobe’s implementation of the Adobe RGB (1998) ICC profile. Adobe does not permit the use of the Adobe RGB trademark for software, hardware, or other related products from companies other than Adobe, unless the company has obtained a prior written license from Adobe to do so. + +## Distributing the Adobe RGB (1998) ICC profile + +You may distribute the Adobe RGB (1998) ICC profile as embedded within digital image files and on a standalone basis so long as you accept the terms and conditions of the Color Profile License Agreement on this page and the Adobe end-user license agreement. + +Keep in mind that you must sign a supplementary license agreement with Adobe if you are interested in distributing the Adobe RGB (1998) ICC profile software embedded or as a bundle with a camera, display or other hardware device or software application. If you have not already signed an agreement, please contact your Adobe representative. diff --git a/vendor/imagine/imagine/src/resources/color.org/sRGB_IEC61966-2-1_black_scaled.icc b/vendor/imagine/imagine/src/resources/color.org/sRGB_IEC61966-2-1_black_scaled.icc new file mode 100644 index 0000000..71e3383 Binary files /dev/null and b/vendor/imagine/imagine/src/resources/color.org/sRGB_IEC61966-2-1_black_scaled.icc differ diff --git a/vendor/imagine/imagine/src/resources/color.org/sRGB_IEC61966-2-1_no_black_scaling.icc b/vendor/imagine/imagine/src/resources/color.org/sRGB_IEC61966-2-1_no_black_scaling.icc new file mode 100644 index 0000000..d0ef573 Binary files /dev/null and b/vendor/imagine/imagine/src/resources/color.org/sRGB_IEC61966-2-1_no_black_scaling.icc differ diff --git a/vendor/imagine/imagine/src/resources/colormanagement.org/ISOcoated_v2_grey1c_bas.ICC b/vendor/imagine/imagine/src/resources/colormanagement.org/ISOcoated_v2_grey1c_bas.ICC new file mode 100644 index 0000000..24adafe Binary files /dev/null and b/vendor/imagine/imagine/src/resources/colormanagement.org/ISOcoated_v2_grey1c_bas.ICC differ