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:
parent
ae3762d455
commit
0e2aa7f595
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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)) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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];
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user