1
0
mirror of https://github.com/Intervention/image.git synced 2025-01-18 04:38:26 +01:00

Implement multiline functionality for TextWriter

This commit is contained in:
Oliver Vogel 2022-06-25 16:43:34 +02:00
parent ae3762d455
commit 0e2aa7f595
7 changed files with 109 additions and 22 deletions

View File

@ -16,6 +16,7 @@ abstract class AbstractFont implements FontInterface
protected $filename;
protected $align = 'left';
protected $valign = 'bottom';
protected $lineHeight = 1.25;
public function __construct(callable $init = null)
{
@ -100,4 +101,16 @@ abstract class AbstractFont implements FontInterface
{
return $this->align;
}
public function lineHeight(float $height): FontInterface
{
$this->lineHeight = $height;
return $this;
}
public function getLineHeight(): float
{
return $this->lineHeight;
}
}

View File

@ -5,6 +5,7 @@ namespace Intervention\Image\Drivers\Abstract;
use Intervention\Image\Geometry\Point;
use Intervention\Image\Interfaces\FontInterface;
use Intervention\Image\Interfaces\ModifierInterface;
use Intervention\Image\Typography\TextBlock;
abstract class AbstractTextWriter implements ModifierInterface
{
@ -15,4 +16,9 @@ abstract class AbstractTextWriter implements ModifierInterface
) {
//
}
public function getTextBlock(): TextBlock
{
return new TextBlock($this->text);
}
}

View File

@ -84,4 +84,19 @@ class Font extends AbstractFont
return 8;
}
}
public function capHeight(): int
{
return $this->getBoxSize('T')->height();
}
public function leadingInPixels(): int
{
return intval(round($this->fontSizeInPixels() * $this->getLineHeight()));
}
public function fontSizeInPixels(): int
{
return $this->getBoxSize('Hy')->height();
}
}

View File

@ -5,26 +5,39 @@ 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\Geometry\Polygon;
use Intervention\Image\Geometry\Size;
use Intervention\Image\Interfaces\ImageInterface;
class TextWriter extends AbstractTextWriter
{
public function apply(ImageInterface $image): ImageInterface
{
$position = $this->getAlignedPosition();
$box = $this->getBoundingBox();
$position = clone $box->last();
$leading = $this->getFont()->leadingInPixels();
foreach ($image as $frame) {
if ($this->font->hasFilename()) {
imagettftext(
$frame->getCore(),
$this->getFont()->getSize(),
$this->getFont()->getAngle() * (-1),
$position->getX(),
$position->getY(),
$this->getFont()->getColor()->toInt(),
$this->getFont()->getFilename(),
$this->text
);
$position->moveY($this->getFont()->capHeight());
$posx = $position->getX();
$posy = $position->getY();
foreach ($this->getTextBlock() as $line) {
imagettftext(
$frame->getCore(),
$this->getFont()->getSize(),
$this->getFont()->getAngle() * (-1),
$posx,
$posy,
$this->getFont()->getColor()->toInt(),
$this->getFont()->getFilename(),
$line
);
$posy += $leading;
}
// debug
imagepolygon($frame->getCore(), $box->toArray(), 0);
} else {
imagestring(
$frame->getCore(),
@ -40,21 +53,36 @@ class TextWriter extends AbstractTextWriter
return $image;
}
private function getAlignedPosition(): Point
private function getBoundingBox(): Polygon
{
$poly = $this->font->getBoxSize($this->text);
$size = new Size(
$this->getTextBlock()->longestLine()->width($this->font),
$this->getFont()->leadingInPixels() * $this->getTextBlock()->count()
);
$poly = $size->toPolygon();
$poly->setPivotPoint($this->position);
$poly->align($this->getFont()->getAlign());
$poly->valign($this->getFont()->getValign());
$poly->align($this->font->getAlign());
$poly->valign($this->font->getValign());
if ($this->font->getAngle() != 0) {
$poly->rotate($this->font->getAngle());
}
return $poly->last();
return $poly;
}
// private function getAlignedPosition(): Point
// {
// $poly = $this->font->getBoxSize($this->text);
// $poly->setPivotPoint($this->position);
//
// $poly->align($this->font->getAlign());
// $poly->valign($this->font->getValign());
//
// if ($this->font->getAngle() != 0) {
// $poly->rotate($this->font->getAngle());
// }
//
// return $poly->last();
// }
private function getFont(): Font
{
if (!is_a($this->font, Font::class)) {

View File

@ -20,5 +20,10 @@ interface FontInterface
public function getAlign(): string;
public function valign(string $align): self;
public function getValign(): string;
public function lineHeight(float $value): self;
public function getLineHeight(): float;
public function leadingInPixels(): int;
public function fontSizeInPixels(): int;
public function capHeight(): int;
public function getBoxSize(string $text): Polygon;
}

View File

@ -2,6 +2,8 @@
namespace Intervention\Image\Typography;
use Intervention\Image\Interfaces\FontInterface;
class Line
{
public function __construct(protected string $text)
@ -13,4 +15,9 @@ class Line
{
return $this->text;
}
public function width(FontInterface $font): int
{
return $font->getBoxSize($this->text)->width();
}
}

View File

@ -17,4 +17,17 @@ class TextBlock extends Collection
{
return $this->items;
}
public function longestLine(): Line
{
$lines = $this->lines();
usort($lines, function ($a, $b) {
if (mb_strlen($a) === mb_strlen($b)) {
return 0;
}
return (mb_strlen($a) > mb_strlen($b)) ? -1 : 1;
});
return $lines[0];
}
}