.github/FUNDING.yml000064400000000105150731646610007726 0ustar00github: [Intervention] custom: https://www.paypal.me/interventionphp .github/workflows/run-tests.yml000064400000001122150731646610012635 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/phpunitLICENSE000064400000002066150731646610005566 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.json000064400000001515150731646610007301 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": "dev-master", "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" } } } readme.md000064400000003115150731646610006334 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.php000064400000006406150731646610010156 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.php000064400000001234150731646610014000 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.php000064400000000137150731646610013755 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.php000064400000000676150731646610015330 0ustar00chain()->handle($input); } } src/Drivers/Abstract/Decoders/AbstractDecoder.php000064400000002202150731646610016013 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.php000064400000001334150731646610016044 0ustar00quality = $quality; return $this; } public function getQuality(): int { return $this->quality; } } src/Drivers/Abstract/Modifiers/AbstractFitModifier.php000064400000001622150731646610017045 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.php000064400000001514150731646610017027 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.php000064400000001653150731646610017565 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.php000064400000001736150731646610011112 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.php000064400000001747150731646610015131 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.php000064400000001114150731646610015027 0ustar00isValidBase64($input)) { $this->fail(); } return parent::decode(base64_decode($input)); } } src/Drivers/Gd/Decoders/BinaryImageDecoder.php000064400000003714150731646610015237 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.php000064400000001522150731646610015337 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.php000064400000001261150731646610015502 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.php000064400000001775150731646610014600 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.php000064400000001046150731646610015215 0ustar00fail(); } return $input; } } src/Drivers/Gd/Decoders/RgbStringColorDecoder.php000064400000002246150731646610015747 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.php000064400000001161150731646610016342 0ustar00fail(); } return parent::decode([0, 0, 0, 0]); } } src/Drivers/Gd/Encoders/GifEncoder.php000064400000002205150731646610013573 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.php000064400000001323150731646610013753 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.php000064400000001146150731646610013615 0ustar00getBuffered(function () use ($image) { imagepng($image->getFrames()->first()->getCore(), null, -1); }); return new EncodedImage($data, 'image/png'); } } src/Drivers/Gd/Frame.php000064400000004224150731646610011061 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.php000064400000002015150731646610011045 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.php000064400000001376150731646610012406 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.php000064400000001763150731646610012431 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.php000064400000001031150731646610015530 0ustar00getCore(), IMG_FILTER_BRIGHTNESS, ($this->level * 2.55)); } return $image; } } src/Drivers/Gd/Modifiers/ContrastModifier.php000064400000001023150731646610015216 0ustar00getCore(), IMG_FILTER_CONTRAST, ($this->level * -1)); } return $image; } } src/Drivers/Gd/Modifiers/DestroyModifier.php000064400000000617150731646610015062 0ustar00unsetCore(); } return $image; } } src/Drivers/Gd/Modifiers/FillModifier.php000064400000002731150731646610014316 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.php000064400000000456150731646610015004 0ustar00scaleDown($this->width, $this->height); } } src/Drivers/Gd/Modifiers/FitModifier.php000064400000004211150731646610014145 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.php000064400000000662150731646610015347 0ustar00getCore(), IMG_FILTER_GRAYSCALE); } return $image; } } src/Drivers/Gd/Modifiers/InvertModifier.php000064400000000654150731646610014701 0ustar00getCore(), IMG_FILTER_NEGATE); } return $image; } } src/Drivers/Gd/Modifiers/PadDownModifier.php000064400000001347150731646610014766 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.php000064400000003737150731646610014143 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.php000064400000001102150731646610015172 0ustar00getCore(), IMG_FILTER_PIXELATE, $this->size, true); } return $image; } } src/Drivers/Gd/Modifiers/PlaceModifier.php000064400000003275150731646610014460 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.php000064400000000567150731646610015526 0ustar00getSize()->resizeDown($this->width, $this->height); } } src/Drivers/Gd/Modifiers/ResizeModifier.php000064400000004375150731646610014677 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.php000064400000001272150731646610014665 0ustar00setCore( imagerotate( $frame->getCore(), $this->rotationAngle(), $this->backgroundColor()->toInt() ) ); } return $image; } } src/Drivers/Gd/Modifiers/ScaleDownModifier.php000064400000000565150731646610015312 0ustar00getSize()->scaleDown($this->width, $this->height); } } src/Drivers/Gd/Modifiers/ScaleModifier.php000064400000000555150731646610014461 0ustar00getSize()->scale($this->width, $this->height); } } src/Drivers/Gd/Modifiers/SharpenModifier.php000064400000001550150731646610015026 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.php000064400000002511150731646610012114 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.php000064400000001634150731646610016136 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.php000064400000001121150731646610016037 0ustar00isValidBase64($input)) { $this->fail(); } return parent::decode(base64_decode($input)); } } src/Drivers/Imagick/Decoders/BinaryImageDecoder.php000064400000002201150731646610016237 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.php000064400000001527150731646610016356 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.php000064400000001266150731646610016521 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.php000064400000002007150731646610015577 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.php000064400000001053150731646610016225 0ustar00fail(); } return $input; } } src/Drivers/Imagick/Decoders/RgbStringColorDecoder.php000064400000001626150731646610016762 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.php000064400000001173150731646610017357 0ustar00fail(); } return parent::decode([0, 0, 0, 0]); } } src/Drivers/Imagick/Encoders/GifEncoder.php000064400000001721150731646610014607 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.php000064400000002162150731646610014767 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.php000064400000001466150731646610014634 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.php000064400000004231150731646610012071 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.php000064400000001733150731646610012065 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.php000064400000001662150731646610013416 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.php000064400000001770150731646610013441 0ustar00getCore()->blurImage(1 * $this->amount, 0.5 * $this->amount); } return $image; } } src/Drivers/Imagick/Modifiers/BrightnessModifier.php000064400000001020150731646610016540 0ustar00getCore()->modulateImage(100 + $this->level, 100, 100); } return $image; } } src/Drivers/Imagick/Modifiers/ContrastModifier.php000064400000001045150731646610016234 0ustar00getCore()->sigmoidalContrastImage($this->level > 0, abs($this->level / 4), 0); } return $image; } } src/Drivers/Imagick/Modifiers/DestroyModifier.php000064400000000633150731646610016072 0ustar00getCore()->clear(); } return $image; } } src/Drivers/Imagick/Modifiers/FillModifier.php000064400000003403150731646610015325 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.php000064400000000463150731646610016014 0ustar00scaleDown($this->width, $this->height); } } src/Drivers/Imagick/Modifiers/FitModifier.php000064400000002023150731646610015156 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.php000064400000000660150731646610016357 0ustar00getCore()->modulateImage(100, 0, 100); } return $image; } } src/Drivers/Imagick/Modifiers/InvertModifier.php000064400000000645150731646610015713 0ustar00getCore()->negateImage(false); } return $image; } } src/Drivers/Imagick/Modifiers/PadDownModifier.php000064400000001354150731646610015776 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.php000064400000005376150731646610015156 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.php000064400000001644150731646610016217 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.php000064400000003023150731646610015461 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.php000064400000000574150731646610016536 0ustar00getSize()->resizeDown($this->width, $this->height); } } src/Drivers/Imagick/Modifiers/ResizeModifier.php000064400000001650150731646610015702 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.php000064400000001333150731646610015675 0ustar00getCore()->rotateImage( $this->backgroundColor()->getPixel(), $this->rotationAngle() ); } return $image; } protected function rotationAngle(): float { return parent::rotationAngle() * -1; } } src/Drivers/Imagick/Modifiers/ScaleDownModifier.php000064400000000572150731646610016322 0ustar00getSize()->scaleDown($this->width, $this->height); } } src/Drivers/Imagick/Modifiers/ScaleModifier.php000064400000000562150731646610015471 0ustar00getSize()->scale($this->width, $this->height); } } src/Drivers/Imagick/Modifiers/SharpenModifier.php000064400000001022150731646610016032 0ustar00getCore()->unsharpMaskImage(1, 1, $this->amount / 6.25, 0); } return $image; } } src/EncodedImage.php000064400000001550150731646610010362 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.php000064400000000155150731646610013423 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.php000064400000015321150731646610011275 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.php000064400000013662150731646610010572 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.php000064400000002043150731646610010371 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.php000064400000000407150731646610014055 0ustar00resolveDriverClass('ImageFactory'); } } src/Traits/CanDecodeDataUri.php000064400000004011150731646610012376 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.php000064400000000550150731646610012160 0ustar00resolveDriverClass('InputHandler')->handle($input); } } src/Traits/CanResizeGeometrically.php000064400000000436150731646610013732 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.php000064400000000457150731646610012451 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; } }