.github/FUNDING.yml000064400000000105150731645360007727 0ustar00github: [Intervention] custom: https://www.paypal.me/interventionphp .github/workflows/run-tests.yml000064400000001122150731645360012636 0ustar00name: run-tests on: [push] jobs: run: runs-on: ubuntu-latest strategy: matrix: php-versions: ['8.0'] name: Testing on PHP ${{ matrix.php-versions }} steps: - name: 'Checkout Project' uses: actions/checkout@v2 - name: 'Setup Environment' uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php-versions }} extensions: imagick,gd tools: phpunit,composer - name: 'Install Dependencies' run: composer install -o -q - name: 'Run PHPUnit' run: vendor/bin/phpunitLICENSE000064400000002066150731645360005567 0ustar00The MIT License (MIT) Copyright (c) 2021 Oliver Vogel Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.composer.json000064400000001551150731645360007302 0ustar00{ "name": "intervention/image", "description": "PHP image manipulation", "homepage": "http://image.intervention.io/", "keywords": ["image", "gd", "imagick", "laravel", "watermark", "thumbnail"], "license": "MIT", "authors": [ { "name": "Oliver Vogel", "email": "oliver@olivervogel.com", "homepage": "http://intervention.io/" } ], "require": { "php": "^8", "intervention/gif": "^3.0", "intervention/mimesniffer": "^0.4.2" }, "require-dev": { "phpunit/phpunit": "^9", "mockery/mockery": "^1.4" }, "autoload": { "psr-4": { "Intervention\\Image\\": "src" } }, "autoload-dev": { "psr-4": { "Intervention\\Image\\Tests\\": "tests" } }, "minimum-stability": "alpha" } readme.md000064400000003115150731645360006335 0ustar00# Intervention Image ## PHP Image Manipulation [![Latest Version](https://img.shields.io/packagist/v/intervention/image.svg)](https://packagist.org/packages/intervention/image) [![Build Status](https://travis-ci.org/Intervention/image.png?branch=master)](https://travis-ci.org/Intervention/image) [![Monthly Downloads](https://img.shields.io/packagist/dm/intervention/image.svg)](https://packagist.org/packages/intervention/image/stats) Intervention Image is a **PHP image handling and manipulation** library providing an easier and expressive way to create, edit, and compose images. - Simple interface for - Driver agnostic - Support for animated images - Framework-agnostic, will work with any project - PSR-12 compliant ## Code Examples ```php // create image manager with desired driver $manager = new ImageManager('gd') // open an image file $image = $manager->make('images/example.jpg'); // resize image instance $image->resize(320, 240); // insert a watermark $image->place('images/watermark.png'); // encode edited image $encoded = $image->toJpg(); // save encoded image $encoded->save('images/example.jpg'); ``` ## Requirements - PHP >=8.0 ## Supported Image Libraries - GD Library - Imagick PHP extension ## Installation ```bash composer require intervention/image ``` ## Getting started Learn the [basics](https://image.intervention.io/) on how to use Intervention Image and more with the [official documentation](https://image.intervention.io/). ## License Intervention Image is licensed under the [MIT License](http://opensource.org/licenses/MIT). Copyright 2021 Oliver Vogel src/Collection.php000064400000006406150731645360010157 0ustar00items); } public function toArray(): array { return $this->items; } /** * Count items in collection * * @return integer */ public function count(): int { return count($this->items); } /** * Append new item to collection * * @param mixed $item * @return CollectionInterface */ public function push($item): CollectionInterface { $this->items[] = $item; return $this; } /** * Return first item in collection * * @return mixed */ public function first() { if ($item = reset($this->items)) { return $item; } return null; } /** * Returns last item in collection * * @return mixed */ public function last() { if ($item = end($this->items)) { return $item; } return null; } /** * Return item with given key * * @param integer $key * @return mixed */ public function get(int $key = 0, $default = null) { if (! array_key_exists($key, $this->items)) { return $default; } return $this->items[$key]; } public function query(string $query, $default = null) { $items = $this->getItemsFlat(); if (!array_key_exists($query, $items)) { return $default; } return $items[$query]; } public function map(callable $callback): self { $items = array_map(function ($item) use ($callback) { return $callback($item); }, $this->items); return new self($items); } public function pushEach(array $data, ?callable $callback = null): CollectionInterface { if (! is_iterable($data)) { throw new RuntimeException('Unable to iterate given data.'); } foreach ($data as $item) { $this->push(is_callable($callback) ? $callback($item) : $item); } return $this; } private function getItemsFlat(): array { $iterator = new RecursiveIteratorIterator( new RecursiveArrayIterator($this->items) ); $items = []; foreach ($iterator as $value) { $keys = []; foreach (range(0, $iterator->getDepth()) as $depth) { $keys[] = $iterator->getSubIterator($depth)->key(); } $items[join('.', $keys)] = $value; } return $items; } } src/Drivers/Abstract/AbstractColor.php000064400000001234150731645360014001 0ustar00red(), $this->green(), $this->blue() ); } /** * Determine if color is greyscale * * @return boolean */ public function isGreyscale(): bool { return ($this->red() === $this->green()) && ($this->green() === $this->blue()); } } src/Drivers/Abstract/AbstractFrame.php000064400000000137150731645360013756 0ustar00frames; } public function getFrames(): Collection { return $this->frames; } public function getFrame(int $key = 0): ?FrameInterface { return $this->frames->get($key); } public function addFrame(FrameInterface $frame): ImageInterface { $this->frames->push($frame); return $this; } public function setLoops(int $count): ImageInterface { $this->loops = $count; return $this; } public function getLoops(): int { return $this->loops; } public function getSize(): SizeInterface { return new Size($this->getWidth(), $this->getHeight()); } public function size(): SizeInterface { return $this->getSize(); } public function isAnimated(): bool { return $this->getFrames()->count() > 1; } public function modify(ModifierInterface $modifier): ImageInterface { return $modifier->apply($this); } public function encode(EncoderInterface $encoder): EncodedImage { return $encoder->encode($this); } public function toJpeg(int $quality = 75): EncodedImage { return $this->encode( $this->resolveDriverClass('Encoders\JpegEncoder', $quality) ); } public function toGif(): EncodedImage { return $this->encode( $this->resolveDriverClass('Encoders\GifEncoder') ); } public function toPng(): EncodedImage { return $this->encode( $this->resolveDriverClass('Encoders\PngEncoder') ); } public function greyscale(): ImageInterface { return $this->modify( $this->resolveDriverClass('Modifiers\GreyscaleModifier') ); } public function invert(): ImageInterface { return $this->modify( $this->resolveDriverClass('Modifiers\InvertModifier') ); } public function brightness(int $level): ImageInterface { return $this->modify( $this->resolveDriverClass('Modifiers\BrightnessModifier', $level) ); } public function contrast(int $level): ImageInterface { return $this->modify( $this->resolveDriverClass('Modifiers\ContrastModifier', $level) ); } public function blur(int $amount = 5): ImageInterface { return $this->modify( $this->resolveDriverClass('Modifiers\BlurModifier', $amount) ); } public function rotate(float $angle, $background = 'ffffff'): ImageInterface { return $this->modify( $this->resolveDriverClass('Modifiers\RotateModifier', $angle, $background) ); } public function place($element, string $position = 'top-left', int $offset_x = 0, int $offset_y = 0): ImageInterface { return $this->modify( $this->resolveDriverClass( 'Modifiers\PlaceModifier', $element, $position, $offset_x, $offset_y ) ); } public function fill($color, ?int $x = null, ?int $y = null): ImageInterface { $color = $this->handleInput($color); $position = (is_null($x) && is_null($y)) ? null : new Point($x, $y); return $this->modify( $this->resolveDriverClass( 'Modifiers\FillModifier', $color, $position ) ); } public function pixelate(int $size): ImageInterface { return $this->modify( $this->resolveDriverClass('Modifiers\PixelateModifier', $size) ); } public function sharpen(int $amount = 10): ImageInterface { return $this->modify( $this->resolveDriverClass('Modifiers\SharpenModifier', $amount) ); } public function pickColors(int $x, int $y): Collection { $colors = new Collection(); foreach ($this->getFrames() as $key => $frame) { $colors->push($this->pickColor($x, $y, $key)); } return $colors; } public function resize(?int $width = null, ?int $height = null): ImageInterface { return $this->modify( $this->resolveDriverClass('Modifiers\ResizeModifier', $width, $height) ); } public function resizeDown(?int $width = null, ?int $height = null): ImageInterface { return $this->modify( $this->resolveDriverClass('Modifiers\ResizeDownModifier', $width, $height) ); } public function scale(?int $width = null, ?int $height = null): ImageInterface { return $this->modify( $this->resolveDriverClass('Modifiers\ScaleModifier', $width, $height) ); } public function scaleDown(?int $width = null, ?int $height = null): ImageInterface { return $this->modify( $this->resolveDriverClass('Modifiers\ScaleDownModifier', $width, $height) ); } public function fit(int $width, int $height, string $position = 'center'): ImageInterface { return $this->modify( $this->resolveDriverClass('Modifiers\FitModifier', $width, $height, $position) ); } public function fitDown(int $width, int $height, string $position = 'center'): ImageInterface { return $this->modify( $this->resolveDriverClass('Modifiers\FitDownModifier', $width, $height, $position) ); } public function pad(int $width, int $height, $background = 'ffffff', string $position = 'center'): ImageInterface { return $this->modify( $this->resolveDriverClass('Modifiers\PadModifier', $width, $height, $background, $position) ); } public function padDown(int $width, int $height, $background = 'ffffff', string $position = 'center'): ImageInterface { return $this->modify( $this->resolveDriverClass('Modifiers\PadDownModifier', $width, $height, $background, $position) ); } public function destroy(): void { $this->modify( $this->resolveDriverClass('Modifiers\DestroyModifier') ); } } src/Drivers/Abstract/AbstractInputHandler.php000064400000000676150731645360015331 0ustar00chain()->handle($input); } } src/Drivers/Abstract/Decoders/AbstractDecoder.php000064400000002202150731645360016014 0ustar00decode($input); } catch (DecoderException $e) { if ($this->hasSuccessor()) { return $this->successor->handle($input); } $this->fail(); } return $decoded; } protected function hasSuccessor(): bool { return $this->successor !== null; } protected function fail(): void { throw new DecoderException("Unable to decode given input."); } protected function inputType($input): AbstractType { return MimeSniffer::createFromString($input)->getType(); } } src/Drivers/Abstract/Encoders/AbstractEncoder.php000064400000001334150731645360016045 0ustar00quality = $quality; return $this; } public function getQuality(): int { return $this->quality; } } src/Drivers/Abstract/Modifiers/AbstractFitModifier.php000064400000001622150731645360017046 0ustar00getSize(); $crop = new Size($this->width, $this->height); $crop = $crop->contain( $imagesize->getWidth(), $imagesize->getHeight() )->alignPivotTo($imagesize, $this->position); return $crop; } protected function getResizeSize(SizeInterface $size): SizeInterface { return $size->scale($this->width, $this->height); } } src/Drivers/Abstract/Modifiers/AbstractPadModifier.php000064400000001514150731645360017030 0ustar00getSize() ->contain($this->width, $this->height) ->alignPivotTo($this->getResizeSize($image), $this->position); } protected function getResizeSize(ImageInterface $image): SizeInterface { return new Size($this->width, $this->height); } } src/Drivers/Abstract/Modifiers/AbstractRotateModifier.php000064400000001653150731645360017566 0ustar00angle, 360); } protected function backgroundColor(): ColorInterface { try { return $this->handleInput($this->background); } catch (DecoderException $e) { throw new TypeException("rotate(): Argument #2 must be a color value."); } } } src/Drivers/Gd/Color.php000064400000001736150731645360011113 0ustar00toArray()[0]; } public function green(): int { return $this->toArray()[1]; } public function blue(): int { return $this->toArray()[2]; } public function alpha(): float { return $this->toArray()[3]; } public function toArray(): array { $a = ($this->value >> 24) & 0xFF; $r = ($this->value >> 16) & 0xFF; $g = ($this->value >> 8) & 0xFF; $b = $this->value & 0xFF; $a = (float) round(1 - $a / 127, 2); return [$r, $g, $b, $a]; } public function toInt(): int { return $this->value; } } src/Drivers/Gd/Decoders/ArrayColorDecoder.php000064400000001747150731645360015132 0ustar00isValidColorArray($input)) { $this->fail(); } if (count($input) === 3) { $input[] = 1; } list($r, $g, $b, $a) = $input; return new Color( ($this->opacityToGdAlpha($a) << 24) + ($r << 16) + ($g << 8) + $b ); } protected function opacityToGdAlpha(float $opacity): int { return intval(round($opacity * 127 * -1 + 127)); } } src/Drivers/Gd/Decoders/Base64ImageDecoder.php000064400000001114150731645360015030 0ustar00isValidBase64($input)) { $this->fail(); } return parent::decode(base64_decode($input)); } } src/Drivers/Gd/Decoders/BinaryImageDecoder.php000064400000003714150731645360015240 0ustar00fail(); } if (! $this->inputType($input)->isBinary()) { $this->fail(); } if (is_a($this->inputType($input), ImageGif::class)) { return $this->decodeGif($input); // decode (animated) gif } $gd = @imagecreatefromstring($input); if ($gd === false) { $this->fail(); } if (! imageistruecolor($gd)) { imagepalettetotruecolor($gd); } imagesavealpha($gd, true); return new Image(new Collection([new Frame($gd)])); } protected function decodeGif($input): ImageInterface { $image = new Image(new Collection()); $gif = GifDecoder::decode($input); if (!$gif->isAnimated()) { return $image->addFrame(new Frame(@imagecreatefromstring($input))); } $image->setLoops($gif->getMainApplicationExtension()?->getLoops()); $splitter = GifSplitter::create($gif)->split(); $delays = $splitter->getDelays(); foreach ($splitter->coalesceToResources() as $key => $gd) { $image->addFrame((new Frame($gd))->setDelay($delays[$key] / 100)); } return $image; } } src/Drivers/Gd/Decoders/DataUriImageDecoder.php000064400000001522150731645360015340 0ustar00fail(); } $uri = $this->decodeDataUri($input); if (! $uri->isValid()) { $this->fail(); } if ($uri->isBase64Encoded()) { return parent::decode(base64_decode($uri->data())); } return parent::decode(urldecode($uri->data())); } } src/Drivers/Gd/Decoders/FilePathImageDecoder.php000064400000001261150731645360015503 0ustar00fail(); } try { if (! @is_file($input)) { $this->fail(); } } catch (Exception $e) { $this->fail(); } return parent::decode(file_get_contents($input)); } } src/Drivers/Gd/Decoders/HexColorDecoder.php000064400000001775150731645360014601 0ustar00fail(); } $pattern = '/^#?([a-f0-9]{1,2})([a-f0-9]{1,2})([a-f0-9]{1,2})$/i'; $result = preg_match($pattern, $input, $matches); if ($result !== 1) { $this->fail(); } return parent::decode([ strlen($matches[1]) == '1' ? hexdec($matches[1] . $matches[1]) : hexdec($matches[1]), strlen($matches[2]) == '1' ? hexdec($matches[2] . $matches[2]) : hexdec($matches[2]), strlen($matches[3]) == '1' ? hexdec($matches[3] . $matches[3]) : hexdec($matches[3]), ]); } } src/Drivers/Gd/Decoders/ImageObjectDecoder.php000064400000001046150731645360015216 0ustar00fail(); } return $input; } } src/Drivers/Gd/Decoders/RgbStringColorDecoder.php000064400000002246150731645360015750 0ustar00fail(); } if (substr($input, 0, 3) !== 'rgb') { $this->fail(); } // rgb string like rgb(102, 200, 0) $pattern = "/^rgb ?\((?P[0-9]{1,3}), ?(?P[0-9]{1,3}), ?(?P[0-9]{1,3})\)$/i"; if ((bool) preg_match($pattern, $input, $matches)) { return parent::decode([$matches['r'], $matches['g'], $matches['b']]); } // rgba string like "rgba(200, 10, 30, 0.5)" $pattern = "/^rgba ?\(((?P[0-9]{1,3})), ?((?P[0-9]{1,3})), ?((?P[0-9]{1,3})), ?(?P[0-9.]{1,4})\)$/i"; if ((bool) preg_match($pattern, $input, $matches)) { return parent::decode([$matches['r'], $matches['g'], $matches['b'], $matches['a']]); } $this->fail(); } } src/Drivers/Gd/Decoders/TransparentColorDecoder.php000064400000001161150731645360016343 0ustar00fail(); } return parent::decode([0, 0, 0, 0]); } } src/Drivers/Gd/Encoders/GifEncoder.php000064400000002205150731645360013574 0ustar00isAnimated()) { return $this->encodeAnimated($image); } $data = $this->getBuffered(function () use ($image) { imagegif($image->getFrames()->first()->getCore()); }); return new EncodedImage($data, 'image/gif'); } protected function encodeAnimated($image): EncodedImage { $builder = GifBuilder::canvas($image->getWidth(), $image->getHeight(), $image->getLoops()); foreach ($image as $key => $frame) { $source = $this->encode($frame->toImage()); $builder->addFrame($source, $frame->getDelay()); } return new EncodedImage($builder->encode(), 'image/gif'); } } src/Drivers/Gd/Encoders/JpegEncoder.php000064400000001323150731645360013754 0ustar00quality = $quality; } public function encode(ImageInterface $image): EncodedImage { $data = $this->getBuffered(function () use ($image) { imagejpeg($image->getFrames()->first()->getCore(), null, $this->quality); }); return new EncodedImage($data, 'image/jpeg'); } } src/Drivers/Gd/Encoders/PngEncoder.php000064400000001146150731645360013616 0ustar00getBuffered(function () use ($image) { imagepng($image->getFrames()->first()->getCore(), null, -1); }); return new EncodedImage($data, 'image/png'); } } src/Drivers/Gd/Frame.php000064400000004224150731645360011062 0ustar00core; } public function setCore(GdImage $core): self { $this->core = $core; return $this; } public function unsetCore(): void { unset($this->core); } public function getSize(): SizeInterface { return new Size(imagesx($this->core), imagesy($this->core)); } public function getDelay(): float { return $this->delay; } public function setDelay(float $delay): FrameInterface { $this->delay = $delay; return $this; } public function getDispose(): int { return $this->dispose; } public function setDispose(int $dispose): FrameInterface { $this->dispose = $dispose; return $this; } public function setOffset(int $left, int $top): FrameInterface { $this->offset_left = $left; $this->offset_top = $top; return $this; } public function getOffsetLeft(): int { return $this->offset_left; } public function setOffsetLeft(int $offset): FrameInterface { $this->offset_left = $offset; return $this; } public function getOffsetTop(): int { return $this->offset_top; } public function setOffsetTop(int $offset): FrameInterface { $this->offset_top = $offset; return $this; } public function toImage(): ImageInterface { return new Image(new Collection([$this])); } } src/Drivers/Gd/Image.php000064400000002015150731645360011046 0ustar00getFrame()->getCore()); } public function getHeight(): int { return imagesy($this->getFrame()->getCore()); } public function pickColor(int $x, int $y, int $frame_key = 0): ?ColorInterface { if ($frame = $this->getFrame($frame_key)) { return new Color(imagecolorat($frame->getCore(), $x, $y)); } return null; } } src/Drivers/Gd/ImageFactory.php000064400000001376150731645360012407 0ustar00newCore($width, $height)) ]) ); } public function newCore(int $width, int $height): GdImage { $core = imagecreatetruecolor($width, $height); $color = imagecolorallocatealpha($core, 0, 0, 0, 127); imagefill($core, 0, 0, $color); imagesavealpha($core, true); return $core; } } src/Drivers/Gd/InputHandler.php000064400000001763150731645360012432 0ustar00blurFrame($frame); } return $image; } protected function blurFrame(FrameInterface $frame): void { for ($i = 0; $i < $this->amount; $i++) { imagefilter($frame->getCore(), IMG_FILTER_GAUSSIAN_BLUR); } } } src/Drivers/Gd/Modifiers/BrightnessModifier.php000064400000001031150731645360015531 0ustar00getCore(), IMG_FILTER_BRIGHTNESS, ($this->level * 2.55)); } return $image; } } src/Drivers/Gd/Modifiers/ContrastModifier.php000064400000001023150731645360015217 0ustar00getCore(), IMG_FILTER_CONTRAST, ($this->level * -1)); } return $image; } } src/Drivers/Gd/Modifiers/DestroyModifier.php000064400000000617150731645360015063 0ustar00unsetCore(); } return $image; } } src/Drivers/Gd/Modifiers/FillModifier.php000064400000002731150731645360014317 0ustar00 $frame) { if ($this->hasPosition()) { $this->floodFillWithColor($frame); } else { $this->fillAllWithColor($frame); } } return $image; } protected function floodFillWithColor(Frame $frame): void { imagefill( $frame->getCore(), $this->position->getX(), $this->position->getY(), $this->color->toInt() ); } protected function fillAllWithColor(Frame $frame): void { imagealphablending($frame->getCore(), true); imagefilledrectangle( $frame->getCore(), 0, 0, $frame->getSize()->getWidth() - 1, $frame->getSize()->getHeight() - 1, $this->color->toInt() ); } protected function hasPosition(): bool { return !empty($this->position); } } src/Drivers/Gd/Modifiers/FitDownModifier.php000064400000000456150731645360015005 0ustar00scaleDown($this->width, $this->height); } } src/Drivers/Gd/Modifiers/FitModifier.php000064400000004211150731645360014146 0ustar00getCropSize($image); $resize = $this->getResizeSize($crop); foreach ($image as $frame) { $this->modifyFrame($frame, $crop, $resize); } return $image; } protected function modifyFrame(FrameInterface $frame, SizeInterface $crop, SizeInterface $resize): void { // create new image $modified = imagecreatetruecolor( $resize->getWidth(), $resize->getHeight() ); // get current image $current = $frame->getCore(); // preserve transparency $transIndex = imagecolortransparent($current); if ($transIndex != -1) { $rgba = imagecolorsforindex($modified, $transIndex); $transColor = imagecolorallocatealpha($modified, $rgba['red'], $rgba['green'], $rgba['blue'], 127); imagefill($modified, 0, 0, $transColor); imagecolortransparent($modified, $transColor); } else { imagealphablending($modified, false); imagesavealpha($modified, true); } // copy content from resource imagecopyresampled( $modified, $current, 0, 0, $crop->getPivot()->getX(), $crop->getPivot()->getY(), $resize->getWidth(), $resize->getHeight(), $crop->getWidth(), $crop->getHeight() ); imagedestroy($current); // set new content as recource $frame->setCore($modified); } } src/Drivers/Gd/Modifiers/GreyscaleModifier.php000064400000000662150731645360015350 0ustar00getCore(), IMG_FILTER_GRAYSCALE); } return $image; } } src/Drivers/Gd/Modifiers/InvertModifier.php000064400000000654150731645360014702 0ustar00getCore(), IMG_FILTER_NEGATE); } return $image; } } src/Drivers/Gd/Modifiers/PadDownModifier.php000064400000001347150731645360014767 0ustar00getResizeSize($image); return $image->getSize() ->contain($resize->getWidth(), $resize->getHeight()) ->alignPivotTo($resize, $this->position); } protected function getResizeSize(ImageInterface $image): SizeInterface { return (new Size($this->width, $this->height)) ->resizeDown($image->getWidth(), $image->getHeight()); } } src/Drivers/Gd/Modifiers/PadModifier.php000064400000003737150731645360014144 0ustar00getCropSize($image); $resize = $this->getResizeSize($image); $background = $this->handleInput($this->background); foreach ($image as $frame) { $this->modify($frame, $crop, $resize, $background); } return $image; } protected function modify( FrameInterface $frame, SizeInterface $crop, SizeInterface $resize, ColorInterface $background ): void { // create new image $modified = imagecreatetruecolor( $resize->getWidth(), $resize->getHeight() ); imagefill($modified, 0, 0, $background->toInt()); // get current image $current = $frame->getCore(); // preserve transparency imagealphablending($modified, false); imagesavealpha($modified, true); // copy content from resource imagecopyresampled( $modified, $current, $crop->getPivot()->getX(), $crop->getPivot()->getY(), 0, 0, $crop->getWidth(), $crop->getHeight(), $frame->getSize()->getWidth(), $frame->getSize()->getHeight() ); imagedestroy($current); // set new content as recource $frame->setCore($modified); } } src/Drivers/Gd/Modifiers/PixelateModifier.php000064400000001102150731645360015173 0ustar00getCore(), IMG_FILTER_PIXELATE, $this->size, true); } return $image; } } src/Drivers/Gd/Modifiers/PlaceModifier.php000064400000003275150731645360014461 0ustar00decodeWatermark(); $position = $this->getPosition($image, $watermark); foreach ($image as $frame) { imagealphablending($frame->getCore(), true); imagecopy( $frame->getCore(), $watermark->getFrame()->getCore(), $position->getX(), $position->getY(), 0, 0, $watermark->getWidth(), $watermark->getHeight() ); } return $image; } protected function decodeWatermark(): Image { return $this->resolveDriverClass('InputHandler')->handle($this->element); } protected function getPosition(Image $image, Image $watermark): Point { $image_size = $image->getSize()->alignPivot($this->position, $this->offset_x, $this->offset_y); $watermark_size = $watermark->getSize()->alignPivot($this->position); return $image_size->getRelativePositionTo($watermark_size); } } src/Drivers/Gd/Modifiers/ResizeDownModifier.php000064400000000567150731645360015527 0ustar00getSize()->resizeDown($this->width, $this->height); } } src/Drivers/Gd/Modifiers/ResizeModifier.php000064400000004375150731645360014700 0ustar00getAdjustedSize($image); foreach ($image as $frame) { $this->resizeFrame($frame, $resizeTo); } return $image; } protected function getAdjustedSize(ImageInterface $image): SizeInterface { return $image->getSize()->resize($this->width, $this->height); } protected function resizeFrame(FrameInterface $frame, SizeInterface $resizeTo): void { // create new image $modified = imagecreatetruecolor( $resizeTo->getWidth(), $resizeTo->getHeight() ); // get current image $current = $frame->getCore(); // preserve transparency $transIndex = imagecolortransparent($current); if ($transIndex != -1) { $rgba = imagecolorsforindex($modified, $transIndex); $transColor = imagecolorallocatealpha($modified, $rgba['red'], $rgba['green'], $rgba['blue'], 127); imagefill($modified, 0, 0, $transColor); imagecolortransparent($modified, $transColor); } else { imagealphablending($modified, false); imagesavealpha($modified, true); } // copy content from resource imagecopyresampled( $modified, $current, $resizeTo->getPivot()->getX(), $resizeTo->getPivot()->getY(), 0, 0, $resizeTo->getWidth(), $resizeTo->getHeight(), $frame->getSize()->getWidth(), $frame->getSize()->getHeight() ); imagedestroy($current); // set new content as recource $frame->setCore($modified); } } src/Drivers/Gd/Modifiers/RotateModifier.php000064400000001272150731645360014666 0ustar00setCore( imagerotate( $frame->getCore(), $this->rotationAngle(), $this->backgroundColor()->toInt() ) ); } return $image; } } src/Drivers/Gd/Modifiers/ScaleDownModifier.php000064400000000565150731645360015313 0ustar00getSize()->scaleDown($this->width, $this->height); } } src/Drivers/Gd/Modifiers/ScaleModifier.php000064400000000555150731645360014462 0ustar00getSize()->scale($this->width, $this->height); } } src/Drivers/Gd/Modifiers/SharpenModifier.php000064400000001550150731645360015027 0ustar00matrix(); foreach ($image as $frame) { imageconvolution($frame->getCore(), $matrix, 1, 0); } return $image; } protected function matrix(): array { $min = $this->amount >= 10 ? $this->amount * -0.01 : 0; $max = $this->amount * -0.025; $abs = ((4 * $min + 4 * $max) * -1) + 1; return [ [$min, $max, $min], [$max, $abs, $max], [$min, $max, $min] ]; } } src/Drivers/Imagick/Color.php000064400000002511150731645360012115 0ustar00pixel; } public function red(): int { return round($this->pixel->getColorValue(Imagick::COLOR_RED) * 255); } public function green(): int { return round($this->pixel->getColorValue(Imagick::COLOR_GREEN) * 255); } public function blue(): int { return round($this->pixel->getColorValue(Imagick::COLOR_BLUE) * 255); } public function alpha(): float { return round($this->pixel->getColorValue(Imagick::COLOR_ALPHA), 2); } public function toArray(): array { return [ $this->red(), $this->green(), $this->blue(), $this->alpha() ]; } public function toInt(): int { $r = $this->red(); $g = $this->green(); $b = $this->blue(); $a = intval(round($this->alpha() * 255)); return intval(($a << 24) + ($r << 16) + ($g << 8) + $b); } } src/Drivers/Imagick/Decoders/ArrayColorDecoder.php000064400000001634150731645360016137 0ustar00isValidColorArray($input)) { $this->fail(); } if (count($input) === 3) { $input[] = 1; } list($r, $g, $b, $a) = $input; $pixel = new ImagickPixel( sprintf('rgba(%d, %d, %d, %.2F)', $r, $g, $b, $a) ); return new Color($pixel); } } src/Drivers/Imagick/Decoders/Base64ImageDecoder.php000064400000001121150731645360016040 0ustar00isValidBase64($input)) { $this->fail(); } return parent::decode(base64_decode($input)); } } src/Drivers/Imagick/Decoders/BinaryImageDecoder.php000064400000002201150731645360016240 0ustar00fail(); } if (! $this->inputType($input)->isBinary()) { $this->fail(); } $imagick = new Imagick(); $imagick->readImageBlob($input); $imagick = $imagick->coalesceImages(); $image = new Image(new Collection()); $image->setLoops($imagick->getImageIterations()); foreach ($imagick as $frame_content) { $image->addFrame( new Frame($frame_content->getImage()) ); } return $image; } } src/Drivers/Imagick/Decoders/DataUriImageDecoder.php000064400000001527150731645360016357 0ustar00fail(); } $uri = $this->decodeDataUri($input); if (! $uri->isValid()) { $this->fail(); } if ($uri->isBase64Encoded()) { return parent::decode(base64_decode($uri->data())); } return parent::decode(urldecode($uri->data())); } } src/Drivers/Imagick/Decoders/FilePathImageDecoder.php000064400000001266150731645360016522 0ustar00fail(); } try { if (! @is_file($input)) { $this->fail(); } } catch (Exception $e) { $this->fail(); } return parent::decode(file_get_contents($input)); } } src/Drivers/Imagick/Decoders/HexColorDecoder.php000064400000002007150731645360015600 0ustar00fail(); } $pattern = '/^#?([a-f0-9]{1,2})([a-f0-9]{1,2})([a-f0-9]{1,2})$/i'; $result = preg_match($pattern, $input, $matches); if ($result !== 1) { $this->fail(); } return parent::decode([ strlen($matches[1]) == '1' ? hexdec($matches[1] . $matches[1]) : hexdec($matches[1]), strlen($matches[2]) == '1' ? hexdec($matches[2] . $matches[2]) : hexdec($matches[2]), strlen($matches[3]) == '1' ? hexdec($matches[3] . $matches[3]) : hexdec($matches[3]), ]); } } src/Drivers/Imagick/Decoders/ImageObjectDecoder.php000064400000001053150731645360016226 0ustar00fail(); } return $input; } } src/Drivers/Imagick/Decoders/RgbStringColorDecoder.php000064400000001626150731645360016763 0ustar00fail(); } if (substr($input, 0, 3) !== 'rgb') { $this->fail(); } try { $pixel = new ImagickPixel($input); } catch (ImagickPixelException $e) { $this->fail(); } return new Color($pixel); } } src/Drivers/Imagick/Decoders/TransparentColorDecoder.php000064400000001173150731645360017360 0ustar00fail(); } return parent::decode([0, 0, 0, 0]); } } src/Drivers/Imagick/Encoders/GifEncoder.php000064400000001721150731645360014610 0ustar00getFrames() as $frame) { $gif->addImage($frame->getCore()); } $gif->setImageIterations($image->getLoops()); $gif->setFormat($format); $gif->setImageFormat($format); $gif->setCompression($compression); $gif->setImageCompression($compression); $gif = $gif->deconstructImages(); return new EncodedImage($gif->getImagesBlob(), 'image/gif'); } } src/Drivers/Imagick/Encoders/JpegEncoder.php000064400000002162150731645360014770 0ustar00quality = $quality; } public function encode(ImageInterface $image): EncodedImage { $format = 'jpeg'; $compression = Imagick::COMPRESSION_JPEG; $imagick = $image->getFrames()->first()->getCore(); $imagick->setImageBackgroundColor('white'); $imagick->setBackgroundColor('white'); $imagick->setFormat($format); $imagick->setImageFormat($format); $imagick->setCompression($compression); $imagick->setImageCompression($compression); $imagick->setCompressionQuality($this->quality); $imagick->setImageCompressionQuality($this->quality); return new EncodedImage($imagick->getImagesBlob(), 'image/jpeg'); } } src/Drivers/Imagick/Encoders/PngEncoder.php000064400000001466150731645360014635 0ustar00getFrames()->first()->getCore(); $imagick->setFormat($format); $imagick->setImageFormat($format); $imagick->setCompression($compression); $imagick->setImageCompression($compression); return new EncodedImage($imagick->getImagesBlob(), 'image/png'); } } src/Drivers/Imagick/Frame.php000064400000004231150731645360012072 0ustar00core; } public function setCore(Imagick $core): FrameInterface { $this->core = $core; return $this; } public function getSize(): SizeInterface { return new Size($this->core->getImageWidth(), $this->core->getImageHeight()); } public function getDelay(): float { return $this->core->getImageDelay() / 100; } public function setDelay(float $delay): FrameInterface { $this->core->setImageDelay(round($delay * 100)); return $this; } public function getDispose(): int { return $this->core->getImageDispose(); } public function setDispose(int $dispose): FrameInterface { $this->core->setImageDispose($dispose); return $this; } public function setOffset(int $left, int $top): FrameInterface { $this->core->setImagePage( $this->core->getImageWidth(), $this->core->getImageHeight(), $left, $top ); return $this; } public function getOffsetLeft(): int { return $this->core->getImagePage()['x']; } public function setOffsetLeft(int $offset): FrameInterface { return $this->setOffset($offset, $this->getOffsetTop()); } public function getOffsetTop(): int { return $this->core->getImagePage()['y']; } public function setOffsetTop(int $offset): FrameInterface { return $this->setOffset($this->getOffsetLeft(), $offset); } public function toImage(): ImageInterface { return new Image(new Collection([$this])); } } src/Drivers/Imagick/Image.php000064400000001733150731645360012066 0ustar00frames->first()->getCore()->getImageWidth(); } public function getHeight(): int { return $this->frames->first()->getCore()->getImageHeight(); } public function pickColor(int $x, int $y, int $frame_key = 0): ?ColorInterface { if ($frame = $this->getFrame($frame_key)) { return new Color($frame->getCore()->getImagePixelColor($x, $y)); } return null; } } src/Drivers/Imagick/ImageFactory.php000064400000001662150731645360013417 0ustar00newCore($width, $height)) ]) ); } public function newCore(int $width, int $height): Imagick { $imagick = new Imagick(); $imagick->newImage($width, $height, new ImagickPixel('rgba(0, 0, 0, 0)'), 'png'); $imagick->setType(Imagick::IMGTYPE_UNDEFINED); $imagick->setImageType(Imagick::IMGTYPE_UNDEFINED); $imagick->setColorspace(Imagick::COLORSPACE_UNDEFINED); return $imagick; } } src/Drivers/Imagick/InputHandler.php000064400000001770150731645360013442 0ustar00getCore()->blurImage(1 * $this->amount, 0.5 * $this->amount); } return $image; } } src/Drivers/Imagick/Modifiers/BrightnessModifier.php000064400000001020150731645360016541 0ustar00getCore()->modulateImage(100 + $this->level, 100, 100); } return $image; } } src/Drivers/Imagick/Modifiers/ContrastModifier.php000064400000001045150731645360016235 0ustar00getCore()->sigmoidalContrastImage($this->level > 0, abs($this->level / 4), 0); } return $image; } } src/Drivers/Imagick/Modifiers/DestroyModifier.php000064400000000633150731645360016073 0ustar00getCore()->clear(); } return $image; } } src/Drivers/Imagick/Modifiers/FillModifier.php000064400000003403150731645360015326 0ustar00hasPosition()) { $this->floodFillWithColor($frame); } else { $this->fillAllWithColor($frame); } } return $image; } protected function floodFillWithColor(Frame $frame): void { $target = $frame->getCore()->getImagePixelColor( $this->position->getX(), $this->position->getY() ); $frame->getCore()->floodfillPaintImage( $this->color->getPixel(), 100, $target, $this->position->getX(), $this->position->getY(), false, Imagick::CHANNEL_ALL ); } protected function fillAllWithColor(Frame $frame): void { $draw = new ImagickDraw(); $draw->setFillColor($this->color->getPixel()); $draw->rectangle( 0, 0, $frame->getCore()->getImageWidth(), $frame->getCore()->getImageHeight() ); $frame->getCore()->drawImage($draw); } protected function hasPosition(): bool { return !empty($this->position); } } src/Drivers/Imagick/Modifiers/FitDownModifier.php000064400000000463150731645360016015 0ustar00scaleDown($this->width, $this->height); } } src/Drivers/Imagick/Modifiers/FitModifier.php000064400000002023150731645360015157 0ustar00getCropSize($image); $resize = $this->getResizeSize($crop); foreach ($image as $frame) { $frame->getCore()->extentImage( $crop->getWidth(), $crop->getHeight(), $crop->getPivot()->getX(), $crop->getPivot()->getY() ); $frame->getCore()->scaleImage( $resize->getWidth(), $resize->getHeight() ); } return $image; } } src/Drivers/Imagick/Modifiers/GreyscaleModifier.php000064400000000660150731645360016360 0ustar00getCore()->modulateImage(100, 0, 100); } return $image; } } src/Drivers/Imagick/Modifiers/InvertModifier.php000064400000000645150731645360015714 0ustar00getCore()->negateImage(false); } return $image; } } src/Drivers/Imagick/Modifiers/PadDownModifier.php000064400000001354150731645360015777 0ustar00getResizeSize($image); return $image->getSize() ->contain($resize->getWidth(), $resize->getHeight()) ->alignPivotTo($resize, $this->position); } protected function getResizeSize(ImageInterface $image): SizeInterface { return (new Size($this->width, $this->height)) ->resizeDown($image->getWidth(), $image->getHeight()); } } src/Drivers/Imagick/Modifiers/PadModifier.php000064400000005376150731645360015157 0ustar00getResizeSize($image); $crop = $this->getCropSize($image); $background = $this->handleInput($this->background); foreach ($image as $frame) { // resize current core $frame->getCore()->scaleImage( $crop->getWidth(), $crop->getHeight() ); // create new canvas, to get newly emerged background color $canvas = $this->buildBaseCanvas($crop, $resize, $background); // place current core onto canvas $canvas->compositeImage( $frame->getCore(), Imagick::COMPOSITE_DEFAULT, $crop->getPivot()->getX(), $crop->getPivot()->getY() ); // replace core $frame->getCore()->destroy(); $frame->setCore($canvas); } return $image; } protected function buildBaseCanvas(SizeInterface $crop, SizeInterface $resize, ColorInterface $background): Imagick { // build base canvas in target size $canvas = $this->imageFactory()->newCore( $resize->getWidth(), $resize->getHeight() ); // draw background color on canvas $draw = new ImagickDraw(); $draw->setFillColor($background->getPixel()); $draw->rectangle(0, 0, $canvas->getImageWidth(), $canvas->getImageHeight()); $canvas->drawImage($draw); // make area where image is placed transparent to keep // transparency even if background-color is set $draw = new ImagickDraw(); $fill = $background->toHex('#') == '#ff0000' ? '#00ff00' : '#ff0000'; $draw->setFillColor($fill); $draw->rectangle( $crop->getPivot()->getX(), $crop->getPivot()->getY(), $crop->getPivot()->getX() + $crop->getWidth() - 1, $crop->getPivot()->getY() + $crop->getHeight() - 1 ); $canvas->drawImage($draw); $canvas->transparentPaintImage($fill, 0, 0, false); return $canvas; } } src/Drivers/Imagick/Modifiers/PixelateModifier.php000064400000001644150731645360016220 0ustar00pixelateFrame($frame); } return $image; } protected function pixelateFrame(Frame $frame): void { $size = $frame->getSize(); $frame->getCore()->scaleImage( max(1, ($size->getWidth() / $this->size)), max(1, ($size->getHeight() / $this->size)) ); $frame->getCore()->scaleImage($size->getWidth(), $size->getHeight()); } } src/Drivers/Imagick/Modifiers/PlaceModifier.php000064400000003023150731645360015462 0ustar00decodeWatermark(); $position = $this->getPosition($image, $watermark); foreach ($image as $frame) { $frame->getCore()->compositeImage( $watermark->getFrame()->getCore(), Imagick::COMPOSITE_DEFAULT, $position->getX(), $position->getY() ); } return $image; } protected function decodeWatermark(): Image { return $this->resolveDriverClass('InputHandler')->handle($this->element); } protected function getPosition(Image $image, Image $watermark): Point { $image_size = $image->getSize()->alignPivot($this->position, $this->offset_x, $this->offset_y); $watermark_size = $watermark->getSize()->alignPivot($this->position); return $image_size->getRelativePositionTo($watermark_size); } } src/Drivers/Imagick/Modifiers/ResizeDownModifier.php000064400000000574150731645360016537 0ustar00getSize()->resizeDown($this->width, $this->height); } } src/Drivers/Imagick/Modifiers/ResizeModifier.php000064400000001650150731645360015703 0ustar00getAdjustedSize($image); foreach ($image as $frame) { $frame->getCore()->scaleImage( $resizeTo->getWidth(), $resizeTo->getHeight() ); } return $image; } protected function getAdjustedSize(ImageInterface $image): SizeInterface { return $image->getSize()->resize($this->width, $this->height); } } src/Drivers/Imagick/Modifiers/RotateModifier.php000064400000001333150731645360015676 0ustar00getCore()->rotateImage( $this->backgroundColor()->getPixel(), $this->rotationAngle() ); } return $image; } protected function rotationAngle(): float { return parent::rotationAngle() * -1; } } src/Drivers/Imagick/Modifiers/ScaleDownModifier.php000064400000000572150731645360016323 0ustar00getSize()->scaleDown($this->width, $this->height); } } src/Drivers/Imagick/Modifiers/ScaleModifier.php000064400000000562150731645360015472 0ustar00getSize()->scale($this->width, $this->height); } } src/Drivers/Imagick/Modifiers/SharpenModifier.php000064400000001022150731645360016033 0ustar00getCore()->unsharpMaskImage(1, 1, $this->amount / 6.25, 0); } return $image; } } src/EncodedImage.php000064400000001550150731645360010363 0ustar00mimetype; } public function save(string $filepath): void { $saved = @file_put_contents($filepath, (string) $this); if ($saved === false) { throw new NotWritableException( "Can't write image data to path ({$filepath})." ); } } public function toDataUri(): string { return sprintf('data:%s;base64,%s', $this->mimetype, base64_encode($this->data)); } public function __toString(): string { return $this->data; } } src/Exceptions/DecoderException.php000064400000000155150731645360013424 0ustar00x = $x; return $this; } /** * Get X coordinate * * @return integer */ public function getX(): int { return $this->x; } /** * Sets Y coordinate * * @param integer $y */ public function setY(int $y): self { $this->y = $y; return $this; } /** * Get Y coordinate * * @return integer */ public function getY(): int { return $this->y; } /** * Move X coordinate * * @param integer $x */ public function moveX(int $value): self { $this->x += $value; return $this; } /** * Move Y coordinate * * @param integer $y */ public function moveY(int $value): self { $this->y += $value; return $this; } /** * Sets both X and Y coordinate * * @param integer $x * @param integer $y * @return Point */ public function setPosition(int $x, int $y): self { $this->setX($x); $this->setY($y); return $this; } /** * Rotate point ccw around pivot * * @param float $angle * @param Point $pivot * @return Point */ public function rotate(float $angle, Point $pivot): self { $sin = round(sin(deg2rad($angle)), 6); $cos = round(cos(deg2rad($angle)), 6); return $this->setPosition( $cos * ($this->x - $pivot->x) - $sin * ($this->y - $pivot->y) + $pivot->x, $sin * ($this->x - $pivot->x) + $cos * ($this->y - $pivot->y) + $pivot->y ); } } src/Geometry/Resizer.php000064400000015321150731645360011276 0ustar00width); } protected function getTargetWidth(): ?int { return $this->hasTargetWidth() ? $this->width : null; } protected function hasTargetHeight(): bool { return is_integer($this->height); } protected function getTargetHeight(): ?int { return $this->hasTargetHeight() ? $this->height : null; } protected function getTargetSize(): SizeInterface { if (!$this->hasTargetWidth() || !$this->hasTargetHeight()) { throw new GeometryException('Target size needs width and height.'); } return new Size($this->width, $this->height); } public function toWidth(int $width): self { $this->width = $width; return $this; } public function toHeight(int $height): self { $this->height = $height; return $this; } public function toSize(SizeInterface $size): self { $this->width = $size->getWidth(); $this->height = $size->getHeight(); return $this; } protected function getProportionalWidth(SizeInterface $size): int { if (! $this->hasTargetHeight()) { return $size->getWidth(); } return (int) round($this->height * $size->getAspectRatio()); } protected function getProportionalHeight(SizeInterface $size): int { if (! $this->hasTargetWidth()) { return $size->getHeight(); } return (int) round($this->width / $size->getAspectRatio()); } public function resize(SizeInterface $size): SizeInterface { $resized = new Size($size->getWidth(), $size->getHeight()); if ($width = $this->getTargetWidth()) { $resized->setWidth($width); } if ($height = $this->getTargetHeight()) { $resized->setHeight($height); } return $resized; } public function resizeDown(SizeInterface $size): SizeInterface { $resized = new Size($size->getWidth(), $size->getHeight()); if ($width = $this->getTargetWidth()) { $resized->setWidth( min($width, $size->getWidth()) ); } if ($height = $this->getTargetHeight()) { $resized->setHeight( min($height, $size->getHeight()) ); } return $resized; } public function scale(SizeInterface $size): SizeInterface { $resized = new Size($size->getWidth(), $size->getHeight()); if ($this->hasTargetWidth() && $this->hasTargetHeight()) { $resized->setWidth(min( $this->getProportionalWidth($size), $this->getTargetWidth() )); $resized->setHeight(min( $this->getProportionalHeight($size), $this->getTargetHeight() )); } elseif ($this->hasTargetWidth()) { $resized->setWidth($this->getTargetWidth()); $resized->setHeight($this->getProportionalHeight($size)); } elseif ($this->hasTargetHeight()) { $resized->setWidth($this->getProportionalWidth($size)); $resized->setHeight($this->getTargetHeight()); } return $resized; } public function scaleDown(SizeInterface $size): SizeInterface { $resized = new Size($size->getWidth(), $size->getHeight()); if ($this->hasTargetWidth() && $this->hasTargetHeight()) { $resized->setWidth(min( $this->getProportionalWidth($size), $this->getTargetWidth(), $size->getWidth() )); $resized->setHeight(min( $this->getProportionalHeight($size), $this->getTargetHeight(), $size->getHeight() )); } elseif ($this->hasTargetWidth()) { $resized->setWidth(min( $this->getTargetWidth(), $size->getWidth() )); $resized->setHeight(min( $this->getProportionalHeight($size), $size->getHeight() )); } elseif ($this->hasTargetHeight()) { $resized->setWidth(min( $this->getProportionalWidth($size), $size->getWidth() )); $resized->setHeight(min( $this->getTargetHeight(), $size->getHeight() )); } return $resized; } /** * Scale given size to cover target size * * @param SizeInterface $size Size to be resized * @return SizeInterface */ public function cover(SizeInterface $size): SizeInterface { $resized = new Size($size->getWidth(), $size->getHeight()); // auto height $resized->setWidth($this->getTargetWidth()); $resized->setHeight($this->getProportionalHeight($size)); if ($resized->fitsInto($this->getTargetSize())) { // auto width $resized->setWidth($this->getProportionalWidth($size)); $resized->setHeight($this->getTargetHeight()); } return $resized; } /** * Scale given size to contain target size * * @param SizeInterface $size Size to be resized * @return SizeInterface */ public function contain(SizeInterface $size): SizeInterface { $resized = new Size($size->getWidth(), $size->getHeight()); // auto height $resized->setWidth($this->getTargetWidth()); $resized->setHeight($this->getProportionalHeight($size)); if (!$resized->fitsInto($this->getTargetSize())) { // auto width $resized->setWidth($this->getProportionalWidth($size)); $resized->setHeight($this->getTargetHeight()); } return $resized; } /** * Crop target size out of given size at given position (i.e. move the pivot point) * * @param SizeInterface $size * @param string $position * @return SizeInterface */ public function crop(SizeInterface $size, string $position = 'top-left'): SizeInterface { return $this->resize($size)->alignPivotTo( $size->alignPivot($position), $position ); } } src/Geometry/Size.php000064400000013662150731645360010573 0ustar00pivot = $pivot ? $pivot : new Point(); } public function getWidth(): int { return $this->width; } public function getHeight(): int { return $this->height; } public function setWidth(int $width): SizeInterface { $this->width = $width; return $this; } public function setHeight(int $height): SizeInterface { $this->height = $height; return $this; } /** * Get current pivot point * * @return Point */ public function getPivot(): PointInterface { return $this->pivot; } public function setPivot(PointInterface $pivot): self { $this->pivot = $pivot; return $this; } public function getAspectRatio(): float { return $this->width / $this->height; } public function fitsInto(SizeInterface $size): bool { if ($this->getWidth() > $size->getWidth()) { return false; } if ($this->getHeight() > $size->getHeight()) { return false; } return true; } /** * Determine if size is landscape format * * @return boolean */ public function isLandscape(): bool { return $this->getWidth() > $this->getHeight(); } /** * Determine if size is portrait format * * @return boolean */ public function isPortrait(): bool { return $this->getWidth() < $this->getHeight(); } /** * Aligns current size's pivot point to given position * and moves point automatically by offset. * * @param string $position * @param int $offset_x * @param int $offset_y * @return Size */ public function alignPivot(string $position, int $offset_x = 0, int $offset_y = 0): self { switch (strtolower($position)) { case 'top': case 'top-center': case 'top-middle': case 'center-top': case 'middle-top': $x = intval($this->width / 2); $y = 0 + $offset_y; break; case 'top-right': case 'right-top': $x = $this->width - $offset_x; $y = 0 + $offset_y; break; case 'left': case 'left-center': case 'left-middle': case 'center-left': case 'middle-left': $x = 0 + $offset_x; $y = intval($this->height / 2); break; case 'right': case 'right-center': case 'right-middle': case 'center-right': case 'middle-right': $x = $this->width - $offset_x; $y = intval($this->height / 2); break; case 'bottom-left': case 'left-bottom': $x = 0 + $offset_x; $y = $this->height - $offset_y; break; case 'bottom': case 'bottom-center': case 'bottom-middle': case 'center-bottom': case 'middle-bottom': $x = intval($this->width / 2); $y = $this->height - $offset_y; break; case 'bottom-right': case 'right-bottom': $x = $this->width - $offset_x; $y = $this->height - $offset_y; break; case 'center': case 'middle': case 'center-center': case 'middle-middle': $x = intval($this->width / 2) + $offset_x; $y = intval($this->height / 2) + $offset_y; break; default: case 'top-left': case 'left-top': $x = 0 + $offset_x; $y = 0 + $offset_y; break; } $this->pivot->setPosition($x, $y); return $this; } public function alignPivotTo(Size $size, string $position): self { $reference = new Size($size->getWidth(), $size->getHeight()); $reference->alignPivot($position); $this->alignPivot($position)->setPivot( $reference->getRelativePositionTo($this) ); return $this; } /** * Calculate the relative position to another Size * based on the pivot point settings of both sizes. * * @param Size $size * @return Point */ public function getRelativePositionTo(Size $size): Point { $x = $this->getPivot()->getX() - $size->getPivot()->getX(); $y = $this->getPivot()->getY() - $size->getPivot()->getY(); return new Point($x, $y); } protected function getResizer(...$arguments): Resizer { return new Resizer(...$arguments); } public function resize(...$arguments): self { return $this->getResizer(...$arguments)->resize($this); } public function resizeDown(...$arguments): self { return $this->getResizer(...$arguments)->resizeDown($this); } public function scale(...$arguments): self { return $this->getResizer(...$arguments)->scale($this); } public function scaleDown(...$arguments): self { return $this->getResizer(...$arguments)->scaleDown($this); } public function cover(int $width, int $height): self { return $this->getResizer($width, $height)->cover($this); } public function contain(int $width, int $height): self { return $this->getResizer($width, $height)->contain($this); } } src/ImageManager.php000064400000002043150731645360010372 0ustar00resolveDriverClass('ImageFactory')->newImage($width, $height); } /** * Create new image instance from source * * @param mixed $source * @return ImageInterface */ public function make($source): ImageInterface { return $this->resolveDriverClass('InputHandler')->handle($source); } /** * Return id of current driver * * @return string */ protected function getCurrentDriver(): string { return strtolower($this->driver); } } src/Interfaces/CollectionInterface.php000064400000000407150731645360014056 0ustar00resolveDriverClass('ImageFactory'); } } src/Traits/CanDecodeDataUri.php000064400000004011150731645360012377 0ustar00\w+\/[-+.\w]+)?(?P(;[-\w]+=[-\w]+)*)(?P;base64)?,(?P.*)/"; $result = preg_match($pattern, $value, $matches); return new class ($matches, $result) { private $matches; private $result; public function __construct($matches, $result) { $this->matches = $matches; $this->result = $result; } public function isValid(): bool { return (bool) $this->result; } public function mediaType(): ?string { if (isset($this->matches['mediatype']) && !empty($this->matches['mediatype'])) { return $this->matches['mediatype']; } return null; } public function hasMediaType(): bool { return !empty($this->mediaType()); } public function parameters(): array { if (isset($this->matches['parameters']) && !empty($this->matches['parameters'])) { return explode(';', trim($this->matches['parameters'], ';')); } return []; } public function isBase64Encoded(): bool { if (isset($this->matches['base64']) && $this->matches['base64'] === ';base64') { return true; } return false; } public function data(): ?string { if (isset($this->matches['data']) && !empty($this->matches['data'])) { return $this->matches['data']; } return null; } }; } } src/Traits/CanHandleInput.php000064400000000550150731645360012161 0ustar00resolveDriverClass('InputHandler')->handle($input); } } src/Traits/CanResizeGeometrically.php000064400000000436150731645360013733 0ustar00getCurrentDriver(); $classname = sprintf( "Intervention\\Image\\Drivers\\%s\\%s", ucfirst($driver_id), $classname ); try { $reflection = new ReflectionClass($classname); } catch (ReflectionException $e) { throw new MissingDriverComponentException( 'Class (' . $classname . ') could not be resolved with driver ' . ucfirst($driver_id) . '.' ); } return $reflection->newInstanceArgs($arguments); } protected function getCurrentDriver(): string { $pattern = '/Intervention\\\Image\\\Drivers\\\(?P[A-Za-z]+)/'; preg_match($pattern, get_class($this), $matches); if (! array_key_exists('driver', $matches)) { throw new RuntimeException('Current driver could not be resolved.'); } return strtolower($matches['driver']); } } src/Traits/CanValidateBase64.php000064400000000457150731645360012452 0ustar00 4) { return false; } // validate rgb values foreach ($input as $value) { if ($value < 0 || $value > 255) { return false; } } // validate alpha value if (isset($input[3]) && ($input[3] > 1 || $input[3] < 0)) { return false; } return true; } }