From 9fe7980bdcbf864dd97e0f82be756f34d64871a1 Mon Sep 17 00:00:00 2001 From: Oliver Vogel Date: Thu, 13 Jun 2024 14:36:55 +0200 Subject: [PATCH] Fix bug when centering non-latin characters (#1366) --- src/Drivers/AbstractFontProcessor.php | 14 +++-- src/Drivers/Gd/FontProcessor.php | 14 +++-- .../Drivers/AbstractFontProcessorTest.php | 62 ++++++++++++++++--- 3 files changed, 69 insertions(+), 21 deletions(-) diff --git a/src/Drivers/AbstractFontProcessor.php b/src/Drivers/AbstractFontProcessor.php index e7817af8..6ffef565 100644 --- a/src/Drivers/AbstractFontProcessor.php +++ b/src/Drivers/AbstractFontProcessor.php @@ -30,14 +30,16 @@ public function textBlock(string $text, FontInterface $font, PointInterface $pos $x = $pivot->x(); $y = $font->hasFilename() ? $pivot->y() + $this->capHeight($font) : $pivot->y(); - $x_adjustment = 0; + $xAdjustment = 0; + // adjust line positions according to alignment foreach ($lines as $line) { - $line_width = $this->boxSize((string) $line, $font)->width(); - $x_adjustment = $font->alignment() == 'left' ? 0 : $blockWidth - $line_width; - $x_adjustment = $font->alignment() == 'right' ? intval(round($x_adjustment)) : $x_adjustment; - $x_adjustment = $font->alignment() == 'center' ? intval(round($x_adjustment / 2)) : $x_adjustment; - $position = new Point($x + $x_adjustment, $y); + $lineBoxSize = $this->boxSize((string) $line, $font); + $lineWidth = $lineBoxSize->width() + $lineBoxSize->pivot()->x(); + $xAdjustment = $font->alignment() == 'left' ? 0 : $blockWidth - $lineWidth; + $xAdjustment = $font->alignment() == 'right' ? intval(round($xAdjustment)) : $xAdjustment; + $xAdjustment = $font->alignment() == 'center' ? intval(round($xAdjustment / 2)) : $xAdjustment; + $position = new Point($x + $xAdjustment, $y); $position->rotate($font->angle(), $pivot); $line->setPosition($position); $y += $leading; diff --git a/src/Drivers/Gd/FontProcessor.php b/src/Drivers/Gd/FontProcessor.php index e7254081..c95f6bff 100644 --- a/src/Drivers/Gd/FontProcessor.php +++ b/src/Drivers/Gd/FontProcessor.php @@ -5,6 +5,7 @@ namespace Intervention\Image\Drivers\Gd; use Intervention\Image\Drivers\AbstractFontProcessor; +use Intervention\Image\Geometry\Point; use Intervention\Image\Geometry\Rectangle; use Intervention\Image\Interfaces\FontInterface; use Intervention\Image\Interfaces\SizeInterface; @@ -37,16 +38,17 @@ public function boxSize(string $text, FontInterface $font): SizeInterface // calculate box size from ttf font file with angle 0 $box = imageftbbox( - $this->nativeFontSize($font), - 0, - $font->filename(), - $text + size: $this->nativeFontSize($font), + angle: 0, + font_filename: $font->filename(), + string: $text ); // build size from points return new Rectangle( - intval(abs($box[4] - $box[0])), - intval(abs($box[5] - $box[1])) + width: intval(abs($box[6] - $box[4])), // difference of upper-left-x and upper-right-x + height: intval(abs($box[7] - $box[1])), // difference if upper-left-y and lower-left-y + pivot: new Point($box[6], $box[7]), // position of upper-left corner ); } diff --git a/tests/Unit/Drivers/AbstractFontProcessorTest.php b/tests/Unit/Drivers/AbstractFontProcessorTest.php index 56e53093..ac819563 100644 --- a/tests/Unit/Drivers/AbstractFontProcessorTest.php +++ b/tests/Unit/Drivers/AbstractFontProcessorTest.php @@ -19,19 +19,63 @@ class AbstractFontProcessorTest extends BaseTestCase public function testTextBlock(): void { $text = 'AAAA BBBB CCCC'; - $font = (new Font($this->getTestResourcePath('test.ttf')))->setWrapWidth(20)->setSize(50); + $font = (new Font($this->getTestResourcePath('test.ttf'))) + ->setWrapWidth(20) + ->setSize(50) + ->setLineHeight(1.25) + ->setAlignment('center'); + $processor = Mockery::mock(AbstractFontProcessor::class)->makePartial(); - $processor->shouldReceive('boxSize')->with('T', $font)->andReturn(new Rectangle(12, 6)); - $processor->shouldReceive('boxSize')->with('Hy', $font)->andReturn(new Rectangle(24, 6)); - $processor->shouldReceive('boxSize')->with('AAAA', $font)->andReturn(new Rectangle(24, 6)); - $processor->shouldReceive('boxSize')->with('AAAA BBBB', $font)->andReturn(new Rectangle(24, 6)); - $processor->shouldReceive('boxSize')->with('BBBB', $font)->andReturn(new Rectangle(24, 6)); - $processor->shouldReceive('boxSize')->with('BBBB CCCC', $font)->andReturn(new Rectangle(24, 6)); - $processor->shouldReceive('boxSize')->with('CCCC', $font)->andReturn(new Rectangle(24, 6)); - $processor->shouldReceive('boxSize')->with($text, $font)->andReturn(new Rectangle(100, 25)); + + $processor + ->shouldReceive('boxSize') + ->with('T', $font) + ->andReturn(new Rectangle(12, 6)); + $processor + ->shouldReceive('boxSize') + ->with('Hy', $font) + ->andReturn(new Rectangle(24, 6)); + + $processor + ->shouldReceive('boxSize') + ->with('AAAA', $font) + ->andReturn(new Rectangle(24, 6, new Point(1000, 0))); + + $processor + ->shouldReceive('boxSize') + ->with('AAAA BBBB', $font) + ->andReturn(new Rectangle(24, 6)); + + $processor + ->shouldReceive('boxSize') + ->with('BBBB', $font) + ->andReturn(new Rectangle(24, 6, new Point(2000, 0))); + + $processor + ->shouldReceive('boxSize') + ->with('BBBB CCCC', $font) + ->andReturn(new Rectangle(24, 6)); + + $processor + ->shouldReceive('boxSize') + ->with('CCCC', $font) + ->andReturn(new Rectangle(24, 6, new Point(3000, 0))); + + $processor + ->shouldReceive('boxSize') + ->with($text, $font) + ->andReturn(new Rectangle(100, 25, new Point(10, 0))); + $block = $processor->textBlock($text, $font, new Point(0, 0)); + $this->assertInstanceOf(TextBlock::class, $block); $this->assertEquals(3, $block->count()); + $this->assertEquals(-512, $block->getAtPosition(0)->position()->x()); + $this->assertEquals(-16, $block->getAtPosition(0)->position()->y()); + $this->assertEquals(-1012, $block->getAtPosition(1)->position()->x()); + $this->assertEquals(-8, $block->getAtPosition(1)->position()->y()); + $this->assertEquals(-1512, $block->getAtPosition(2)->position()->x()); + $this->assertEquals(0, $block->getAtPosition(2)->position()->y()); } public function testNativeFontSize(): void