From 7abf23edbb93d023681ca535f595fca81f0c1f53 Mon Sep 17 00:00:00 2001 From: Oliver Vogel Date: Thu, 23 Jun 2022 12:04:04 +0200 Subject: [PATCH] Implement FontWriter Modifier --- src/Drivers/Gd/Font.php | 22 +- src/Drivers/Gd/Modifiers/TextWriter.php | 35 +- src/Drivers/Imagick/Font.php | 18 +- src/Drivers/Imagick/Modifiers/TextWriter.php | 10 +- src/Geometry/Point.php | 13 +- src/Geometry/Polygon.php | 455 +++++++++++++++++++ src/Geometry/Size.php | 24 + src/Interfaces/FontInterface.php | 4 +- tests/Geometry/PolygonTest.php | 397 ++++++++++++++++ tests/Geometry/SizeTest.php | 18 +- 10 files changed, 942 insertions(+), 54 deletions(-) create mode 100644 src/Geometry/Polygon.php create mode 100644 tests/Geometry/PolygonTest.php diff --git a/src/Drivers/Gd/Font.php b/src/Drivers/Gd/Font.php index 90a15b0c..3ac9c1c7 100644 --- a/src/Drivers/Gd/Font.php +++ b/src/Drivers/Gd/Font.php @@ -3,6 +3,8 @@ namespace Intervention\Image\Drivers\Gd; use Intervention\Image\Drivers\Abstract\AbstractFont; +use Intervention\Image\Geometry\Point; +use Intervention\Image\Geometry\Polygon; use Intervention\Image\Geometry\Size; class Font extends AbstractFont @@ -15,9 +17,9 @@ class Font extends AbstractFont /** * Calculate size of bounding box of current text * - * @return Size + * @return Polygon */ - public function getBoxSize(): Size + public function getBoxSize(): Polygon { if (!$this->hasFilename()) { // calculate box size from gd font @@ -27,18 +29,26 @@ class Font extends AbstractFont $box->setWidth($chars * $this->getGdFontWidth()); $box->setHeight($this->getGdFontHeight()); } - return $box; + return $box->toPolygon(); } - // calculate box size from font file + // calculate box size from font file with angle 0 $box = imageftbbox( $this->getSize(), - $this->getAngle(), + 0, $this->getFilename(), $this->getText() ); - return new Size(abs($box[0] - $box[2]), abs($box[1] - $box[7])); + // build polygon from points + $polygon = new Polygon(); + $polygon->addPoint(new Point($box[6], $box[7])); + $polygon->addPoint(new Point($box[4], $box[5])); + $polygon->addPoint(new Point($box[2], $box[3])); + $polygon->addPoint(new Point($box[0], $box[1])); + + + return $polygon; } public function getGdFont(): int diff --git a/src/Drivers/Gd/Modifiers/TextWriter.php b/src/Drivers/Gd/Modifiers/TextWriter.php index 6c6277c3..3a6b18a6 100644 --- a/src/Drivers/Gd/Modifiers/TextWriter.php +++ b/src/Drivers/Gd/Modifiers/TextWriter.php @@ -19,13 +19,12 @@ class TextWriter implements ModifierInterface public function apply(ImageInterface $image): ImageInterface { $position = $this->getAlignedPosition(); - foreach ($image as $frame) { if ($this->font->hasFilename()) { imagettftext( $frame->getCore(), $this->font->getSize(), - $this->font->getAngle(), + $this->font->getAngle() * (-1), $position->getX(), $position->getY(), $this->font->getColor()->toInt(), @@ -47,34 +46,18 @@ class TextWriter implements ModifierInterface return $image; } - protected function getAlignedPosition(): Point + public function getAlignedPosition(): Point { - $position = $this->position; - $box = $this->font->getBoxSize(); + $poly = $this->font->getBoxSize(); + $poly->setPivotPoint($this->position); - // adjust x pos - switch ($this->font->getAlign()) { - case 'center': - $position->setX($position->getX() - round($box->getWidth() / 2)); - break; + $poly->align($this->font->getAlign()); + $poly->valign($this->font->getValign()); - case 'right': - $position->setX($position->getX() - $box->getWidth()); - break; + if ($this->font->getAngle() != 0) { + $poly->rotate($this->font->getAngle()); } - // adjust y pos - switch ($this->font->getValign()) { - case 'top': - $position->setY($position->getY() + $box->getHeight()); - break; - - case 'middle': - case 'center': - $position->setY($position->getY() + round($box->getHeight() / 2)); - break; - } - - return $position; + return $poly->last(); } } diff --git a/src/Drivers/Imagick/Font.php b/src/Drivers/Imagick/Font.php index df32d284..93f21943 100644 --- a/src/Drivers/Imagick/Font.php +++ b/src/Drivers/Imagick/Font.php @@ -6,6 +6,7 @@ use Imagick; use ImagickDraw; use Intervention\Image\Drivers\Abstract\AbstractFont; use Intervention\Image\Exceptions\FontException; +use Intervention\Image\Geometry\Polygon; use Intervention\Image\Geometry\Size; class Font extends AbstractFont @@ -13,7 +14,7 @@ class Font extends AbstractFont public function toImagickDraw(): ImagickDraw { if (!$this->hasFilename()) { - throw new FontException('No font file.'); + throw new FontException('No font file specified.'); } $draw = new ImagickDraw(); @@ -50,14 +51,13 @@ class Font extends AbstractFont /** * Calculate box size of current font * - * @return Size + * @return Polygon */ - public function getBoxSize(): Size + public function getBoxSize(): Polygon { - $foo = null; // no text - no box size if (mb_strlen($this->getText()) === 0) { - return new Size(0, 0); + return (new Size(0, 0))->toPolygon(); } $dimensions = (new Imagick())->queryFontMetrics( @@ -65,9 +65,9 @@ class Font extends AbstractFont $this->getText() ); - return new Size( - intval(abs($dimensions['textWidth'])), - intval(abs($dimensions['textHeight'])) - ); + return (new Size( + intval(round(abs($dimensions['boundingBox']['x1'] - $dimensions['boundingBox']['x2']))), + intval(round(abs($dimensions['boundingBox']['y1'] - $dimensions['boundingBox']['y2']))), + ))->toPolygon(); } } diff --git a/src/Drivers/Imagick/Modifiers/TextWriter.php b/src/Drivers/Imagick/Modifiers/TextWriter.php index 52c6b7be..4fe1dc2a 100644 --- a/src/Drivers/Imagick/Modifiers/TextWriter.php +++ b/src/Drivers/Imagick/Modifiers/TextWriter.php @@ -18,15 +18,13 @@ class TextWriter implements ModifierInterface public function apply(ImageInterface $image): ImageInterface { - $draw = $this->font->toImagickDraw(); $position = $this->getAlignedPosition(); - foreach ($image as $frame) { $frame->getCore()->annotateImage( - $draw, + $this->font->toImagickDraw(), $position->getX(), $position->getY(), - $this->font->getAngle(), + $this->font->getAngle() * (-1), $this->font->getText() ); } @@ -42,12 +40,12 @@ class TextWriter implements ModifierInterface // adjust y pos switch ($this->font->getValign()) { case 'top': - $position->setY($position->getY() + $box->getHeight()); + $position->setY($position->getY() + $box->height()); break; case 'middle': case 'center': - $position->setY($position->getY() + round($box->getHeight() / 2)); + $position->setY(intval($position->getY() + round($box->height() / 2))); break; } diff --git a/src/Geometry/Point.php b/src/Geometry/Point.php index 44f3c976..a83ba007 100644 --- a/src/Geometry/Point.php +++ b/src/Geometry/Point.php @@ -58,7 +58,7 @@ class Point implements PointInterface /** * Move X coordinate * - * @param integer $x + * @param integer $value */ public function moveX(int $value): self { @@ -70,7 +70,7 @@ class Point implements PointInterface /** * Move Y coordinate * - * @param integer $y + * @param integer $value */ public function moveY(int $value): self { @@ -79,6 +79,11 @@ class Point implements PointInterface return $this; } + public function move(int $x, int $y): self + { + return $this->moveX($x)->moveY($y); + } + /** * Sets both X and Y coordinate * @@ -107,8 +112,8 @@ class Point implements PointInterface $cos = round(cos(deg2rad($angle)), 6); return $this->setPosition( - $cos * ($this->x - $pivot->x) - $sin * ($this->y - $pivot->y) + $pivot->x, - $sin * ($this->x - $pivot->x) + $cos * ($this->y - $pivot->y) + $pivot->y + 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) ); } } diff --git a/src/Geometry/Polygon.php b/src/Geometry/Polygon.php new file mode 100644 index 00000000..f7d1eef3 --- /dev/null +++ b/src/Geometry/Polygon.php @@ -0,0 +1,455 @@ +pivot = $pivot ? $pivot : new Point(); + } + + /** + * Return current pivot point + * + * @return Point + */ + public function getPivotPoint(): Point + { + return $this->pivot; + } + + /** + * Change pivot point to given point + * + * @param Point $pivot + * @return Polygon + */ + public function setPivotPoint(Point $pivot): self + { + $this->pivot = $pivot; + + return $this; + } + + /** + * Return first point of polygon + * + * @return ?Point + */ + public function first(): ?Point + { + if ($point = reset($this->points)) { + return $point; + } + + return null; + } + + /** + * Return last point of polygon + * + * @return ?Point + */ + public function last(): ?Point + { + if ($point = end($this->points)) { + return $point; + } + + return null; + } + + /** + * Return polygon's point count + * + * @return int + */ + public function count(): int + { + return count($this->points); + } + + /** + * Determine if point exists at given offset + * + * @param mixed $offset + * @return bool + */ + public function offsetExists($offset): bool + { + return array_key_exists($offset, $this->points); + } + + /** + * Return point at given offset + * + * @param mixed $offset + * @return Point + */ + public function offsetGet($offset) + { + return $this->points[$offset]; + } + + /** + * Set point at given offset + * + * @param mixed $offset + * @param Point $value + * @return void + */ + public function offsetSet($offset, $value): void + { + $this->points[$offset] = $value; + } + + /** + * Unset offset at given offset + * + * @param mixed $offset + * @return void + */ + public function offsetUnset($offset): void + { + unset($this->points[$offset]); + } + + /** + * Add given point to polygon + * + * @param Point $point + * @return Polygon + */ + public function addPoint(Point $point): self + { + $this->points[] = $point; + + return $this; + } + + /** + * Calculate total horizontal span of polygon + * + * @return int + */ + public function width(): int + { + return abs($this->getMostLeftPoint()->getX() - $this->getMostRightPoint()->getX()); + } + + /** + * Calculate total vertical span of polygon + * + * @return int + */ + public function height(): int + { + return abs($this->getMostBottomPoint()->getY() - $this->getMostTopPoint()->getY()); + } + + /** + * Return most left point of all points in polygon + * + * @return Point + */ + public function getMostLeftPoint(): Point + { + $points = []; + foreach ($this->points as $point) { + $points[] = $point; + } + + usort($points, function ($a, $b) { + if ($a->getX() === $b->getX()) { + return 0; + } + return ($a->getX() < $b->getX()) ? -1 : 1; + }); + + return $points[0]; + } + + /** + * Return most right point in polygon + * + * @return Point + */ + public function getMostRightPoint(): Point + { + $points = []; + foreach ($this->points as $point) { + $points[] = $point; + } + + usort($points, function ($a, $b) { + if ($a->getX() === $b->getX()) { + return 0; + } + return ($a->getX() > $b->getX()) ? -1 : 1; + }); + + return $points[0]; + } + + /** + * Return most top point in polygon + * + * @return Point + */ + public function getMostTopPoint(): Point + { + $points = []; + foreach ($this->points as $point) { + $points[] = $point; + } + + usort($points, function ($a, $b) { + if ($a->getY() === $b->getY()) { + return 0; + } + return ($a->getY() > $b->getY()) ? -1 : 1; + }); + + return $points[0]; + } + + /** + * Return most bottom point in polygon + * + * @return Point + */ + public function getMostBottomPoint(): Point + { + $points = []; + foreach ($this->points as $point) { + $points[] = $point; + } + + usort($points, function ($a, $b) { + if ($a->getY() === $b->getY()) { + return 0; + } + return ($a->getY() < $b->getY()) ? -1 : 1; + }); + + return $points[0]; + } + + /** + * Create and return point in absolute center of the polygon + * + * @return Point + */ + public function getCenterPoint(): Point + { + return new Point( + $this->getMostRightPoint()->getX() - (intval(round($this->width() / 2))), + $this->getMostTopPoint()->getY() - (intval(round($this->height() / 2))) + ); + } + + /** + * Align pivot point to given horizontal position + * + * @param string $position + * @return Polygon + */ + public function alignPivot(string $position): self + { + switch (strtolower($position)) { + case 'center': + $this->pivot->setX( + intval(($this->getMostRightPoint()->getX() + $this->getMostLeftPoint()->getX()) / 2) + ); + break; + + case 'right': + $this->pivot->setX( + $this->getMostRightPoint()->getX() + ); + break; + + case 'left': + $this->pivot->setX( + $this->getMostLeftPoint()->getX() + ); + break; + } + + return $this; + } + + /** + * Align pivot point to given vertical position + * + * @param string $position + * @return Polygon + */ + public function valignPivot(string $position): self + { + switch (strtolower($position)) { + case 'center': + case 'middle': + $this->pivot->setY( + intval(($this->getMostTopPoint()->getY() + $this->getMostBottomPoint()->getY()) / 2) + ); + break; + + case 'top': + $this->pivot->setY( + $this->getMostTopPoint()->getY() + ); + break; + + case 'bottom': + $this->pivot->setY( + $this->getMostBottomPoint()->getY() + ); + break; + } + + return $this; + } + + /** + * Align all points of polygon horizontally to given position around pivot point + * + * @param string $position + * @return Polygon + */ + public function align(string $position): self + { + switch (strtolower($position)) { + case 'center': + case 'middle': + $diff = ($this->getCenterPoint()->getX() - $this->pivot->getX()); + break; + + case 'right': + $diff = ($this->getMostRightPoint()->getX() - $this->pivot->getX()); + break; + + default: + case 'left': + $diff = ($this->getMostLeftPoint()->getX() - $this->pivot->getX()); + break; + } + + foreach ($this->points as $point) { + $point->setX($point->getX() - $diff); + } + + return $this; + } + + /** + * Align all points of polygon vertically to given position around pivot point + * + * @param string $position + * @return Polygon + */ + public function valign(string $position): self + { + switch (strtolower($position)) { + case 'center': + case 'middle': + $diff = ($this->getCenterPoint()->getY() - $this->pivot->getY()); + break; + + case 'top': + $diff = ($this->getMostTopPoint()->getY() - $this->pivot->getY()) - $this->height(); + break; + + default: + case 'bottom': + $diff = ($this->getMostBottomPoint()->getY() - $this->pivot->getY()) + $this->height(); + break; + } + + foreach ($this->points as $point) { + $point->setY($point->getY() - $diff); + } + + return $this; + } + + /** + * Rotate points of polygon around pivot point with given angle + * + * @param float $angle + * @return Polygon + */ + 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($point->getX() - $this->pivot->getX()); + $point->setY($point->getY() - $this->pivot->getY()); + + // rotate point + $x = $point->getX() * $cos - $point->getY() * $sin; + $y = $point->getX() * $sin + $point->getY() * $cos; + + // translate point back + $point->setX($x + $this->pivot->getX()); + $point->setY($y + $this->pivot->getY()); + } + + return $this; + } + + /** + * Move all points by given amount on the x-axis + * + * @param int $amount + * @return Polygon + */ + public function movePointsX(int $amount): self + { + foreach ($this->points as $point) { + $point->moveX($amount); + } + + return $this; + } + + /** + * Move all points by given amount on the y-axis + * + * @param int $amount + * @return Polygon + */ + public function movePointsY(int $amount): self + { + foreach ($this->points as $point) { + $point->moveY($amount); + } + + return $this; + } + + /** + * Return array of all x/y values of all points of polygon + * + * @return array + */ + public function toArray(): array + { + $coordinates = []; + foreach ($this->points as $point) { + $coordinates[] = $point->getX(); + $coordinates[] = $point->getY(); + } + + return $coordinates; + } +} diff --git a/src/Geometry/Size.php b/src/Geometry/Size.php index 04886285..532940b5 100644 --- a/src/Geometry/Size.php +++ b/src/Geometry/Size.php @@ -209,6 +209,30 @@ class Size implements SizeInterface return new Point($x, $y); } + public function toPolygon(): Polygon + { + $polygon = new Polygon([ + $this->pivot // top/left + ], $this->pivot); + + // top/right + $polygon->addPoint( + new Point($this->pivot->getX() + $this->getWidth(), $this->pivot->getY()) + ); + + // bottom/right + $polygon->addPoint( + new Point($this->pivot->getX() + $this->getWidth(), $this->pivot->getY() - $this->getHeight()) + ); + + // bottom/left + $polygon->addPoint( + new Point($this->pivot->getX(), $this->pivot->getY() - $this->getHeight()) + ); + + return $polygon; + } + protected function getResizer(?int $width = null, ?int $height = null): Resizer { return new Resizer($width, $height); diff --git a/src/Interfaces/FontInterface.php b/src/Interfaces/FontInterface.php index 26d42fc7..92e47008 100644 --- a/src/Interfaces/FontInterface.php +++ b/src/Interfaces/FontInterface.php @@ -2,7 +2,7 @@ namespace Intervention\Image\Interfaces; -use Intervention\Image\Geometry\Size; +use Intervention\Image\Geometry\Polygon; use Intervention\Image\Interfaces\ColorInterface; interface FontInterface @@ -19,5 +19,5 @@ interface FontInterface public function hasFilename(): bool; public function align(string $align): self; public function getAlign(): string; - public function getBoxSize(): Size; + public function getBoxSize(): Polygon; } diff --git a/tests/Geometry/PolygonTest.php b/tests/Geometry/PolygonTest.php new file mode 100644 index 00000000..3ed904de --- /dev/null +++ b/tests/Geometry/PolygonTest.php @@ -0,0 +1,397 @@ +assertInstanceOf(Polygon::class, $poly); + $this->assertEquals(0, $poly->count()); + } + + public function testCount(): void + { + $poly = new Polygon([new Point(), new Point()]); + $this->assertEquals(2, $poly->count()); + } + + public function testArrayAccess(): void + { + $poly = new Polygon([new Point(), new Point()]); + $this->assertInstanceOf(Point::class, $poly[0]); + $this->assertInstanceOf(Point::class, $poly[1]); + } + + public function testAddPoint(): void + { + $poly = new Polygon([new Point(), new Point()]); + $this->assertEquals(2, $poly->count()); + $result = $poly->addPoint(new Point()); + $this->assertEquals(3, $poly->count()); + $this->assertInstanceOf(Polygon::class, $result); + } + + public function testGetCenterPoint(): void + { + $poly = new Polygon([ + new Point(0, 0), + new Point(20, 0), + new Point(20, -20), + new Point(0, -20), + ]); + + $result = $poly->getCenterPoint(); + $this->assertEquals(10, $result->getX()); + $this->assertEquals(-10, $result->getY()); + + $poly = new Polygon([ + new Point(0, 0), + new Point(300, 0), + new Point(300, -200), + new Point(0, -200), + ], new Point(0, 0)); + + $result = $poly->getCenterPoint(); + $this->assertEquals(150, $result->getX()); + $this->assertEquals(-100, $result->getY()); + } + + public function testWidth(): void + { + $poly = new Polygon([ + new Point(12, 45), + new Point(-23, -49), + new Point(3, 566), + ]); + + $this->assertEquals($poly->width(), 35); + } + + public function testHeight(): void + { + $poly = new Polygon([ + new Point(12, 45), + new Point(-23, -49), + new Point(3, 566), + ]); + + $this->assertEquals(615, $poly->height()); + + $poly = new Polygon([ + new Point(250, 207), + new Point(473, 207), + new Point(473, 250), + new Point(250, 250), + ], new Point(250, 250)); + + $this->assertEquals(43, $poly->height()); + } + + public function testFirst(): void + { + $poly = new Polygon([ + new Point(12, 45), + new Point(-23, -49), + new Point(3, 566), + ]); + + $this->assertEquals(12, $poly->first()->getX()); + $this->assertEquals(45, $poly->first()->getY()); + } + + public function testLast(): void + { + $poly = new Polygon([ + new Point(12, 45), + new Point(-23, -49), + new Point(3, 566), + ]); + + $this->assertEquals(3, $poly->last()->getX()); + $this->assertEquals(566, $poly->last()->getY()); + } + + public function testGetPivotPoint(): void + { + $poly = new Polygon(); + $this->assertInstanceOf(Point::class, $poly->getPivotPoint()); + } + + public function testAlignPivot(): void + { + $poly = new Polygon([ + new Point(12, 45), + new Point(-24, -49), + new Point(3, 566), + ]); + + $this->assertEquals(0, $poly->getPivotPoint()->getX()); + $this->assertEquals(0, $poly->getPivotPoint()->getY()); + + $result = $poly->alignPivot('center'); + $this->assertInstanceOf(Polygon::class, $result); + + $this->assertEquals(-6, $result->getPivotPoint()->getX()); + $this->assertEquals(0, $result->getPivotPoint()->getY()); + } + + public function testValignPivot(): void + { + $poly = new Polygon([ + new Point(12, 45), + new Point(-24, -50), + new Point(3, 566), + ]); + + $this->assertEquals(0, $poly->getPivotPoint()->getX()); + $this->assertEquals(0, $poly->getPivotPoint()->getY()); + + $result = $poly->valignPivot('middle'); + $this->assertInstanceOf(Polygon::class, $result); + + $this->assertEquals(0, $result->getPivotPoint()->getX()); + $this->assertEquals(258, $result->getPivotPoint()->getY()); + } + + public function testGetMostLeftPoint(): void + { + $poly = new Polygon([ + new Point(0, 0), + new Point(300, 0), + new Point(300, -200), + new Point(-32, -200), + ], new Point(0, 0)); + + $result = $poly->getMostLeftPoint(); + $this->assertEquals(-32, $result->getX()); + $this->assertEquals(-200, $result->getY()); + } + + public function testGetMostRightPoint(): void + { + $poly = new Polygon([ + new Point(0, 0), + new Point(350, 0), + new Point(300, -200), + new Point(-32, -200), + ], new Point(0, 0)); + + $result = $poly->getMostRightPoint(); + $this->assertEquals(350, $result->getX()); + $this->assertEquals(0, $result->getY()); + } + + public function testGetMostTopPoint(): void + { + $poly = new Polygon([ + new Point(0, 100), + new Point(350, 0), + new Point(300, -200), + new Point(-32, 200), + ], new Point(0, 0)); + + $result = $poly->getMostTopPoint(); + $this->assertEquals(-32, $result->getX()); + $this->assertEquals(200, $result->getY()); + } + + public function testGetMostBottomPoint(): void + { + $poly = new Polygon([ + new Point(0, 100), + new Point(350, 0), + new Point(300, -200), + new Point(-32, 200), + ], new Point(0, 0)); + + $result = $poly->getMostBottomPoint(); + $this->assertEquals(300, $result->getX()); + $this->assertEquals(-200, $result->getY()); + } + + public function testAlignCenter(): void + { + $poly = new Polygon([ + new Point(0, 0), + new Point(300, 0), + new Point(300, -200), + new Point(0, -200), + ], new Point(0, 0)); + + $result = $poly->align('center'); + + $this->assertInstanceOf(Polygon::class, $result); + $this->assertEquals(-150, $result[0]->getX()); + $this->assertEquals(0, $result[0]->getY()); + $this->assertEquals(150, $result[1]->getX()); + $this->assertEquals(0, $result[1]->getY()); + $this->assertEquals(150, $result[2]->getX()); + $this->assertEquals(-200, $result[2]->getY()); + $this->assertEquals(-150, $result[3]->getX()); + $this->assertEquals(-200, $result[3]->getY()); + + $poly = new Polygon([ + new Point(0, 0), + new Point(300, 0), + new Point(300, -200), + new Point(0, -200), + ], new Point(-1000, -1000)); + + $result = $poly->align('center'); + + $this->assertInstanceOf(Polygon::class, $result); + $this->assertEquals(-1150, $result[0]->getX()); + $this->assertEquals(0, $result[0]->getY()); + $this->assertEquals(-850, $result[1]->getX()); + $this->assertEquals(0, $result[1]->getY()); + $this->assertEquals(-850, $result[2]->getX()); + $this->assertEquals(-200, $result[2]->getY()); + $this->assertEquals(-1150, $result[3]->getX()); + $this->assertEquals(-200, $result[3]->getY()); + } + + public function testAlignLeft(): void + { + $poly = new Polygon([ + new Point(0, 0), + new Point(300, 0), + new Point(300, -200), + new Point(0, -200), + ], new Point(100, 100)); + + $result = $poly->align('left'); + + $this->assertInstanceOf(Polygon::class, $result); + $this->assertEquals(100, $result[0]->getX()); + $this->assertEquals(0, $result[0]->getY()); + $this->assertEquals(400, $result[1]->getX()); + $this->assertEquals(0, $result[1]->getY()); + $this->assertEquals(400, $result[2]->getX()); + $this->assertEquals(-200, $result[2]->getY()); + $this->assertEquals(100, $result[3]->getX()); + $this->assertEquals(-200, $result[3]->getY()); + + $poly = new Polygon([ + new Point(0, 0), + new Point(300, 0), + new Point(300, -200), + new Point(0, -200), + ], new Point(-1000, -1000)); + + $result = $poly->align('left'); + + $this->assertInstanceOf(Polygon::class, $result); + $this->assertEquals(-1000, $result[0]->getX()); + $this->assertEquals(0, $result[0]->getY()); + $this->assertEquals(-700, $result[1]->getX()); + $this->assertEquals(0, $result[1]->getY()); + $this->assertEquals(-700, $result[2]->getX()); + $this->assertEquals(-200, $result[2]->getY()); + $this->assertEquals(-1000, $result[3]->getX()); + $this->assertEquals(-200, $result[3]->getY()); + } + + public function testAlignRight(): void + { + $poly = new Polygon([ + new Point(0, 0), + new Point(300, 0), + new Point(300, -200), + new Point(0, -200), + ], new Point(100, 100)); + + $result = $poly->align('right'); + + $this->assertInstanceOf(Polygon::class, $result); + $this->assertEquals(-200, $result[0]->getX()); + $this->assertEquals(0, $result[0]->getY()); + $this->assertEquals(100, $result[1]->getX()); + $this->assertEquals(0, $result[1]->getY()); + $this->assertEquals(100, $result[2]->getX()); + $this->assertEquals(-200, $result[2]->getY()); + $this->assertEquals(-200, $result[3]->getX()); + $this->assertEquals(-200, $result[3]->getY()); + + $poly = new Polygon([ + new Point(0, 0), + new Point(300, 0), + new Point(300, -200), + new Point(0, -200), + ], new Point(-1000, -1000)); + + $result = $poly->align('right'); + + $this->assertInstanceOf(Polygon::class, $result); + $this->assertEquals(-1300, $result[0]->getX()); + $this->assertEquals(0, $result[0]->getY()); + $this->assertEquals(-1000, $result[1]->getX()); + $this->assertEquals(0, $result[1]->getY()); + $this->assertEquals(-1000, $result[2]->getX()); + $this->assertEquals(-200, $result[2]->getY()); + $this->assertEquals(-1300, $result[3]->getX()); + $this->assertEquals(-200, $result[3]->getY()); + } + + public function testValignMiddle(): void + { + $poly = new Polygon([ + new Point(-21, -22), + new Point(91, -135), + new Point(113, -113), + new Point(0, 0), + ], new Point(250, 250)); + + $result = $poly->valign('middle'); + + $this->assertInstanceOf(Polygon::class, $result); + $this->assertEquals(-21, $result[0]->getX()); + $this->assertEquals(296, $result[0]->getY()); + $this->assertEquals(91, $result[1]->getX()); + $this->assertEquals(183, $result[1]->getY()); + $this->assertEquals(113, $result[2]->getX()); + $this->assertEquals(205, $result[2]->getY()); + $this->assertEquals(0, $result[3]->getX()); + $this->assertEquals(318, $result[3]->getY()); + } + + public function testRotate(): void + { + $poly = new Polygon([ + new Point(0, 0), + new Point(50, 0), + new Point(50, -50), + new Point(0, -50), + ]); + + $result = $poly->rotate(45); + $this->assertInstanceOf(Polygon::class, $result); + $this->assertEquals(0, $result[0]->getX()); + $this->assertEquals(0, $result[0]->getY()); + $this->assertEquals(35, $result[1]->getX()); + $this->assertEquals(35, $result[1]->getY()); + $this->assertEquals(70, $result[2]->getX()); + $this->assertEquals(0, $result[2]->getY()); + $this->assertEquals(35, $result[3]->getX()); + $this->assertEquals(-35, $result[3]->getY()); + } + + public function testToArray(): void + { + $poly = new Polygon([ + new Point(0, 0), + new Point(50, 0), + new Point(50, -50), + new Point(0, -50), + ]); + + $this->assertEquals([0, 0, 50, 0, 50, -50, 0, -50], $poly->toArray()); + } +} diff --git a/tests/Geometry/SizeTest.php b/tests/Geometry/SizeTest.php index 68dbe2cd..c11031f8 100644 --- a/tests/Geometry/SizeTest.php +++ b/tests/Geometry/SizeTest.php @@ -2,7 +2,7 @@ namespace Intervention\Image\Tests\Geometry; -use Intervention\Image\Geometry\{Point, Size,}; +use Intervention\Image\Geometry\{Point, Polygon, Size,}; use Intervention\Image\Tests\TestCase; /** @@ -254,6 +254,22 @@ class SizeTest extends TestCase $this->assertEquals(50, $pos->getY()); } + public function testToPolygon(): void + { + $size = new Size(300, 200); + $poly = $size->toPolygon(); + $this->assertInstanceOf(Polygon::class, $poly); + $this->assertCount(4, $poly); + $this->assertEquals(0, $poly[0]->getX()); + $this->assertEquals(0, $poly[0]->getY()); + $this->assertEquals(300, $poly[1]->getX()); + $this->assertEquals(0, $poly[1]->getY()); + $this->assertEquals(300, $poly[2]->getX()); + $this->assertEquals(-200, $poly[2]->getY()); + $this->assertEquals(0, $poly[3]->getX()); + $this->assertEquals(-200, $poly[3]->getY()); + } + public function testResize(): void { $size = new Size(300, 200);