1
0
mirror of https://github.com/Intervention/image.git synced 2025-08-12 08:54:03 +02:00

Refactor architecture

This commit is contained in:
Oliver Vogel
2023-11-19 12:20:15 +01:00
parent a9922e2c9a
commit 293c4efc84
189 changed files with 2306 additions and 1827 deletions

View File

@@ -13,7 +13,6 @@ class Collection implements CollectionInterface, IteratorAggregate, Countable
{ {
public function __construct(protected array $items = []) public function __construct(protected array $items = [])
{ {
//
} }
/** /**
@@ -27,6 +26,11 @@ class Collection implements CollectionInterface, IteratorAggregate, Countable
return new self($items); return new self($items);
} }
public function has(int|string $key): bool
{
return array_key_exists($key, $this->items);
}
/** /**
* Returns Iterator * Returns Iterator
* *

View File

@@ -3,7 +3,7 @@
namespace Intervention\Image\Colors\Cmyk\Decoders; namespace Intervention\Image\Colors\Cmyk\Decoders;
use Intervention\Image\Colors\Cmyk\Color; use Intervention\Image\Colors\Cmyk\Color;
use Intervention\Image\Drivers\Abstract\Decoders\AbstractDecoder; use Intervention\Image\Drivers\AbstractDecoder;
use Intervention\Image\Exceptions\DecoderException; use Intervention\Image\Exceptions\DecoderException;
use Intervention\Image\Interfaces\ColorInterface; use Intervention\Image\Interfaces\ColorInterface;
use Intervention\Image\Interfaces\DecoderInterface; use Intervention\Image\Interfaces\DecoderInterface;

View File

@@ -7,5 +7,4 @@ use Intervention\Image\Interfaces\ProfileInterface;
class Profile extends GenericData implements ProfileInterface class Profile extends GenericData implements ProfileInterface
{ {
//
} }

View File

@@ -3,7 +3,7 @@
namespace Intervention\Image\Colors\Rgb\Decoders; namespace Intervention\Image\Colors\Rgb\Decoders;
use Intervention\Image\Colors\Rgb\Color; use Intervention\Image\Colors\Rgb\Color;
use Intervention\Image\Drivers\Abstract\Decoders\AbstractDecoder; use Intervention\Image\Drivers\AbstractDecoder;
use Intervention\Image\Exceptions\DecoderException; use Intervention\Image\Exceptions\DecoderException;
use Intervention\Image\Interfaces\ColorInterface; use Intervention\Image\Interfaces\ColorInterface;
use Intervention\Image\Interfaces\DecoderInterface; use Intervention\Image\Interfaces\DecoderInterface;

View File

@@ -3,7 +3,7 @@
namespace Intervention\Image\Colors\Rgb\Decoders; namespace Intervention\Image\Colors\Rgb\Decoders;
use Intervention\Image\Colors\Rgb\Color; use Intervention\Image\Colors\Rgb\Color;
use Intervention\Image\Drivers\Abstract\Decoders\AbstractDecoder; use Intervention\Image\Drivers\AbstractDecoder;
use Intervention\Image\Exceptions\DecoderException; use Intervention\Image\Exceptions\DecoderException;
use Intervention\Image\Interfaces\ColorInterface; use Intervention\Image\Interfaces\ColorInterface;
use Intervention\Image\Interfaces\DecoderInterface; use Intervention\Image\Interfaces\DecoderInterface;

View File

@@ -19,7 +19,7 @@ use Intervention\Image\Traits\CanHandleInput;
use Intervention\Image\Traits\CanResolveDriverClass; use Intervention\Image\Traits\CanResolveDriverClass;
use Intervention\Image\Traits\CanRunCallback; use Intervention\Image\Traits\CanRunCallback;
abstract class AbstractImage implements ImageInterface abstract class DELETE___AbstractImage implements ImageInterface
{ {
use CanResolveDriverClass; use CanResolveDriverClass;
use CanHandleInput; use CanHandleInput;

View File

@@ -8,7 +8,7 @@ use Intervention\Image\Interfaces\ColorInterface;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\InputHandlerInterface; use Intervention\Image\Interfaces\InputHandlerInterface;
abstract class AbstractInputHandler implements InputHandlerInterface abstract class DELETE____AbstractInputHandler implements InputHandlerInterface
{ {
/** /**
* Array of decoders which will be stacked into to the input handler chain * Array of decoders which will be stacked into to the input handler chain

View File

@@ -9,7 +9,7 @@ use Intervention\Image\Interfaces\DecoderInterface;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Traits\CanBuildFilePointer; use Intervention\Image\Traits\CanBuildFilePointer;
abstract class AbstractDecoder implements DecoderInterface abstract class DELETE___AbstractDecoder implements DecoderInterface
{ {
use CanBuildFilePointer; use CanBuildFilePointer;

View File

@@ -14,18 +14,11 @@ use Intervention\Image\Interfaces\PointInterface;
use Intervention\Image\Traits\CanCheckType; use Intervention\Image\Traits\CanCheckType;
use Intervention\Image\Traits\CanHandleInput; use Intervention\Image\Traits\CanHandleInput;
class AbstractDrawModifier class DELETE__AbstractDrawModifier
{ {
use CanHandleInput; use CanHandleInput;
use CanCheckType; use CanCheckType;
public function __construct(
protected PointInterface $position,
protected DrawableInterface $drawable
) {
//
}
public function drawable(): DrawableInterface public function drawable(): DrawableInterface
{ {
return $this->drawable; return $this->drawable;

View File

@@ -6,14 +6,13 @@ use Intervention\Image\Geometry\Rectangle;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\SizeInterface; use Intervention\Image\Interfaces\SizeInterface;
abstract class AbstractFitModifier abstract class DELETE___AbstractFitModifier
{ {
public function __construct( public function __construct(
protected int $width, protected int $width,
protected int $height, protected int $height,
protected string $position = 'center' protected string $position = 'center'
) { ) {
//
} }
protected function getCropSize(ImageInterface $image): SizeInterface protected function getCropSize(ImageInterface $image): SizeInterface

View File

@@ -7,7 +7,7 @@ use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\SizeInterface; use Intervention\Image\Interfaces\SizeInterface;
use Intervention\Image\Traits\CanCheckType; use Intervention\Image\Traits\CanCheckType;
abstract class AbstractPadModifier abstract class DELETE___AbstractPadModifier
{ {
use CanCheckType; use CanCheckType;
@@ -20,14 +20,14 @@ abstract class AbstractPadModifier
// //
} }
protected function getCropSize(ImageInterface $image): SizeInterface public function getCropSize(ImageInterface $image): SizeInterface
{ {
return $image->size() return $image->size()
->contain($this->width, $this->height) ->contain($this->width, $this->height)
->alignPivotTo($this->getResizeSize($image), $this->position); ->alignPivotTo($this->getResizeSize($image), $this->position);
} }
protected function getResizeSize(ImageInterface $image): SizeInterface public function getResizeSize(ImageInterface $image): SizeInterface
{ {
return new Rectangle($this->width, $this->height); return new Rectangle($this->width, $this->height);
} }

View File

@@ -6,7 +6,7 @@ use Intervention\Image\Exceptions\InputException;
use Intervention\Image\Interfaces\FrameInterface; use Intervention\Image\Interfaces\FrameInterface;
use Intervention\Image\Interfaces\ModifierInterface; use Intervention\Image\Interfaces\ModifierInterface;
abstract class AbstractRemoveAnimationModifier implements ModifierInterface abstract class DELETE___AbstractRemoveAnimationModifier implements ModifierInterface
{ {
protected function chosenFrame($image, int|string $position): FrameInterface protected function chosenFrame($image, int|string $position): FrameInterface
{ {

View File

@@ -8,7 +8,7 @@ use Intervention\Image\Interfaces\ColorInterface;
use Intervention\Image\Traits\CanCheckType; use Intervention\Image\Traits\CanCheckType;
use Intervention\Image\Traits\CanHandleInput; use Intervention\Image\Traits\CanHandleInput;
abstract class AbstractRotateModifier abstract class DELETE____AbstractRotateModifier
{ {
use CanHandleInput; use CanHandleInput;
use CanCheckType; use CanCheckType;

View File

@@ -0,0 +1,155 @@
<?php
namespace Intervention\Image\Drivers;
use Exception;
use Intervention\Image\Collection;
use Intervention\Image\Exceptions\DecoderException;
use Intervention\Image\Interfaces\CollectionInterface;
use Intervention\Image\Interfaces\ColorInterface;
use Intervention\Image\Interfaces\DecoderInterface;
use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Traits\CanBuildFilePointer;
abstract class AbstractDecoder implements DecoderInterface
{
use CanBuildFilePointer;
public function __construct(protected ?AbstractDecoder $successor = null)
{
//
}
final public function handle($input): ImageInterface|ColorInterface
{
try {
$decoded = $this->decode($input);
} catch (DecoderException $e) {
if (!$this->hasSuccessor()) {
throw new DecoderException($e->getMessage());
}
return $this->successor->handle($input);
}
return $decoded;
}
protected function hasSuccessor(): bool
{
return $this->successor !== null;
}
/**
* Return media type (MIME) of given input
*
* @param string $input
* @return string
*/
protected function mediaType(string $input): string
{
$pointer = $this->buildFilePointer($input);
$type = mime_content_type($pointer);
fclose($pointer);
return $type;
}
protected function decodeExifData(string $image_data): CollectionInterface
{
if (!function_exists('exif_read_data')) {
return [];
}
try {
$pointer = $this->buildFilePointer($image_data);
$data = @exif_read_data($pointer, null, true);
fclose($pointer);
} catch (Exception $e) {
$data = [];
}
return new Collection(is_array($data) ? $data : []);
}
protected function isValidBase64($input): bool
{
if (!is_string($input)) {
return false;
}
return base64_encode(base64_decode($input)) === str_replace(["\n", "\r"], '', $input);
}
/**
* Parse data uri
*
* @param mixed $value
* @return object
*/
protected function parseDataUri($value): object
{
$pattern = "/^data:(?P<mediatype>\w+\/[-+.\w]+)?" .
"(?P<parameters>(;[-\w]+=[-\w]+)*)(?P<base64>;base64)?,(?P<data>.*)/";
$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;
}
};
}
}

View File

@@ -0,0 +1,33 @@
<?php
namespace Intervention\Image\Drivers;
use Intervention\Image\Interfaces\DriverInterface;
use ReflectionClass;
abstract class AbstractDriver implements DriverInterface
{
public function resolve(object $input): object
{
$ns = (new ReflectionClass($this))->getNamespaceName();
$classname = (new ReflectionClass($input))->getShortName();
preg_match("/(?P<dept>[A-Z][a-z]+)$/", $classname, $matches);
$department = array_key_exists('dept', $matches) ? $matches['dept'] : null;
$department = match ($department) {
'Modifier', 'Writer' => 'Modifiers',
'Encoder' => 'Encoders',
default => null,
};
$specialized = implode("\\", array_filter([
$ns,
$department,
$classname
], function ($dept) {
return !empty($dept);
}));
return new $specialized($input, $this);
}
}

View File

@@ -1,6 +1,6 @@
<?php <?php
namespace Intervention\Image\Drivers\Abstract; namespace Intervention\Image\Drivers;
use Intervention\Image\Interfaces\ColorInterface; use Intervention\Image\Interfaces\ColorInterface;
use Intervention\Image\Interfaces\FontInterface; use Intervention\Image\Interfaces\FontInterface;

View File

@@ -0,0 +1,52 @@
<?php
namespace Intervention\Image\Drivers;
use Intervention\Image\Drivers\AbstractDecoder;
use Intervention\Image\Exceptions\DecoderException;
use Intervention\Image\Interfaces\ColorInterface;
use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\InputHandlerInterface;
abstract class AbstractInputHandler implements InputHandlerInterface
{
protected array $decoders = [];
public function __construct(array $decoders = [])
{
$this->decoders = count($decoders) ? $decoders : $this->decoders;
}
/**
* {@inheritdoc}
*
* @see InputHandlerInterface::handle()
*/
public function handle($input): ImageInterface|ColorInterface
{
return $this->chain()->handle($input);
}
/**
* Stack the decoder array into a nested decoder object
*
* @return AbstractDecoder
*/
protected function chain(): AbstractDecoder
{
if (count($this->decoders) == 0) {
throw new DecoderException('No decoders found in ' . get_class($this));
}
// get instance of last decoder in stack
list($classname) = array_slice(array_reverse($this->decoders), 0, 1);
$chain = new $classname();
// build decoder chain
foreach (array_slice(array_reverse($this->decoders), 1) as $classname) {
$chain = new $classname($chain);
}
return $chain;
}
}

View File

@@ -0,0 +1,37 @@
<?php
namespace Intervention\Image\Drivers;
use Intervention\Image\Exceptions\DecoderException;
use Intervention\Image\Geometry\Point;
use Intervention\Image\Interfaces\ColorInterface;
abstract class DrawModifier extends DriverModifier
{
public function position(): Point
{
return $this->drawable->pivot();
}
public function backgroundColor(): ColorInterface
{
try {
$color = $this->driver()->handleInput($this->drawable->backgroundColor());
} catch (DecoderException $e) {
return $this->driver()->handleInput('transparent');
}
return $color;
}
public function borderColor(): ColorInterface
{
try {
$color = $this->driver()->handleInput($this->drawable->borderColor());
} catch (DecoderException $e) {
return $this->driver()->handleInput('transparent');
}
return $color;
}
}

View File

@@ -0,0 +1,47 @@
<?php
namespace Intervention\Image\Drivers;
use Intervention\Image\Interfaces\DriverInterface;
use Intervention\Image\Interfaces\EncoderInterface;
abstract class DriverEncoder implements EncoderInterface
{
public function __construct(
protected EncoderInterface $encoder,
protected DriverInterface $driver
) {
}
public function driver(): DriverInterface
{
return $this->driver;
}
/**
* Magic method to read attributes of underlying endcoder
*
* @param string $name
* @return mixed
*/
public function __get(string $name): mixed
{
return $this->encoder->$name;
}
/**
* Get return value of callback through output buffer
*
* @param callable $callback
* @return string
*/
protected function getBuffered(callable $callback): string
{
ob_start();
$callback();
$buffer = ob_get_contents();
ob_end_clean();
return $buffer;
}
}

View File

@@ -0,0 +1,43 @@
<?php
namespace Intervention\Image\Drivers;
use Intervention\Image\Interfaces\DriverInterface;
use Intervention\Image\Interfaces\ModifierInterface;
abstract class DriverModifier implements ModifierInterface
{
public function __construct(
protected ModifierInterface $modifier,
protected DriverInterface $driver
) {
}
public function driver(): DriverInterface
{
return $this->driver;
}
/**
* Magic method to read attributes of underlying modifier
*
* @param string $name
* @return mixed
*/
public function __get(string $name): mixed
{
return $this->modifier->$name;
}
/**
* Magic method to call methods of underlying modifier
*
* @param string $name
* @param array $arguments
* @return mixed
*/
public function __call(string $name, array $arguments): mixed
{
return $this->modifier->$name(...$arguments);
}
}

View File

@@ -0,0 +1,54 @@
<?php
namespace Intervention\Image\Drivers\Gd;
use Intervention\Image\Colors\Rgb\Channels\Alpha;
use Intervention\Image\Colors\Rgb\Channels\Blue;
use Intervention\Image\Colors\Rgb\Channels\Green;
use Intervention\Image\Colors\Rgb\Channels\Red;
use Intervention\Image\Colors\Rgb\Colorspace;
use Intervention\Image\Interfaces\ColorInterface;
use Intervention\Image\Interfaces\ColorProcessorInterface;
use Intervention\Image\Interfaces\ColorspaceInterface;
class ColorProcessor implements ColorProcessorInterface
{
public function __construct(protected ColorspaceInterface $colorspace = new Colorspace())
{
}
public function colorToNative(ColorInterface $color): int
{
$r = $color->channel(Red::class)->value();
$g = $color->channel(Green::class)->value();
$b = $color->channel(Blue::class)->value();
$a = $color->channel(Alpha::class)->value();
// convert alpha value to gd alpha
// ([opaque]255-0[transparent]) to ([opaque]0-127[transparent])
$a = (int) $this->convertRange($a, 0, 255, 127, 0);
return ($a << 24) + ($r << 16) + ($g << 8) + $b;
}
/**
* Convert input in range (min) to (max) to the corresponding value
* in target range (targetMin) to (targetMax).
*
* @param float|int $input
* @param float|int $min
* @param float|int $max
* @param float|int $targetMin
* @param float|int $targetMax
* @return float|int
*/
protected function convertRange(
float|int $input,
float|int $min,
float|int $max,
float|int $targetMin,
float|int $targetMax
): float|int {
return ceil(((($input - $min) * ($targetMax - $targetMin)) / ($max - $min)) + $targetMin);
}
}

51
src/Drivers/Gd/Core.php Normal file
View File

@@ -0,0 +1,51 @@
<?php
namespace Intervention\Image\Drivers\Gd;
use Intervention\Image\Collection;
use Intervention\Image\Colors\Rgb\Colorspace as RgbColorspace;
use Intervention\Image\Interfaces\ColorspaceInterface;
use Intervention\Image\Interfaces\CoreInterface;
use Intervention\Image\Interfaces\FrameInterface;
class Core extends Collection implements CoreInterface
{
protected int $loops = 0;
public function native()
{
return $this->first()->data();
}
public function width(): int
{
return imagesx($this->native());
}
public function height(): int
{
return imagesy($this->native());
}
public function frame(int $position): FrameInterface
{
return $this->getAtPosition($position);
}
public function loops(): int
{
return $this->loops;
}
public function setLoops(int $loops): self
{
$this->loops = $loops;
return $this;
}
public function colorspace(): ColorspaceInterface
{
return new RgbColorspace();
}
}

View File

@@ -2,17 +2,17 @@
namespace Intervention\Image\Drivers\Gd\Decoders; namespace Intervention\Image\Drivers\Gd\Decoders;
use GdImage; use Intervention\Image\Drivers\AbstractDecoder;
use Intervention\Image\Collection;
use Intervention\Image\Drivers\Abstract\Decoders\AbstractDecoder;
use Intervention\Image\Drivers\Gd\Frame; use Intervention\Image\Drivers\Gd\Frame;
use Intervention\Image\Drivers\Gd\Image;
use Intervention\Image\Interfaces\ColorInterface; use Intervention\Image\Interfaces\ColorInterface;
use Intervention\Image\Interfaces\DecoderInterface; use Intervention\Image\Interfaces\DecoderInterface;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Gif\Decoder as GifDecoder; use Intervention\Gif\Decoder as GifDecoder;
use Intervention\Gif\Splitter as GifSplitter; use Intervention\Gif\Splitter as GifSplitter;
use Intervention\Image\Drivers\Gd\Core;
use Intervention\Image\Drivers\Gd\Driver;
use Intervention\Image\Exceptions\DecoderException; use Intervention\Image\Exceptions\DecoderException;
use Intervention\Image\Image;
class BinaryImageDecoder extends AbstractDecoder implements DecoderInterface class BinaryImageDecoder extends AbstractDecoder implements DecoderInterface
{ {
@@ -26,40 +26,45 @@ class BinaryImageDecoder extends AbstractDecoder implements DecoderInterface
return $this->decodeGif($input); // decode (animated) gif return $this->decodeGif($input); // decode (animated) gif
} }
$gd = $this->coreFromString($input);
// build image instance // build image instance
$image = new Image(new Collection([new Frame($gd)])); $image = new Image(
$image->setExif($this->decodeExifData($input)); new Driver(),
$this->coreFromString($input),
$this->decodeExifData($input)
);
return $image;
// fix image orientation // fix image orientation
return match ($image->exif('IFD0.Orientation')) { // return match ($image->exif('IFD0.Orientation')) {
2 => $image->flip(), // 2 => $image->flip(),
3 => $image->rotate(180), // 3 => $image->rotate(180),
4 => $image->rotate(180)->flip(), // 4 => $image->rotate(180)->flip(),
5 => $image->rotate(270)->flip(), // 5 => $image->rotate(270)->flip(),
6 => $image->rotate(270), // 6 => $image->rotate(270),
7 => $image->rotate(90)->flip(), // 7 => $image->rotate(90)->flip(),
8 => $image->rotate(90), // 8 => $image->rotate(90),
default => $image // default => $image
}; // };
} }
private function coreFromString(string $input): GdImage private function coreFromString(string $input): Core
{ {
$gd = @imagecreatefromstring($input); $data = @imagecreatefromstring($input);
if ($gd === false) { if ($data === false) {
throw new DecoderException('Unable to decode input'); throw new DecoderException('Unable to decode input');
} }
if (!imageistruecolor($gd)) { if (!imageistruecolor($data)) {
imagepalettetotruecolor($gd); imagepalettetotruecolor($data);
} }
imagesavealpha($gd, true); imagesavealpha($data, true);
return $gd; return new Core([
new Frame($data)
]);
} }
private function decodeGif(string $input): ImageInterface private function decodeGif(string $input): ImageInterface
@@ -68,22 +73,26 @@ class BinaryImageDecoder extends AbstractDecoder implements DecoderInterface
if (!$gif->isAnimated()) { if (!$gif->isAnimated()) {
return new Image( return new Image(
new Collection([new Frame( new Driver(),
$this->coreFromString($input) $this->coreFromString($input)
)]),
); );
} }
$image = new Image(new Collection());
$image->setLoops($gif->getMainApplicationExtension()?->getLoops());
$splitter = GifSplitter::create($gif)->split(); $splitter = GifSplitter::create($gif)->split();
$delays = $splitter->getDelays(); $delays = $splitter->getDelays();
foreach ($splitter->coalesceToResources() as $key => $gd) {
$image->addFrame((new Frame($gd))->setDelay($delays[$key] / 100)); // build core
$core = new Core();
$core->setLoops($gif->getMainApplicationExtension()?->getLoops());
foreach ($splitter->coalesceToResources() as $key => $data) {
$core->push(
(new Frame($data))->setDelay($delays[$key] / 100)
);
} }
return $image; return new Image(
new Driver(),
$core
);
} }
} }

View File

@@ -2,7 +2,7 @@
namespace Intervention\Image\Drivers\Gd\Decoders; namespace Intervention\Image\Drivers\Gd\Decoders;
use Intervention\Image\Drivers\Abstract\Decoders\AbstractDecoder; use Intervention\Image\Drivers\AbstractDecoder;
use Intervention\Image\Exceptions\DecoderException; use Intervention\Image\Exceptions\DecoderException;
use Intervention\Image\Interfaces\ColorInterface; use Intervention\Image\Interfaces\ColorInterface;
use Intervention\Image\Interfaces\DecoderInterface; use Intervention\Image\Interfaces\DecoderInterface;

View File

@@ -2,7 +2,7 @@
namespace Intervention\Image\Drivers\Gd\Decoders; namespace Intervention\Image\Drivers\Gd\Decoders;
use Intervention\Image\Drivers\Abstract\Decoders\AbstractDecoder; use Intervention\Image\Drivers\AbstractDecoder;
use Intervention\Image\Exceptions\DecoderException; use Intervention\Image\Exceptions\DecoderException;
use Intervention\Image\Interfaces\ColorInterface; use Intervention\Image\Interfaces\ColorInterface;
use Intervention\Image\Interfaces\DecoderInterface; use Intervention\Image\Interfaces\DecoderInterface;

40
src/Drivers/Gd/Driver.php Normal file
View File

@@ -0,0 +1,40 @@
<?php
namespace Intervention\Image\Drivers\Gd;
use Intervention\Image\Drivers\AbstractDriver;
use Intervention\Image\Image;
use Intervention\Image\Interfaces\ColorInterface;
use Intervention\Image\Interfaces\ColorspaceInterface;
use Intervention\Image\Interfaces\ImageInterface;
class Driver extends AbstractDriver
{
public function createImage(int $width, int $height): ImageInterface
{
// build new transparent GDImage
$data = imagecreatetruecolor($width, $height);
imagesavealpha($data, true);
$background = imagecolorallocatealpha($data, 255, 0, 255, 127);
imagealphablending($data, false);
imagefill($data, 0, 0, $background);
imagecolortransparent($data, $background);
return new Image(
$this,
new Core([
new Frame($data)
])
);
}
public function handleInput(mixed $input): ImageInterface|ColorInterface
{
return (new InputHandler())->handle($input);
}
public function colorToNative(ColorInterface $color, ColorspaceInterface $colorspace): mixed
{
return (new ColorProcessor($colorspace))->colorToNative($color);
}
}

View File

@@ -0,0 +1,9 @@
<?php
namespace Intervention\Image\Drivers\Gd;
use Intervention\Image\Collection;
class Element extends Collection
{
}

View File

@@ -2,22 +2,17 @@
namespace Intervention\Image\Drivers\Gd\Encoders; namespace Intervention\Image\Drivers\Gd\Encoders;
use Intervention\Image\Drivers\Abstract\Encoders\AbstractEncoder; use Intervention\Image\Drivers\DriverEncoder;
use Intervention\Image\EncodedImage; use Intervention\Image\EncodedImage;
use Intervention\Image\Interfaces\EncoderInterface;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
class AvifEncoder extends AbstractEncoder implements EncoderInterface class AvifEncoder extends DriverEncoder
{ {
public function __construct(int $quality)
{
$this->quality = $quality;
}
public function encode(ImageInterface $image): EncodedImage public function encode(ImageInterface $image): EncodedImage
{ {
$data = $this->getBuffered(function () use ($image) { $gd = $image->core()->native();
imageavif($image->frame()->core(), null, $this->quality); $data = $this->getBuffered(function () use ($gd) {
imageavif($gd, null, $this->quality);
}); });
return new EncodedImage($data, 'image/avif'); return new EncodedImage($data, 'image/avif');

View File

@@ -2,24 +2,19 @@
namespace Intervention\Image\Drivers\Gd\Encoders; namespace Intervention\Image\Drivers\Gd\Encoders;
use Intervention\Image\Drivers\Abstract\Encoders\AbstractEncoder; use Intervention\Image\Drivers\DriverEncoder;
use Intervention\Image\Drivers\Gd\Modifiers\LimitColorsModifier; use Intervention\Image\Modifiers\LimitColorsModifier;
use Intervention\Image\EncodedImage; use Intervention\Image\EncodedImage;
use Intervention\Image\Interfaces\EncoderInterface;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
class BmpEncoder extends AbstractEncoder implements EncoderInterface class BmpEncoder extends DriverEncoder
{ {
public function __construct(protected int $color_limit = 0)
{
//
}
public function encode(ImageInterface $image): EncodedImage public function encode(ImageInterface $image): EncodedImage
{ {
$image = $image->modify(new LimitColorsModifier($this->color_limit)); $image = $image->modify(new LimitColorsModifier($this->color_limit));
$data = $this->getBuffered(function () use ($image) { $gd = $image->core()->native();
imagebmp($image->frame()->core(), null, false); $data = $this->getBuffered(function () use ($gd) {
imagebmp($gd, null, false);
}); });
return new EncodedImage($data, 'image/bmp'); return new EncodedImage($data, 'image/bmp');

View File

@@ -3,19 +3,13 @@
namespace Intervention\Image\Drivers\Gd\Encoders; namespace Intervention\Image\Drivers\Gd\Encoders;
use Intervention\Gif\Builder as GifBuilder; use Intervention\Gif\Builder as GifBuilder;
use Intervention\Image\Drivers\Abstract\Encoders\AbstractEncoder; use Intervention\Image\Drivers\DriverEncoder;
use Intervention\Image\Drivers\Gd\Modifiers\LimitColorsModifier; use Intervention\Image\Modifiers\LimitColorsModifier;
use Intervention\Image\EncodedImage; use Intervention\Image\EncodedImage;
use Intervention\Image\Interfaces\EncoderInterface;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
class GifEncoder extends AbstractEncoder implements EncoderInterface class GifEncoder extends DriverEncoder
{ {
public function __construct(protected int $color_limit = 0)
{
//
}
public function encode(ImageInterface $image): EncodedImage public function encode(ImageInterface $image): EncodedImage
{ {
if ($image->isAnimated()) { if ($image->isAnimated()) {
@@ -23,8 +17,9 @@ class GifEncoder extends AbstractEncoder implements EncoderInterface
} }
$image = $image->modify(new LimitColorsModifier($this->color_limit)); $image = $image->modify(new LimitColorsModifier($this->color_limit));
$data = $this->getBuffered(function () use ($image) { $gd = $image->core()->native();
imagegif($image->frame()->core()); $data = $this->getBuffered(function () use ($gd) {
imagegif($gd);
}); });
return new EncodedImage($data, 'image/gif'); return new EncodedImage($data, 'image/gif');
@@ -40,7 +35,7 @@ class GifEncoder extends AbstractEncoder implements EncoderInterface
foreach ($image as $frame) { foreach ($image as $frame) {
$builder->addFrame( $builder->addFrame(
$this->encode($frame->toImage()), $this->encode($frame->toImage($image->driver())),
$frame->delay() $frame->delay()
); );
} }

View File

@@ -2,22 +2,17 @@
namespace Intervention\Image\Drivers\Gd\Encoders; namespace Intervention\Image\Drivers\Gd\Encoders;
use Intervention\Image\Drivers\Abstract\Encoders\AbstractEncoder; use Intervention\Image\Drivers\DriverEncoder;
use Intervention\Image\EncodedImage; use Intervention\Image\EncodedImage;
use Intervention\Image\Interfaces\EncoderInterface;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
class JpegEncoder extends AbstractEncoder implements EncoderInterface class JpegEncoder extends DriverEncoder
{ {
public function __construct(int $quality)
{
$this->quality = $quality;
}
public function encode(ImageInterface $image): EncodedImage public function encode(ImageInterface $image): EncodedImage
{ {
$data = $this->getBuffered(function () use ($image) { $gd = $image->core()->native();
imagejpeg($image->frame()->core(), null, $this->quality); $data = $this->getBuffered(function () use ($gd) {
imagejpeg($gd, null, $this->quality);
}); });
return new EncodedImage($data, 'image/jpeg'); return new EncodedImage($data, 'image/jpeg');

View File

@@ -2,24 +2,19 @@
namespace Intervention\Image\Drivers\Gd\Encoders; namespace Intervention\Image\Drivers\Gd\Encoders;
use Intervention\Image\Drivers\Abstract\Encoders\AbstractEncoder; use Intervention\Image\Drivers\DriverEncoder;
use Intervention\Image\Drivers\Gd\Modifiers\LimitColorsModifier;
use Intervention\Image\EncodedImage; use Intervention\Image\EncodedImage;
use Intervention\Image\Interfaces\EncoderInterface;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Modifiers\LimitColorsModifier;
class PngEncoder extends AbstractEncoder implements EncoderInterface class PngEncoder extends DriverEncoder
{ {
public function __construct(protected int $color_limit = 0)
{
//
}
public function encode(ImageInterface $image): EncodedImage public function encode(ImageInterface $image): EncodedImage
{ {
$image = $image->modify(new LimitColorsModifier($this->color_limit)); $image = $image->modify(new LimitColorsModifier($this->color_limit));
$data = $this->getBuffered(function () use ($image) { $gd = $image->core()->native();
imagepng($image->frame()->core(), null, -1); $data = $this->getBuffered(function () use ($gd) {
imagepng($gd, null, -1);
}); });
return new EncodedImage($data, 'image/png'); return new EncodedImage($data, 'image/png');

View File

@@ -2,22 +2,17 @@
namespace Intervention\Image\Drivers\Gd\Encoders; namespace Intervention\Image\Drivers\Gd\Encoders;
use Intervention\Image\Drivers\Abstract\Encoders\AbstractEncoder; use Intervention\Image\Drivers\DriverEncoder;
use Intervention\Image\EncodedImage; use Intervention\Image\EncodedImage;
use Intervention\Image\Interfaces\EncoderInterface;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
class WebpEncoder extends AbstractEncoder implements EncoderInterface class WebpEncoder extends DriverEncoder
{ {
public function __construct(int $quality)
{
$this->quality = $quality;
}
public function encode(ImageInterface $image): EncodedImage public function encode(ImageInterface $image): EncodedImage
{ {
$data = $this->getBuffered(function () use ($image) { $gd = $image->core()->native();
imagewebp($image->frame()->core(), null, $this->quality); $data = $this->getBuffered(function () use ($gd) {
imagewebp($gd, null, $this->quality);
}); });
return new EncodedImage($data, 'image/webp'); return new EncodedImage($data, 'image/webp');

View File

@@ -12,7 +12,7 @@ use Intervention\Image\Interfaces\FactoryInterface;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Traits\CanHandleInput; use Intervention\Image\Traits\CanHandleInput;
class Factory implements FactoryInterface class DELETE___Factory implements FactoryInterface
{ {
use CanHandleInput; use CanHandleInput;
use CanHandleColors; use CanHandleColors;

View File

@@ -2,7 +2,7 @@
namespace Intervention\Image\Drivers\Gd; namespace Intervention\Image\Drivers\Gd;
use Intervention\Image\Drivers\Abstract\AbstractFont; use Intervention\Image\Drivers\AbstractFont;
use Intervention\Image\Geometry\Point; use Intervention\Image\Geometry\Point;
use Intervention\Image\Geometry\Polygon; use Intervention\Image\Geometry\Polygon;
use Intervention\Image\Geometry\Rectangle; use Intervention\Image\Geometry\Rectangle;

View File

@@ -3,8 +3,9 @@
namespace Intervention\Image\Drivers\Gd; namespace Intervention\Image\Drivers\Gd;
use GdImage; use GdImage;
use Intervention\Image\Collection;
use Intervention\Image\Geometry\Rectangle; use Intervention\Image\Geometry\Rectangle;
use Intervention\Image\Image;
use Intervention\Image\Interfaces\DriverInterface;
use Intervention\Image\Interfaces\FrameInterface; use Intervention\Image\Interfaces\FrameInterface;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\SizeInterface; use Intervention\Image\Interfaces\SizeInterface;
@@ -12,7 +13,7 @@ use Intervention\Image\Interfaces\SizeInterface;
class Frame implements FrameInterface class Frame implements FrameInterface
{ {
public function __construct( public function __construct(
protected GdImage $core, protected GdImage $data,
protected float $delay = 0, protected float $delay = 0,
protected int $dispose = 1, protected int $dispose = 1,
protected int $offset_left = 0, protected int $offset_left = 0,
@@ -21,26 +22,31 @@ class Frame implements FrameInterface
// //
} }
public function setCore($core): FrameInterface public function toImage(DriverInterface $driver): ImageInterface
{ {
$this->core = $core; return new Image($driver, new Core([$this]));
}
public function setData($data): FrameInterface
{
$this->data = $data;
return $this; return $this;
} }
public function core(): GdImage public function data(): GdImage
{ {
return $this->core; return $this->data;
} }
public function unsetCore(): void public function unsetData(): void
{ {
unset($this->core); unset($this->data);
} }
public function size(): SizeInterface public function size(): SizeInterface
{ {
return new Rectangle(imagesx($this->core), imagesy($this->core)); return new Rectangle(imagesx($this->data), imagesy($this->data));
} }
public function delay(): float public function delay(): float
@@ -98,9 +104,4 @@ class Frame implements FrameInterface
return $this; return $this;
} }
public function toImage(): ImageInterface
{
return new Image(new Collection([$this]));
}
} }

View File

@@ -19,7 +19,7 @@ use Intervention\Image\Resolution;
use IteratorAggregate; use IteratorAggregate;
use Traversable; use Traversable;
class Image extends AbstractImage implements ImageInterface, IteratorAggregate class DELETE__Image extends AbstractImage implements ImageInterface, IteratorAggregate
{ {
use CanHandleColors; use CanHandleColors;

View File

@@ -7,7 +7,7 @@ use Intervention\Image\Colors\Rgb\Decoders\StringColorDecoder as RgbStringColorD
use Intervention\Image\Colors\Rgb\Decoders\HtmlColornameDecoder; use Intervention\Image\Colors\Rgb\Decoders\HtmlColornameDecoder;
use Intervention\Image\Colors\Rgb\Decoders\TransparentColorDecoder; use Intervention\Image\Colors\Rgb\Decoders\TransparentColorDecoder;
use Intervention\Image\Colors\Cmyk\Decoders\StringColorDecoder as CmykStringColorDecoder; use Intervention\Image\Colors\Cmyk\Decoders\StringColorDecoder as CmykStringColorDecoder;
use Intervention\Image\Drivers\Abstract\AbstractInputHandler; use Intervention\Image\Drivers\AbstractInputHandler;
use Intervention\Image\Drivers\Gd\Decoders\ImageObjectDecoder; use Intervention\Image\Drivers\Gd\Decoders\ImageObjectDecoder;
use Intervention\Image\Drivers\Gd\Decoders\ColorObjectDecoder; use Intervention\Image\Drivers\Gd\Decoders\ColorObjectDecoder;
use Intervention\Image\Drivers\Gd\Decoders\FilePointerImageDecoder; use Intervention\Image\Drivers\Gd\Decoders\FilePointerImageDecoder;

View File

@@ -2,30 +2,19 @@
namespace Intervention\Image\Drivers\Gd\Modifiers; namespace Intervention\Image\Drivers\Gd\Modifiers;
use Intervention\Image\Interfaces\FrameInterface; use Intervention\Image\Drivers\DriverModifier;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ModifierInterface;
class BlurModifier implements ModifierInterface class BlurModifier extends DriverModifier
{ {
public function __construct(protected int $amount)
{
//
}
public function apply(ImageInterface $image): ImageInterface public function apply(ImageInterface $image): ImageInterface
{ {
foreach ($image as $frame) { foreach ($image as $frame) {
$this->blurFrame($frame); for ($i = 0; $i < $this->amount; $i++) {
imagefilter($frame->data(), IMG_FILTER_GAUSSIAN_BLUR);
}
} }
return $image; return $image;
} }
protected function blurFrame(FrameInterface $frame): void
{
for ($i = 0; $i < $this->amount; $i++) {
imagefilter($frame->core(), IMG_FILTER_GAUSSIAN_BLUR);
}
}
} }

View File

@@ -2,20 +2,15 @@
namespace Intervention\Image\Drivers\Gd\Modifiers; namespace Intervention\Image\Drivers\Gd\Modifiers;
use Intervention\Image\Drivers\DriverModifier;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ModifierInterface;
class BrightnessModifier implements ModifierInterface class BrightnessModifier extends DriverModifier
{ {
public function __construct(protected int $level)
{
//
}
public function apply(ImageInterface $image): ImageInterface public function apply(ImageInterface $image): ImageInterface
{ {
foreach ($image as $frame) { foreach ($image as $frame) {
imagefilter($frame->core(), IMG_FILTER_BRIGHTNESS, intval($this->level * 2.55)); imagefilter($frame->data(), IMG_FILTER_BRIGHTNESS, intval($this->level * 2.55));
} }
return $image; return $image;

View File

@@ -2,19 +2,11 @@
namespace Intervention\Image\Drivers\Gd\Modifiers; namespace Intervention\Image\Drivers\Gd\Modifiers;
use Intervention\Image\Drivers\DriverModifier;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ModifierInterface;
class ColorizeModifier implements ModifierInterface class ColorizeModifier extends DriverModifier
{ {
public function __construct(
protected int $red = 0,
protected int $green = 0,
protected int $blue = 0
) {
//
}
public function apply(ImageInterface $image): ImageInterface public function apply(ImageInterface $image): ImageInterface
{ {
// normalize colorize levels // normalize colorize levels
@@ -23,7 +15,7 @@ class ColorizeModifier implements ModifierInterface
$blue = round($this->blue * 2.55); $blue = round($this->blue * 2.55);
foreach ($image as $frame) { foreach ($image as $frame) {
imagefilter($frame->core(), IMG_FILTER_COLORIZE, $red, $green, $blue); imagefilter($frame->data(), IMG_FILTER_COLORIZE, $red, $green, $blue);
} }
return $image; return $image;

View File

@@ -0,0 +1,22 @@
<?php
namespace Intervention\Image\Drivers\Gd\Modifiers;
use Intervention\Image\Colors\Rgb\Colorspace as RgbColorspace;
use Intervention\Image\Drivers\DriverModifier;
use Intervention\Image\Exceptions\NotSupportedException;
use Intervention\Image\Interfaces\ImageInterface;
class ColorspaceModifier extends DriverModifier
{
public function apply(ImageInterface $image): ImageInterface
{
if (!is_a($this->targetColorspace(), RgbColorspace::class)) {
throw new NotSupportedException(
'Only RGB colorspace is supported with GD driver.'
);
}
return $image;
}
}

View File

@@ -2,20 +2,15 @@
namespace Intervention\Image\Drivers\Gd\Modifiers; namespace Intervention\Image\Drivers\Gd\Modifiers;
use Intervention\Image\Drivers\DriverModifier;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ModifierInterface;
class ContrastModifier implements ModifierInterface class ContrastModifier extends DriverModifier
{ {
public function __construct(protected int $level)
{
//
}
public function apply(ImageInterface $image): ImageInterface public function apply(ImageInterface $image): ImageInterface
{ {
foreach ($image as $frame) { foreach ($image as $frame) {
imagefilter($frame->core(), IMG_FILTER_CONTRAST, ($this->level * -1)); imagefilter($frame->data(), IMG_FILTER_CONTRAST, ($this->level * -1));
} }
return $image; return $image;

View File

@@ -2,32 +2,16 @@
namespace Intervention\Image\Drivers\Gd\Modifiers; namespace Intervention\Image\Drivers\Gd\Modifiers;
use Intervention\Image\Geometry\Rectangle; use Intervention\Image\Drivers\DriverModifier;
use Intervention\Image\Interfaces\FrameInterface; use Intervention\Image\Interfaces\FrameInterface;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ModifierInterface;
use Intervention\Image\Interfaces\SizeInterface; use Intervention\Image\Interfaces\SizeInterface;
use Intervention\Image\Traits\CanBuildNewImage;
class CropModifier implements ModifierInterface class CropModifier extends DriverModifier
{ {
use CanBuildNewImage;
public function __construct(
protected int $width,
protected int $height,
protected int $offset_x = 0,
protected int $offset_y = 0,
protected string $position = 'top-left'
) {
//
}
public function apply(ImageInterface $image): ImageInterface public function apply(ImageInterface $image): ImageInterface
{ {
$crop = new Rectangle($this->width, $this->height); $crop = $this->crop($image);
$crop->align($this->position);
$crop->alignPivotTo($image->size(), $this->position);
foreach ($image as $frame) { foreach ($image as $frame) {
$this->cropFrame($frame, $crop); $this->cropFrame($frame, $crop);
@@ -39,13 +23,13 @@ class CropModifier implements ModifierInterface
protected function cropFrame(FrameInterface $frame, SizeInterface $resizeTo): void protected function cropFrame(FrameInterface $frame, SizeInterface $resizeTo): void
{ {
// create new image // create new image
$modified = $this->imageFactory()->newCore( $modified = $this->driver()
$resizeTo->width(), ->createImage($resizeTo->width(), $resizeTo->height())
$resizeTo->height() ->core()
); ->native();
// get original image // get original image
$original = $frame->core(); $original = $frame->data();
// preserve transparency // preserve transparency
$transIndex = imagecolortransparent($original); $transIndex = imagecolortransparent($original);
@@ -72,6 +56,6 @@ class CropModifier implements ModifierInterface
); );
// set new content as recource // set new content as recource
$frame->setCore($modified); $frame->setData($modified);
} }
} }

View File

@@ -1,18 +0,0 @@
<?php
namespace Intervention\Image\Drivers\Gd\Modifiers;
use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ModifierInterface;
class DestroyModifier implements ModifierInterface
{
public function apply(ImageInterface $image): ImageInterface
{
foreach ($image as $frame) {
$frame->unsetCore();
}
return $image;
}
}

View File

@@ -2,55 +2,65 @@
namespace Intervention\Image\Drivers\Gd\Modifiers; namespace Intervention\Image\Drivers\Gd\Modifiers;
use Intervention\Image\Drivers\Abstract\Modifiers\AbstractDrawModifier; use Intervention\Image\Drivers\DrawModifier;
use Intervention\Image\Drivers\Gd\Traits\CanHandleColors;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ModifierInterface;
class DrawEllipseModifier extends AbstractDrawModifier implements ModifierInterface class DrawEllipseModifier extends DrawModifier
{ {
use CanHandleColors;
public function apply(ImageInterface $image): ImageInterface public function apply(ImageInterface $image): ImageInterface
{ {
return $image->mapFrames(function ($frame) { foreach ($image as $frame) {
if ($this->ellipse()->hasBorder()) { if ($this->drawable->hasBorder()) {
// slightly smaller ellipse to keep 1px bordered edges clean // slightly smaller ellipse to keep 1px bordered edges clean
if ($this->ellipse()->hasBackgroundColor()) { if ($this->drawable->hasBackgroundColor()) {
imagefilledellipse( imagefilledellipse(
$frame->core(), $frame->data(),
$this->position->x(), $this->position()->x(),
$this->position->y(), $this->position()->y(),
$this->ellipse()->getWidth() - 1, $this->drawable->width() - 1,
$this->ellipse()->getHeight() - 1, $this->drawable->height() - 1,
$this->colorToInteger($this->getBackgroundColor()) $this->driver()->colorToNative(
$this->backgroundColor(),
$image->colorspace()
)
); );
} }
imagesetthickness($frame->core(), $this->ellipse()->getBorderSize()); // gd's imageellipse ignores imagesetthickness
// so i use imagearc with 360 degrees instead.
imagesetthickness(
$frame->data(),
$this->drawable->borderSize(),
);
// gd's imageellipse ignores imagesetthickness so i use
// imagearc with 360 degrees instead.
imagearc( imagearc(
$frame->core(), $frame->data(),
$this->position->x(), $this->position()->x(),
$this->position->y(), $this->position()->y(),
$this->ellipse()->getWidth(), $this->drawable->width(),
$this->ellipse()->getHeight(), $this->drawable->height(),
0, 0,
360, 360,
$this->colorToInteger($this->getBorderColor()) $this->driver()->colorToNative(
$this->borderColor(),
$image->colorspace()
)
); );
} else { } else {
imagefilledellipse( imagefilledellipse(
$frame->core(), $frame->data(),
$this->position->x(), $this->position()->x(),
$this->position->y(), $this->position()->y(),
$this->ellipse()->getWidth(), $this->drawable->width(),
$this->ellipse()->getHeight(), $this->drawable->height(),
$this->colorToInteger($this->getBackgroundColor()) $this->driver()->colorToNative(
$this->backgroundColor(),
$image->colorspace()
)
); );
} }
}); }
return $image;
} }
} }

View File

@@ -2,26 +2,27 @@
namespace Intervention\Image\Drivers\Gd\Modifiers; namespace Intervention\Image\Drivers\Gd\Modifiers;
use Intervention\Image\Drivers\Abstract\Modifiers\AbstractDrawModifier; use Intervention\Image\Drivers\DrawModifier;
use Intervention\Image\Drivers\Gd\Traits\CanHandleColors;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ModifierInterface;
class DrawLineModifier extends AbstractDrawModifier implements ModifierInterface class DrawLineModifier extends DrawModifier
{ {
use CanHandleColors;
public function apply(ImageInterface $image): ImageInterface public function apply(ImageInterface $image): ImageInterface
{ {
return $image->mapFrames(function ($frame) { foreach ($image as $frame) {
imageline( imageline(
$frame->core(), $frame->data(),
$this->line()->getStart()->x(), $this->drawable->getStart()->x(),
$this->line()->getStart()->y(), $this->drawable->getStart()->y(),
$this->line()->getEnd()->x(), $this->drawable->getEnd()->x(),
$this->line()->getEnd()->y(), $this->drawable->getEnd()->y(),
$this->colorToInteger($this->getBackgroundColor()) $this->driver()->colorToNative(
$this->backgroundColor(),
$image->colorspace()
)
); );
}); }
return $image;
} }
} }

View File

@@ -2,34 +2,27 @@
namespace Intervention\Image\Drivers\Gd\Modifiers; namespace Intervention\Image\Drivers\Gd\Modifiers;
use Intervention\Image\Drivers\Gd\Traits\CanHandleColors; use Intervention\Image\Drivers\DriverModifier;
use Intervention\Image\Geometry\Point;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ModifierInterface;
use Intervention\Image\Traits\CanHandleInput;
class DrawPixelModifier implements ModifierInterface class DrawPixelModifier extends DriverModifier
{ {
use CanHandleInput;
use CanHandleColors;
public function __construct(
protected Point $position,
protected $color
) {
//
}
public function apply(ImageInterface $image): ImageInterface public function apply(ImageInterface $image): ImageInterface
{ {
$color = $this->handleInput($this->color); $color = $this->driver()->colorToNative(
return $image->mapFrames(function ($frame) use ($color) { $this->driver()->handleInput($this->color),
$image->colorspace()
);
foreach ($image as $frame) {
imagesetpixel( imagesetpixel(
$frame->core(), $frame->data(),
$this->position->x(), $this->position->x(),
$this->position->y(), $this->position->y(),
$this->colorToInteger($color) $color
); );
}); }
return $image;
} }
} }

View File

@@ -2,42 +2,38 @@
namespace Intervention\Image\Drivers\Gd\Modifiers; namespace Intervention\Image\Drivers\Gd\Modifiers;
use Intervention\Image\Drivers\Abstract\Modifiers\AbstractDrawModifier; use Intervention\Image\Drivers\DrawModifier;
use Intervention\Image\Drivers\Gd\Traits\CanHandleColors;
use Intervention\Image\Interfaces\DrawableInterface;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ModifierInterface;
class DrawPolygonModifier extends AbstractDrawModifier implements ModifierInterface class DrawPolygonModifier extends DrawModifier
{ {
use CanHandleColors;
public function __construct(
protected DrawableInterface $drawable
) {
//
}
public function apply(ImageInterface $image): ImageInterface public function apply(ImageInterface $image): ImageInterface
{ {
return $image->mapFrames(function ($frame) { foreach ($image as $frame) {
if ($this->polygon()->hasBackgroundColor()) { if ($this->drawable->hasBackgroundColor()) {
imagefilledpolygon( imagefilledpolygon(
$frame->core(), $frame->data(),
$this->polygon()->toArray(), $this->drawable->toArray(),
$this->colorToInteger($this->getBackgroundColor()) $this->driver()->colorToNative(
$this->backgroundColor(),
$image->colorspace()
)
); );
} }
if ($this->polygon()->hasBorder()) { if ($this->drawable->hasBorder()) {
imagesetthickness($frame->core(), $this->polygon()->getBorderSize()); imagesetthickness($frame->data(), $this->drawable->borderSize());
imagepolygon( imagepolygon(
$frame->core(), $frame->data(),
$this->polygon()->toArray(), $this->drawable->toArray(),
$this->polygon()->count(), $this->driver()->colorToNative(
$this->colorToInteger($this->getBorderColor()) $this->borderColor(),
$image->colorspace()
)
); );
} }
}); }
return $image;
} }
} }

View File

@@ -2,43 +2,45 @@
namespace Intervention\Image\Drivers\Gd\Modifiers; namespace Intervention\Image\Drivers\Gd\Modifiers;
use Intervention\Image\Drivers\Abstract\Modifiers\AbstractDrawModifier; use Intervention\Image\Drivers\DrawModifier;
use Intervention\Image\Drivers\Gd\Traits\CanHandleColors;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ModifierInterface;
class DrawRectangleModifier extends AbstractDrawModifier implements ModifierInterface class DrawRectangleModifier extends DrawModifier
{ {
use CanHandleColors;
public function apply(ImageInterface $image): ImageInterface public function apply(ImageInterface $image): ImageInterface
{ {
$image->mapFrames(function ($frame) { foreach ($image as $frame) {
// draw background // draw background
if ($this->rectangle()->hasBackgroundColor()) { if ($this->drawable->hasBackgroundColor()) {
imagefilledrectangle( imagefilledrectangle(
$frame->core(), $frame->data(),
$this->position->x(), $this->position->x(),
$this->position->y(), $this->position->y(),
$this->position->x() + $this->rectangle()->bottomRightPoint()->x(), $this->position->x() + $this->drawable->width(),
$this->position->y() + $this->rectangle()->bottomRightPoint()->y(), $this->position->y() + $this->drawable->height(),
$this->colorToInteger($this->getBackgroundColor()) $this->driver()->colorToNative(
$this->backgroundColor(),
$image->colorspace()
)
); );
} }
if ($this->rectangle()->hasBorder()) { // draw border
// draw border if ($this->drawable->hasBorder()) {
imagesetthickness($frame->core(), $this->rectangle()->getBorderSize()); imagesetthickness($frame->data(), $this->drawable->borderSize());
imagerectangle( imagerectangle(
$frame->core(), $frame->data(),
$this->position->x(), $this->position->x(),
$this->position->y(), $this->position->y(),
$this->position->x() + $this->rectangle()->bottomRightPoint()->x(), $this->position->x() + $this->drawable->width(),
$this->position->y() + $this->rectangle()->bottomRightPoint()->y(), $this->position->y() + $this->drawable->height(),
$this->colorToInteger($this->getBorderColor()) $this->driver()->colorToNative(
$this->borderColor(),
$image->colorspace()
)
); );
} }
}); }
return $image; return $image;
} }

View File

@@ -2,25 +2,16 @@
namespace Intervention\Image\Drivers\Gd\Modifiers; namespace Intervention\Image\Drivers\Gd\Modifiers;
use Intervention\Image\Colors\Rgb\Colorspace;
use Intervention\Image\Drivers\DriverModifier;
use Intervention\Image\Drivers\Gd\Frame; use Intervention\Image\Drivers\Gd\Frame;
use Intervention\Image\Drivers\Gd\Traits\CanHandleColors;
use Intervention\Image\Geometry\Point;
use Intervention\Image\Interfaces\ColorInterface;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ModifierInterface;
class FillModifier implements ModifierInterface class FillModifier extends DriverModifier
{ {
use CanHandleColors;
public function __construct(protected ColorInterface $color, protected ?Point $position = null)
{
//
}
public function apply(ImageInterface $image): ImageInterface public function apply(ImageInterface $image): ImageInterface
{ {
$color = $this->colorToInteger($this->color); $color = $this->color();
foreach ($image as $frame) { foreach ($image as $frame) {
if ($this->hasPosition()) { if ($this->hasPosition()) {
@@ -33,21 +24,29 @@ class FillModifier implements ModifierInterface
return $image; return $image;
} }
protected function floodFillWithColor(Frame $frame, int $color): void private function color(): int
{
return $this->driver()->colorToNative(
$this->driver()->handleInput($this->color),
new Colorspace()
);
}
private function floodFillWithColor(Frame $frame, int $color): void
{ {
imagefill( imagefill(
$frame->core(), $frame->data(),
$this->position->x(), $this->position->x(),
$this->position->y(), $this->position->y(),
$color $color
); );
} }
protected function fillAllWithColor(Frame $frame, int $color): void private function fillAllWithColor(Frame $frame, int $color): void
{ {
imagealphablending($frame->core(), true); imagealphablending($frame->data(), true);
imagefilledrectangle( imagefilledrectangle(
$frame->core(), $frame->data(),
0, 0,
0, 0,
$frame->size()->width() - 1, $frame->size()->width() - 1,
@@ -55,9 +54,4 @@ class FillModifier implements ModifierInterface
$color $color
); );
} }
protected function hasPosition(): bool
{
return !empty($this->position);
}
} }

View File

@@ -6,7 +6,7 @@ use Intervention\Image\Interfaces\SizeInterface;
class FitDownModifier extends FitModifier class FitDownModifier extends FitModifier
{ {
protected function getResizeSize(SizeInterface $size): SizeInterface public function getResizeSize(SizeInterface $size): SizeInterface
{ {
return $size->scaleDown($this->width, $this->height); return $size->scaleDown($this->width, $this->height);
} }

View File

@@ -2,17 +2,13 @@
namespace Intervention\Image\Drivers\Gd\Modifiers; namespace Intervention\Image\Drivers\Gd\Modifiers;
use Intervention\Image\Drivers\Abstract\Modifiers\AbstractFitModifier; use Intervention\Image\Drivers\DriverModifier;
use Intervention\Image\Interfaces\FrameInterface; use Intervention\Image\Interfaces\FrameInterface;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ModifierInterface;
use Intervention\Image\Interfaces\SizeInterface; use Intervention\Image\Interfaces\SizeInterface;
use Intervention\Image\Traits\CanBuildNewImage;
class FitModifier extends AbstractFitModifier implements ModifierInterface class FitModifier extends DriverModifier
{ {
use CanBuildNewImage;
public function apply(ImageInterface $image): ImageInterface public function apply(ImageInterface $image): ImageInterface
{ {
$crop = $this->getCropSize($image); $crop = $this->getCropSize($image);
@@ -28,13 +24,13 @@ class FitModifier extends AbstractFitModifier implements ModifierInterface
protected function modifyFrame(FrameInterface $frame, SizeInterface $crop, SizeInterface $resize): void protected function modifyFrame(FrameInterface $frame, SizeInterface $crop, SizeInterface $resize): void
{ {
// create new image // create new image
$modified = $this->imageFactory()->newCore( $modified = $this->driver()->createImage(
$resize->width(), $resize->width(),
$resize->height() $resize->height()
); )->core()->native();
// get original image // get original image
$original = $frame->core(); $original = $frame->data();
// preserve transparency // preserve transparency
$transIndex = imagecolortransparent($original); $transIndex = imagecolortransparent($original);
@@ -61,6 +57,6 @@ class FitModifier extends AbstractFitModifier implements ModifierInterface
); );
// set new content as resource // set new content as resource
$frame->setCore($modified); $frame->setData($modified);
} }
} }

View File

@@ -2,15 +2,15 @@
namespace Intervention\Image\Drivers\Gd\Modifiers; namespace Intervention\Image\Drivers\Gd\Modifiers;
use Intervention\Image\Drivers\DriverModifier;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ModifierInterface;
class FlipModifier implements ModifierInterface class FlipModifier extends DriverModifier
{ {
public function apply(ImageInterface $image): ImageInterface public function apply(ImageInterface $image): ImageInterface
{ {
foreach ($image as $frame) { foreach ($image as $frame) {
imageflip($frame->core(), IMG_FLIP_VERTICAL); imageflip($frame->data(), IMG_FLIP_VERTICAL);
} }
return $image; return $image;

View File

@@ -2,15 +2,15 @@
namespace Intervention\Image\Drivers\Gd\Modifiers; namespace Intervention\Image\Drivers\Gd\Modifiers;
use Intervention\Image\Drivers\DriverModifier;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ModifierInterface;
class FlopModifier implements ModifierInterface class FlopModifier extends DriverModifier
{ {
public function apply(ImageInterface $image): ImageInterface public function apply(ImageInterface $image): ImageInterface
{ {
foreach ($image as $frame) { foreach ($image as $frame) {
imageflip($frame->core(), IMG_FLIP_HORIZONTAL); imageflip($frame->data(), IMG_FLIP_HORIZONTAL);
} }
return $image; return $image;

View File

@@ -2,20 +2,15 @@
namespace Intervention\Image\Drivers\Gd\Modifiers; namespace Intervention\Image\Drivers\Gd\Modifiers;
use Intervention\Image\Drivers\DriverModifier;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ModifierInterface;
class GammaModifier implements ModifierInterface class GammaModifier extends DriverModifier
{ {
public function __construct(protected float $gamma)
{
//
}
public function apply(ImageInterface $image): ImageInterface public function apply(ImageInterface $image): ImageInterface
{ {
foreach ($image as $frame) { foreach ($image as $frame) {
imagegammacorrect($frame->core(), 1, $this->gamma); imagegammacorrect($frame->data(), 1, $this->gamma);
} }
return $image; return $image;

View File

@@ -2,15 +2,15 @@
namespace Intervention\Image\Drivers\Gd\Modifiers; namespace Intervention\Image\Drivers\Gd\Modifiers;
use Intervention\Image\Drivers\DriverModifier;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ModifierInterface;
class GreyscaleModifier implements ModifierInterface class GreyscaleModifier extends DriverModifier
{ {
public function apply(ImageInterface $image): ImageInterface public function apply(ImageInterface $image): ImageInterface
{ {
foreach ($image as $frame) { foreach ($image as $frame) {
imagefilter($frame->core(), IMG_FILTER_GRAYSCALE); imagefilter($frame->data(), IMG_FILTER_GRAYSCALE);
} }
return $image; return $image;

View File

@@ -2,15 +2,15 @@
namespace Intervention\Image\Drivers\Gd\Modifiers; namespace Intervention\Image\Drivers\Gd\Modifiers;
use Intervention\Image\Drivers\DriverModifier;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ModifierInterface;
class InvertModifier implements ModifierInterface class InvertModifier extends DriverModifier
{ {
public function apply(ImageInterface $image): ImageInterface public function apply(ImageInterface $image): ImageInterface
{ {
foreach ($image as $frame) { foreach ($image as $frame) {
imagefilter($frame->core(), IMG_FILTER_NEGATE); imagefilter($frame->data(), IMG_FILTER_NEGATE);
} }
return $image; return $image;

View File

@@ -2,16 +2,11 @@
namespace Intervention\Image\Drivers\Gd\Modifiers; namespace Intervention\Image\Drivers\Gd\Modifiers;
use Intervention\Image\Drivers\DriverModifier;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ModifierInterface;
class LimitColorsModifier implements ModifierInterface class LimitColorsModifier extends DriverModifier
{ {
public function __construct(protected int $limit = 0, protected int $threshold = 256)
{
//
}
public function apply(ImageInterface $image): ImageInterface public function apply(ImageInterface $image): ImageInterface
{ {
// no color limit: no reduction // no color limit: no reduction
@@ -43,15 +38,15 @@ class LimitColorsModifier implements ModifierInterface
imagecolortransparent($reduced, $matte); imagecolortransparent($reduced, $matte);
// copy original image // copy original image
imagecopy($reduced, $frame->core(), 0, 0, 0, 0, $width, $height); imagecopy($reduced, $frame->data(), 0, 0, 0, 0, $width, $height);
// reduce limit by one to include possible transparency in palette // reduce limit by one to include possible transparency in palette
$limit = imagecolortransparent($frame->core()) === -1 ? $this->limit : $this->limit - 1; $limit = imagecolortransparent($frame->data()) === -1 ? $this->limit : $this->limit - 1;
// decrease colors // decrease colors
imagetruecolortopalette($reduced, true, $limit); imagetruecolortopalette($reduced, true, $limit);
$frame->setCore($reduced); $frame->setData($reduced);
} }

View File

@@ -2,24 +2,6 @@
namespace Intervention\Image\Drivers\Gd\Modifiers; namespace Intervention\Image\Drivers\Gd\Modifiers;
use Intervention\Image\Geometry\Rectangle;
use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\SizeInterface;
class PadDownModifier extends PadModifier class PadDownModifier extends PadModifier
{ {
protected function getCropSize(ImageInterface $image): SizeInterface
{
$resize = $this->getResizeSize($image);
return $image->size()
->contain($resize->width(), $resize->height())
->alignPivotTo($resize, $this->position);
}
protected function getResizeSize(ImageInterface $image): SizeInterface
{
return (new Rectangle($this->width, $this->height))
->resizeDown($image->width(), $image->height());
}
} }

View File

@@ -2,27 +2,20 @@
namespace Intervention\Image\Drivers\Gd\Modifiers; namespace Intervention\Image\Drivers\Gd\Modifiers;
use Intervention\Image\Drivers\Abstract\Modifiers\AbstractPadModifier; use Intervention\Image\Drivers\DriverModifier;
use Intervention\Image\Drivers\Gd\Traits\CanHandleColors;
use Intervention\Image\Interfaces\ColorInterface; use Intervention\Image\Interfaces\ColorInterface;
use Intervention\Image\Interfaces\FrameInterface; use Intervention\Image\Interfaces\FrameInterface;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ModifierInterface;
use Intervention\Image\Interfaces\SizeInterface; use Intervention\Image\Interfaces\SizeInterface;
use Intervention\Image\Traits\CanBuildNewImage; use Intervention\Image\Modifiers\FillModifier;
use Intervention\Image\Traits\CanHandleInput;
class PadModifier extends AbstractPadModifier implements ModifierInterface class PadModifier extends DriverModifier
{ {
use CanHandleInput;
use CanHandleColors;
use CanBuildNewImage;
public function apply(ImageInterface $image): ImageInterface public function apply(ImageInterface $image): ImageInterface
{ {
$crop = $this->getCropSize($image); $crop = $this->getCropSize($image);
$resize = $this->getResizeSize($image); $resize = $this->getResizeSize($image);
$background = $this->handleInput($this->background); $background = $this->driver()->handleInput($this->background);
foreach ($image as $frame) { foreach ($image as $frame) {
$this->modify($frame, $crop, $resize, $background); $this->modify($frame, $crop, $resize, $background);
@@ -38,11 +31,12 @@ class PadModifier extends AbstractPadModifier implements ModifierInterface
ColorInterface $background ColorInterface $background
): void { ): void {
// create new gd image // create new gd image
$modified = $this->imageFactory()->newCore( $modified = $this->driver()->createImage(
$resize->width(), $resize->width(),
$resize->height(), $resize->height()
$background )->modify(
); new FillModifier($background)
)->core()->native();
// make image area transparent to keep transparency // make image area transparent to keep transparency
// even if background-color is set // even if background-color is set
@@ -62,7 +56,7 @@ class PadModifier extends AbstractPadModifier implements ModifierInterface
imagealphablending($modified, true); imagealphablending($modified, true);
imagecopyresampled( imagecopyresampled(
$modified, $modified,
$frame->core(), $frame->data(),
$crop->pivot()->x(), $crop->pivot()->x(),
$crop->pivot()->y(), $crop->pivot()->y(),
0, 0,
@@ -74,6 +68,6 @@ class PadModifier extends AbstractPadModifier implements ModifierInterface
); );
// set new content as recource // set new content as recource
$frame->setCore($modified); $frame->setData($modified);
} }
} }

View File

@@ -2,21 +2,15 @@
namespace Intervention\Image\Drivers\Gd\Modifiers; namespace Intervention\Image\Drivers\Gd\Modifiers;
use Intervention\Image\Interfaces\FrameInterface; use Intervention\Image\Drivers\DriverModifier;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ModifierInterface;
class PixelateModifier implements ModifierInterface class PixelateModifier extends DriverModifier
{ {
public function __construct(protected int $size)
{
//
}
public function apply(ImageInterface $image): ImageInterface public function apply(ImageInterface $image): ImageInterface
{ {
foreach ($image as $frame) { foreach ($image as $frame) {
imagefilter($frame->core(), IMG_FILTER_PIXELATE, $this->size, true); imagefilter($frame->data(), IMG_FILTER_PIXELATE, $this->size, true);
} }
return $image; return $image;

View File

@@ -2,38 +2,21 @@
namespace Intervention\Image\Drivers\Gd\Modifiers; namespace Intervention\Image\Drivers\Gd\Modifiers;
use Intervention\Image\Drivers\DriverModifier;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ModifierInterface;
use Intervention\Image\Interfaces\PointInterface;
use Intervention\Image\Traits\CanHandleInput;
class PlaceModifier implements ModifierInterface class PlaceModifier extends DriverModifier
{ {
use CanHandleInput;
/**
* Create new modifier
*
*/
public function __construct(
protected $element,
protected string $position,
protected int $offset_x,
protected int $offset_y
) {
//
}
public function apply(ImageInterface $image): ImageInterface public function apply(ImageInterface $image): ImageInterface
{ {
$watermark = $this->handleInput($this->element); $watermark = $this->driver()->handleInput($this->element);
$position = $this->getPosition($image, $watermark); $position = $this->getPosition($image, $watermark);
foreach ($image as $frame) { foreach ($image as $frame) {
imagealphablending($frame->core(), true); imagealphablending($frame->data(), true);
imagecopy( imagecopy(
$frame->core(), $frame->data(),
$watermark->frame()->core(), $watermark->core()->native(),
$position->x(), $position->x(),
$position->y(), $position->y(),
0, 0,
@@ -45,12 +28,4 @@ class PlaceModifier implements ModifierInterface
return $image; return $image;
} }
protected function getPosition(ImageInterface $image, ImageInterface $watermark): PointInterface
{
$image_size = $image->size()->movePivot($this->position, $this->offset_x, $this->offset_y);
$watermark_size = $watermark->size()->movePivot($this->position);
return $image_size->relativePositionTo($watermark_size);
}
} }

View File

@@ -0,0 +1,17 @@
<?php
namespace Intervention\Image\Drivers\Imagick\Modifiers;
use Intervention\Image\Drivers\DriverModifier;
use Intervention\Image\Exceptions\NotSupportedException;
use Intervention\Image\Interfaces\ImageInterface;
class ProfileModifier extends DriverModifier
{
public function apply(ImageInterface $image): ImageInterface
{
throw new NotSupportedException(
'Color profiles are not supported by GD driver.'
);
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace Intervention\Image\Drivers\Gd\Modifiers;
use Intervention\Image\Drivers\DriverModifier;
use Intervention\Image\Exceptions\NotSupportedException;
use Intervention\Image\Interfaces\ImageInterface;
class ProfileRemovalModifier extends DriverModifier
{
public function apply(ImageInterface $image): ImageInterface
{
throw new NotSupportedException(
'Color profiles are not supported by GD driver.'
);
}
}

View File

@@ -2,26 +2,21 @@
namespace Intervention\Image\Drivers\Gd\Modifiers; namespace Intervention\Image\Drivers\Gd\Modifiers;
use Intervention\Image\Collection; use Intervention\Image\Drivers\DriverModifier;
use Intervention\Image\Drivers\Abstract\Modifiers\AbstractRemoveAnimationModifier; use Intervention\Image\Drivers\Gd\Core;
use Intervention\Image\Image;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Traits\CanCheckType;
use Intervention\Image\Drivers\Gd\Image;
class RemoveAnimationModifier extends AbstractRemoveAnimationModifier class RemoveAnimationModifier extends DriverModifier
{ {
use CanCheckType;
public function __construct(protected int|string $position = 0)
{
//
}
public function apply(ImageInterface $image): ImageInterface public function apply(ImageInterface $image): ImageInterface
{ {
$image = $this->failIfNotClass($image, Image::class); return new Image(
return $image->setFrames(new Collection([ $image->driver(),
$this->chosenFrame($image, $this->position) new Core([
])); $this->chosenFrame($image, $this->position)
]),
$image->exif()
);
} }
} }

View File

@@ -2,22 +2,16 @@
namespace Intervention\Image\Drivers\Gd\Modifiers; namespace Intervention\Image\Drivers\Gd\Modifiers;
use Intervention\Image\Drivers\DriverModifier;
use Intervention\Image\Interfaces\FrameInterface; use Intervention\Image\Interfaces\FrameInterface;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ModifierInterface;
use Intervention\Image\Interfaces\SizeInterface; use Intervention\Image\Interfaces\SizeInterface;
class ResizeModifier implements ModifierInterface class ResizeModifier extends DriverModifier
{ {
public function __construct(protected ?int $width = null, protected ?int $height = null)
{
//
}
public function apply(ImageInterface $image): ImageInterface public function apply(ImageInterface $image): ImageInterface
{ {
$resizeTo = $this->getAdjustedSize($image); $resizeTo = $this->getAdjustedSize($image);
foreach ($image as $frame) { foreach ($image as $frame) {
$this->resizeFrame($frame, $resizeTo); $this->resizeFrame($frame, $resizeTo);
} }
@@ -25,12 +19,7 @@ class ResizeModifier implements ModifierInterface
return $image; return $image;
} }
protected function getAdjustedSize(ImageInterface $image): SizeInterface private function resizeFrame(FrameInterface $frame, SizeInterface $resizeTo): void
{
return $image->size()->resize($this->width, $this->height);
}
protected function resizeFrame(FrameInterface $frame, SizeInterface $resizeTo): void
{ {
// create new image // create new image
$modified = imagecreatetruecolor( $modified = imagecreatetruecolor(
@@ -38,8 +27,8 @@ class ResizeModifier implements ModifierInterface
$resizeTo->height() $resizeTo->height()
); );
// get current image // get current GDImage
$current = $frame->core(); $current = $frame->data();
// preserve transparency // preserve transparency
$transIndex = imagecolortransparent($current); $transIndex = imagecolortransparent($current);
@@ -69,6 +58,11 @@ class ResizeModifier implements ModifierInterface
); );
// set new content as recource // set new content as recource
$frame->setCore($modified); $frame->setData($modified);
}
protected function getAdjustedSize(ImageInterface $image): SizeInterface
{
return $image->size()->resize($this->width, $this->height);
} }
} }

View File

@@ -2,23 +2,18 @@
namespace Intervention\Image\Drivers\Gd\Modifiers; namespace Intervention\Image\Drivers\Gd\Modifiers;
use Intervention\Image\Drivers\DriverModifier;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ModifierInterface;
class ResolutionModifier implements ModifierInterface class ResolutionModifier extends DriverModifier
{ {
public function __construct(protected float $x, protected float $y)
{
//
}
public function apply(ImageInterface $image): ImageInterface public function apply(ImageInterface $image): ImageInterface
{ {
$x = intval(round($this->x)); $x = intval(round($this->x));
$y = intval(round($this->y)); $y = intval(round($this->y));
foreach ($image as $frame) { foreach ($image as $frame) {
imageresolution($frame->core(), $x, $y); imageresolution($frame->data(), $x, $y);
} }
return $image; return $image;

View File

@@ -5,29 +5,24 @@ namespace Intervention\Image\Drivers\Gd\Modifiers;
use Intervention\Image\Colors\Rgb\Channels\Blue; use Intervention\Image\Colors\Rgb\Channels\Blue;
use Intervention\Image\Colors\Rgb\Channels\Green; use Intervention\Image\Colors\Rgb\Channels\Green;
use Intervention\Image\Colors\Rgb\Channels\Red; use Intervention\Image\Colors\Rgb\Channels\Red;
use Intervention\Image\Drivers\Abstract\Modifiers\AbstractRotateModifier; use Intervention\Image\Drivers\DriverModifier;
use Intervention\Image\Drivers\Gd\Traits\CanHandleColors;
use Intervention\Image\Exceptions\RuntimeException; use Intervention\Image\Exceptions\RuntimeException;
use Intervention\Image\Exceptions\MissingDriverComponentException; use Intervention\Image\Exceptions\MissingDriverComponentException;
use Intervention\Image\Geometry\Rectangle; use Intervention\Image\Geometry\Rectangle;
use Intervention\Image\Interfaces\ColorInterface; use Intervention\Image\Interfaces\ColorInterface;
use Intervention\Image\Interfaces\FrameInterface; use Intervention\Image\Interfaces\FrameInterface;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ModifierInterface; use Intervention\Image\Modifiers\FillModifier;
use Intervention\Image\Traits\CanBuildNewImage;
use ReflectionException; use ReflectionException;
class RotateModifier extends AbstractRotateModifier implements ModifierInterface class RotateModifier extends DriverModifier
{ {
use CanHandleColors;
use CanBuildNewImage;
public function apply(ImageInterface $image): ImageInterface public function apply(ImageInterface $image): ImageInterface
{ {
$background = $this->handleInput($this->background); $background = $this->driver()->handleInput($this->background);
foreach ($image as $frame) { foreach ($image as $frame) {
$this->modify($frame, $background); $this->modifyFrame($frame, $background);
} }
return $image; return $image;
@@ -44,12 +39,12 @@ class RotateModifier extends AbstractRotateModifier implements ModifierInterface
* @throws MissingDriverComponentException * @throws MissingDriverComponentException
* @throws ReflectionException * @throws ReflectionException
*/ */
protected function modify(FrameInterface $frame, ColorInterface $background): void protected function modifyFrame(FrameInterface $frame, ColorInterface $background): void
{ {
// get transparent color from frame core // get transparent color from frame core
$transparent = match ($transparent = imagecolortransparent($frame->core())) { $transparent = match ($transparent = imagecolortransparent($frame->data())) {
-1 => imagecolorallocatealpha( -1 => imagecolorallocatealpha(
$frame->core(), $frame->data(),
$background->channel(Red::class)->value(), $background->channel(Red::class)->value(),
$background->channel(Green::class)->value(), $background->channel(Green::class)->value(),
$background->channel(Blue::class)->value(), $background->channel(Blue::class)->value(),
@@ -60,7 +55,7 @@ class RotateModifier extends AbstractRotateModifier implements ModifierInterface
// rotate original image against transparent background // rotate original image against transparent background
$rotated = imagerotate( $rotated = imagerotate(
$frame->core(), $frame->data(),
$this->rotationAngle(), $this->rotationAngle(),
$transparent $transparent
); );
@@ -73,19 +68,20 @@ class RotateModifier extends AbstractRotateModifier implements ModifierInterface
// create size from original and rotate points // create size from original and rotate points
$cutout = (new Rectangle( $cutout = (new Rectangle(
imagesx($frame->core()), imagesx($frame->data()),
imagesy($frame->core()), imagesy($frame->data()),
$container->pivot() $container->pivot()
))->align('center') ))->align('center')
->valign('center') ->valign('center')
->rotate($this->rotationAngle() * -1); ->rotate($this->rotationAngle() * -1);
// create new gd core // create new gd image
$modified = $this->imageFactory()->newCore( $modified = $this->driver()->createImage(
imagesx($rotated), imagesx($rotated),
imagesy($rotated), imagesy($rotated)
$background )->modify(new FillModifier($background))
); ->core()
->native();
// draw the cutout on new gd image to have a transparent // draw the cutout on new gd image to have a transparent
// background where the rotated image will be placed // background where the rotated image will be placed
@@ -109,6 +105,6 @@ class RotateModifier extends AbstractRotateModifier implements ModifierInterface
imagesy($rotated) imagesy($rotated)
); );
$frame->setCore($modified); $frame->setData($modified);
} }
} }

View File

@@ -2,27 +2,22 @@
namespace Intervention\Image\Drivers\Gd\Modifiers; namespace Intervention\Image\Drivers\Gd\Modifiers;
use Intervention\Image\Drivers\DriverModifier;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ModifierInterface;
class SharpenModifier implements ModifierInterface class SharpenModifier extends DriverModifier
{ {
public function __construct(protected int $amount)
{
//
}
public function apply(ImageInterface $image): ImageInterface public function apply(ImageInterface $image): ImageInterface
{ {
$matrix = $this->matrix(); $matrix = $this->matrix();
foreach ($image as $frame) { foreach ($image as $frame) {
imageconvolution($frame->core(), $matrix, 1, 0); imageconvolution($frame->data(), $matrix, 1, 0);
} }
return $image; return $image;
} }
protected function matrix(): array private function matrix(): array
{ {
$min = $this->amount >= 10 ? $this->amount * -0.01 : 0; $min = $this->amount >= 10 ? $this->amount * -0.01 : 0;
$max = $this->amount * -0.025; $max = $this->amount * -0.025;

View File

@@ -2,26 +2,25 @@
namespace Intervention\Image\Drivers\Gd\Modifiers; namespace Intervention\Image\Drivers\Gd\Modifiers;
use Intervention\Image\Drivers\Abstract\AbstractTextWriter; use Intervention\Image\Drivers\DriverModifier;
use Intervention\Image\Drivers\Gd\Font;
use Intervention\Image\Drivers\Gd\Traits\CanHandleColors; use Intervention\Image\Drivers\Gd\Traits\CanHandleColors;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
class TextWriter extends AbstractTextWriter class TextWriter extends DriverModifier
{ {
use CanHandleColors; use CanHandleColors;
public function apply(ImageInterface $image): ImageInterface public function apply(ImageInterface $image): ImageInterface
{ {
$lines = $this->getAlignedTextBlock(); $lines = $this->getAlignedTextBlock();
$font = $this->failIfNotClass($this->getFont(), Font::class); $font = $this->font;
$color = $this->colorToInteger($font->getColor()); $color = $this->colorToInteger($font->getColor());
foreach ($image as $frame) { foreach ($image as $frame) {
if ($this->font->hasFilename()) { if ($this->font->hasFilename()) {
foreach ($lines as $line) { foreach ($lines as $line) {
imagettftext( imagettftext(
$frame->core(), $frame->data(),
$font->getSize(), $font->getSize(),
$font->getAngle() * (-1), $font->getAngle() * (-1),
$line->getPosition()->x(), $line->getPosition()->x(),
@@ -34,7 +33,7 @@ class TextWriter extends AbstractTextWriter
} else { } else {
foreach ($lines as $line) { foreach ($lines as $line) {
imagestring( imagestring(
$frame->core(), $frame->data(),
$font->getGdFont(), $font->getGdFont(),
$line->getPosition()->x(), $line->getPosition()->x(),
$line->getPosition()->y(), $line->getPosition()->y(),

View File

@@ -10,7 +10,7 @@ use Intervention\Image\Colors\Rgb\Channels\Blue;
use Intervention\Image\Colors\Rgb\Channels\Green; use Intervention\Image\Colors\Rgb\Channels\Green;
use Intervention\Image\Colors\Rgb\Channels\Red; use Intervention\Image\Colors\Rgb\Channels\Red;
trait CanHandleColors trait DELETE___CanHandleColors
{ {
/** /**
* Allocate given color in given gd image and return color value/index * Allocate given color in given gd image and return color value/index

View File

@@ -0,0 +1,22 @@
<?php
namespace Intervention\Image\Drivers\Imagick;
use ImagickPixel;
use Intervention\Image\Interfaces\ColorInterface;
use Intervention\Image\Interfaces\ColorProcessorInterface;
use Intervention\Image\Interfaces\ColorspaceInterface;
class ColorProcessor implements ColorProcessorInterface
{
public function __construct(protected ColorspaceInterface $colorspace)
{
}
public function colorToNative(ColorInterface $color): ImagickPixel
{
return new ImagickPixel(
(string) $color->convertTo($this->colorspace)
);
}
}

View File

@@ -0,0 +1,107 @@
<?php
namespace Intervention\Image\Drivers\Imagick;
use Imagick;
use ImagickException;
use Iterator;
use Intervention\Image\Interfaces\ColorspaceInterface;
use Intervention\Image\Interfaces\CoreInterface;
use Intervention\Image\Colors\Cmyk\Colorspace as CmykColorspace;
use Intervention\Image\Colors\Rgb\Colorspace as RgbColorspace;
use Intervention\Image\Exceptions\AnimationException;
use Intervention\Image\Interfaces\FrameInterface;
class Core implements CoreInterface, Iterator
{
protected int $iteratorIndex = 0;
public function __construct(protected Imagick $imagick)
{
}
public function count(): int
{
return $this->imagick->getNumberImages();
}
public function current(): mixed
{
$this->imagick->setIteratorIndex($this->iteratorIndex);
return new Frame($this->imagick->current());
}
public function next(): void
{
$this->iteratorIndex = $this->iteratorIndex + 1;
}
public function key(): mixed
{
return $this->iteratorIndex;
}
public function valid(): bool
{
try {
$result = $this->imagick->setIteratorIndex($this->iteratorIndex);
} catch (ImagickException $e) {
return false;
}
return $result;
}
public function rewind(): void
{
$this->iteratorIndex = 0;
}
public function native()
{
return $this->imagick;
}
public function width(): int
{
return $this->imagick->getImageWidth();
}
public function height(): int
{
return $this->imagick->getImageHeight();
}
public function frame(int $position): FrameInterface
{
foreach ($this->imagick as $core) {
if ($core->getIteratorIndex() == $position) {
return new Frame($core);
}
}
throw new AnimationException('Frame #' . $position . ' is not be found in the image.');
}
public function loops(): int
{
return $this->imagick->getImageIterations();
}
public function setLoops(int $loops): CoreInterface
{
$this->imagick = $this->imagick->coalesceImages();
$this->imagick->setImageIterations($loops);
return $this;
}
public function colorspace(): ColorspaceInterface
{
return match ($this->imagick->getImageColorspace()) {
Imagick::COLORSPACE_CMYK => new CmykColorspace(),
default => new RgbColorspace(),
};
}
}

View File

@@ -4,9 +4,11 @@ namespace Intervention\Image\Drivers\Imagick\Decoders;
use Imagick; use Imagick;
use ImagickException; use ImagickException;
use Intervention\Image\Drivers\Abstract\Decoders\AbstractDecoder; use Intervention\Image\Drivers\AbstractDecoder;
use Intervention\Image\Drivers\Imagick\Image; use Intervention\Image\Drivers\Imagick\Core;
use Intervention\Image\Drivers\Imagick\Driver;
use Intervention\Image\Exceptions\DecoderException; use Intervention\Image\Exceptions\DecoderException;
use Intervention\Image\Image;
use Intervention\Image\Interfaces\ColorInterface; use Intervention\Image\Interfaces\ColorInterface;
use Intervention\Image\Interfaces\DecoderInterface; use Intervention\Image\Interfaces\DecoderInterface;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
@@ -46,9 +48,11 @@ class BinaryImageDecoder extends AbstractDecoder implements DecoderInterface
// set new orientation in image // set new orientation in image
$imagick->setImageOrientation(Imagick::ORIENTATION_TOPLEFT); $imagick->setImageOrientation(Imagick::ORIENTATION_TOPLEFT);
$image = new Image($imagick); $image = new Image(
$image->setLoops($imagick->getImageIterations()); new Driver(),
$image->setExif($this->decodeExifData($input)); new Core($imagick),
$this->decodeExifData($input)
);
return $image; return $image;
} }

View File

@@ -2,7 +2,7 @@
namespace Intervention\Image\Drivers\Imagick\Decoders; namespace Intervention\Image\Drivers\Imagick\Decoders;
use Intervention\Image\Drivers\Abstract\Decoders\AbstractDecoder; use Intervention\Image\Drivers\AbstractDecoder;
use Intervention\Image\Exceptions\DecoderException; use Intervention\Image\Exceptions\DecoderException;
use Intervention\Image\Interfaces\ColorInterface; use Intervention\Image\Interfaces\ColorInterface;
use Intervention\Image\Interfaces\DecoderInterface; use Intervention\Image\Interfaces\DecoderInterface;

View File

@@ -2,7 +2,7 @@
namespace Intervention\Image\Drivers\Imagick\Decoders; namespace Intervention\Image\Drivers\Imagick\Decoders;
use Intervention\Image\Drivers\Abstract\Decoders\AbstractDecoder; use Intervention\Image\Drivers\AbstractDecoder;
use Intervention\Image\Exceptions\DecoderException; use Intervention\Image\Exceptions\DecoderException;
use Intervention\Image\Interfaces\ColorInterface; use Intervention\Image\Interfaces\ColorInterface;
use Intervention\Image\Interfaces\DecoderInterface; use Intervention\Image\Interfaces\DecoderInterface;

View File

@@ -0,0 +1,38 @@
<?php
namespace Intervention\Image\Drivers\Imagick;
use Imagick;
use ImagickPixel;
use Intervention\Image\Drivers\AbstractDriver;
use Intervention\Image\Image;
use Intervention\Image\Interfaces\ColorInterface;
use Intervention\Image\Interfaces\ColorspaceInterface;
use Intervention\Image\Interfaces\ImageInterface;
class Driver extends AbstractDriver
{
public function createImage(int $width, int $height): ImageInterface
{
$background = new ImagickPixel('rgba(0, 0, 0, 0)');
$imagick = new Imagick();
$imagick->newImage($width, $height, $background, 'png');
$imagick->setType(Imagick::IMGTYPE_UNDEFINED);
$imagick->setImageType(Imagick::IMGTYPE_UNDEFINED);
$imagick->setColorspace(Imagick::COLORSPACE_SRGB);
$imagick->setImageResolution(96, 96);
return new Image($this, new Core($imagick));
}
public function handleInput(mixed $input): ImageInterface|ColorInterface
{
return (new InputHandler())->handle($input);
}
public function colorToNative(ColorInterface $color, ColorspaceInterface $colorspace): mixed
{
return (new ColorProcessor($colorspace))->colorToNative($color);
}
}

View File

@@ -3,24 +3,18 @@
namespace Intervention\Image\Drivers\Imagick\Encoders; namespace Intervention\Image\Drivers\Imagick\Encoders;
use Imagick; use Imagick;
use Intervention\Image\Drivers\Abstract\Encoders\AbstractEncoder; use Intervention\Image\Drivers\DriverEncoder;
use Intervention\Image\EncodedImage; use Intervention\Image\EncodedImage;
use Intervention\Image\Interfaces\EncoderInterface;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
class AvifEncoder extends AbstractEncoder implements EncoderInterface class AvifEncoder extends DriverEncoder
{ {
public function __construct(int $quality)
{
$this->quality = $quality;
}
public function encode(ImageInterface $image): EncodedImage public function encode(ImageInterface $image): EncodedImage
{ {
$format = 'AVIF'; $format = 'AVIF';
$compression = Imagick::COMPRESSION_ZIP; $compression = Imagick::COMPRESSION_ZIP;
$imagick = $image->frame()->core(); $imagick = $image->core()->native();
$imagick->setFormat($format); $imagick->setFormat($format);
$imagick->setImageFormat($format); $imagick->setImageFormat($format);
$imagick->setCompression($compression); $imagick->setCompression($compression);

View File

@@ -3,26 +3,20 @@
namespace Intervention\Image\Drivers\Imagick\Encoders; namespace Intervention\Image\Drivers\Imagick\Encoders;
use Imagick; use Imagick;
use Intervention\Image\Drivers\Abstract\Encoders\AbstractEncoder; use Intervention\Image\Drivers\DriverEncoder;
use Intervention\Image\Drivers\Imagick\Modifiers\LimitColorsModifier; use Intervention\Image\Modifiers\LimitColorsModifier;
use Intervention\Image\EncodedImage; use Intervention\Image\EncodedImage;
use Intervention\Image\Interfaces\EncoderInterface;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
class BmpEncoder extends AbstractEncoder implements EncoderInterface class BmpEncoder extends DriverEncoder
{ {
public function __construct(protected int $color_limit = 0)
{
//
}
public function encode(ImageInterface $image): EncodedImage public function encode(ImageInterface $image): EncodedImage
{ {
$format = 'bmp'; $format = 'bmp';
$compression = Imagick::COMPRESSION_NO; $compression = Imagick::COMPRESSION_NO;
$image = $image->modify(new LimitColorsModifier($this->color_limit)); $image = $image->modify(new LimitColorsModifier($this->color_limit));
$imagick = $image->frame()->core(); $imagick = $image->core()->native();
$imagick->setFormat($format); $imagick->setFormat($format);
$imagick->setImageFormat($format); $imagick->setImageFormat($format);
$imagick->setCompression($compression); $imagick->setCompression($compression);

View File

@@ -3,37 +3,23 @@
namespace Intervention\Image\Drivers\Imagick\Encoders; namespace Intervention\Image\Drivers\Imagick\Encoders;
use Imagick; use Imagick;
use Intervention\Image\Drivers\Abstract\Encoders\AbstractEncoder; use Intervention\Image\Drivers\DriverEncoder;
use Intervention\Image\Drivers\Imagick\Image; use Intervention\Image\Modifiers\LimitColorsModifier;
use Intervention\Image\Drivers\Imagick\Modifiers\LimitColorsModifier;
use Intervention\Image\EncodedImage; use Intervention\Image\EncodedImage;
use Intervention\Image\Exceptions\EncoderException;
use Intervention\Image\Interfaces\EncoderInterface;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Traits\CanCheckType;
class GifEncoder extends AbstractEncoder implements EncoderInterface class GifEncoder extends DriverEncoder
{ {
use CanCheckType;
public function __construct(protected int $color_limit = 0)
{
//
}
public function encode(ImageInterface $image): EncodedImage public function encode(ImageInterface $image): EncodedImage
{ {
$image = $image->modify(new LimitColorsModifier($this->color_limit));
$format = 'gif'; $format = 'gif';
$compression = Imagick::COMPRESSION_LZW; $compression = Imagick::COMPRESSION_LZW;
if (!is_a($image, Image::class)) { $imagick = $image->core()->native();
throw new EncoderException('Image does not match the current driver.');
}
$image = $this->failIfNotClass($image, Image::class);
$image = $image->modify(new LimitColorsModifier($this->color_limit));
$imagick = $image->getImagick();
$imagick->setFormat($format); $imagick->setFormat($format);
$imagick->setImageFormat($format); $imagick->setImageFormat($format);
$imagick->setCompression($compression); $imagick->setCompression($compression);

View File

@@ -3,24 +3,18 @@
namespace Intervention\Image\Drivers\Imagick\Encoders; namespace Intervention\Image\Drivers\Imagick\Encoders;
use Imagick; use Imagick;
use Intervention\Image\Drivers\Abstract\Encoders\AbstractEncoder; use Intervention\Image\Drivers\DriverEncoder;
use Intervention\Image\EncodedImage; use Intervention\Image\EncodedImage;
use Intervention\Image\Interfaces\EncoderInterface;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
class JpegEncoder extends AbstractEncoder implements EncoderInterface class JpegEncoder extends DriverEncoder
{ {
public function __construct(int $quality)
{
$this->quality = $quality;
}
public function encode(ImageInterface $image): EncodedImage public function encode(ImageInterface $image): EncodedImage
{ {
$format = 'jpeg'; $format = 'jpeg';
$compression = Imagick::COMPRESSION_JPEG; $compression = Imagick::COMPRESSION_JPEG;
$imagick = $image->frame()->core(); $imagick = $image->core()->native();
$imagick->setImageBackgroundColor('white'); $imagick->setImageBackgroundColor('white');
$imagick->setBackgroundColor('white'); $imagick->setBackgroundColor('white');
$imagick->setFormat($format); $imagick->setFormat($format);

View File

@@ -3,26 +3,20 @@
namespace Intervention\Image\Drivers\Imagick\Encoders; namespace Intervention\Image\Drivers\Imagick\Encoders;
use Imagick; use Imagick;
use Intervention\Image\Drivers\Abstract\Encoders\AbstractEncoder; use Intervention\Image\Drivers\DriverEncoder;
use Intervention\Image\Drivers\Imagick\Modifiers\LimitColorsModifier; use Intervention\Image\Modifiers\LimitColorsModifier;
use Intervention\Image\EncodedImage; use Intervention\Image\EncodedImage;
use Intervention\Image\Interfaces\EncoderInterface;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
class PngEncoder extends AbstractEncoder implements EncoderInterface class PngEncoder extends DriverEncoder
{ {
public function __construct(protected int $color_limit = 0)
{
//
}
public function encode(ImageInterface $image): EncodedImage public function encode(ImageInterface $image): EncodedImage
{ {
$format = 'png'; $format = 'png';
$compression = Imagick::COMPRESSION_ZIP; $compression = Imagick::COMPRESSION_ZIP;
$image = $image->modify(new LimitColorsModifier($this->color_limit)); $image = $image->modify(new LimitColorsModifier($this->color_limit));
$imagick = $image->frame()->core(); $imagick = $image->core()->frame()->data();
$imagick->setFormat($format); $imagick->setFormat($format);
$imagick->setImageFormat($format); $imagick->setImageFormat($format);
$imagick->setCompression($compression); $imagick->setCompression($compression);

View File

@@ -4,24 +4,18 @@ namespace Intervention\Image\Drivers\Imagick\Encoders;
use Imagick; use Imagick;
use ImagickPixel; use ImagickPixel;
use Intervention\Image\Drivers\Abstract\Encoders\AbstractEncoder; use Intervention\Image\Drivers\DriverEncoder;
use Intervention\Image\EncodedImage; use Intervention\Image\EncodedImage;
use Intervention\Image\Interfaces\EncoderInterface;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
class WebpEncoder extends AbstractEncoder implements EncoderInterface class WebpEncoder extends DriverEncoder
{ {
public function __construct(int $quality)
{
$this->quality = $quality;
}
public function encode(ImageInterface $image): EncodedImage public function encode(ImageInterface $image): EncodedImage
{ {
$format = 'webp'; $format = 'webp';
$compression = Imagick::COMPRESSION_ZIP; $compression = Imagick::COMPRESSION_ZIP;
$imagick = $image->frame()->core(); $imagick = $image->core()->native();
$imagick->setImageBackgroundColor(new ImagickPixel('transparent')); $imagick->setImageBackgroundColor(new ImagickPixel('transparent'));
$imagick = $imagick->mergeImageLayers(Imagick::LAYERMETHOD_MERGE); $imagick = $imagick->mergeImageLayers(Imagick::LAYERMETHOD_MERGE);

View File

@@ -13,7 +13,7 @@ use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Traits\CanCheckType; use Intervention\Image\Traits\CanCheckType;
use Intervention\Image\Traits\CanHandleInput; use Intervention\Image\Traits\CanHandleInput;
class Factory implements FactoryInterface class DELETE___FactoryFactory implements FactoryInterface
{ {
use CanHandleInput; use CanHandleInput;
use CanCheckType; use CanCheckType;

View File

@@ -4,7 +4,7 @@ namespace Intervention\Image\Drivers\Imagick;
use Imagick; use Imagick;
use ImagickDraw; use ImagickDraw;
use Intervention\Image\Drivers\Abstract\AbstractFont; use Intervention\Image\Drivers\AbstractFont;
use Intervention\Image\Drivers\Imagick\Traits\CanHandleColors; use Intervention\Image\Drivers\Imagick\Traits\CanHandleColors;
use Intervention\Image\Exceptions\FontException; use Intervention\Image\Exceptions\FontException;
use Intervention\Image\Geometry\Polygon; use Intervention\Image\Geometry\Polygon;

View File

@@ -4,66 +4,72 @@ namespace Intervention\Image\Drivers\Imagick;
use Imagick; use Imagick;
use Intervention\Image\Geometry\Rectangle; use Intervention\Image\Geometry\Rectangle;
use Intervention\Image\Image;
use Intervention\Image\Interfaces\DriverInterface;
use Intervention\Image\Interfaces\FrameInterface; use Intervention\Image\Interfaces\FrameInterface;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\SizeInterface; use Intervention\Image\Interfaces\SizeInterface;
class Frame implements FrameInterface class Frame implements FrameInterface
{ {
public function __construct(protected Imagick $core) public function __construct(protected Imagick $data)
{ {
//
} }
public function setCore($core): FrameInterface public function toImage(DriverInterface $driver): ImageInterface
{ {
$this->core = $core; return new Image($driver, new Core($this->data()));
}
public function setData($data): FrameInterface
{
$this->data = $data;
return $this; return $this;
} }
public function core(): Imagick public function data(): Imagick
{ {
return $this->core; return $this->data;
} }
public function size(): SizeInterface public function size(): SizeInterface
{ {
return new Rectangle( return new Rectangle(
$this->core->getImageWidth(), $this->data->getImageWidth(),
$this->core->getImageHeight() $this->data->getImageHeight()
); );
} }
public function delay(): float public function delay(): float
{ {
return $this->core->getImageDelay() / 100; return $this->data->getImageDelay() / 100;
} }
public function setDelay(float $delay): FrameInterface public function setDelay(float $delay): FrameInterface
{ {
$this->core->setImageDelay(intval(round($delay * 100))); $this->data->setImageDelay(intval(round($delay * 100)));
return $this; return $this;
} }
public function dispose(): int public function dispose(): int
{ {
return $this->core->getImageDispose(); return $this->data->getImageDispose();
} }
public function setDispose(int $dispose): FrameInterface public function setDispose(int $dispose): FrameInterface
{ {
$this->core->setImageDispose($dispose); $this->data->setImageDispose($dispose);
return $this; return $this;
} }
public function setOffset(int $left, int $top): FrameInterface public function setOffset(int $left, int $top): FrameInterface
{ {
$this->core->setImagePage( $this->data->setImagePage(
$this->core->getImageWidth(), $this->data->getImageWidth(),
$this->core->getImageHeight(), $this->data->getImageHeight(),
$left, $left,
$top $top
); );
@@ -73,7 +79,7 @@ class Frame implements FrameInterface
public function offsetLeft(): int public function offsetLeft(): int
{ {
return $this->core->getImagePage()['x']; return $this->data->getImagePage()['x'];
} }
public function setOffsetLeft(int $offset): FrameInterface public function setOffsetLeft(int $offset): FrameInterface
@@ -83,16 +89,11 @@ class Frame implements FrameInterface
public function offsetTop(): int public function offsetTop(): int
{ {
return $this->core->getImagePage()['y']; return $this->data->getImagePage()['y'];
} }
public function setOffsetTop(int $offset): FrameInterface public function setOffsetTop(int $offset): FrameInterface
{ {
return $this->setOffset($this->offsetLeft(), $offset); return $this->setOffset($this->offsetLeft(), $offset);
} }
public function toImage(): ImageInterface
{
return new Image($this->core());
}
} }

View File

@@ -23,7 +23,7 @@ use Intervention\Image\Interfaces\ResolutionInterface;
use Intervention\Image\Resolution; use Intervention\Image\Resolution;
use Iterator; use Iterator;
class Image extends AbstractImage implements ImageInterface, Iterator class DELETE__Image extends AbstractImage implements ImageInterface, Iterator
{ {
use CanHandleColors; use CanHandleColors;

View File

@@ -7,7 +7,7 @@ use Intervention\Image\Colors\Rgb\Decoders\StringColorDecoder as RgbStringColorD
use Intervention\Image\Colors\Rgb\Decoders\HtmlColornameDecoder; use Intervention\Image\Colors\Rgb\Decoders\HtmlColornameDecoder;
use Intervention\Image\Colors\Rgb\Decoders\TransparentColorDecoder; use Intervention\Image\Colors\Rgb\Decoders\TransparentColorDecoder;
use Intervention\Image\Colors\Cmyk\Decoders\StringColorDecoder as CmykStringColorDecoder; use Intervention\Image\Colors\Cmyk\Decoders\StringColorDecoder as CmykStringColorDecoder;
use Intervention\Image\Drivers\Abstract\AbstractInputHandler; use Intervention\Image\Drivers\AbstractInputHandler;
use Intervention\Image\Drivers\Imagick\Decoders\ImageObjectDecoder; use Intervention\Image\Drivers\Imagick\Decoders\ImageObjectDecoder;
use Intervention\Image\Drivers\Imagick\Decoders\ColorObjectDecoder; use Intervention\Image\Drivers\Imagick\Decoders\ColorObjectDecoder;
use Intervention\Image\Drivers\Imagick\Decoders\FilePointerImageDecoder; use Intervention\Image\Drivers\Imagick\Decoders\FilePointerImageDecoder;

View File

@@ -2,20 +2,15 @@
namespace Intervention\Image\Drivers\Imagick\Modifiers; namespace Intervention\Image\Drivers\Imagick\Modifiers;
use Intervention\Image\Drivers\DriverModifier;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ModifierInterface;
class BlurModifier implements ModifierInterface class BlurModifier extends DriverModifier
{ {
public function __construct(protected int $amount)
{
//
}
public function apply(ImageInterface $image): ImageInterface public function apply(ImageInterface $image): ImageInterface
{ {
foreach ($image as $frame) { foreach ($image as $frame) {
$frame->core()->blurImage(1 * $this->amount, 0.5 * $this->amount); $frame->data()->blurImage(1 * $this->amount, 0.5 * $this->amount);
} }
return $image; return $image;

View File

@@ -2,20 +2,15 @@
namespace Intervention\Image\Drivers\Imagick\Modifiers; namespace Intervention\Image\Drivers\Imagick\Modifiers;
use Intervention\Image\Drivers\DriverModifier;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ModifierInterface;
class BrightnessModifier implements ModifierInterface class BrightnessModifier extends DriverModifier
{ {
public function __construct(protected int $level)
{
//
}
public function apply(ImageInterface $image): ImageInterface public function apply(ImageInterface $image): ImageInterface
{ {
foreach ($image as $frame) { foreach ($image as $frame) {
$frame->core()->modulateImage(100 + $this->level, 100, 100); $frame->data()->modulateImage(100 + $this->level, 100, 100);
} }
return $image; return $image;

View File

@@ -3,31 +3,22 @@
namespace Intervention\Image\Drivers\Imagick\Modifiers; namespace Intervention\Image\Drivers\Imagick\Modifiers;
use Imagick; use Imagick;
use Intervention\Image\Drivers\DriverModifier;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ModifierInterface;
class ColorizeModifier implements ModifierInterface class ColorizeModifier extends DriverModifier
{ {
public function __construct(
protected int $red = 0,
protected int $green = 0,
protected int $blue = 0
) {
//
}
public function apply(ImageInterface $image): ImageInterface public function apply(ImageInterface $image): ImageInterface
{ {
// normalize colorize levels
$red = $this->normalizeLevel($this->red); $red = $this->normalizeLevel($this->red);
$green = $this->normalizeLevel($this->green); $green = $this->normalizeLevel($this->green);
$blue = $this->normalizeLevel($this->blue); $blue = $this->normalizeLevel($this->blue);
foreach ($image as $frame) { foreach ($image as $frame) {
$qrange = $frame->core()->getQuantumRange(); $qrange = $frame->data()->getQuantumRange();
$frame->core()->levelImage(0, $red, $qrange['quantumRangeLong'], Imagick::CHANNEL_RED); $frame->data()->levelImage(0, $red, $qrange['quantumRangeLong'], Imagick::CHANNEL_RED);
$frame->core()->levelImage(0, $green, $qrange['quantumRangeLong'], Imagick::CHANNEL_GREEN); $frame->data()->levelImage(0, $green, $qrange['quantumRangeLong'], Imagick::CHANNEL_GREEN);
$frame->core()->levelImage(0, $blue, $qrange['quantumRangeLong'], Imagick::CHANNEL_BLUE); $frame->data()->levelImage(0, $blue, $qrange['quantumRangeLong'], Imagick::CHANNEL_BLUE);
} }
return $image; return $image;

View File

@@ -3,34 +3,23 @@
namespace Intervention\Image\Drivers\Imagick\Modifiers; namespace Intervention\Image\Drivers\Imagick\Modifiers;
use Imagick; use Imagick;
use Intervention\Image\Colors\Cmyk\Colorspace as CmykColorspace; use Intervention\Image\Drivers\DriverModifier;
use Intervention\Image\Colors\Rgb\Colorspace as RgbColorspace;
use Intervention\Image\Drivers\Imagick\Image;
use Intervention\Image\Exceptions\NotSupportedException; use Intervention\Image\Exceptions\NotSupportedException;
use Intervention\Image\Interfaces\ColorspaceInterface; use Intervention\Image\Interfaces\ColorspaceInterface;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ModifierInterface;
use Intervention\Image\Traits\CanCheckType;
class ColorspaceModifier implements ModifierInterface class ColorspaceModifier extends DriverModifier
{ {
use CanCheckType;
protected static $mapping = [ protected static $mapping = [
RgbColorspace::class => Imagick::COLORSPACE_SRGB, RgbColorspace::class => Imagick::COLORSPACE_SRGB,
CmykColorspace::class => Imagick::COLORSPACE_CMYK, CmykColorspace::class => Imagick::COLORSPACE_CMYK,
]; ];
public function __construct(protected string|ColorspaceInterface $target)
{
//
}
public function apply(ImageInterface $image): ImageInterface public function apply(ImageInterface $image): ImageInterface
{ {
$colorspace = $this->targetColorspace(); $colorspace = $this->targetColorspace();
$imagick = $this->failIfNotClass($image, Image::class)->getImagick(); $imagick = $image->core()->native();
$imagick->transformImageColorspace( $imagick->transformImageColorspace(
$this->getImagickColorspace($colorspace) $this->getImagickColorspace($colorspace)
); );
@@ -46,21 +35,4 @@ class ColorspaceModifier implements ModifierInterface
return self::$mapping[get_class($colorspace)]; return self::$mapping[get_class($colorspace)];
} }
private function targetColorspace(): ColorspaceInterface
{
if (is_object($this->target)) {
return $this->target;
}
if (in_array($this->target, ['rgb', 'RGB', RgbColorspace::class])) {
return new RgbColorspace();
}
if (in_array($this->target, ['cmyk', 'CMYK', CmykColorspace::class])) {
return new CmykColorspace();
}
throw new NotSupportedException('Given colorspace is not supported.');
}
} }

View File

@@ -2,20 +2,15 @@
namespace Intervention\Image\Drivers\Imagick\Modifiers; namespace Intervention\Image\Drivers\Imagick\Modifiers;
use Intervention\Image\Drivers\DriverModifier;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ModifierInterface;
class ContrastModifier implements ModifierInterface class ContrastModifier extends DriverModifier
{ {
public function __construct(protected int $level)
{
//
}
public function apply(ImageInterface $image): ImageInterface public function apply(ImageInterface $image): ImageInterface
{ {
foreach ($image as $frame) { foreach ($image as $frame) {
$frame->core()->sigmoidalContrastImage($this->level > 0, abs($this->level / 4), 0); $frame->data()->sigmoidalContrastImage($this->level > 0, abs($this->level / 4), 0);
} }
return $image; return $image;

View File

@@ -2,30 +2,17 @@
namespace Intervention\Image\Drivers\Imagick\Modifiers; namespace Intervention\Image\Drivers\Imagick\Modifiers;
use Intervention\Image\Geometry\Rectangle; use Intervention\Image\Drivers\DriverModifier;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ModifierInterface;
class CropModifier implements ModifierInterface class CropModifier extends DriverModifier
{ {
public function __construct(
protected int $width,
protected int $height,
protected int $offset_x = 0,
protected int $offset_y = 0,
protected string $position = 'top-left'
) {
//
}
public function apply(ImageInterface $image): ImageInterface public function apply(ImageInterface $image): ImageInterface
{ {
$crop = new Rectangle($this->width, $this->height); $crop = $this->crop($image);
$crop->align($this->position);
$crop->alignPivotTo($image->size(), $this->position);
foreach ($image as $frame) { foreach ($image as $frame) {
$frame->core()->extentImage( $frame->data()->extentImage(
$crop->width(), $crop->width(),
$crop->height(), $crop->height(),
$crop->pivot()->x() + $this->offset_x, $crop->pivot()->x() + $this->offset_x,

View File

@@ -1,18 +0,0 @@
<?php
namespace Intervention\Image\Drivers\Imagick\Modifiers;
use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ModifierInterface;
class DestroyModifier implements ModifierInterface
{
public function apply(ImageInterface $image): ImageInterface
{
foreach ($image as $frame) {
$frame->core()->clear();
}
return $image;
}
}

View File

@@ -3,40 +3,44 @@
namespace Intervention\Image\Drivers\Imagick\Modifiers; namespace Intervention\Image\Drivers\Imagick\Modifiers;
use ImagickDraw; use ImagickDraw;
use Intervention\Image\Drivers\Abstract\Modifiers\AbstractDrawModifier; use Intervention\Image\Drivers\DrawModifier;
use Intervention\Image\Drivers\Imagick\Traits\CanHandleColors;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ModifierInterface;
class DrawEllipseModifier extends AbstractDrawModifier implements ModifierInterface class DrawEllipseModifier extends DrawModifier
{ {
use CanHandleColors;
public function apply(ImageInterface $image): ImageInterface public function apply(ImageInterface $image): ImageInterface
{ {
$colorspace = $image->colorspace(); $background_color = $this->driver()->colorToNative(
$background_color = $this->colorToPixel($this->getBackgroundColor(), $colorspace); $this->backgroundColor(),
$border_color = $this->colorToPixel($this->getBorderColor(), $colorspace); $image->colorspace()
);
return $image->mapFrames(function ($frame) use ($background_color, $border_color) { $border_color = $this->driver()->colorToNative(
$this->borderColor(),
$image->colorspace()
);
foreach ($image as $frame) {
$drawing = new ImagickDraw(); $drawing = new ImagickDraw();
$drawing->setFillColor($background_color); $drawing->setFillColor($background_color);
if ($this->ellipse()->hasBorder()) { if ($this->drawable->hasBorder()) {
$drawing->setStrokeWidth($this->ellipse()->getBorderSize()); $drawing->setStrokeWidth($this->drawable->borderSize());
$drawing->setStrokeColor($border_color); $drawing->setStrokeColor($border_color);
} }
$drawing->ellipse( $drawing->ellipse(
$this->position->x(), $this->position()->x(),
$this->position->y(), $this->position()->y(),
$this->ellipse()->getWidth() / 2, $this->drawable->width() / 2,
$this->ellipse()->getHeight() / 2, $this->drawable->height() / 2,
0, 0,
360 360
); );
$frame->core()->drawImage($drawing); $frame->data()->drawImage($drawing);
}); }
return $image;
} }
} }

View File

@@ -3,32 +3,33 @@
namespace Intervention\Image\Drivers\Imagick\Modifiers; namespace Intervention\Image\Drivers\Imagick\Modifiers;
use ImagickDraw; use ImagickDraw;
use Intervention\Image\Drivers\Abstract\Modifiers\AbstractDrawModifier; use Intervention\Image\Drivers\DrawModifier;
use Intervention\Image\Drivers\Imagick\Traits\CanHandleColors;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ModifierInterface;
class DrawLineModifier extends AbstractDrawModifier implements ModifierInterface class DrawLineModifier extends DrawModifier
{ {
use CanHandleColors;
public function apply(ImageInterface $image): ImageInterface public function apply(ImageInterface $image): ImageInterface
{ {
$drawing = new ImagickDraw(); $drawing = new ImagickDraw();
$drawing->setStrokeWidth($this->line()->getWidth()); $drawing->setStrokeWidth($this->drawable->getWidth());
$drawing->setStrokeColor( $drawing->setStrokeColor(
$this->colorToPixel($this->getBackgroundColor(), $image->colorspace()) $this->driver()->colorToNative(
$this->backgroundColor(),
$image->colorspace()
)
); );
$drawing->line( $drawing->line(
$this->line()->getStart()->x(), $this->drawable->getStart()->x(),
$this->line()->getStart()->y(), $this->drawable->getStart()->y(),
$this->line()->getEnd()->x(), $this->drawable->getEnd()->x(),
$this->line()->getEnd()->y(), $this->drawable->getEnd()->y(),
); );
return $image->mapFrames(function ($frame) use ($drawing) { foreach ($image as $frame) {
$frame->core()->drawImage($drawing); $frame->data()->drawImage($drawing);
}); }
return $image;
} }
} }

View File

@@ -3,38 +3,26 @@
namespace Intervention\Image\Drivers\Imagick\Modifiers; namespace Intervention\Image\Drivers\Imagick\Modifiers;
use ImagickDraw; use ImagickDraw;
use Intervention\Image\Drivers\Imagick\Traits\CanHandleColors; use Intervention\Image\Drivers\DriverModifier;
use Intervention\Image\Geometry\Point;
use Intervention\Image\Interfaces\ColorInterface;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ModifierInterface;
use Intervention\Image\Traits\CanCheckType;
use Intervention\Image\Traits\CanHandleInput;
class DrawPixelModifier implements ModifierInterface class DrawPixelModifier extends DriverModifier
{ {
use CanHandleInput;
use CanHandleColors;
use CanCheckType;
public function __construct(protected Point $position, protected mixed $color)
{
//
}
public function apply(ImageInterface $image): ImageInterface public function apply(ImageInterface $image): ImageInterface
{ {
$color = $this->failIfNotInstance( $color = $this->driver()->colorToNative(
$this->handleInput($this->color), $this->driver()->handleInput($this->color),
ColorInterface::class $image->colorspace()
); );
$pixel = new ImagickDraw(); $pixel = new ImagickDraw();
$pixel->setFillColor($this->colorToPixel($color, $image->colorspace())); $pixel->setFillColor($color);
$pixel->point($this->position->x(), $this->position->y()); $pixel->point($this->position->x(), $this->position->y());
return $image->mapFrames(function ($frame) use ($pixel) { foreach ($image as $frame) {
$frame->core()->drawImage($pixel); $frame->data()->drawImage($pixel);
}); }
return $image;
} }
} }

View File

@@ -3,49 +3,47 @@
namespace Intervention\Image\Drivers\Imagick\Modifiers; namespace Intervention\Image\Drivers\Imagick\Modifiers;
use ImagickDraw; use ImagickDraw;
use Intervention\Image\Drivers\Abstract\Modifiers\AbstractDrawModifier; use Intervention\Image\Drivers\DrawModifier;
use Intervention\Image\Drivers\Imagick\Traits\CanHandleColors;
use Intervention\Image\Interfaces\DrawableInterface;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ModifierInterface;
class DrawPolygonModifier extends AbstractDrawModifier implements ModifierInterface class DrawPolygonModifier extends DrawModifier
{ {
use CanHandleColors;
public function __construct(
protected DrawableInterface $drawable
) {
//
}
public function apply(ImageInterface $image): ImageInterface public function apply(ImageInterface $image): ImageInterface
{ {
$drawing = new ImagickDraw(); $drawing = new ImagickDraw();
$colorspace = $image->colorspace();
$background_color = $this->colorToPixel($this->getBackgroundColor(), $colorspace);
$border_color = $this->colorToPixel($this->getBorderColor(), $colorspace);
if ($this->polygon()->hasBackgroundColor()) { if ($this->drawable->hasBackgroundColor()) {
$background_color = $this->driver()->colorToNative(
$this->backgroundColor(),
$image->colorspace()
);
$drawing->setFillColor($background_color); $drawing->setFillColor($background_color);
} }
if ($this->polygon()->hasBorder()) { if ($this->drawable->hasBorder()) {
$border_color = $this->driver()->colorToNative(
$this->borderColor(),
$image->colorspace()
);
$drawing->setStrokeColor($border_color); $drawing->setStrokeColor($border_color);
$drawing->setStrokeWidth($this->polygon()->getBorderSize()); $drawing->setStrokeWidth($this->drawable->borderSize());
} }
$drawing->polygon($this->points()); $drawing->polygon($this->points());
return $image->mapFrames(function ($frame) use ($drawing) { foreach ($image as $frame) {
$frame->core()->drawImage($drawing); $frame->data()->drawImage($drawing);
}); }
return $image;
} }
private function points(): array private function points(): array
{ {
$points = []; $points = [];
foreach ($this->polygon() as $point) { foreach ($this->drawable as $point) {
$points[] = ['x' => $point->x(), 'y' => $point->y()]; $points[] = ['x' => $point->x(), 'y' => $point->y()];
} }

Some files were not shown because too many files have changed in this diff Show More