1
0
mirror of https://github.com/Intervention/image.git synced 2025-08-01 11:30:16 +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 = [])
{
//
}
/**
@@ -27,6 +26,11 @@ class Collection implements CollectionInterface, IteratorAggregate, Countable
return new self($items);
}
public function has(int|string $key): bool
{
return array_key_exists($key, $this->items);
}
/**
* Returns Iterator
*

View File

@@ -3,7 +3,7 @@
namespace Intervention\Image\Colors\Cmyk\Decoders;
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\Interfaces\ColorInterface;
use Intervention\Image\Interfaces\DecoderInterface;

View File

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

View File

@@ -3,7 +3,7 @@
namespace Intervention\Image\Colors\Rgb\Decoders;
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\Interfaces\ColorInterface;
use Intervention\Image\Interfaces\DecoderInterface;

View File

@@ -3,7 +3,7 @@
namespace Intervention\Image\Colors\Rgb\Decoders;
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\Interfaces\ColorInterface;
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\CanRunCallback;
abstract class AbstractImage implements ImageInterface
abstract class DELETE___AbstractImage implements ImageInterface
{
use CanResolveDriverClass;
use CanHandleInput;

View File

@@ -8,7 +8,7 @@ use Intervention\Image\Interfaces\ColorInterface;
use Intervention\Image\Interfaces\ImageInterface;
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

View File

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

View File

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

View File

@@ -6,14 +6,13 @@ use Intervention\Image\Geometry\Rectangle;
use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\SizeInterface;
abstract class AbstractFitModifier
abstract class DELETE___AbstractFitModifier
{
public function __construct(
protected int $width,
protected int $height,
protected string $position = 'center'
) {
//
}
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\Traits\CanCheckType;
abstract class AbstractPadModifier
abstract class DELETE___AbstractPadModifier
{
use CanCheckType;
@@ -20,14 +20,14 @@ abstract class AbstractPadModifier
//
}
protected function getCropSize(ImageInterface $image): SizeInterface
public function getCropSize(ImageInterface $image): SizeInterface
{
return $image->size()
->contain($this->width, $this->height)
->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);
}

View File

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

View File

@@ -2,7 +2,7 @@
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\Interfaces\ColorInterface;
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;
use Intervention\Image\Drivers\Abstract\Encoders\AbstractEncoder;
use Intervention\Image\Drivers\DriverEncoder;
use Intervention\Image\EncodedImage;
use Intervention\Image\Interfaces\EncoderInterface;
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
{
$data = $this->getBuffered(function () use ($image) {
imageavif($image->frame()->core(), null, $this->quality);
$gd = $image->core()->native();
$data = $this->getBuffered(function () use ($gd) {
imageavif($gd, null, $this->quality);
});
return new EncodedImage($data, 'image/avif');

View File

@@ -2,24 +2,19 @@
namespace Intervention\Image\Drivers\Gd\Encoders;
use Intervention\Image\Drivers\Abstract\Encoders\AbstractEncoder;
use Intervention\Image\Drivers\Gd\Modifiers\LimitColorsModifier;
use Intervention\Image\Drivers\DriverEncoder;
use Intervention\Image\Modifiers\LimitColorsModifier;
use Intervention\Image\EncodedImage;
use Intervention\Image\Interfaces\EncoderInterface;
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
{
$image = $image->modify(new LimitColorsModifier($this->color_limit));
$data = $this->getBuffered(function () use ($image) {
imagebmp($image->frame()->core(), null, false);
$gd = $image->core()->native();
$data = $this->getBuffered(function () use ($gd) {
imagebmp($gd, null, false);
});
return new EncodedImage($data, 'image/bmp');

View File

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

View File

@@ -2,22 +2,17 @@
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\Interfaces\EncoderInterface;
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
{
$data = $this->getBuffered(function () use ($image) {
imagejpeg($image->frame()->core(), null, $this->quality);
$gd = $image->core()->native();
$data = $this->getBuffered(function () use ($gd) {
imagejpeg($gd, null, $this->quality);
});
return new EncodedImage($data, 'image/jpeg');

View File

@@ -2,24 +2,19 @@
namespace Intervention\Image\Drivers\Gd\Encoders;
use Intervention\Image\Drivers\Abstract\Encoders\AbstractEncoder;
use Intervention\Image\Drivers\Gd\Modifiers\LimitColorsModifier;
use Intervention\Image\Drivers\DriverEncoder;
use Intervention\Image\EncodedImage;
use Intervention\Image\Interfaces\EncoderInterface;
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
{
$image = $image->modify(new LimitColorsModifier($this->color_limit));
$data = $this->getBuffered(function () use ($image) {
imagepng($image->frame()->core(), null, -1);
$gd = $image->core()->native();
$data = $this->getBuffered(function () use ($gd) {
imagepng($gd, null, -1);
});
return new EncodedImage($data, 'image/png');

View File

@@ -2,22 +2,17 @@
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\Interfaces\EncoderInterface;
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
{
$data = $this->getBuffered(function () use ($image) {
imagewebp($image->frame()->core(), null, $this->quality);
$gd = $image->core()->native();
$data = $this->getBuffered(function () use ($gd) {
imagewebp($gd, null, $this->quality);
});
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\Traits\CanHandleInput;
class Factory implements FactoryInterface
class DELETE___Factory implements FactoryInterface
{
use CanHandleInput;
use CanHandleColors;

View File

@@ -2,7 +2,7 @@
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\Polygon;
use Intervention\Image\Geometry\Rectangle;

View File

@@ -3,8 +3,9 @@
namespace Intervention\Image\Drivers\Gd;
use GdImage;
use Intervention\Image\Collection;
use Intervention\Image\Geometry\Rectangle;
use Intervention\Image\Image;
use Intervention\Image\Interfaces\DriverInterface;
use Intervention\Image\Interfaces\FrameInterface;
use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\SizeInterface;
@@ -12,7 +13,7 @@ use Intervention\Image\Interfaces\SizeInterface;
class Frame implements FrameInterface
{
public function __construct(
protected GdImage $core,
protected GdImage $data,
protected float $delay = 0,
protected int $dispose = 1,
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;
}
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
{
return new Rectangle(imagesx($this->core), imagesy($this->core));
return new Rectangle(imagesx($this->data), imagesy($this->data));
}
public function delay(): float
@@ -98,9 +104,4 @@ class Frame implements FrameInterface
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 Traversable;
class Image extends AbstractImage implements ImageInterface, IteratorAggregate
class DELETE__Image extends AbstractImage implements ImageInterface, IteratorAggregate
{
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\TransparentColorDecoder;
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\ColorObjectDecoder;
use Intervention\Image\Drivers\Gd\Decoders\FilePointerImageDecoder;

View File

@@ -2,30 +2,19 @@
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\ModifierInterface;
class BlurModifier implements ModifierInterface
class BlurModifier extends DriverModifier
{
public function __construct(protected int $amount)
{
//
}
public function apply(ImageInterface $image): ImageInterface
{
foreach ($image as $frame) {
$this->blurFrame($frame);
for ($i = 0; $i < $this->amount; $i++) {
imagefilter($frame->data(), IMG_FILTER_GAUSSIAN_BLUR);
}
}
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;
use Intervention\Image\Drivers\DriverModifier;
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
{
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;

View File

@@ -2,19 +2,11 @@
namespace Intervention\Image\Drivers\Gd\Modifiers;
use Intervention\Image\Drivers\DriverModifier;
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
{
// normalize colorize levels
@@ -23,7 +15,7 @@ class ColorizeModifier implements ModifierInterface
$blue = round($this->blue * 2.55);
foreach ($image as $frame) {
imagefilter($frame->core(), IMG_FILTER_COLORIZE, $red, $green, $blue);
imagefilter($frame->data(), IMG_FILTER_COLORIZE, $red, $green, $blue);
}
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;
use Intervention\Image\Drivers\DriverModifier;
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
{
foreach ($image as $frame) {
imagefilter($frame->core(), IMG_FILTER_CONTRAST, ($this->level * -1));
imagefilter($frame->data(), IMG_FILTER_CONTRAST, ($this->level * -1));
}
return $image;

View File

@@ -2,32 +2,16 @@
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\ImageInterface;
use Intervention\Image\Interfaces\ModifierInterface;
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
{
$crop = new Rectangle($this->width, $this->height);
$crop->align($this->position);
$crop->alignPivotTo($image->size(), $this->position);
$crop = $this->crop($image);
foreach ($image as $frame) {
$this->cropFrame($frame, $crop);
@@ -39,13 +23,13 @@ class CropModifier implements ModifierInterface
protected function cropFrame(FrameInterface $frame, SizeInterface $resizeTo): void
{
// create new image
$modified = $this->imageFactory()->newCore(
$resizeTo->width(),
$resizeTo->height()
);
$modified = $this->driver()
->createImage($resizeTo->width(), $resizeTo->height())
->core()
->native();
// get original image
$original = $frame->core();
$original = $frame->data();
// preserve transparency
$transIndex = imagecolortransparent($original);
@@ -72,6 +56,6 @@ class CropModifier implements ModifierInterface
);
// 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;
use Intervention\Image\Drivers\Abstract\Modifiers\AbstractDrawModifier;
use Intervention\Image\Drivers\Gd\Traits\CanHandleColors;
use Intervention\Image\Drivers\DrawModifier;
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
{
return $image->mapFrames(function ($frame) {
if ($this->ellipse()->hasBorder()) {
foreach ($image as $frame) {
if ($this->drawable->hasBorder()) {
// slightly smaller ellipse to keep 1px bordered edges clean
if ($this->ellipse()->hasBackgroundColor()) {
if ($this->drawable->hasBackgroundColor()) {
imagefilledellipse(
$frame->core(),
$this->position->x(),
$this->position->y(),
$this->ellipse()->getWidth() - 1,
$this->ellipse()->getHeight() - 1,
$this->colorToInteger($this->getBackgroundColor())
$frame->data(),
$this->position()->x(),
$this->position()->y(),
$this->drawable->width() - 1,
$this->drawable->height() - 1,
$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(
$frame->core(),
$this->position->x(),
$this->position->y(),
$this->ellipse()->getWidth(),
$this->ellipse()->getHeight(),
$frame->data(),
$this->position()->x(),
$this->position()->y(),
$this->drawable->width(),
$this->drawable->height(),
0,
360,
$this->colorToInteger($this->getBorderColor())
$this->driver()->colorToNative(
$this->borderColor(),
$image->colorspace()
)
);
} else {
imagefilledellipse(
$frame->core(),
$this->position->x(),
$this->position->y(),
$this->ellipse()->getWidth(),
$this->ellipse()->getHeight(),
$this->colorToInteger($this->getBackgroundColor())
$frame->data(),
$this->position()->x(),
$this->position()->y(),
$this->drawable->width(),
$this->drawable->height(),
$this->driver()->colorToNative(
$this->backgroundColor(),
$image->colorspace()
)
);
}
});
}
return $image;
}
}

View File

@@ -2,26 +2,27 @@
namespace Intervention\Image\Drivers\Gd\Modifiers;
use Intervention\Image\Drivers\Abstract\Modifiers\AbstractDrawModifier;
use Intervention\Image\Drivers\Gd\Traits\CanHandleColors;
use Intervention\Image\Drivers\DrawModifier;
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
{
return $image->mapFrames(function ($frame) {
foreach ($image as $frame) {
imageline(
$frame->core(),
$this->line()->getStart()->x(),
$this->line()->getStart()->y(),
$this->line()->getEnd()->x(),
$this->line()->getEnd()->y(),
$this->colorToInteger($this->getBackgroundColor())
$frame->data(),
$this->drawable->getStart()->x(),
$this->drawable->getStart()->y(),
$this->drawable->getEnd()->x(),
$this->drawable->getEnd()->y(),
$this->driver()->colorToNative(
$this->backgroundColor(),
$image->colorspace()
)
);
});
}
return $image;
}
}

View File

@@ -2,34 +2,27 @@
namespace Intervention\Image\Drivers\Gd\Modifiers;
use Intervention\Image\Drivers\Gd\Traits\CanHandleColors;
use Intervention\Image\Geometry\Point;
use Intervention\Image\Drivers\DriverModifier;
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
{
$color = $this->handleInput($this->color);
return $image->mapFrames(function ($frame) use ($color) {
$color = $this->driver()->colorToNative(
$this->driver()->handleInput($this->color),
$image->colorspace()
);
foreach ($image as $frame) {
imagesetpixel(
$frame->core(),
$frame->data(),
$this->position->x(),
$this->position->y(),
$this->colorToInteger($color)
$color
);
});
}
return $image;
}
}

View File

@@ -2,42 +2,38 @@
namespace Intervention\Image\Drivers\Gd\Modifiers;
use Intervention\Image\Drivers\Abstract\Modifiers\AbstractDrawModifier;
use Intervention\Image\Drivers\Gd\Traits\CanHandleColors;
use Intervention\Image\Interfaces\DrawableInterface;
use Intervention\Image\Drivers\DrawModifier;
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
{
return $image->mapFrames(function ($frame) {
if ($this->polygon()->hasBackgroundColor()) {
foreach ($image as $frame) {
if ($this->drawable->hasBackgroundColor()) {
imagefilledpolygon(
$frame->core(),
$this->polygon()->toArray(),
$this->colorToInteger($this->getBackgroundColor())
$frame->data(),
$this->drawable->toArray(),
$this->driver()->colorToNative(
$this->backgroundColor(),
$image->colorspace()
)
);
}
if ($this->polygon()->hasBorder()) {
imagesetthickness($frame->core(), $this->polygon()->getBorderSize());
if ($this->drawable->hasBorder()) {
imagesetthickness($frame->data(), $this->drawable->borderSize());
imagepolygon(
$frame->core(),
$this->polygon()->toArray(),
$this->polygon()->count(),
$this->colorToInteger($this->getBorderColor())
$frame->data(),
$this->drawable->toArray(),
$this->driver()->colorToNative(
$this->borderColor(),
$image->colorspace()
)
);
}
});
}
return $image;
}
}

View File

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

View File

@@ -2,25 +2,16 @@
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\Traits\CanHandleColors;
use Intervention\Image\Geometry\Point;
use Intervention\Image\Interfaces\ColorInterface;
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
{
$color = $this->colorToInteger($this->color);
$color = $this->color();
foreach ($image as $frame) {
if ($this->hasPosition()) {
@@ -33,21 +24,29 @@ class FillModifier implements ModifierInterface
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(
$frame->core(),
$frame->data(),
$this->position->x(),
$this->position->y(),
$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(
$frame->core(),
$frame->data(),
0,
0,
$frame->size()->width() - 1,
@@ -55,9 +54,4 @@ class FillModifier implements ModifierInterface
$color
);
}
protected function hasPosition(): bool
{
return !empty($this->position);
}
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -2,20 +2,15 @@
namespace Intervention\Image\Drivers\Gd\Modifiers;
use Intervention\Image\Drivers\DriverModifier;
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
{
foreach ($image as $frame) {
imagegammacorrect($frame->core(), 1, $this->gamma);
imagegammacorrect($frame->data(), 1, $this->gamma);
}
return $image;

View File

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

View File

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

View File

@@ -2,16 +2,11 @@
namespace Intervention\Image\Drivers\Gd\Modifiers;
use Intervention\Image\Drivers\DriverModifier;
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
{
// no color limit: no reduction
@@ -43,15 +38,15 @@ class LimitColorsModifier implements ModifierInterface
imagecolortransparent($reduced, $matte);
// 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
$limit = imagecolortransparent($frame->core()) === -1 ? $this->limit : $this->limit - 1;
$limit = imagecolortransparent($frame->data()) === -1 ? $this->limit : $this->limit - 1;
// decrease colors
imagetruecolortopalette($reduced, true, $limit);
$frame->setCore($reduced);
$frame->setData($reduced);
}

View File

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

View File

@@ -2,21 +2,15 @@
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\ModifierInterface;
class PixelateModifier implements ModifierInterface
class PixelateModifier extends DriverModifier
{
public function __construct(protected int $size)
{
//
}
public function apply(ImageInterface $image): ImageInterface
{
foreach ($image as $frame) {
imagefilter($frame->core(), IMG_FILTER_PIXELATE, $this->size, true);
imagefilter($frame->data(), IMG_FILTER_PIXELATE, $this->size, true);
}
return $image;

View File

@@ -2,38 +2,21 @@
namespace Intervention\Image\Drivers\Gd\Modifiers;
use Intervention\Image\Drivers\DriverModifier;
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
{
$watermark = $this->handleInput($this->element);
$watermark = $this->driver()->handleInput($this->element);
$position = $this->getPosition($image, $watermark);
foreach ($image as $frame) {
imagealphablending($frame->core(), true);
imagealphablending($frame->data(), true);
imagecopy(
$frame->core(),
$watermark->frame()->core(),
$frame->data(),
$watermark->core()->native(),
$position->x(),
$position->y(),
0,
@@ -45,12 +28,4 @@ class PlaceModifier implements ModifierInterface
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;
use Intervention\Image\Collection;
use Intervention\Image\Drivers\Abstract\Modifiers\AbstractRemoveAnimationModifier;
use Intervention\Image\Drivers\DriverModifier;
use Intervention\Image\Drivers\Gd\Core;
use Intervention\Image\Image;
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
{
$image = $this->failIfNotClass($image, Image::class);
return $image->setFrames(new Collection([
$this->chosenFrame($image, $this->position)
]));
return new Image(
$image->driver(),
new Core([
$this->chosenFrame($image, $this->position)
]),
$image->exif()
);
}
}

View File

@@ -2,22 +2,16 @@
namespace Intervention\Image\Drivers\Gd\Modifiers;
use Intervention\Image\Drivers\DriverModifier;
use Intervention\Image\Interfaces\FrameInterface;
use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ModifierInterface;
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
{
$resizeTo = $this->getAdjustedSize($image);
foreach ($image as $frame) {
$this->resizeFrame($frame, $resizeTo);
}
@@ -25,12 +19,7 @@ class ResizeModifier implements ModifierInterface
return $image;
}
protected function getAdjustedSize(ImageInterface $image): SizeInterface
{
return $image->size()->resize($this->width, $this->height);
}
protected function resizeFrame(FrameInterface $frame, SizeInterface $resizeTo): void
private function resizeFrame(FrameInterface $frame, SizeInterface $resizeTo): void
{
// create new image
$modified = imagecreatetruecolor(
@@ -38,8 +27,8 @@ class ResizeModifier implements ModifierInterface
$resizeTo->height()
);
// get current image
$current = $frame->core();
// get current GDImage
$current = $frame->data();
// preserve transparency
$transIndex = imagecolortransparent($current);
@@ -69,6 +58,11 @@ class ResizeModifier implements ModifierInterface
);
// 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;
use Intervention\Image\Drivers\DriverModifier;
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
{
$x = intval(round($this->x));
$y = intval(round($this->y));
foreach ($image as $frame) {
imageresolution($frame->core(), $x, $y);
imageresolution($frame->data(), $x, $y);
}
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\Green;
use Intervention\Image\Colors\Rgb\Channels\Red;
use Intervention\Image\Drivers\Abstract\Modifiers\AbstractRotateModifier;
use Intervention\Image\Drivers\Gd\Traits\CanHandleColors;
use Intervention\Image\Drivers\DriverModifier;
use Intervention\Image\Exceptions\RuntimeException;
use Intervention\Image\Exceptions\MissingDriverComponentException;
use Intervention\Image\Geometry\Rectangle;
use Intervention\Image\Interfaces\ColorInterface;
use Intervention\Image\Interfaces\FrameInterface;
use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ModifierInterface;
use Intervention\Image\Traits\CanBuildNewImage;
use Intervention\Image\Modifiers\FillModifier;
use ReflectionException;
class RotateModifier extends AbstractRotateModifier implements ModifierInterface
class RotateModifier extends DriverModifier
{
use CanHandleColors;
use CanBuildNewImage;
public function apply(ImageInterface $image): ImageInterface
{
$background = $this->handleInput($this->background);
$background = $this->driver()->handleInput($this->background);
foreach ($image as $frame) {
$this->modify($frame, $background);
$this->modifyFrame($frame, $background);
}
return $image;
@@ -44,12 +39,12 @@ class RotateModifier extends AbstractRotateModifier implements ModifierInterface
* @throws MissingDriverComponentException
* @throws ReflectionException
*/
protected function modify(FrameInterface $frame, ColorInterface $background): void
protected function modifyFrame(FrameInterface $frame, ColorInterface $background): void
{
// get transparent color from frame core
$transparent = match ($transparent = imagecolortransparent($frame->core())) {
$transparent = match ($transparent = imagecolortransparent($frame->data())) {
-1 => imagecolorallocatealpha(
$frame->core(),
$frame->data(),
$background->channel(Red::class)->value(),
$background->channel(Green::class)->value(),
$background->channel(Blue::class)->value(),
@@ -60,7 +55,7 @@ class RotateModifier extends AbstractRotateModifier implements ModifierInterface
// rotate original image against transparent background
$rotated = imagerotate(
$frame->core(),
$frame->data(),
$this->rotationAngle(),
$transparent
);
@@ -73,19 +68,20 @@ class RotateModifier extends AbstractRotateModifier implements ModifierInterface
// create size from original and rotate points
$cutout = (new Rectangle(
imagesx($frame->core()),
imagesy($frame->core()),
imagesx($frame->data()),
imagesy($frame->data()),
$container->pivot()
))->align('center')
->valign('center')
->rotate($this->rotationAngle() * -1);
// create new gd core
$modified = $this->imageFactory()->newCore(
// create new gd image
$modified = $this->driver()->createImage(
imagesx($rotated),
imagesy($rotated),
$background
);
imagesy($rotated)
)->modify(new FillModifier($background))
->core()
->native();
// draw the cutout on new gd image to have a transparent
// background where the rotated image will be placed
@@ -109,6 +105,6 @@ class RotateModifier extends AbstractRotateModifier implements ModifierInterface
imagesy($rotated)
);
$frame->setCore($modified);
$frame->setData($modified);
}
}

View File

@@ -2,27 +2,22 @@
namespace Intervention\Image\Drivers\Gd\Modifiers;
use Intervention\Image\Drivers\DriverModifier;
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
{
$matrix = $this->matrix();
foreach ($image as $frame) {
imageconvolution($frame->core(), $matrix, 1, 0);
imageconvolution($frame->data(), $matrix, 1, 0);
}
return $image;
}
protected function matrix(): array
private function matrix(): array
{
$min = $this->amount >= 10 ? $this->amount * -0.01 : 0;
$max = $this->amount * -0.025;

View File

@@ -2,26 +2,25 @@
namespace Intervention\Image\Drivers\Gd\Modifiers;
use Intervention\Image\Drivers\Abstract\AbstractTextWriter;
use Intervention\Image\Drivers\Gd\Font;
use Intervention\Image\Drivers\DriverModifier;
use Intervention\Image\Drivers\Gd\Traits\CanHandleColors;
use Intervention\Image\Interfaces\ImageInterface;
class TextWriter extends AbstractTextWriter
class TextWriter extends DriverModifier
{
use CanHandleColors;
public function apply(ImageInterface $image): ImageInterface
{
$lines = $this->getAlignedTextBlock();
$font = $this->failIfNotClass($this->getFont(), Font::class);
$font = $this->font;
$color = $this->colorToInteger($font->getColor());
foreach ($image as $frame) {
if ($this->font->hasFilename()) {
foreach ($lines as $line) {
imagettftext(
$frame->core(),
$frame->data(),
$font->getSize(),
$font->getAngle() * (-1),
$line->getPosition()->x(),
@@ -34,7 +33,7 @@ class TextWriter extends AbstractTextWriter
} else {
foreach ($lines as $line) {
imagestring(
$frame->core(),
$frame->data(),
$font->getGdFont(),
$line->getPosition()->x(),
$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\Red;
trait CanHandleColors
trait DELETE___CanHandleColors
{
/**
* 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 ImagickException;
use Intervention\Image\Drivers\Abstract\Decoders\AbstractDecoder;
use Intervention\Image\Drivers\Imagick\Image;
use Intervention\Image\Drivers\AbstractDecoder;
use Intervention\Image\Drivers\Imagick\Core;
use Intervention\Image\Drivers\Imagick\Driver;
use Intervention\Image\Exceptions\DecoderException;
use Intervention\Image\Image;
use Intervention\Image\Interfaces\ColorInterface;
use Intervention\Image\Interfaces\DecoderInterface;
use Intervention\Image\Interfaces\ImageInterface;
@@ -46,9 +48,11 @@ class BinaryImageDecoder extends AbstractDecoder implements DecoderInterface
// set new orientation in image
$imagick->setImageOrientation(Imagick::ORIENTATION_TOPLEFT);
$image = new Image($imagick);
$image->setLoops($imagick->getImageIterations());
$image->setExif($this->decodeExifData($input));
$image = new Image(
new Driver(),
new Core($imagick),
$this->decodeExifData($input)
);
return $image;
}

View File

@@ -2,7 +2,7 @@
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\Interfaces\ColorInterface;
use Intervention\Image\Interfaces\DecoderInterface;

View File

@@ -2,7 +2,7 @@
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\Interfaces\ColorInterface;
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;
use Imagick;
use Intervention\Image\Drivers\Abstract\Encoders\AbstractEncoder;
use Intervention\Image\Drivers\DriverEncoder;
use Intervention\Image\EncodedImage;
use Intervention\Image\Interfaces\EncoderInterface;
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
{
$format = 'AVIF';
$compression = Imagick::COMPRESSION_ZIP;
$imagick = $image->frame()->core();
$imagick = $image->core()->native();
$imagick->setFormat($format);
$imagick->setImageFormat($format);
$imagick->setCompression($compression);

View File

@@ -3,26 +3,20 @@
namespace Intervention\Image\Drivers\Imagick\Encoders;
use Imagick;
use Intervention\Image\Drivers\Abstract\Encoders\AbstractEncoder;
use Intervention\Image\Drivers\Imagick\Modifiers\LimitColorsModifier;
use Intervention\Image\Drivers\DriverEncoder;
use Intervention\Image\Modifiers\LimitColorsModifier;
use Intervention\Image\EncodedImage;
use Intervention\Image\Interfaces\EncoderInterface;
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
{
$format = 'bmp';
$compression = Imagick::COMPRESSION_NO;
$image = $image->modify(new LimitColorsModifier($this->color_limit));
$imagick = $image->frame()->core();
$imagick = $image->core()->native();
$imagick->setFormat($format);
$imagick->setImageFormat($format);
$imagick->setCompression($compression);

View File

@@ -3,37 +3,23 @@
namespace Intervention\Image\Drivers\Imagick\Encoders;
use Imagick;
use Intervention\Image\Drivers\Abstract\Encoders\AbstractEncoder;
use Intervention\Image\Drivers\Imagick\Image;
use Intervention\Image\Drivers\Imagick\Modifiers\LimitColorsModifier;
use Intervention\Image\Drivers\DriverEncoder;
use Intervention\Image\Modifiers\LimitColorsModifier;
use Intervention\Image\EncodedImage;
use Intervention\Image\Exceptions\EncoderException;
use Intervention\Image\Interfaces\EncoderInterface;
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
{
$image = $image->modify(new LimitColorsModifier($this->color_limit));
$format = 'gif';
$compression = Imagick::COMPRESSION_LZW;
if (!is_a($image, Image::class)) {
throw new EncoderException('Image does not match the current driver.');
}
$imagick = $image->core()->native();
$image = $this->failIfNotClass($image, Image::class);
$image = $image->modify(new LimitColorsModifier($this->color_limit));
$imagick = $image->getImagick();
$imagick->setFormat($format);
$imagick->setImageFormat($format);
$imagick->setCompression($compression);

View File

@@ -3,24 +3,18 @@
namespace Intervention\Image\Drivers\Imagick\Encoders;
use Imagick;
use Intervention\Image\Drivers\Abstract\Encoders\AbstractEncoder;
use Intervention\Image\Drivers\DriverEncoder;
use Intervention\Image\EncodedImage;
use Intervention\Image\Interfaces\EncoderInterface;
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
{
$format = 'jpeg';
$compression = Imagick::COMPRESSION_JPEG;
$imagick = $image->frame()->core();
$imagick = $image->core()->native();
$imagick->setImageBackgroundColor('white');
$imagick->setBackgroundColor('white');
$imagick->setFormat($format);

View File

@@ -3,26 +3,20 @@
namespace Intervention\Image\Drivers\Imagick\Encoders;
use Imagick;
use Intervention\Image\Drivers\Abstract\Encoders\AbstractEncoder;
use Intervention\Image\Drivers\Imagick\Modifiers\LimitColorsModifier;
use Intervention\Image\Drivers\DriverEncoder;
use Intervention\Image\Modifiers\LimitColorsModifier;
use Intervention\Image\EncodedImage;
use Intervention\Image\Interfaces\EncoderInterface;
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
{
$format = 'png';
$compression = Imagick::COMPRESSION_ZIP;
$image = $image->modify(new LimitColorsModifier($this->color_limit));
$imagick = $image->frame()->core();
$imagick = $image->core()->frame()->data();
$imagick->setFormat($format);
$imagick->setImageFormat($format);
$imagick->setCompression($compression);

View File

@@ -4,24 +4,18 @@ namespace Intervention\Image\Drivers\Imagick\Encoders;
use Imagick;
use ImagickPixel;
use Intervention\Image\Drivers\Abstract\Encoders\AbstractEncoder;
use Intervention\Image\Drivers\DriverEncoder;
use Intervention\Image\EncodedImage;
use Intervention\Image\Interfaces\EncoderInterface;
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
{
$format = 'webp';
$compression = Imagick::COMPRESSION_ZIP;
$imagick = $image->frame()->core();
$imagick = $image->core()->native();
$imagick->setImageBackgroundColor(new ImagickPixel('transparent'));
$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\CanHandleInput;
class Factory implements FactoryInterface
class DELETE___FactoryFactory implements FactoryInterface
{
use CanHandleInput;
use CanCheckType;

View File

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

View File

@@ -4,66 +4,72 @@ namespace Intervention\Image\Drivers\Imagick;
use Imagick;
use Intervention\Image\Geometry\Rectangle;
use Intervention\Image\Image;
use Intervention\Image\Interfaces\DriverInterface;
use Intervention\Image\Interfaces\FrameInterface;
use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\SizeInterface;
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;
}
public function core(): Imagick
public function data(): Imagick
{
return $this->core;
return $this->data;
}
public function size(): SizeInterface
{
return new Rectangle(
$this->core->getImageWidth(),
$this->core->getImageHeight()
$this->data->getImageWidth(),
$this->data->getImageHeight()
);
}
public function delay(): float
{
return $this->core->getImageDelay() / 100;
return $this->data->getImageDelay() / 100;
}
public function setDelay(float $delay): FrameInterface
{
$this->core->setImageDelay(intval(round($delay * 100)));
$this->data->setImageDelay(intval(round($delay * 100)));
return $this;
}
public function dispose(): int
{
return $this->core->getImageDispose();
return $this->data->getImageDispose();
}
public function setDispose(int $dispose): FrameInterface
{
$this->core->setImageDispose($dispose);
$this->data->setImageDispose($dispose);
return $this;
}
public function setOffset(int $left, int $top): FrameInterface
{
$this->core->setImagePage(
$this->core->getImageWidth(),
$this->core->getImageHeight(),
$this->data->setImagePage(
$this->data->getImageWidth(),
$this->data->getImageHeight(),
$left,
$top
);
@@ -73,7 +79,7 @@ class Frame implements FrameInterface
public function offsetLeft(): int
{
return $this->core->getImagePage()['x'];
return $this->data->getImagePage()['x'];
}
public function setOffsetLeft(int $offset): FrameInterface
@@ -83,16 +89,11 @@ class Frame implements FrameInterface
public function offsetTop(): int
{
return $this->core->getImagePage()['y'];
return $this->data->getImagePage()['y'];
}
public function setOffsetTop(int $offset): FrameInterface
{
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 Iterator;
class Image extends AbstractImage implements ImageInterface, Iterator
class DELETE__Image extends AbstractImage implements ImageInterface, Iterator
{
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\TransparentColorDecoder;
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\ColorObjectDecoder;
use Intervention\Image\Drivers\Imagick\Decoders\FilePointerImageDecoder;

View File

@@ -2,20 +2,15 @@
namespace Intervention\Image\Drivers\Imagick\Modifiers;
use Intervention\Image\Drivers\DriverModifier;
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
{
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;

View File

@@ -2,20 +2,15 @@
namespace Intervention\Image\Drivers\Imagick\Modifiers;
use Intervention\Image\Drivers\DriverModifier;
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
{
foreach ($image as $frame) {
$frame->core()->modulateImage(100 + $this->level, 100, 100);
$frame->data()->modulateImage(100 + $this->level, 100, 100);
}
return $image;

View File

@@ -3,31 +3,22 @@
namespace Intervention\Image\Drivers\Imagick\Modifiers;
use Imagick;
use Intervention\Image\Drivers\DriverModifier;
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
{
// normalize colorize levels
$red = $this->normalizeLevel($this->red);
$green = $this->normalizeLevel($this->green);
$blue = $this->normalizeLevel($this->blue);
foreach ($image as $frame) {
$qrange = $frame->core()->getQuantumRange();
$frame->core()->levelImage(0, $red, $qrange['quantumRangeLong'], Imagick::CHANNEL_RED);
$frame->core()->levelImage(0, $green, $qrange['quantumRangeLong'], Imagick::CHANNEL_GREEN);
$frame->core()->levelImage(0, $blue, $qrange['quantumRangeLong'], Imagick::CHANNEL_BLUE);
$qrange = $frame->data()->getQuantumRange();
$frame->data()->levelImage(0, $red, $qrange['quantumRangeLong'], Imagick::CHANNEL_RED);
$frame->data()->levelImage(0, $green, $qrange['quantumRangeLong'], Imagick::CHANNEL_GREEN);
$frame->data()->levelImage(0, $blue, $qrange['quantumRangeLong'], Imagick::CHANNEL_BLUE);
}
return $image;

View File

@@ -3,34 +3,23 @@
namespace Intervention\Image\Drivers\Imagick\Modifiers;
use Imagick;
use Intervention\Image\Colors\Cmyk\Colorspace as CmykColorspace;
use Intervention\Image\Colors\Rgb\Colorspace as RgbColorspace;
use Intervention\Image\Drivers\Imagick\Image;
use Intervention\Image\Drivers\DriverModifier;
use Intervention\Image\Exceptions\NotSupportedException;
use Intervention\Image\Interfaces\ColorspaceInterface;
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 = [
RgbColorspace::class => Imagick::COLORSPACE_SRGB,
CmykColorspace::class => Imagick::COLORSPACE_CMYK,
];
public function __construct(protected string|ColorspaceInterface $target)
{
//
}
public function apply(ImageInterface $image): ImageInterface
{
$colorspace = $this->targetColorspace();
$imagick = $this->failIfNotClass($image, Image::class)->getImagick();
$imagick = $image->core()->native();
$imagick->transformImageColorspace(
$this->getImagickColorspace($colorspace)
);
@@ -46,21 +35,4 @@ class ColorspaceModifier implements ModifierInterface
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;
use Intervention\Image\Drivers\DriverModifier;
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
{
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;

View File

@@ -2,30 +2,17 @@
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\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
{
$crop = new Rectangle($this->width, $this->height);
$crop->align($this->position);
$crop->alignPivotTo($image->size(), $this->position);
$crop = $this->crop($image);
foreach ($image as $frame) {
$frame->core()->extentImage(
$frame->data()->extentImage(
$crop->width(),
$crop->height(),
$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;
use ImagickDraw;
use Intervention\Image\Drivers\Abstract\Modifiers\AbstractDrawModifier;
use Intervention\Image\Drivers\Imagick\Traits\CanHandleColors;
use Intervention\Image\Drivers\DrawModifier;
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
{
$colorspace = $image->colorspace();
$background_color = $this->colorToPixel($this->getBackgroundColor(), $colorspace);
$border_color = $this->colorToPixel($this->getBorderColor(), $colorspace);
$background_color = $this->driver()->colorToNative(
$this->backgroundColor(),
$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->setFillColor($background_color);
if ($this->ellipse()->hasBorder()) {
$drawing->setStrokeWidth($this->ellipse()->getBorderSize());
if ($this->drawable->hasBorder()) {
$drawing->setStrokeWidth($this->drawable->borderSize());
$drawing->setStrokeColor($border_color);
}
$drawing->ellipse(
$this->position->x(),
$this->position->y(),
$this->ellipse()->getWidth() / 2,
$this->ellipse()->getHeight() / 2,
$this->position()->x(),
$this->position()->y(),
$this->drawable->width() / 2,
$this->drawable->height() / 2,
0,
360
);
$frame->core()->drawImage($drawing);
});
$frame->data()->drawImage($drawing);
}
return $image;
}
}

View File

@@ -3,32 +3,33 @@
namespace Intervention\Image\Drivers\Imagick\Modifiers;
use ImagickDraw;
use Intervention\Image\Drivers\Abstract\Modifiers\AbstractDrawModifier;
use Intervention\Image\Drivers\Imagick\Traits\CanHandleColors;
use Intervention\Image\Drivers\DrawModifier;
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
{
$drawing = new ImagickDraw();
$drawing->setStrokeWidth($this->line()->getWidth());
$drawing->setStrokeWidth($this->drawable->getWidth());
$drawing->setStrokeColor(
$this->colorToPixel($this->getBackgroundColor(), $image->colorspace())
$this->driver()->colorToNative(
$this->backgroundColor(),
$image->colorspace()
)
);
$drawing->line(
$this->line()->getStart()->x(),
$this->line()->getStart()->y(),
$this->line()->getEnd()->x(),
$this->line()->getEnd()->y(),
$this->drawable->getStart()->x(),
$this->drawable->getStart()->y(),
$this->drawable->getEnd()->x(),
$this->drawable->getEnd()->y(),
);
return $image->mapFrames(function ($frame) use ($drawing) {
$frame->core()->drawImage($drawing);
});
foreach ($image as $frame) {
$frame->data()->drawImage($drawing);
}
return $image;
}
}

View File

@@ -3,38 +3,26 @@
namespace Intervention\Image\Drivers\Imagick\Modifiers;
use ImagickDraw;
use Intervention\Image\Drivers\Imagick\Traits\CanHandleColors;
use Intervention\Image\Geometry\Point;
use Intervention\Image\Interfaces\ColorInterface;
use Intervention\Image\Drivers\DriverModifier;
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
{
$color = $this->failIfNotInstance(
$this->handleInput($this->color),
ColorInterface::class
$color = $this->driver()->colorToNative(
$this->driver()->handleInput($this->color),
$image->colorspace()
);
$pixel = new ImagickDraw();
$pixel->setFillColor($this->colorToPixel($color, $image->colorspace()));
$pixel->setFillColor($color);
$pixel->point($this->position->x(), $this->position->y());
return $image->mapFrames(function ($frame) use ($pixel) {
$frame->core()->drawImage($pixel);
});
foreach ($image as $frame) {
$frame->data()->drawImage($pixel);
}
return $image;
}
}

View File

@@ -3,49 +3,47 @@
namespace Intervention\Image\Drivers\Imagick\Modifiers;
use ImagickDraw;
use Intervention\Image\Drivers\Abstract\Modifiers\AbstractDrawModifier;
use Intervention\Image\Drivers\Imagick\Traits\CanHandleColors;
use Intervention\Image\Interfaces\DrawableInterface;
use Intervention\Image\Drivers\DrawModifier;
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
{
$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);
}
if ($this->polygon()->hasBorder()) {
if ($this->drawable->hasBorder()) {
$border_color = $this->driver()->colorToNative(
$this->borderColor(),
$image->colorspace()
);
$drawing->setStrokeColor($border_color);
$drawing->setStrokeWidth($this->polygon()->getBorderSize());
$drawing->setStrokeWidth($this->drawable->borderSize());
}
$drawing->polygon($this->points());
return $image->mapFrames(function ($frame) use ($drawing) {
$frame->core()->drawImage($drawing);
});
foreach ($image as $frame) {
$frame->data()->drawImage($drawing);
}
return $image;
}
private function points(): array
{
$points = [];
foreach ($this->polygon() as $point) {
foreach ($this->drawable as $point) {
$points[] = ['x' => $point->x(), 'y' => $point->y()];
}

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