diff --git a/src/Drivers/Abstract/AbstractFont.php b/src/Drivers/Abstract/AbstractFont.php index 8991cd90..dd03a831 100644 --- a/src/Drivers/Abstract/AbstractFont.php +++ b/src/Drivers/Abstract/AbstractFont.php @@ -17,18 +17,13 @@ abstract class AbstractFont implements FontInterface protected $align = 'left'; protected $valign = 'bottom'; - public function __construct(protected string $text, ?callable $init = null) + public function __construct(callable $init = null) { if (is_callable($init)) { $init($this); } } - public function getText(): string - { - return $this->text; - } - public function size(float $size): FontInterface { $this->size = $size; diff --git a/src/Drivers/Abstract/AbstractImage.php b/src/Drivers/Abstract/AbstractImage.php index 2342b29c..2136c3bd 100644 --- a/src/Drivers/Abstract/AbstractImage.php +++ b/src/Drivers/Abstract/AbstractImage.php @@ -194,8 +194,8 @@ abstract class AbstractImage implements ImageInterface public function text(string $text, int $x, int $y, ?callable $init = null): ImageInterface { - $font = $this->resolveDriverClass('Font', $text, $init); - $modifier = $this->resolveDriverClass('Modifiers\TextWriter', new Point($x, $y), $font); + $font = $this->resolveDriverClass('Font', $init); + $modifier = $this->resolveDriverClass('Modifiers\TextWriter', new Point($x, $y), $font, $text); return $this->modify($modifier); } diff --git a/src/Drivers/Abstract/AbstractTextWriter.php b/src/Drivers/Abstract/AbstractTextWriter.php new file mode 100644 index 00000000..9b1e7a3a --- /dev/null +++ b/src/Drivers/Abstract/AbstractTextWriter.php @@ -0,0 +1,18 @@ +hasFilename()) { // calculate box size from gd font $box = new Size(0, 0); - $chars = mb_strlen($this->getText()); + $chars = mb_strlen($text); if ($chars > 0) { $box->setWidth($chars * $this->getGdFontWidth()); $box->setHeight($this->getGdFontHeight()); @@ -37,7 +37,7 @@ class Font extends AbstractFont $this->getSize(), 0, $this->getFilename(), - $this->getText() + $text ); // build polygon from points @@ -47,7 +47,6 @@ class Font extends AbstractFont $polygon->addPoint(new Point($box[2], $box[3])); $polygon->addPoint(new Point($box[0], $box[1])); - return $polygon; } diff --git a/src/Drivers/Gd/Modifiers/TextWriter.php b/src/Drivers/Gd/Modifiers/TextWriter.php index 3a6b18a6..486dedb2 100644 --- a/src/Drivers/Gd/Modifiers/TextWriter.php +++ b/src/Drivers/Gd/Modifiers/TextWriter.php @@ -2,20 +2,14 @@ namespace Intervention\Image\Drivers\Gd\Modifiers; +use Intervention\Image\Drivers\Abstract\AbstractTextWriter; use Intervention\Image\Drivers\Gd\Font; +use Intervention\Image\Exceptions\FontException; use Intervention\Image\Geometry\Point; use Intervention\Image\Interfaces\ImageInterface; -use Intervention\Image\Interfaces\ModifierInterface; -class TextWriter implements ModifierInterface +class TextWriter extends AbstractTextWriter { - public function __construct( - protected Point $position, - protected Font $font - ) { - // - } - public function apply(ImageInterface $image): ImageInterface { $position = $this->getAlignedPosition(); @@ -23,21 +17,21 @@ class TextWriter implements ModifierInterface if ($this->font->hasFilename()) { imagettftext( $frame->getCore(), - $this->font->getSize(), - $this->font->getAngle() * (-1), + $this->getFont()->getSize(), + $this->getFont()->getAngle() * (-1), $position->getX(), $position->getY(), - $this->font->getColor()->toInt(), - $this->font->getFilename(), - $this->font->getText() + $this->getFont()->getColor()->toInt(), + $this->getFont()->getFilename(), + $this->text ); } else { imagestring( $frame->getCore(), - $this->font->getGdFont(), + $this->getFont()->getGdFont(), $position->getX(), $position->getY(), - $this->font->getText(), + $this->text, $this->font->getColor()->toInt() ); } @@ -46,9 +40,9 @@ class TextWriter implements ModifierInterface return $image; } - public function getAlignedPosition(): Point + private function getAlignedPosition(): Point { - $poly = $this->font->getBoxSize(); + $poly = $this->font->getBoxSize($this->text); $poly->setPivotPoint($this->position); $poly->align($this->font->getAlign()); @@ -60,4 +54,12 @@ class TextWriter implements ModifierInterface return $poly->last(); } + + private function getFont(): Font + { + if (!is_a($this->font, Font::class)) { + throw new FontException('Font is not compatible to current driver.'); + } + return $this->font; + } } diff --git a/src/Drivers/Imagick/Font.php b/src/Drivers/Imagick/Font.php index e719fe7a..2d46a71b 100644 --- a/src/Drivers/Imagick/Font.php +++ b/src/Drivers/Imagick/Font.php @@ -5,10 +5,10 @@ namespace Intervention\Image\Drivers\Imagick; use Imagick; use ImagickDraw; use Intervention\Image\Drivers\Abstract\AbstractFont; -use Intervention\Image\Exceptions\DecoderException; use Intervention\Image\Exceptions\FontException; use Intervention\Image\Geometry\Polygon; use Intervention\Image\Geometry\Size; +use Intervention\Image\Interfaces\ColorInterface; class Font extends AbstractFont { @@ -18,22 +18,28 @@ class Font extends AbstractFont throw new FontException('No font file specified.'); } - $color = $this->getColor(); - if (!is_a($color, Color::class)) { - throw new DecoderException('Unable to decode font color.'); - } - $draw = new ImagickDraw(); $draw->setStrokeAntialias(true); $draw->setTextAntialias(true); $draw->setFont($this->getFilename()); $draw->setFontSize($this->getSize()); - $draw->setFillColor($color->getPixel()); + $draw->setFillColor($this->getColor()->getPixel()); $draw->setTextAlignment($this->getImagickAlign()); return $draw; } + public function getColor(): ?ColorInterface + { + $color = parent::getColor(); + + if (!is_a($color, Color::class)) { + throw new FontException('Font is not compatible to current driver.'); + } + + return $color; + } + public function getAngle(): float { return parent::getAngle() * (-1); @@ -57,16 +63,16 @@ class Font extends AbstractFont * * @return Polygon */ - public function getBoxSize(): Polygon + public function getBoxSize(string $text): Polygon { // no text - no box size - if (mb_strlen($this->getText()) === 0) { + if (mb_strlen($text) === 0) { return (new Size(0, 0))->toPolygon(); } $dimensions = (new Imagick())->queryFontMetrics( $this->toImagickDraw(), - $this->getText() + $text ); return (new Size( diff --git a/src/Drivers/Imagick/Modifiers/TextWriter.php b/src/Drivers/Imagick/Modifiers/TextWriter.php index 4fe1dc2a..a85fd8b4 100644 --- a/src/Drivers/Imagick/Modifiers/TextWriter.php +++ b/src/Drivers/Imagick/Modifiers/TextWriter.php @@ -2,30 +2,24 @@ namespace Intervention\Image\Drivers\Imagick\Modifiers; +use Intervention\Image\Drivers\Abstract\AbstractTextWriter; use Intervention\Image\Drivers\Imagick\Font; +use Intervention\Image\Exceptions\FontException; use Intervention\Image\Geometry\Point; use Intervention\Image\Interfaces\ImageInterface; -use Intervention\Image\Interfaces\ModifierInterface; -class TextWriter implements ModifierInterface +class TextWriter extends AbstractTextWriter { - public function __construct( - protected Point $position, - protected Font $font - ) { - // - } - public function apply(ImageInterface $image): ImageInterface { $position = $this->getAlignedPosition(); foreach ($image as $frame) { $frame->getCore()->annotateImage( - $this->font->toImagickDraw(), + $this->getFont()->toImagickDraw(), $position->getX(), $position->getY(), - $this->font->getAngle() * (-1), - $this->font->getText() + $this->getFont()->getAngle() * (-1), + $this->text ); } @@ -35,10 +29,10 @@ class TextWriter implements ModifierInterface protected function getAlignedPosition(): Point { $position = $this->position; - $box = $this->font->getBoxSize(); + $box = $this->getFont()->getBoxSize($this->text); // adjust y pos - switch ($this->font->getValign()) { + switch ($this->getFont()->getValign()) { case 'top': $position->setY($position->getY() + $box->height()); break; @@ -51,4 +45,12 @@ class TextWriter implements ModifierInterface return $position; } + + private function getFont(): Font + { + if (!is_a($this->font, Font::class)) { + throw new FontException('Font is not compatible to current driver.'); + } + return $this->font; + } } diff --git a/src/Interfaces/FontInterface.php b/src/Interfaces/FontInterface.php index 92e47008..66a78b15 100644 --- a/src/Interfaces/FontInterface.php +++ b/src/Interfaces/FontInterface.php @@ -7,7 +7,6 @@ use Intervention\Image\Interfaces\ColorInterface; interface FontInterface { - public function getText(): string; public function color($color): self; public function getColor(): ?ColorInterface; public function size(float $size): self; @@ -19,5 +18,7 @@ interface FontInterface public function hasFilename(): bool; public function align(string $align): self; public function getAlign(): string; - public function getBoxSize(): Polygon; + public function valign(string $align): self; + public function getValign(): string; + public function getBoxSize(string $text): Polygon; } diff --git a/src/Typography/Line.php b/src/Typography/Line.php new file mode 100644 index 00000000..80037869 --- /dev/null +++ b/src/Typography/Line.php @@ -0,0 +1,16 @@ +text; + } +} diff --git a/src/Typography/TextBlock.php b/src/Typography/TextBlock.php new file mode 100644 index 00000000..c8cdadf3 --- /dev/null +++ b/src/Typography/TextBlock.php @@ -0,0 +1,20 @@ +push(new Line($line)); + } + } + + public function lines(): array + { + return $this->items; + } +} diff --git a/tests/Drivers/Abstract/AbstractFontTest.php b/tests/Drivers/Abstract/AbstractFontTest.php index e39d345d..0a5be182 100644 --- a/tests/Drivers/Abstract/AbstractFontTest.php +++ b/tests/Drivers/Abstract/AbstractFontTest.php @@ -12,7 +12,7 @@ class AbstractFontTest extends TestCase private function getAbstractFontMock() { // create mock - $mock = Mockery::mock(AbstractFont::class, ['test123']) + $mock = Mockery::mock(AbstractFont::class) ->shouldAllowMockingProtectedMethods() ->makePartial(); @@ -34,7 +34,6 @@ class AbstractFontTest extends TestCase public function testConstructor(): void { $mock = $this->getAbstractFontMock(); - $this->assertEquals('test123', $mock->getText()); $this->assertEquals(24.0, $mock->getSize()); $this->assertEquals(30, $mock->getAngle()); $this->assertEquals(__DIR__ . '/AbstractFontTest.php', $mock->getFilename()); diff --git a/tests/Typography/LineTest.php b/tests/Typography/LineTest.php new file mode 100644 index 00000000..fb7de727 --- /dev/null +++ b/tests/Typography/LineTest.php @@ -0,0 +1,21 @@ +assertInstanceOf(Line::class, $line); + } + + public function testToString(): void + { + $line = new Line('foo'); + $this->assertEquals('foo', (string) $line); + } +} diff --git a/tests/Typography/TextBlockTest.php b/tests/Typography/TextBlockTest.php new file mode 100644 index 00000000..bb4a901c --- /dev/null +++ b/tests/Typography/TextBlockTest.php @@ -0,0 +1,30 @@ +getTestBlock(); + $this->assertInstanceOf(TextBlock::class, $block); + $this->assertEquals(3, $block->count()); + } + + public function testLines(): void + { + $block = $this->getTestBlock(); + $this->assertCount(3, $block->lines()); + } +}