Файл: vendor/intervention/image/src/Image.php
Строк: 1791
<?php
declare(strict_types=1);
namespace InterventionImage;
use InterventionImageAnalyzersColorspaceAnalyzer;
use InterventionImageAnalyzersHeightAnalyzer;
use InterventionImageAnalyzersPixelColorAnalyzer;
use InterventionImageAnalyzersPixelColorsAnalyzer;
use InterventionImageAnalyzersProfileAnalyzer;
use InterventionImageAnalyzersResolutionAnalyzer;
use InterventionImageAnalyzersWidthAnalyzer;
use InterventionImageEncodersAutoEncoder;
use InterventionImageEncodersFileExtensionEncoder;
use InterventionImageEncodersFilePathEncoder;
use InterventionImageEncodersFormatEncoder;
use InterventionImageEncodersMediaTypeEncoder;
use InterventionImageExceptionsAnalyzerException;
use InterventionImageExceptionsColorDecoderException;
use InterventionImageExceptionsDirectoryNotFoundException;
use InterventionImageExceptionsEncoderException;
use InterventionImageExceptionsFileNotWritableException;
use InterventionImageExceptionsInvalidArgumentException;
use InterventionImageExceptionsModifierException;
use InterventionImageExceptionsNotSupportedException;
use InterventionImageExceptionsStateException;
use InterventionImageExceptionsStreamException;
use InterventionImageGeometryBezier;
use InterventionImageGeometryCircle;
use InterventionImageGeometryEllipse;
use InterventionImageGeometryFactoriesBezierFactory;
use InterventionImageGeometryFactoriesCircleFactory;
use InterventionImageGeometryFactoriesEllipseFactory;
use InterventionImageGeometryFactoriesLineFactory;
use InterventionImageGeometryFactoriesPolygonFactory;
use InterventionImageGeometryFactoriesRectangleFactory;
use InterventionImageGeometryLine;
use InterventionImageGeometryPoint;
use InterventionImageGeometryPolygon;
use InterventionImageGeometryRectangle;
use InterventionImageInterfacesAnalyzerInterface;
use InterventionImageInterfacesCollectionInterface;
use InterventionImageInterfacesColorInterface;
use InterventionImageInterfacesColorspaceInterface;
use InterventionImageInterfacesCoreInterface;
use InterventionImageInterfacesDrawableInterface;
use InterventionImageInterfacesDriverInterface;
use InterventionImageInterfacesEncodedImageInterface;
use InterventionImageInterfacesEncoderInterface;
use InterventionImageInterfacesFontInterface;
use InterventionImageInterfacesFrameInterface;
use InterventionImageInterfacesImageInterface;
use InterventionImageInterfacesModifierInterface;
use InterventionImageInterfacesOriginInterface;
use InterventionImageInterfacesProfileInterface;
use InterventionImageInterfacesResolutionInterface;
use InterventionImageInterfacesSizeInterface;
use InterventionImageModifiersBlurModifier;
use InterventionImageModifiersBrightnessModifier;
use InterventionImageModifiersColorizeModifier;
use InterventionImageModifiersColorspaceModifier;
use InterventionImageModifiersContainDownModifier;
use InterventionImageModifiersContainModifier;
use InterventionImageModifiersContrastModifier;
use InterventionImageModifiersCoverDownModifier;
use InterventionImageModifiersCoverModifier;
use InterventionImageModifiersCropModifier;
use InterventionImageModifiersDrawBezierModifier;
use InterventionImageModifiersDrawEllipseModifier;
use InterventionImageModifiersDrawLineModifier;
use InterventionImageModifiersDrawPixelModifier;
use InterventionImageModifiersDrawPolygonModifier;
use InterventionImageModifiersDrawRectangleModifier;
use InterventionImageModifiersFillModifier;
use InterventionImageModifiersFillTransparentAreasModifier;
use InterventionImageModifiersFlipModifier;
use InterventionImageModifiersGammaModifier;
use InterventionImageModifiersGrayscaleModifier;
use InterventionImageModifiersInsertModifier;
use InterventionImageModifiersInvertModifier;
use InterventionImageModifiersOrientModifier;
use InterventionImageModifiersPixelateModifier;
use InterventionImageModifiersProfileModifier;
use InterventionImageModifiersReduceColorsModifier;
use InterventionImageModifiersRemoveAnimationModifier;
use InterventionImageModifiersRemoveProfileModifier;
use InterventionImageModifiersResizeCanvasModifier;
use InterventionImageModifiersResizeCanvasRelativeModifier;
use InterventionImageModifiersResizeDownModifier;
use InterventionImageModifiersResizeModifier;
use InterventionImageModifiersResolutionModifier;
use InterventionImageModifiersRotateModifier;
use InterventionImageModifiersScaleDownModifier;
use InterventionImageModifiersScaleModifier;
use InterventionImageModifiersSharpenModifier;
use InterventionImageModifiersSliceAnimationModifier;
use InterventionImageModifiersTextModifier;
use InterventionImageModifiersTrimModifier;
use InterventionImageTypographyFontFactory;
use Throwable;
use Traversable;
final class Image implements ImageInterface
{
/**
* Origin containing the source from which the image was originally created.
*/
private OriginInterface $origin;
/**
* Exif data of the current image.
*/
private CollectionInterface $exif;
/**
* Create new instance.
*/
public function __construct(
private DriverInterface $driver,
private CoreInterface $core,
) {
$this->origin = new Origin();
$this->exif = new Collection();
}
/**
* {@inheritdoc}
*
* @see ImageInterface::driver()
*/
public function driver(): DriverInterface
{
return $this->driver;
}
/**
* {@inheritdoc}
*
* @see ImageInterface::core()
*/
public function core(): CoreInterface
{
return $this->core;
}
/**
* {@inheritdoc}
*
* @see ImageInterface::origin()
*/
public function origin(): OriginInterface
{
return $this->origin;
}
/**
* {@inheritdoc}
*
* @see ImageInterface::setOrigin()
*/
public function setOrigin(OriginInterface $origin): ImageInterface
{
$this->origin = $origin;
return $this;
}
/**
* {@inheritdoc}
*
* @see ImageInterface::count()
*/
public function count(): int
{
return $this->core->count();
}
/**
* Implementation of IteratorAggregate
*
* @return Traversable<FrameInterface>
*/
public function getIterator(): Traversable
{
return $this->core;
}
/**
* {@inheritdoc}
*
* @see ImageInterface::isAnimated()
*/
public function isAnimated(): bool
{
return $this->count() > 1;
}
/**
* {@inheritdoc}
*
* @see ImageInterface::removeAnimation()
*
* @throws InvalidArgumentException
* @throws ModifierException
*/
public function removeAnimation(int|string $position = 0): ImageInterface
{
return $this->modify(new RemoveAnimationModifier($position));
}
/**
* {@inheritdoc}
*
* @see ImageInterface::sliceAnimation()
*
* @throws InvalidArgumentException
* @throws ModifierException
*/
public function sliceAnimation(int $offset = 0, ?int $length = null): ImageInterface
{
return $this->modify(new SliceAnimationModifier($offset, $length));
}
/**
* {@inheritdoc}
*
* @see ImageInterface::loops()
*/
public function loops(): int
{
return $this->core->loops();
}
/**
* {@inheritdoc}
*
* @see ImageInterface::setLoops()
*/
public function setLoops(int $loops): ImageInterface
{
$this->core->setLoops($loops);
return $this;
}
/**
* {@inheritdoc}
*
* @see ImageInterface::exif()
*/
public function exif(?string $query = null): mixed
{
return is_null($query) ? $this->exif : $this->exif->get($query);
}
/**
* {@inheritdoc}
*
* @see ImageInterface::setExif()
*/
public function setExif(CollectionInterface $exif): ImageInterface
{
$this->exif = $exif;
return $this;
}
/**
* {@inheritdoc}
*
* @see ImageInterface::modify()
*
* @throws ModifierException
*/
public function modify(ModifierInterface $modifier): ImageInterface
{
return $this->driver()->specializeModifier($modifier)->apply($this);
}
/**
* {@inheritdoc}
*
* @see ImageInterface::analyze()
*
* @throws AnalyzerException
*/
public function analyze(AnalyzerInterface $analyzer): mixed
{
return $this->driver()->specializeAnalyzer($analyzer)->analyze($this);
}
/**
* {@inheritdoc}
*
* @see ImageInterface::save()
*
* @throws InvalidArgumentException
* @throws EncoderException
* @throws DirectoryNotFoundException
* @throws FileNotWritableException
* @throws StreamException
* @throws NotSupportedException
*/
public function save(?string $path = null, mixed ...$options): ImageInterface
{
if ($path === '') {
throw new InvalidArgumentException('Argument $path must not be an empty string');
}
if (is_null($path) && is_null($this->origin()->filePath())) {
throw new EncoderException('Unable to determine path for saving');
}
$path = is_null($path) ? $this->origin()->filePath() : $path;
try {
// try to determine encoding format by file extension of the path
$encoded = $this->encode(new FilePathEncoder($path, ...$options));
} catch (EncoderException) {
// fallback to encoding format by media type
$encoded = $this->encode(new MediaTypeEncoder(null, ...$options));
}
$encoded->save($path);
return $this;
}
/**
* {@inheritdoc}
*
* @see ImageInterface::width()
*
* @throws AnalyzerException
*/
public function width(): int
{
return $this->analyze(new WidthAnalyzer());
}
/**
* {@inheritdoc}
*
* @see ImageInterface::height()
*
* @throws AnalyzerException
*/
public function height(): int
{
return $this->analyze(new HeightAnalyzer());
}
/**
* {@inheritdoc}
*
* @see ImageInterface::size()
*
* @throws AnalyzerException
*/
public function size(): SizeInterface
{
try {
return new Size($this->width(), $this->height());
} catch (InvalidArgumentException $e) {
throw new AnalyzerException('Failed to read image size', previous: $e);
}
}
/**
* {@inheritdoc}
*
* @see ImageInterface::colorspace()
*
* @throws AnalyzerException
*/
public function colorspace(): ColorspaceInterface
{
return $this->analyze(new ColorspaceAnalyzer());
}
/**
* {@inheritdoc}
*
* @see ImageInterface::setColorspace()
*
* @throws ModifierException
* @throws NotSupportedException
*/
public function setColorspace(string|ColorspaceInterface $colorspace): ImageInterface
{
return $this->modify(new ColorspaceModifier($colorspace));
}
/**
* {@inheritdoc}
*
* @see ImageInterface::resolution()
*
* @throws AnalyzerException
*/
public function resolution(): ResolutionInterface
{
return $this->analyze(new ResolutionAnalyzer());
}
/**
* {@inheritdoc}
*
* @see ImageInterface::setResolution()
*
* @throws ModifierException
*/
public function setResolution(float $x, float $y): ImageInterface
{
return $this->modify(new ResolutionModifier($x, $y));
}
/**
* {@inheritdoc}
*
* @see ImageInterface::colorAt()
*
* @throws AnalyzerException
*/
public function colorAt(int $x, int $y, int $frame = 0): ColorInterface
{
return $this->analyze(new PixelColorAnalyzer($x, $y, $frame));
}
/**
* {@inheritdoc}
*
* @see ImageInterface::colorsAt()
*
* @throws AnalyzerException
*/
public function colorsAt(int $x, int $y): CollectionInterface
{
return $this->analyze(new PixelColorsAnalyzer($x, $y));
}
/**
* {@inheritdoc}
*
* @see ImageInterface::backgroundColor()
*
* @throws ColorDecoderException
*/
public function backgroundColor(): ColorInterface
{
return $this->driver()->decodeColor(
$this->driver()->config()->backgroundColor,
);
}
/**
* {@inheritdoc}
*
* @see ImageInterface::setBackgroundColor()
*
* @throws InvalidArgumentException
* @throws ColorDecoderException
*/
public function setBackgroundColor(string|ColorInterface $color): ImageInterface
{
$this->driver()->config()->setOptions(
backgroundColor: $this->driver()->decodeColor($color),
);
return $this;
}
/**
* {@inheritdoc}
*
* @see ImageInterface::profile()
*
* @throws AnalyzerException
*/
public function profile(): ProfileInterface
{
return $this->analyze(new ProfileAnalyzer());
}
/**
* {@inheritdoc}
*
* @see ImageInterface::setProfile()
*
* @throws ModifierException
*/
public function setProfile(ProfileInterface $profile): ImageInterface
{
return $this->modify(new ProfileModifier($profile));
}
/**
* {@inheritdoc}
*
* @see ImageInterface::removeProfile()
*
* @throws ModifierException
*/
public function removeProfile(): ImageInterface
{
return $this->modify(new RemoveProfileModifier());
}
/**
* {@inheritdoc}
*
* @see ImageInterface::reduceColors()
*
* @throws InvalidArgumentException
* @throws ModifierException
*/
public function reduceColors(int $limit, null|string|ColorInterface $background = null): ImageInterface
{
return $this->modify(new ReduceColorsModifier($limit, $background));
}
/**
* {@inheritdoc}
*
* @see ImageInterface::sharpen()
*
* @throws InvalidArgumentException
* @throws ModifierException
*/
public function sharpen(int $level = 10): ImageInterface
{
return $this->modify(new SharpenModifier($level));
}
/**
* {@inheritdoc}
*
* @see ImageInterface::invert()
*
* @throws ModifierException
*/
public function invert(): ImageInterface
{
return $this->modify(new InvertModifier());
}
/**
* {@inheritdoc}
*
* @see ImageInterface::pixelate()
*
* @throws InvalidArgumentException
* @throws ModifierException
*/
public function pixelate(int $size): ImageInterface
{
return $this->modify(new PixelateModifier($size));
}
/**
* {@inheritdoc}
*
* @see ImageInterface::grayscale()
*
* @throws ModifierException
*/
public function grayscale(): ImageInterface
{
return $this->modify(new GrayscaleModifier());
}
/**
* {@inheritdoc}
*
* @see ImageInterface::brightness()
*
* @throws ModifierException
*/
public function brightness(int $level): ImageInterface
{
return $this->modify(new BrightnessModifier($level));
}
/**
* {@inheritdoc}
*
* @see ImageInterface::contrast()
*
* @throws ModifierException
*/
public function contrast(int $level): ImageInterface
{
return $this->modify(new ContrastModifier($level));
}
/**
* {@inheritdoc}
*
* @see ImageInterface::gamma()
*
* @throws ModifierException
*/
public function gamma(float $gamma): ImageInterface
{
return $this->modify(new GammaModifier($gamma));
}
/**
* {@inheritdoc}
*
* @see ImageInterface::colorize()
*
* @throws InvalidArgumentException
* @throws ModifierException
*/
public function colorize(int $red = 0, int $green = 0, int $blue = 0): ImageInterface
{
return $this->modify(new ColorizeModifier($red, $green, $blue));
}
/**
* {@inheritdoc}
*
* @see ImageInterface::flip()
*
* @throws ModifierException
*/
public function flip(Direction $direction = Direction::HORIZONTAL): ImageInterface
{
return $this->modify(new FlipModifier($direction));
}
/**
* {@inheritdoc}
*
* @see ImageInterface::blur()
*
* @throws InvalidArgumentException
* @throws ModifierException
*/
public function blur(int $level = 5): ImageInterface
{
return $this->modify(new BlurModifier($level));
}
/**
* {@inheritdoc}
*
* @see ImageInterface::rotate()
*
* @throws InvalidArgumentException
* @throws ColorDecoderException
* @throws ModifierException
*/
public function rotate(float $angle, null|string|ColorInterface $background = null): ImageInterface
{
return $this->modify(new RotateModifier($angle, $background));
}
/**
* {@inheritdoc}
*
* @see ImageInterface::orient()
*
* @throws ModifierException
*/
public function orient(): ImageInterface
{
return $this->modify(new OrientModifier());
}
/**
* {@inheritdoc}
*
* @see ImageInterface::text()
*
* @throws InvalidArgumentException
* @throws ModifierException
* @throws StateException
*/
public function text(string $text, int $x, int $y, callable|FontInterface $font): ImageInterface
{
return $this->modify(
new TextModifier(
$text,
new Point($x, $y),
FontFactory::build($font),
),
);
}
/**
* {@inheritdoc}
*
* @see ImageInterface::resize()
*
* @throws InvalidArgumentException
* @throws ModifierException
*/
public function resize(null|int|Fraction $width = null, null|int|Fraction $height = null): ImageInterface
{
try {
return $this->modify(new ResizeModifier(...$this->resolveDimension($width, $height)));
} catch (AnalyzerException $e) {
throw new ModifierException('Failed to resize image', previous: $e);
}
}
/**
* {@inheritdoc}
*
* @see ImageInterface::resizeDown()
*
* @throws InvalidArgumentException
* @throws ModifierException
*/
public function resizeDown(null|int|Fraction $width = null, null|int|Fraction $height = null): ImageInterface
{
try {
return $this->modify(new ResizeDownModifier(...$this->resolveDimension($width, $height)));
} catch (AnalyzerException $e) {
throw new ModifierException('Failed to resize image', previous: $e);
}
}
/**
* {@inheritdoc}
*
* @see ImageInterface::scale()
*
* @throws InvalidArgumentException
* @throws ModifierException
*/
public function scale(null|int|Fraction $width = null, null|int|Fraction $height = null): ImageInterface
{
try {
return $this->modify(new ScaleModifier(...$this->resolveDimension($width, $height)));
} catch (AnalyzerException $e) {
throw new ModifierException('Failed to resize image', previous: $e);
}
}
/**
* {@inheritdoc}
*
* @see ImageInterface::scaleDown()
*
* @throws InvalidArgumentException
* @throws ModifierException
*/
public function scaleDown(null|int|Fraction $width = null, null|int|Fraction $height = null): ImageInterface
{
try {
return $this->modify(new ScaleDownModifier(...$this->resolveDimension($width, $height)));
} catch (AnalyzerException $e) {
throw new ModifierException('Failed to resize image', previous: $e);
}
}
/**
* {@inheritdoc}
*
* @see ImageInterface::cover()
*
* @throws InvalidArgumentException
* @throws ModifierException
*/
public function cover(
int|Fraction $width,
int|Fraction $height,
string|Alignment $alignment = Alignment::CENTER,
): ImageInterface {
try {
return $this->modify(new CoverModifier(...[
...$this->resolveDimension($width, $height),
...['alignment' => $alignment],
]));
} catch (AnalyzerException $e) {
throw new ModifierException('Failed to resize image', previous: $e);
}
}
/**
* {@inheritdoc}
*
* @see ImageInterface::coverDown()
*
* @throws InvalidArgumentException
* @throws ModifierException
*/
public function coverDown(
int|Fraction $width,
int|Fraction $height,
string|Alignment $alignment = Alignment::CENTER,
): ImageInterface {
try {
return $this->modify(new CoverDownModifier(...[
...$this->resolveDimension($width, $height),
...['alignment' => $alignment],
]));
} catch (AnalyzerException $e) {
throw new ModifierException('Failed to resize image', previous: $e);
}
}
/**
* {@inheritdoc}
*
* @see ImageInterface::resizeCanvas()
*
* @throws InvalidArgumentException
* @throws ModifierException
*/
public function resizeCanvas(
null|int|Fraction $width = null,
null|int|Fraction $height = null,
null|string|ColorInterface $background = null,
string|Alignment $alignment = Alignment::CENTER,
): ImageInterface {
try {
return $this->modify(new ResizeCanvasModifier(...[
...$this->resolveDimension($width, $height),
...[
'background' => $background,
'alignment' => $alignment,
],
]));
} catch (AnalyzerException $e) {
throw new ModifierException('Failed to resize image', previous: $e);
}
}
/**
* {@inheritdoc}
*
* @see ImageInterface::resizeCanvasRelative()
*
* @throws InvalidArgumentException
* @throws ModifierException
*/
public function resizeCanvasRelative(
null|int|Fraction $width = null,
null|int|Fraction $height = null,
null|string|ColorInterface $background = null,
string|Alignment $alignment = Alignment::CENTER,
): ImageInterface {
try {
return $this->modify(new ResizeCanvasRelativeModifier(...[
...$this->resolveDimension($width, $height),
...[
'background' => $background,
'alignment' => $alignment,
],
]));
} catch (AnalyzerException $e) {
throw new ModifierException('Failed to resize image', previous: $e);
}
}
/**
* {@inheritdoc}
*
* @see ImageInterface::containDown()
*
* @throws InvalidArgumentException
* @throws ModifierException
*/
public function containDown(
int|Fraction $width,
int|Fraction $height,
null|string|ColorInterface $background = null,
string|Alignment $alignment = Alignment::CENTER,
): ImageInterface {
try {
return $this->modify(new ContainDownModifier(...[
...$this->resolveDimension($width, $height),
...[
'background' => $background,
'alignment' => $alignment,
],
]));
} catch (AnalyzerException $e) {
throw new ModifierException('Failed to resize image', previous: $e);
}
}
/**
* {@inheritdoc}
*
* @see ImageInterface::contain()
*
* @throws InvalidArgumentException
* @throws ModifierException
*/
public function contain(
int|Fraction $width,
int|Fraction $height,
null|string|ColorInterface $background = null,
string|Alignment $alignment = Alignment::CENTER,
): ImageInterface {
try {
return $this->modify(new ContainModifier(...[
...$this->resolveDimension($width, $height),
...[
'background' => $background,
'alignment' => $alignment,
],
]));
} catch (AnalyzerException $e) {
throw new ModifierException('Failed to resize image', previous: $e);
}
}
/**
* {@inheritdoc}
*
* @see ImageInterface::crop()
*
* @throws InvalidArgumentException
* @throws ModifierException
*/
public function crop(
int|Fraction $width,
int|Fraction $height,
int $x = 0,
int $y = 0,
null|string|ColorInterface $background = null,
string|Alignment $alignment = Alignment::TOP_LEFT,
): ImageInterface {
try {
return $this->modify(new CropModifier(...[
...$this->resolveDimension($width, $height),
...[
'x' => $x,
'y' => $y,
'background' => $background,
'alignment' => $alignment,
],
]));
} catch (AnalyzerException $e) {
throw new ModifierException('Failed to resize image', previous: $e);
}
}
/**
* {@inheritdoc}
*
* @see ImageInterface::trim()
*
* @throws InvalidArgumentException
* @throws ModifierException
*/
public function trim(int $tolerance = 0): ImageInterface
{
return $this->modify(new TrimModifier($tolerance));
}
/**
* {@inheritdoc}
*
* @see ImageInterface::insert()
*
* @throws InvalidArgumentException
* @throws ModifierException
*/
public function insert(
mixed $image,
int $x = 0,
int $y = 0,
string|Alignment $alignment = Alignment::TOP_LEFT,
float $transparency = 1,
): ImageInterface {
return $this->modify(new InsertModifier($image, $x, $y, $alignment, $transparency));
}
/**
* {@inheritdoc}
*
* @see ImageInterface::fill()
*
* @throws ModifierException
*/
public function fill(string|ColorInterface $color, ?int $x = null, ?int $y = null): ImageInterface
{
return $this->modify(
new FillModifier(
$color,
is_null($x) || is_null($y) ? null : new Point($x, $y),
),
);
}
/**
* {@inheritdoc}
*
* @see ImageInterface::fillTransparentAreas()
*
* @throws ModifierException
*/
public function fillTransparentAreas(null|string|ColorInterface $color = null): ImageInterface
{
return $this->modify(new FillTransparentAreasModifier($color));
}
/**
* {@inheritdoc}
*
* @see ImageInterface::drawPixel()
*
* @throws ModifierException
* @throws ColorDecoderException
*/
public function drawPixel(int $x, int $y, string|ColorInterface $color): ImageInterface
{
return $this->modify(new DrawPixelModifier(new Point($x, $y), $color));
}
/**
* {@inheritdoc}
*
* @see ImageInterface::drawRectangle()
*
* @throws InvalidArgumentException
* @throws ModifierException
* @throws ColorDecoderException
*/
public function drawRectangle(callable|Rectangle $rectangle): ImageInterface
{
return $this->modify(
new DrawRectangleModifier(
RectangleFactory::build($rectangle),
),
);
}
/**
* {@inheritdoc}
*
* @see ImageInterface::drawEllipse()
*
* @throws ModifierException
* @throws ColorDecoderException
*/
public function drawEllipse(callable|Ellipse $ellipse): ImageInterface
{
return $this->modify(
new DrawEllipseModifier(
EllipseFactory::build($ellipse),
),
);
}
/**
* {@inheritdoc}
*
* @see ImageInterface::drawCircle()
*
* @throws ModifierException
* @throws ColorDecoderException
*/
public function drawCircle(callable|Circle $circle): ImageInterface
{
return $this->modify(
new DrawEllipseModifier(
CircleFactory::build($circle),
),
);
}
/**
* {@inheritdoc}
*
* @see ImageInterface::drawPolygon()
*
* @throws InvalidArgumentException
* @throws ModifierException
* @throws ColorDecoderException
*/
public function drawPolygon(callable|Polygon $polygon): ImageInterface
{
return $this->modify(
new DrawPolygonModifier(
PolygonFactory::build($polygon),
),
);
}
/**
* {@inheritdoc}
*
* @see ImageInterface::drawLine()
*
* @throws ModifierException
* @throws ColorDecoderException
*/
public function drawLine(callable|Line $line): ImageInterface
{
return $this->modify(
new DrawLineModifier(
LineFactory::build($line),
),
);
}
/**
* {@inheritdoc}
*
* @see ImageInterface::drawBezier()
*
* @throws ModifierException
* @throws ColorDecoderException
*/
public function drawBezier(callable|Bezier $bezier): ImageInterface
{
return $this->modify(
new DrawBezierModifier(
BezierFactory::build($bezier),
),
);
}
/**
* {@inheritdoc}
*
* @see ImageInterface::draw()
*
* @throws InvalidArgumentException
* @throws NotSupportedException
* @throws ModifierException
* @throws ColorDecoderException
*/
public function draw(DrawableInterface $drawable): ImageInterface
{
return $this->modify(match ($drawable::class) {
Rectangle::class => new DrawRectangleModifier($drawable),
Circle::class, Ellipse::class => new DrawEllipseModifier($drawable),
Bezier::class => new DrawBezierModifier($drawable),
Line::class => new DrawLineModifier($drawable),
Polygon::class => new DrawPolygonModifier($drawable),
default => throw new NotSupportedException('No modifier for ' . $drawable::class . ' found'),
});
}
/**
* {@inheritdoc}
*
* @see ImageInterface::encode()
*
* @throws EncoderException
*/
public function encode(?EncoderInterface $encoder = null): EncodedImageInterface
{
return $this->driver()->specializeEncoder(
$encoder ?: new AutoEncoder(),
)->encode($this);
}
/**
* {@inheritdoc}
*
* @see ImageInterface::encodeUsingFormat()
*
* @throws EncoderException
*/
public function encodeUsingFormat(Format $format, mixed ...$options): EncodedImageInterface
{
return $this->encode(new FormatEncoder($format, ...$options));
}
/**
* {@inheritdoc}
*
* @see ImageInterface::encodeUsingMediaType()
*
* @throws EncoderException
*/
public function encodeUsingMediaType(string|MediaType $mediaType, mixed ...$options): EncodedImageInterface
{
return $this->encode(new MediaTypeEncoder($mediaType, ...$options));
}
/**
* {@inheritdoc}
*
* @see ImageInterface::encodeUsingFileExtension()
*
* @throws InvalidArgumentException
* @throws NotSupportedException
* @throws EncoderException
*/
public function encodeUsingFileExtension(
string|FileExtension $fileExtension,
mixed ...$options,
): EncodedImageInterface {
return $this->encode(new FileExtensionEncoder($fileExtension, ...$options));
}
/**
* {@inheritdoc}
*
* @see ImageInterface::encodeUsingPath()
*
* @throws InvalidArgumentException
* @throws NotSupportedException
* @throws EncoderException
*/
public function encodeUsingPath(string $path, mixed ...$options,): EncodedImageInterface
{
return $this->encode(new FilePathEncoder($path, ...$options));
}
/**
* Build resizing dimension from various inputs including fractions based lengths.
*
* @throws InvalidArgumentException
* @throws AnalyzerException
* @return array{'width': ?int, 'height': ?int}
*/
private function resolveDimension(null|int|Fraction $width, null|int|Fraction $height): array
{
if ($width instanceof Fraction || $height instanceof Fraction) {
$size = $this->size();
$width = ($width instanceof Fraction) ? (int) round($width->of($size->width())) : $width;
$height = ($height instanceof Fraction) ? (int) round($height->of($size->height())) : $height;
}
return [
'width' => $width,
'height' => $height,
];
}
/**
* Show debug info for the current image.
*
* @return array<string, ?int>
*/
public function __debugInfo(): array
{
try {
return [
'width' => $this->width(),
'height' => $this->height(),
];
} catch (Throwable) {
return [
'width' => null,
'height' => null,
];
}
}
/**
* Clone image.
*/
public function __clone(): void
{
$this->driver = clone $this->driver;
$this->core = clone $this->core;
$this->exif = clone $this->exif;
}
}