refactor: susun semula struktur folder — Laravel source ke src/

This commit is contained in:
Saufi
2026-05-19 15:58:35 +08:00
parent f052251b94
commit bf53c71b45
10806 changed files with 1385379 additions and 121 deletions

View File

@@ -0,0 +1,244 @@
<?php
declare(strict_types=1);
namespace Intervention\Image\Geometry;
use ArrayAccess;
use ArrayIterator;
use Countable;
use Intervention\Image\Colors\AbstractColor;
use Intervention\Image\Geometry\Factories\BezierFactory;
use Traversable;
use IteratorAggregate;
use Intervention\Image\Geometry\Traits\HasBackgroundColor;
use Intervention\Image\Geometry\Traits\HasBorder;
use Intervention\Image\Interfaces\DrawableFactoryInterface;
use Intervention\Image\Interfaces\DrawableInterface;
use Intervention\Image\Interfaces\PointInterface;
/**
* @implements IteratorAggregate<PointInterface>
* @implements ArrayAccess<int, PointInterface>
*/
class Bezier implements IteratorAggregate, Countable, ArrayAccess, DrawableInterface
{
use HasBorder;
use HasBackgroundColor;
/**
* Create new bezier instance.
*
* @param array<PointInterface> $points
*/
public function __construct(
protected array $points = [],
protected PointInterface $pivot = new Point()
) {
//
}
/**
* {@inheritdoc}
*
* @see DrawableInterface::position()
*/
public function position(): PointInterface
{
return $this->pivot;
}
/**
* {@inheritdoc}
*
* @see DrawableInterface::setPosition()
*/
public function setPosition(PointInterface $position): self
{
$this->pivot = $position;
return $this;
}
/**
* Implement iteration through all points of bezier.
*
* @return Traversable<PointInterface>
*/
public function getIterator(): Traversable
{
return new ArrayIterator($this->points);
}
/**
* Return current pivot point.
*/
public function pivot(): PointInterface
{
return $this->pivot;
}
/**
* Change pivot point to given point.
*/
public function setPivot(PointInterface $pivot): self
{
$this->pivot = $pivot;
return $this;
}
/**
* Return first control point of bezier.
*/
public function first(): ?PointInterface
{
if ($point = reset($this->points)) {
return $point;
}
return null;
}
/**
* Return second control point of bezier.
*/
public function second(): ?PointInterface
{
if (array_key_exists(1, $this->points)) {
return $this->points[1];
}
return null;
}
/**
* Return third control point of bezier.
*/
public function third(): ?PointInterface
{
if (array_key_exists(2, $this->points)) {
return $this->points[2];
}
return null;
}
/**
* Return last control point of bezier.
*/
public function last(): ?PointInterface
{
if ($point = end($this->points)) {
return $point;
}
return null;
}
/**
* Return bezier's point count.
*/
public function count(): int
{
return count($this->points);
}
/**
* Determine if point exists at given offset.
*/
public function offsetExists(mixed $offset): bool
{
return array_key_exists($offset, $this->points);
}
/**
* Return point at given offset.
*/
public function offsetGet(mixed $offset): mixed
{
return $this->points[$offset];
}
/**
* Set point at given offset.
*/
public function offsetSet(mixed $offset, mixed $value): void
{
$this->points[$offset] = $value;
}
/**
* Unset offset at given offset.
*/
public function offsetUnset(mixed $offset): void
{
unset($this->points[$offset]);
}
/**
* Add given point to bezier.
*/
public function addPoint(PointInterface $point): self
{
$this->points[] = $point;
return $this;
}
/**
* Return array of all x/y values of all points of bezier.
*
* @return array<int>
*/
public function toArray(): array
{
$coordinates = [];
foreach ($this->points as $point) {
$coordinates[] = $point->x();
$coordinates[] = $point->y();
}
return $coordinates;
}
/**
* {@inheritdoc}
*
* @see DrawableInterface::factory()
*/
public function factory(): DrawableFactoryInterface
{
return new BezierFactory($this);
}
/**
* {@inheritdoc}
*
* @see DrawableInterface::adjust()
*/
public function adjust(callable $adjustments): DrawableInterface
{
$factory = $this->factory();
$adjustments($factory);
return $factory->drawable();
}
/**
* Clone bezier.
*/
public function __clone(): void
{
$this->points = array_map(fn($point) => clone $point, $this->points);
$this->pivot = clone $this->pivot;
if ($this->backgroundColor instanceof AbstractColor) {
$this->backgroundColor = clone $this->backgroundColor;
}
if ($this->borderColor instanceof AbstractColor) {
$this->borderColor = clone $this->borderColor;
}
}
}

View File

@@ -0,0 +1,67 @@
<?php
declare(strict_types=1);
namespace Intervention\Image\Geometry;
use Intervention\Image\Geometry\Factories\CircleFactory;
use Intervention\Image\Interfaces\DrawableFactoryInterface;
use Intervention\Image\Interfaces\PointInterface;
class Circle extends Ellipse
{
/**
* Create new circle instance.
*/
public function __construct(
int $diameter,
PointInterface $pivot = new Point()
) {
parent::__construct($diameter, $diameter, $pivot);
}
/**
* Set diameter of circle.
*/
public function setDiameter(int $diameter): self
{
$this->setWidth($diameter);
$this->setHeight($diameter);
return $this;
}
/**
* Get diameter of circle.
*/
public function diameter(): int
{
return $this->width();
}
/**
* Set radius of circle.
*/
public function setRadius(int $radius): self
{
return $this->setDiameter(intval($radius * 2));
}
/**
* Get radius of circle.
*/
public function radius(): int
{
return intval(round($this->diameter() / 2));
}
/**
* {@inheritdoc}
*
* @see DrawableInterface::factory()
*/
public function factory(): DrawableFactoryInterface
{
return new CircleFactory($this);
}
}

View File

@@ -0,0 +1,143 @@
<?php
declare(strict_types=1);
namespace Intervention\Image\Geometry;
use Intervention\Image\Colors\AbstractColor;
use Intervention\Image\Geometry\Factories\EllipseFactory;
use Intervention\Image\Geometry\Traits\HasBackgroundColor;
use Intervention\Image\Geometry\Traits\HasBorder;
use Intervention\Image\Interfaces\DrawableFactoryInterface;
use Intervention\Image\Interfaces\DrawableInterface;
use Intervention\Image\Interfaces\PointInterface;
class Ellipse implements DrawableInterface
{
use HasBorder;
use HasBackgroundColor;
/**
* Create new ellipse instance.
*/
public function __construct(
protected int $width,
protected int $height,
protected PointInterface $pivot = new Point()
) {
//
}
/**
* {@inheritdoc}
*
* @see DrawableInterface::position()
*/
public function position(): PointInterface
{
return $this->pivot;
}
/**
* {@inheritdoc}
*
* @see DrawableInterface::setPosition()
*/
public function setPosition(PointInterface $position): self
{
$this->pivot = $position;
return $this;
}
/**
* Return pivot point of Ellipse.
*/
public function pivot(): PointInterface
{
return $this->pivot;
}
/**
* Set size of Ellipse.
*/
public function setSize(int $width, int $height): self
{
return $this->setWidth($width)->setHeight($height);
}
/**
* Set width of Ellipse.
*/
public function setWidth(int $width): self
{
$this->width = $width;
return $this;
}
/**
* Set height of Ellipse.
*/
public function setHeight(int $height): self
{
$this->height = $height;
return $this;
}
/**
* Get width of Ellipse.
*/
public function width(): int
{
return $this->width;
}
/**
* Get height of Ellipse.
*/
public function height(): int
{
return $this->height;
}
/**
* {@inheritdoc}
*
* @see DrawableInterface::factory()
*/
public function factory(): DrawableFactoryInterface
{
return new EllipseFactory($this);
}
/**
* {@inheritdoc}
*
* @see DrawableInterface::adjust()
*/
public function adjust(callable $adjustments): DrawableInterface
{
$factory = $this->factory();
$adjustments($factory);
return $factory->drawable();
}
/**
* Clone ellipse.
*/
public function __clone(): void
{
$this->pivot = clone $this->pivot;
if ($this->backgroundColor instanceof AbstractColor) {
$this->backgroundColor = clone $this->backgroundColor;
}
if ($this->borderColor instanceof AbstractColor) {
$this->borderColor = clone $this->borderColor;
}
}
}

View File

@@ -0,0 +1,81 @@
<?php
declare(strict_types=1);
namespace Intervention\Image\Geometry\Factories;
use Intervention\Image\Exceptions\InvalidArgumentException;
use Intervention\Image\Geometry\Point;
use Intervention\Image\Geometry\Bezier;
use Intervention\Image\Interfaces\ColorInterface;
use Intervention\Image\Interfaces\DrawableFactoryInterface;
use Intervention\Image\Interfaces\DrawableInterface;
class BezierFactory implements DrawableFactoryInterface
{
protected Bezier $bezier;
/**
* Create new factory instance.
*/
public function __construct(null|callable|Bezier $bezier = null)
{
$this->bezier = $bezier instanceof Bezier ? clone $bezier : new Bezier([]);
if (is_callable($bezier)) {
$bezier($this);
}
}
/**
* {@inheritdoc}
*
* @see DrawableFactoryInterface::build()
*/
public static function build(null|callable|DrawableInterface $drawable = null): Bezier
{
return (new self($drawable))->drawable();
}
/**
* {@inheritdoc}
*
* @see DrawableFactoryInterface::drawable()
*/
public function drawable(): Bezier
{
return $this->bezier;
}
/**
* Add a point to the bezier to be produced.
*/
public function point(int $x, int $y): self
{
$this->bezier->addPoint(new Point($x, $y));
return $this;
}
/**
* Set the background color of the bezier to be produced.
*/
public function background(string|ColorInterface $color): self
{
$this->bezier->setBackgroundColor($color);
return $this;
}
/**
* Set the border color & border size of the bezier to be produced.
*
* @throws InvalidArgumentException
*/
public function border(string|ColorInterface $color, int $size = 1): self
{
$this->bezier->setBorder($color, $size);
return $this;
}
}

View File

@@ -0,0 +1,100 @@
<?php
declare(strict_types=1);
namespace Intervention\Image\Geometry\Factories;
use Intervention\Image\Exceptions\InvalidArgumentException;
use Intervention\Image\Geometry\Circle;
use Intervention\Image\Interfaces\ColorInterface;
use Intervention\Image\Interfaces\DrawableFactoryInterface;
use Intervention\Image\Interfaces\DrawableInterface;
class CircleFactory implements DrawableFactoryInterface
{
protected Circle $circle;
/**
* Create new factory instance.
*/
public function __construct(null|callable|Circle $circle = null)
{
$this->circle = $circle instanceof Circle ? clone $circle : new Circle(0);
if (is_callable($circle)) {
$circle($this);
}
}
/**
* {@inheritdoc}
*
* @see DrawableFactoryInterface::build()
*/
public static function build(null|callable|DrawableInterface $drawable = null): Circle
{
return (new self($drawable))->drawable();
}
/**
* {@inheritdoc}
*
* @see DrawableFactoryInterface::drawable()
*/
public function drawable(): Circle
{
return $this->circle;
}
/**
* Set the radius of the circle to be produced.
*/
public function radius(int $radius): self
{
$this->circle->setSize($radius * 2, $radius * 2);
return $this;
}
/**
* Set the diameter of the circle to be produced.
*/
public function diameter(int $diameter): self
{
$this->circle->setSize($diameter, $diameter);
return $this;
}
/**
* Set the background color of the circle to be produced.
*/
public function background(string|ColorInterface $color): self
{
$this->circle->setBackgroundColor($color);
return $this;
}
/**
* Set the border color & border size of the circle to be produced.
*
* @throws InvalidArgumentException
*/
public function border(string|ColorInterface $color, int $size = 1): self
{
$this->circle->setBorder($color, $size);
return $this;
}
/**
* Set the position where the circle should be drawn.
*/
public function at(int $x, int $y): self
{
$this->circle->position()->setPosition($x, $y);
return $this;
}
}

View File

@@ -0,0 +1,76 @@
<?php
declare(strict_types=1);
namespace Intervention\Image\Geometry\Factories;
use Intervention\Image\Exceptions\InvalidArgumentException;
use Intervention\Image\Geometry\Bezier;
use Intervention\Image\Geometry\Circle;
use Intervention\Image\Geometry\Ellipse;
use Intervention\Image\Geometry\Line;
use Intervention\Image\Geometry\Polygon;
use Intervention\Image\Geometry\Rectangle;
class Drawable
{
/**
* Create Bezier statically.
*
* @throws InvalidArgumentException
*/
public static function bezier(null|callable|Bezier $bezier = null): Bezier
{
return BezierFactory::build($bezier);
}
/**
* Create Circle statically.
*
* @throws InvalidArgumentException
*/
public static function circle(null|callable|Circle $circle = null): Circle
{
return CircleFactory::build($circle);
}
/**
* Create Ellipse statically.
*
* @throws InvalidArgumentException
*/
public static function ellipse(null|callable|Ellipse $ellipse = null): Ellipse
{
return EllipseFactory::build($ellipse);
}
/**
* Create Line statically.
*
* @throws InvalidArgumentException
*/
public static function line(null|callable|Line $line = null): Line
{
return LineFactory::build($line);
}
/**
* Create Polygon statically.
*
* @throws InvalidArgumentException
*/
public static function polygon(null|callable|Polygon $polygon = null): Polygon
{
return PolygonFactory::build($polygon);
}
/**
* Create Rectangle statically.
*
* @throws InvalidArgumentException
*/
public static function rectangle(null|callable|Rectangle $rectangle = null): Rectangle
{
return RectangleFactory::build($rectangle);
}
}

View File

@@ -0,0 +1,110 @@
<?php
declare(strict_types=1);
namespace Intervention\Image\Geometry\Factories;
use Intervention\Image\Exceptions\InvalidArgumentException;
use Intervention\Image\Geometry\Ellipse;
use Intervention\Image\Interfaces\ColorInterface;
use Intervention\Image\Interfaces\DrawableFactoryInterface;
use Intervention\Image\Interfaces\DrawableInterface;
class EllipseFactory implements DrawableFactoryInterface
{
protected Ellipse $ellipse;
/**
* Create new factory instance.
*/
public function __construct(null|callable|Ellipse $ellipse = null)
{
$this->ellipse = $ellipse instanceof Ellipse ? clone $ellipse : new Ellipse(0, 0);
if (is_callable($ellipse)) {
$ellipse($this);
}
}
/**
* {@inheritdoc}
*
* @see DrawableFactoryInterface::build()
*/
public static function build(null|callable|DrawableInterface $drawable = null): Ellipse
{
return (new self($drawable))->drawable();
}
/**
* {@inheritdoc}
*
* @see DrawableFactoryInterface::drawable()
*/
public function drawable(): Ellipse
{
return $this->ellipse;
}
/**
* Set the size of the ellipse to be produced.
*/
public function size(int $width, int $height): self
{
$this->ellipse->setSize($width, $height);
return $this;
}
/**
* Set the width of the ellipse to be produced.
*/
public function width(int $width): self
{
$this->ellipse->setWidth($width);
return $this;
}
/**
* Set the height of the ellipse to be produced.
*/
public function height(int $height): self
{
$this->ellipse->setHeight($height);
return $this;
}
/**
* Set the background color of the ellipse to be produced.
*/
public function background(string|ColorInterface $color): self
{
$this->ellipse->setBackgroundColor($color);
return $this;
}
/**
* Set the border color & border size of the ellipse to be produced.
*
* @throws InvalidArgumentException
*/
public function border(string|ColorInterface $color, int $size = 1): self
{
$this->ellipse->setBorder($color, $size);
return $this;
}
/**
* Set the position where the ellipse should be drawn.
*/
public function at(int $x, int $y): self
{
$this->ellipse->position()->setPosition($x, $y);
return $this;
}
}

View File

@@ -0,0 +1,112 @@
<?php
declare(strict_types=1);
namespace Intervention\Image\Geometry\Factories;
use Intervention\Image\Geometry\Point;
use Intervention\Image\Geometry\Line;
use Intervention\Image\Interfaces\ColorInterface;
use Intervention\Image\Interfaces\DrawableFactoryInterface;
use Intervention\Image\Interfaces\DrawableInterface;
class LineFactory implements DrawableFactoryInterface
{
protected Line $line;
/**
* Create the factory instance.
*/
public function __construct(null|callable|Line $line = null)
{
$this->line = $line instanceof Line ? clone $line : new Line(new Point(), new Point());
if (is_callable($line)) {
$line($this);
}
}
/**
* {@inheritdoc}
*
* @see DrawableFactoryInterface::build()
*/
public static function build(null|callable|DrawableInterface $drawable = null): Line
{
return (new self($drawable))->drawable();
}
/**
* {@inheritdoc}
*
* @see DrawableFactoryInterface::drawable()
*/
public function drawable(): Line
{
return $this->line;
}
/**
* Set the color of the line to be produced.
*/
public function color(string|ColorInterface $color): self
{
$this->line->setBackgroundColor($color);
$this->line->setBorderColor($color);
return $this;
}
/**
* Set the (background) color of the line to be produced.
*/
public function background(string|ColorInterface $color): self
{
$this->line->setBackgroundColor($color);
$this->line->setBorderColor($color);
return $this;
}
/**
* Set the border size & border color of the line to be produced.
*/
public function border(string|ColorInterface $color, int $size = 1): self
{
$this->line->setBackgroundColor($color);
$this->line->setBorderColor($color);
$this->line->setWidth($size);
return $this;
}
/**
* Set the width of the line to be produced.
*/
public function width(int $size): self
{
$this->line->setWidth($size);
return $this;
}
/**
* Set the coordinates of the starting point of the line to be produced.
*/
public function from(int $x, int $y): self
{
$this->line->setStart(new Point($x, $y));
return $this;
}
/**
* Set the coordinates of the end point of the line to be produced.
*/
public function to(int $x, int $y): self
{
$this->line->setEnd(new Point($x, $y));
return $this;
}
}

View File

@@ -0,0 +1,81 @@
<?php
declare(strict_types=1);
namespace Intervention\Image\Geometry\Factories;
use Intervention\Image\Exceptions\InvalidArgumentException;
use Intervention\Image\Geometry\Point;
use Intervention\Image\Geometry\Polygon;
use Intervention\Image\Interfaces\ColorInterface;
use Intervention\Image\Interfaces\DrawableFactoryInterface;
use Intervention\Image\Interfaces\DrawableInterface;
class PolygonFactory implements DrawableFactoryInterface
{
protected Polygon $polygon;
/**
* Create new factory instance.
*/
public function __construct(null|callable|Polygon $polygon = null)
{
$this->polygon = $polygon instanceof Polygon ? clone $polygon : new Polygon([]);
if (is_callable($polygon)) {
$polygon($this);
}
}
/**
* {@inheritdoc}
*
* @see DrawableFactoryInterface::build()
*/
public static function build(null|callable|DrawableInterface $drawable = null): Polygon
{
return (new self($drawable))->drawable();
}
/**
* {@inheritdoc}
*
* @see DrawableFactoryInterface::drawable()
*/
public function drawable(): Polygon
{
return $this->polygon;
}
/**
* Add a point to the polygon to be produced.
*/
public function point(int $x, int $y): self
{
$this->polygon->addPoint(new Point($x, $y));
return $this;
}
/**
* Set the background color of the polygon to be produced.
*/
public function background(string|ColorInterface $color): self
{
$this->polygon->setBackgroundColor($color);
return $this;
}
/**
* Set the border color & border size of the polygon to be produced.
*
* @throws InvalidArgumentException
*/
public function border(string|ColorInterface $color, int $size = 1): self
{
$this->polygon->setBorder($color, $size);
return $this;
}
}

View File

@@ -0,0 +1,115 @@
<?php
declare(strict_types=1);
namespace Intervention\Image\Geometry\Factories;
use Intervention\Image\Exceptions\InvalidArgumentException;
use Intervention\Image\Geometry\Rectangle;
use Intervention\Image\Interfaces\ColorInterface;
use Intervention\Image\Interfaces\DrawableFactoryInterface;
use Intervention\Image\Interfaces\DrawableInterface;
class RectangleFactory implements DrawableFactoryInterface
{
protected Rectangle $rectangle;
/**
* Create new instance.
*
* @throws InvalidArgumentException
*/
public function __construct(null|callable|Rectangle $rectangle = null)
{
$this->rectangle = $rectangle instanceof Rectangle ? clone $rectangle : new Rectangle(0, 0);
if (is_callable($rectangle)) {
$rectangle($this);
}
}
/**
* {@inheritdoc}
*
* @see DrawableFactoryInterface::build()
*
* @throws InvalidArgumentException
*/
public static function build(null|callable|DrawableInterface $drawable = null): Rectangle
{
return (new self($drawable))->drawable();
}
/**
* {@inheritdoc}
*
* @see DrawableFactoryInterface::drawable()
*/
public function drawable(): Rectangle
{
return $this->rectangle;
}
/**
* Set the size of the rectangle to be produced.
*/
public function size(int $width, int $height): self
{
$this->rectangle->setWidth($width);
$this->rectangle->setHeight($height);
return $this;
}
/**
* Set the width of the rectangle to be produced.
*/
public function width(int $width): self
{
$this->rectangle->setWidth($width);
return $this;
}
/**
* Set the height of the rectangle to be produced.
*/
public function height(int $height): self
{
$this->rectangle->setHeight($height);
return $this;
}
/**
* Set the background color of the rectangle to be produced.
*/
public function background(string|ColorInterface $color): self
{
$this->rectangle->setBackgroundColor($color);
return $this;
}
/**
* Set the border color & border size of the rectangle to be produced.
*
* @throws InvalidArgumentException
*/
public function border(string|ColorInterface $color, int $size = 1): self
{
$this->rectangle->setBorder($color, $size);
return $this;
}
/**
* Set the position where the rectangle should be drawn.
*/
public function at(int $x, int $y): self
{
$this->rectangle->position()->setPosition($x, $y);
return $this;
}
}

View File

@@ -0,0 +1,168 @@
<?php
declare(strict_types=1);
namespace Intervention\Image\Geometry;
use Intervention\Image\Colors\AbstractColor;
use Intervention\Image\Geometry\Factories\LineFactory;
use Intervention\Image\Geometry\Traits\HasBackgroundColor;
use Intervention\Image\Geometry\Traits\HasBorder;
use Intervention\Image\Interfaces\DrawableFactoryInterface;
use Intervention\Image\Interfaces\DrawableInterface;
use Intervention\Image\Interfaces\PointInterface;
class Line implements DrawableInterface
{
use HasBorder;
use HasBackgroundColor;
/**
* Create new line instance.
*/
public function __construct(
protected PointInterface $start,
protected PointInterface $end,
protected int $width = 1
) {
//
}
/**
* {@inheritdoc}
*
* @see DrawableInterface::position()
*/
public function position(): PointInterface
{
return $this->start;
}
/**
* {@inheritdoc}
*
* @see DrawableInterface::setPosition()
*/
public function setPosition(PointInterface $position): self
{
$this->start = $position;
return $this;
}
/**
* Return line width
*/
public function width(): int
{
return $this->width;
}
/**
* Set line width.
*/
public function setWidth(int $width): self
{
$this->width = $width;
return $this;
}
/**
* Get starting point of line.
*/
public function start(): PointInterface
{
return $this->start;
}
/**
* get end point of line.
*/
public function end(): PointInterface
{
return $this->end;
}
/**
* Set starting point of line.
*/
public function setStart(PointInterface $start): self
{
$this->start = $start;
return $this;
}
/**
* Set starting point of line by coordinates.
*/
public function from(int $x, int $y): self
{
$this->start()->setX($x);
$this->start()->setY($y);
return $this;
}
/**
* Set end point of line by coordinates.
*/
public function to(int $x, int $y): self
{
$this->end()->setX($x);
$this->end()->setY($y);
return $this;
}
/**
* Set end point of line.
*/
public function setEnd(PointInterface $end): self
{
$this->end = $end;
return $this;
}
/**
* {@inheritdoc}
*
* @see DrawableInterface::factory()
*/
public function factory(): DrawableFactoryInterface
{
return new LineFactory($this);
}
/**
* {@inheritdoc}
*
* @see DrawableInterface::adjust()
*/
public function adjust(callable $adjustments): DrawableInterface
{
$factory = $this->factory();
$adjustments($factory);
return $factory->drawable();
}
/**
* Clone line.
*/
public function __clone(): void
{
$this->start = clone $this->start;
$this->end = clone $this->end;
if ($this->backgroundColor instanceof AbstractColor) {
$this->backgroundColor = clone $this->backgroundColor;
}
if ($this->borderColor instanceof AbstractColor) {
$this->borderColor = clone $this->borderColor;
}
}
}

View File

@@ -0,0 +1,43 @@
<?php
declare(strict_types=1);
namespace Intervention\Image\Geometry;
use Intervention\Image\Interfaces\ColorInterface;
class Pixel extends Point
{
/**
* Create new pixel instance.
*/
public function __construct(
protected ColorInterface $background,
protected int $x,
protected int $y
) {
parent::__construct($x, $y);
}
/**
* {@inheritdoc}
*
* @see DrawableInterface::setBackgroundColor()
*/
public function setBackgroundColor(ColorInterface $background): self
{
$this->background = $background;
return $this;
}
/**
* {@inheritdoc}
*
* @see DrawableInterface::backgroundColor()
*/
public function backgroundColor(): ColorInterface
{
return $this->background;
}
}

View File

@@ -0,0 +1,143 @@
<?php
declare(strict_types=1);
namespace Intervention\Image\Geometry;
use ArrayIterator;
use Intervention\Image\Interfaces\PointInterface;
use IteratorAggregate;
use Traversable;
/**
* @implements IteratorAggregate<int>
*/
class Point implements PointInterface, IteratorAggregate
{
/**
* Create new point instance.
*/
public function __construct(
protected int $x = 0,
protected int $y = 0
) {
//
}
/**
* {@inheritdoc}
*
* @see IteratorAggregate::getIterator()
*/
public function getIterator(): Traversable
{
return new ArrayIterator([$this->x, $this->y]);
}
/**
* {@inheritdoc}
*
* @see PointInterface::setX()
*/
public function setX(int $x): self
{
$this->x = $x;
return $this;
}
/**
* {@inheritdoc}
*
* @see PointInterface::x()
*/
public function x(): int
{
return $this->x;
}
/**
* {@inheritdoc}
*
* @see PointInterface::setY()
*/
public function setY(int $y): self
{
$this->y = $y;
return $this;
}
/**
* {@inheritdoc}
*
* @see PointInterface::y()
*/
public function y(): int
{
return $this->y;
}
/**
* {@inheritdoc}
*
* @see PointInterface::moveX()
*/
public function moveX(int $value): self
{
$this->x += $value;
return $this;
}
/**
* {@inheritdoc}
*
* @see PointInterface::moveY()
*/
public function moveY(int $value): self
{
$this->y += $value;
return $this;
}
/**
* {@inheritdoc}
*
* @see PointInterface::move()
*/
public function move(int $x, int $y): self
{
return $this->moveX($x)->moveY($y);
}
/**
* {@inheritdoc}
*
* @see PointInterface::setPosition()
*/
public function setPosition(int $x, int $y): self
{
$this->setX($x);
$this->setY($y);
return $this;
}
/**
* {@inheritdoc}
*
* @see PointInterface::rotate()
*/
public function rotate(float $angle, PointInterface $pivot): self
{
$sin = round(sin(deg2rad($angle)), 6);
$cos = round(cos(deg2rad($angle)), 6);
return $this->setPosition(
intval($cos * ($this->x() - $pivot->x()) - $sin * ($this->y() - $pivot->y()) + $pivot->x()),
intval($sin * ($this->x() - $pivot->x()) + $cos * ($this->y() - $pivot->y()) + $pivot->y())
);
}
}

View File

@@ -0,0 +1,441 @@
<?php
declare(strict_types=1);
namespace Intervention\Image\Geometry;
use ArrayAccess;
use ArrayIterator;
use Countable;
use Intervention\Image\Alignment;
use Intervention\Image\Colors\AbstractColor;
use Intervention\Image\Exceptions\InvalidArgumentException;
use Intervention\Image\Geometry\Factories\PolygonFactory;
use Traversable;
use IteratorAggregate;
use Intervention\Image\Geometry\Traits\HasBackgroundColor;
use Intervention\Image\Geometry\Traits\HasBorder;
use Intervention\Image\Interfaces\DrawableFactoryInterface;
use Intervention\Image\Interfaces\DrawableInterface;
use Intervention\Image\Interfaces\PointInterface;
use Intervention\Image\Interfaces\SizeInterface;
/**
* @implements IteratorAggregate<PointInterface>
* @implements ArrayAccess<int, PointInterface>
*/
class Polygon implements IteratorAggregate, Countable, ArrayAccess, DrawableInterface
{
use HasBorder;
use HasBackgroundColor;
/**
* Create new polygon instance.
*
* @param array<PointInterface> $points
*/
public function __construct(
protected array $points = [],
protected PointInterface $pivot = new Point()
) {
//
}
/**
* Create polygon from given size.
*/
public static function fromSize(SizeInterface $size): self
{
return new self(
[
new Point(0, 0),
new Point($size->width(), 0),
new Point($size->width(), $size->height() * -1),
new Point(0, $size->height() * -1),
],
$size->pivot()
);
}
/**
* {@inheritdoc}
*
* @see DrawableInterface::position()
*/
public function position(): PointInterface
{
return $this->pivot;
}
/**
* {@inheritdoc}
*
* @see DrawableInterface::setPosition()
*/
public function setPosition(PointInterface $position): self
{
$this->pivot = $position;
return $this;
}
/**
* Implement iteration through all points of polygon.
*
* @return Traversable<mixed>
*/
public function getIterator(): Traversable
{
return new ArrayIterator($this->points);
}
/**
* Return current pivot point.
*/
public function pivot(): PointInterface
{
return $this->pivot;
}
/**
* Change pivot point to given point.
*/
public function setPivot(PointInterface $pivot): self
{
$this->pivot = $pivot;
return $this;
}
/**
* Return first point of polygon.
*/
public function first(): ?PointInterface
{
if ($point = reset($this->points)) {
return $point;
}
return null;
}
/**
* Return last point of polygon.
*/
public function last(): ?PointInterface
{
if ($point = end($this->points)) {
return $point;
}
return null;
}
/**
* Return polygon's point count.
*/
public function count(): int
{
return count($this->points);
}
/**
* Determine if point exists at given offset.
*/
public function offsetExists(mixed $offset): bool
{
return array_key_exists($offset, $this->points);
}
/**
* Return point at given offset.
*/
public function offsetGet(mixed $offset): mixed
{
return $this->points[$offset];
}
/**
* Set point at given offset
*/
public function offsetSet(mixed $offset, mixed $value): void
{
$this->points[$offset] = $value;
}
/**
* Unset offset at given offset.
*/
public function offsetUnset(mixed $offset): void
{
unset($this->points[$offset]);
}
/**
* Add given point to polygon.
*/
public function addPoint(PointInterface $point): self
{
$this->points[] = $point;
return $this;
}
/**
* Calculate total horizontal span of polygon.
*/
public function width(): int
{
return abs($this->mostLeftPoint()->x() - $this->mostRightPoint()->x());
}
/**
* Calculate total vertical span of polygon.
*/
public function height(): int
{
return abs($this->mostBottomPoint()->y() - $this->mostTopPoint()->y());
}
/**
* Return most left point of all points in polygon.
*/
public function mostLeftPoint(): PointInterface
{
$points = $this->points;
usort($points, function (PointInterface $a, PointInterface $b): int {
if ($a->x() === $b->x()) {
return 0;
}
return $a->x() < $b->x() ? -1 : 1;
});
return $points[0];
}
/**
* Return most right point in polygon.
*/
public function mostRightPoint(): PointInterface
{
$points = $this->points;
usort($points, function (PointInterface $a, PointInterface $b): int {
if ($a->x() === $b->x()) {
return 0;
}
return $a->x() > $b->x() ? -1 : 1;
});
return $points[0];
}
/**
* Return most top point in polygon.
*/
public function mostTopPoint(): PointInterface
{
$points = $this->points;
usort($points, function (PointInterface $a, PointInterface $b): int {
if ($a->y() === $b->y()) {
return 0;
}
return $a->y() > $b->y() ? -1 : 1;
});
return $points[0];
}
/**
* Return most bottom point in polygon.
*/
public function mostBottomPoint(): PointInterface
{
$points = $this->points;
usort($points, function (PointInterface $a, PointInterface $b): int {
if ($a->y() === $b->y()) {
return 0;
}
return $a->y() < $b->y() ? -1 : 1;
});
return $points[0];
}
/**
* Return point in absolute center of the polygon.
*/
public function centerPoint(): PointInterface
{
return new Point(
$this->mostRightPoint()->x() - (intval(round($this->width() / 2))),
$this->mostTopPoint()->y() - (intval(round($this->height() / 2)))
);
}
/**
* Align all points of the polygon horizontally to given position around pivot point.
*
* @throws InvalidArgumentException
*/
public function alignHorizontally(string|Alignment $position): self
{
$diff = match (Alignment::create($position)) {
Alignment::CENTER => $this->centerPoint()->x() - $this->pivot()->x(),
Alignment::RIGHT,
Alignment::TOP_RIGHT,
Alignment::BOTTOM_RIGHT => $this->mostRightPoint()->x() - $this->pivot()->x(),
Alignment::LEFT,
Alignment::TOP_LEFT,
Alignment::BOTTOM_LEFT => $this->mostLeftPoint()->x() - $this->pivot()->x(),
default => 0,
};
foreach ($this->points as $point) {
$point->setX(intval($point->x() - $diff));
}
return $this;
}
/**
* Align all points of the polygon vertically to given position around pivot point.
*
* @throws InvalidArgumentException
*/
public function alignVertically(string|Alignment $position): self
{
$diff = match (Alignment::create($position)) {
Alignment::CENTER => $this->centerPoint()->y() - $this->pivot()->y(),
Alignment::TOP,
Alignment::TOP_RIGHT,
Alignment::TOP_LEFT => $this->mostTopPoint()->y() - $this->pivot()->y() - $this->height(),
Alignment::BOTTOM,
Alignment::BOTTOM_LEFT,
Alignment::BOTTOM_RIGHT => $this->mostBottomPoint()->y() - $this->pivot()->y() + $this->height(),
default => 0,
};
foreach ($this->points as $point) {
$point->setY(intval($point->y() - $diff));
}
return $this;
}
/**
* Rotate points of polygon clockwise around pivot point with given angle.
*/
public function rotate(float $angle): self
{
$sin = sin(deg2rad($angle));
$cos = cos(deg2rad($angle));
foreach ($this->points as $point) {
// translate point to pivot
$point->setX(
intval($point->x() - $this->pivot()->x()),
);
$point->setY(
intval($point->y() - $this->pivot()->y()),
);
// rotate point
$x = $point->x() * $cos - $point->y() * $sin;
$y = $point->x() * $sin + $point->y() * $cos;
// translate point back
$point->setX(
intval($x + $this->pivot()->x()),
);
$point->setY(
intval($y + $this->pivot()->y()),
);
}
return $this;
}
/**
* Move all points by given distance on the x-axis.
*/
public function movePointsX(int $distance): self
{
foreach ($this->points as $point) {
$point->moveX($distance);
}
return $this;
}
/**
* Move all points by given distance on the y-axis.
*/
public function movePointsY(int $distance): self
{
foreach ($this->points as $point) {
$point->moveY($distance);
}
return $this;
}
/**
* Return array of all x/y values of all points of polygon
*
* @return array<int>
*/
public function toArray(): array
{
$coordinates = [];
foreach ($this->points as $point) {
$coordinates[] = $point->x();
$coordinates[] = $point->y();
}
return $coordinates;
}
/**
* {@inheritdoc}
*
* @see DrawableInterface::factory()
*/
public function factory(): DrawableFactoryInterface
{
return new PolygonFactory($this);
}
/**
* {@inheritdoc}
*
* @see DrawableInterface::adjust()
*/
public function adjust(callable $adjustments): DrawableInterface
{
$factory = $this->factory();
$adjustments($factory);
return $factory->drawable();
}
/**
* Clone polygon.
*/
public function __clone(): void
{
$this->points = array_map(fn($point) => clone $point, $this->points);
$this->pivot = clone $this->pivot;
if ($this->backgroundColor instanceof AbstractColor) {
$this->backgroundColor = clone $this->backgroundColor;
}
if ($this->borderColor instanceof AbstractColor) {
$this->borderColor = clone $this->borderColor;
}
}
}

View File

@@ -0,0 +1,503 @@
<?php
declare(strict_types=1);
namespace Intervention\Image\Geometry;
use ArrayIterator;
use DivisionByZeroError;
use Intervention\Image\Alignment;
use Intervention\Image\Exceptions\InvalidArgumentException;
use Intervention\Image\Exceptions\RuntimeException;
use Intervention\Image\Exceptions\StateException;
use Intervention\Image\Geometry\Factories\RectangleFactory;
use Intervention\Image\Geometry\Tools\Resizer;
use Intervention\Image\Interfaces\DrawableFactoryInterface;
use Intervention\Image\Interfaces\DrawableInterface;
use Intervention\Image\Interfaces\PointInterface;
use Intervention\Image\Interfaces\SizeInterface;
use Traversable;
class Rectangle extends Polygon implements DrawableInterface, SizeInterface
{
/**
* Create new rectangle.
*
* @throws InvalidArgumentException
*/
public function __construct(
int $width,
int $height,
protected PointInterface $pivot = new Point()
) {
if ($width < 0) {
throw new InvalidArgumentException(
'Width of ' . $this::class . ' must be greater than or equal to 0'
);
}
if ($height < 0) {
throw new InvalidArgumentException(
'Height of ' . $this::class . ' must be greater than or equal to 0'
);
}
parent::__construct([
new Point(0, 0),
new Point($width, 0),
new Point($width, $height * -1),
new Point(0, $height * -1),
], $pivot);
}
/**
* Create rectangle statically.
*
* @deprecated Use Intervention\Image\Size::class instead.
*
* @throws InvalidArgumentException
*/
public static function create(int $width, int $height, PointInterface $pivot = new Point()): self
{
return new self($width, $height, $pivot);
}
/**
* Calculate width of rectangle.
*/
public function width(): int
{
return abs($this->mostLeftPoint()->x() - $this->mostRightPoint()->x());
}
/**
* Calculate height of rectangle.
*/
public function height(): int
{
return abs($this->mostBottomPoint()->y() - $this->mostTopPoint()->y());
}
/**
* {@inheritdoc}
*
* @see SizeInterface::setWidth()
*/
public function setWidth(int $width): self
{
$this[1]->setX($this[0]->x() + $width);
$this[2]->setX($this[3]->x() + $width);
return $this;
}
/**
* {@inheritdoc}
*
* @see SizeInterface::setHeight()
*/
public function setHeight(int $height): self
{
$this[2]->setY($this[1]->y() + $height);
$this[3]->setY($this[0]->y() + $height);
return $this;
}
/**
* {@inheritdoc}
*
* @see DrawableInterface::setPosition()
*/
public function setPosition(PointInterface $position): self
{
$this->pivot = $position;
return $this;
}
/**
* {@inheritdoc}
*
* @see DrawableInterface::position()
*/
public function position(): PointInterface
{
return $this->pivot;
}
/**
* {@inheritdoc}
*
* @see DrawableInterface::factory()
*
* @throws RuntimeException
*/
public function factory(): DrawableFactoryInterface
{
// @phpstan-ignore missingType.checkedException
return new RectangleFactory($this);
}
/**
* {@inheritdoc}
*
* @see DrawableInterface::adjust()
*
* @throws RuntimeException
*/
public function adjust(callable $adjustments): DrawableInterface
{
$factory = $this->factory();
$adjustments($factory);
return $factory->drawable();
}
/**
* Set size of rectangle.
*
* @deprecated Use Intervention\Image\Size::class instead.
*/
public function setSize(int $width, int $height): self
{
return $this->setWidth($width)->setHeight($height);
}
/**
* {@inheritdoc}
*
* @deprecated Use Intervention\Image\Size::class instead.
* @see SizeInterface::aspectRatio()
*
* @throws RuntimeException
*/
public function aspectRatio(): float
{
try {
return $this->width() / $this->height();
} catch (DivisionByZeroError) {
throw new RuntimeException('Division by zero');
}
}
/**
* {@inheritdoc}
*
* @deprecated Use Intervention\Image\Size::class instead.
* @see SizeInterface::fitsWithin()
*/
public function fitsWithin(SizeInterface $size): bool
{
if ($this->width() > $size->width()) {
return false;
}
if ($this->height() > $size->height()) {
return false;
}
return true;
}
/**
* {@inheritdoc}
*
* @deprecated Use Intervention\Image\Size::class instead.
* @see SizeInterface::isLandscape()
*/
public function isLandscape(): bool
{
return $this->width() > $this->height();
}
/**
* {@inheritdoc}
*
* @deprecated Use Intervention\Image\Size::class instead.
* @see SizeInterface::isPortrait()
*/
public function isPortrait(): bool
{
return $this->width() < $this->height();
}
/**
* {@inheritdoc}
*
* @deprecated Use Intervention\Image\Size::class instead.
* @see SizeInterface::setPivot()
*/
public function setPivot(PointInterface $pivot): self
{
$this->pivot = $pivot;
return $this;
}
/**
* {@inheritdoc}
*
* @deprecated Use Intervention\Image\Size::class instead.
* @see SizeInterface::movePivot()
*
* @throws InvalidArgumentException
*/
public function movePivot(string|Alignment $alignment, int $x = 0, int $y = 0): self
{
$alignment = Alignment::create($alignment); // normalize alignment
$point = match ($alignment) {
Alignment::TOP => new Point(
intval(round($this->width() / 2)) + $x,
$y,
),
Alignment::TOP_RIGHT => new Point(
$this->width() - $x,
$y,
),
Alignment::LEFT => new Point(
$x,
intval(round($this->height() / 2)) + $y,
),
Alignment::RIGHT => new Point(
$this->width() - $x,
intval(round($this->height() / 2)) + $y,
),
Alignment::BOTTOM_LEFT => new Point(
$x,
$this->height() - $y,
),
Alignment::BOTTOM => new Point(
intval(round($this->width() / 2)) + $x,
$this->height() - $y,
),
Alignment::BOTTOM_RIGHT => new Point(
$this->width() - $x,
$this->height() - $y,
),
Alignment::CENTER => new Point(
intval(round($this->width() / 2)) + $x,
intval(round($this->height() / 2)) + $y,
),
Alignment::TOP_LEFT => new Point(
$x,
$y,
),
};
$this->pivot->setPosition(...$point);
return $this;
}
/**
* {@inheritdoc}
*
* @deprecated Use Intervention\Image\Size::class instead.
* @see SizeInterface::alignPivotTo()
*
* @throws InvalidArgumentException
*/
public function alignPivotTo(SizeInterface $size, string|Alignment $alignment): self
{
$reference = new self($size->width(), $size->height());
$reference->movePivot($alignment);
$this->movePivot($alignment)->setPivot(
$reference->offsetTo($this)
);
return $this;
}
/**
* {@inheritdoc}
*
* @deprecated Use Intervention\Image\Size::class instead.
* @see SizeInterface::offsetTo()
*/
public function offsetTo(SizeInterface $rectangle): PointInterface
{
return new Point(
$this->pivot()->x() - $rectangle->pivot()->x(),
$this->pivot()->y() - $rectangle->pivot()->y()
);
}
/**
* {@inheritdoc}
*
* @deprecated Use Intervention\Image\Size::class instead.
* @see SizeInterface::resize()
*
* @throws InvalidArgumentException
*/
public function resize(?int $width = null, ?int $height = null): SizeInterface
{
try {
return $this->resizer($width, $height)->resize($this);
} catch (InvalidArgumentException $e) {
throw new InvalidArgumentException(
'Invalid target size ' . $width . 'x' . $height,
previous: $e,
);
}
}
/**
* {@inheritdoc}
*
* @deprecated Use Intervention\Image\Size::class instead.
* @see SizeInterface::resizeDown()
*
* @throws InvalidArgumentException
*/
public function resizeDown(?int $width = null, ?int $height = null): SizeInterface
{
try {
return $this->resizer($width, $height)->resizeDown($this);
} catch (InvalidArgumentException $e) {
throw new InvalidArgumentException(
'Invalid target size ' . $width . 'x' . $height,
previous: $e,
);
}
}
/**
* {@inheritdoc}
*
* @deprecated Use Intervention\Image\Size::class instead.
* @see SizeInterface::scale()
*
* @throws InvalidArgumentException
*/
public function scale(?int $width = null, ?int $height = null): SizeInterface
{
try {
return $this->resizer($width, $height)->scale($this);
} catch (InvalidArgumentException $e) {
throw new InvalidArgumentException(
'Invalid target size ' . $width . 'x' . $height,
previous: $e,
);
}
}
/**
* {@inheritdoc}
*
* @deprecated Use Intervention\Image\Size::class instead.
* @see SizeInterface::scaleDown()
*
* @throws InvalidArgumentException
*/
public function scaleDown(?int $width = null, ?int $height = null): SizeInterface
{
try {
return $this->resizer($width, $height)->scaleDown($this);
} catch (InvalidArgumentException $e) {
throw new InvalidArgumentException(
'Invalid target size ' . $width . 'x' . $height,
previous: $e,
);
}
}
/**
* {@inheritdoc}
*
* @deprecated Use Intervention\Image\Size::class instead.
* @see SizeInterface::cover()
*
* @throws InvalidArgumentException
*/
public function cover(int $width, int $height): SizeInterface
{
try {
return $this->resizer($width, $height)->cover($this);
} catch (InvalidArgumentException | StateException $e) {
throw new InvalidArgumentException(
'Invalid target size ' . $width . 'x' . $height,
previous: $e,
);
}
}
/**
* {@inheritdoc}
*
* @deprecated Use Intervention\Image\Size::class instead.
* @see SizeInterface::contain()
*
* @throws InvalidArgumentException
*/
public function contain(int $width, int $height): SizeInterface
{
try {
return $this->resizer($width, $height)->contain($this);
} catch (StateException $e) {
throw new InvalidArgumentException(
'Invalid target size ' . $width . 'x' . $height,
previous: $e,
);
}
}
/**
* {@inheritdoc}
*
* @deprecated Use Intervention\Image\Size::class instead.
* @see SizeInterface::containDown()
*
* @throws InvalidArgumentException
*/
public function containDown(int $width, int $height): SizeInterface
{
try {
return $this->resizer($width, $height)->containDown($this);
} catch (StateException $e) {
throw new InvalidArgumentException(
'Invalid target size ' . $width . 'x' . $height,
previous: $e,
);
}
}
/**
* Create resizer instance with given target size.
*
* @deprecated Use Intervention\Image\Size::class instead.
*
* @throws InvalidArgumentException
*/
protected function resizer(?int $width = null, ?int $height = null): Resizer
{
return new Resizer($width, $height);
}
/**
* Implement iteration.
*
* @return Traversable<mixed>
*/
public function getIterator(): Traversable
{
return new ArrayIterator([$this->width(), $this->height()]);
}
/**
* Show debug info for the current rectangle.
*
* @return array<string, int|object>
*/
public function __debugInfo(): array
{
return [
'width' => $this->width(),
'height' => $this->height(),
'pivot' => $this->pivot,
];
}
}

View File

@@ -0,0 +1,363 @@
<?php
declare(strict_types=1);
namespace Intervention\Image\Geometry\Tools;
use Intervention\Image\Alignment;
use Intervention\Image\Exceptions\InvalidArgumentException;
use Intervention\Image\Exceptions\StateException;
use Intervention\Image\Interfaces\SizeInterface;
use Intervention\Image\Size;
class Resizer
{
/**
* @throws InvalidArgumentException
*/
public function __construct(
protected ?int $width = null,
protected ?int $height = null,
) {
if (is_int($width) && $width < 1) {
throw new InvalidArgumentException(
'Width must be greater than or equal to 1'
);
}
if (is_int($height) && $height < 1) {
throw new InvalidArgumentException(
'Height must be greater than or equal to 1'
);
}
}
/**
* Static factory method to create resizer with given target size.
*
* @throws InvalidArgumentException
*/
public static function to(?int $width = null, ?int $height = null): self
{
return new self($width, $height);
}
/**
* Determine if resize has target width.
*/
protected function hasTargetWidth(): bool
{
return is_int($this->width);
}
/**
* Return target width of resizer if available.
*/
protected function targetWidth(): ?int
{
return $this->hasTargetWidth() ? $this->width : null;
}
/**
* Determine if resize has target height.
*/
protected function hasTargetHeight(): bool
{
return is_int($this->height);
}
/**
* Return target width of resizer if available.
*/
protected function targetHeight(): ?int
{
return $this->hasTargetHeight() ? $this->height : null;
}
/**
* Return target size object.
*
* @throws StateException
*/
protected function targetSize(): SizeInterface
{
if (!$this->hasTargetWidth() || !$this->hasTargetHeight()) {
throw new StateException('Target size needs width and height');
}
try {
return new Size($this->width, $this->height);
} catch (InvalidArgumentException $e) {
throw new StateException('Invalid target size', previous: $e);
}
}
/**
* Set target width of resizer.
*/
public function toWidth(int $width): self
{
$this->width = $width;
return $this;
}
/**
* Set target height of resizer.
*/
public function toHeight(int $height): self
{
$this->height = $height;
return $this;
}
/**
* Set target size to given size object.
*/
public function toSize(SizeInterface $size): self
{
$this->width = $size->width();
$this->height = $size->height();
return $this;
}
/**
* Get proportinal width.
*/
protected function proportionalWidth(SizeInterface $size): int
{
if (!$this->hasTargetHeight()) {
return $size->width();
}
return max([1, (int) round($this->height * $size->aspectRatio())]);
}
/**
* Get proportinal height.
*/
protected function proportionalHeight(SizeInterface $size): int
{
if (!$this->hasTargetWidth()) {
return $size->height();
}
return max([1, (int) round($this->width / $size->aspectRatio())]);
}
/**
* Resize given size to target size of the resizer.
*
* @throws InvalidArgumentException
*/
public function resize(SizeInterface $size): SizeInterface
{
$resized = new Size($size->width(), $size->height());
$width = $this->targetWidth();
$height = $this->targetHeight();
if ($width !== null) {
$resized->setWidth($width);
}
if ($height !== null) {
$resized->setHeight($height);
}
return $resized;
}
/**
* Resize given size to target size of the resizer but do not exceed original size.
*
* @throws InvalidArgumentException
*/
public function resizeDown(SizeInterface $size): SizeInterface
{
$resized = new Size($size->width(), $size->height());
$width = $this->targetWidth();
$height = $this->targetHeight();
if ($width !== null) {
$resized->setWidth(
min($width, $size->width())
);
}
if ($height !== null) {
$resized->setHeight(
min($height, $size->height())
);
}
return $resized;
}
/**
* Resize given size to target size proportinally.
*
* @throws InvalidArgumentException
*/
public function scale(SizeInterface $size): SizeInterface
{
$resized = new Size($size->width(), $size->height());
if ($this->hasTargetWidth() && $this->hasTargetHeight()) {
$resized->setWidth(min(
$this->proportionalWidth($size),
$this->targetWidth()
));
$resized->setHeight(min(
$this->proportionalHeight($size),
$this->targetHeight()
));
} elseif ($this->hasTargetWidth()) {
$resized->setWidth($this->targetWidth());
$resized->setHeight($this->proportionalHeight($size));
} elseif ($this->hasTargetHeight()) {
$resized->setWidth($this->proportionalWidth($size));
$resized->setHeight($this->targetHeight());
}
return $resized;
}
/**
* Resize given size to target size proportinally but do not exceed original size.
*
* @throws InvalidArgumentException
*/
public function scaleDown(SizeInterface $size): SizeInterface
{
$resized = new Size($size->width(), $size->height());
if ($this->hasTargetWidth() && $this->hasTargetHeight()) {
$resized->setWidth(min(
$this->proportionalWidth($size),
$this->targetWidth(),
$size->width()
));
$resized->setHeight(min(
$this->proportionalHeight($size),
$this->targetHeight(),
$size->height()
));
} elseif ($this->hasTargetWidth()) {
$resized->setWidth(min(
$this->targetWidth(),
$size->width()
));
$resized->setHeight(min(
$this->proportionalHeight($size),
$size->height()
));
} elseif ($this->hasTargetHeight()) {
$resized->setWidth(min(
$this->proportionalWidth($size),
$size->width()
));
$resized->setHeight(min(
$this->targetHeight(),
$size->height()
));
}
return $resized;
}
/**
* Scale given size to cover target size.
*
* @param SizeInterface $size Size to be resized
* @throws InvalidArgumentException
* @throws StateException
*/
public function cover(SizeInterface $size): SizeInterface
{
$resized = new Size($size->width(), $size->height());
// auto height
$resized->setWidth($this->targetWidth());
$resized->setHeight($this->proportionalHeight($size));
if ($resized->fitsWithin($this->targetSize())) {
// auto width
$resized->setWidth($this->proportionalWidth($size));
$resized->setHeight($this->targetHeight());
}
return $resized;
}
/**
* Scale the given size up or down so that the result can fit into the target size.
*
* @param SizeInterface $size Size to be resized
* @throws InvalidArgumentException
* @throws StateException
*/
public function contain(SizeInterface $size): SizeInterface
{
$resized = new Size($size->width(), $size->height());
// auto height
$resized->setWidth($this->targetWidth());
$resized->setHeight($this->proportionalHeight($size));
if (!$resized->fitsWithin($this->targetSize())) {
// auto width
$resized->setWidth($this->proportionalWidth($size));
$resized->setHeight($this->targetHeight());
}
return $resized;
}
/**
* Scale the given size down so that the result can fit into the target size.
*
* @param SizeInterface $size Size to be resized
* @throws InvalidArgumentException
* @throws StateException
*/
public function containDown(SizeInterface $size): SizeInterface
{
$resized = new Size($size->width(), $size->height());
// auto height
$resized->setWidth(
min($size->width(), $this->targetWidth())
);
$resized->setHeight(
min($size->height(), $this->proportionalHeight($size))
);
if (!$resized->fitsWithin($this->targetSize())) {
// auto width
$resized->setWidth(
min($size->width(), $this->proportionalWidth($size))
);
$resized->setHeight(
min($size->height(), $this->targetHeight())
);
}
return $resized;
}
/**
* Crop target size out of given size at given alignment position (i.e. move the pivot point).
*
* @throws InvalidArgumentException
*/
public function crop(SizeInterface $size, string|Alignment $alignment = Alignment::TOP_LEFT): SizeInterface
{
return $this->resize($size)->alignPivotTo(
$size->movePivot($alignment),
$alignment
);
}
}

View File

@@ -0,0 +1,44 @@
<?php
declare(strict_types=1);
namespace Intervention\Image\Geometry\Traits;
use Intervention\Image\Interfaces\ColorInterface;
trait HasBackgroundColor
{
protected null|string|ColorInterface $backgroundColor = null;
/**
* {@inheritdoc}
*
* @see DrawableInterface::setBackgroundColor()
*/
public function setBackgroundColor(string|ColorInterface $color): self
{
$this->backgroundColor = $color;
return $this;
}
/**
* {@inheritdoc}
*
* @see DrawableInterface::backgroundColor()
*/
public function backgroundColor(): null|string|ColorInterface
{
return $this->backgroundColor;
}
/**
* {@inheritdoc}
*
* @see DrawableInterface::hasBackgroundColor()
*/
public function hasBackgroundColor(): bool
{
return $this->backgroundColor !== null;
}
}

View File

@@ -0,0 +1,88 @@
<?php
declare(strict_types=1);
namespace Intervention\Image\Geometry\Traits;
use Intervention\Image\Exceptions\InvalidArgumentException;
use Intervention\Image\Interfaces\ColorInterface;
trait HasBorder
{
protected null|string|ColorInterface $borderColor = null;
protected int $borderSize = 0;
/**
* {@inheritdoc}
*
* @see DrawableInterface::setBorder()
*
* @throws InvalidArgumentException
*/
public function setBorder(string|ColorInterface $color, int $size = 1): self
{
return $this->setBorderSize($size)->setBorderColor($color);
}
/**
* {@inheritdoc}
*
* @see DrawableInterface::setBorderSize()
*
* @throws InvalidArgumentException
*/
public function setBorderSize(int $size): self
{
if ($size < 0) {
throw new InvalidArgumentException(
'Border size must be greater than or equal to 0'
);
}
$this->borderSize = $size;
return $this;
}
/**
* {@inheritdoc}
*
* @see DrawableInterface::borderSize()
*/
public function borderSize(): int
{
return $this->borderSize;
}
/**
* {@inheritdoc}
*
* @see DrawableInterface::setBorderColor()
*/
public function setBorderColor(string|ColorInterface $color): self
{
$this->borderColor = $color;
return $this;
}
/**
* {@inheritdoc}
*
* @see DrawableInterface::borderColor()
*/
public function borderColor(): null|string|ColorInterface
{
return $this->borderColor;
}
/**
* {@inheritdoc}
*
* @see DrawableInterface::hasBorder()
*/
public function hasBorder(): bool
{
return $this->borderSize > 0 && !is_null($this->borderColor);
}
}