Skip to content

Commit

Permalink
Add code from stil#30
Browse files Browse the repository at this point in the history
  • Loading branch information
duncte123 committed Jun 2, 2020
1 parent dd74137 commit d8546e4
Show file tree
Hide file tree
Showing 2 changed files with 137 additions and 33 deletions.
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"description": "A class drawing multiline and aligned text on pictures. Uses GD extension.",
"license": "MIT",
"require": {
"php": ">=5.3",
"php": ">=7.1",
"ext-gd": "*"
},
"require-dev": {
Expand Down
168 changes: 136 additions & 32 deletions src/Box.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php

namespace GDText;

use GDText\Struct\Point;
Expand Down Expand Up @@ -120,7 +121,7 @@ public function setStrokeColor(Color $color)
{
$this->strokeColor = $color;
}

/**
* @param int $v Stroke size in *pixels*
*/
Expand All @@ -130,16 +131,16 @@ public function setStrokeSize($v)
}

/**
* @param Color $color Shadow color
* @param int $xShift Relative shadow position in pixels. Positive values move shadow to right, negative to left.
* @param int $yShift Relative shadow position in pixels. Positive values move shadow to bottom, negative to up.
* @param Color $color Shadow color
* @param int $xShift Relative shadow position in pixels. Positive values move shadow to right, negative to left.
* @param int $yShift Relative shadow position in pixels. Positive values move shadow to bottom, negative to up.
*/
public function setTextShadow(Color $color, $xShift, $yShift)
{
$this->textShadow = array(
$this->textShadow = [
'color' => $color,
'offset' => new Point($xShift, $yShift)
);
'offset' => new Point($xShift, $yShift),
];
}

/**
Expand All @@ -152,6 +153,7 @@ public function setBackgroundColor(Color $color)

/**
* Allows to customize spacing between lines.
*
* @param float $v Height of the single text line, in percents, proportionally to font size
*/
public function setLineHeight($v)
Expand All @@ -169,13 +171,14 @@ public function setBaseline($v)

/**
* Sets text alignment inside textbox
*
* @param string $x Horizontal alignment. Allowed values are: left, center, right.
* @param string $y Vertical alignment. Allowed values are: top, center, bottom.
*/
public function setTextAlign($x = 'left', $y = 'top')
{
$xAllowed = array('left', 'right', 'center');
$yAllowed = array('top', 'bottom', 'center');
$xAllowed = ['left', 'right', 'center'];
$yAllowed = ['top', 'bottom', 'center'];

if (!in_array($x, $xAllowed)) {
throw new \InvalidArgumentException('Invalid horizontal alignement value was specified.');
Expand All @@ -191,9 +194,10 @@ public function setTextAlign($x = 'left', $y = 'top')

/**
* Sets textbox position and dimensions
* @param int $x Distance in pixels from left edge of image.
* @param int $y Distance in pixels from top edge of image.
* @param int $width Width of texbox in pixels.
*
* @param int $x Distance in pixels from left edge of image.
* @param int $y Distance in pixels from top edge of image.
* @param int $width Width of texbox in pixels.
* @param int $height Height of textbox in pixels.
*/
public function setBox($x, $y, $width, $height)
Expand All @@ -219,17 +223,99 @@ public function setTextWrapping($textWrapping)

/**
* Draws the text on the picture.
*
* @param string $text Text to draw. May contain newline characters.
*
* @return Rectangle Area that cover the drawn text
*/
public function draw(string $text): Rectangle
{
return $this->drawText($text, true);
}

/**
* Draws the text on the picture, fitting it to the current box
*
* @param string $text Text to draw. May contain newline characters.
* @param int $precision Increment or decrement of font size. The lower this value, the slower this method.
* @param int $maxFontSize The maximum size that the font is allowed to be.
* @param int $minFontSize The minimum size that the font is allowed to be.
* @param int|null $usedFontSize The font size that was used
*
* @return Rectangle Area that cover the drawn text
*/
public function drawFitFontSize(string $text, int $precision, int $maxFontSize = -1, int $minFontSize = -1, ?int &$usedFontSize = null)
{
$initialFontSize = $this->fontSize;

$usedFontSize = $this->fontSize;
$rectangle = $this->calculate($text);

if ($rectangle->getHeight() > $this->box->getHeight() || $rectangle->getWidth() > $this->box->getWidth()) {
// Decrement font size
do {
$this->setFontSize($usedFontSize);
$rectangle = $this->calculate($text);

$usedFontSize -= $precision;
} while (($minFontSize == -1 || $usedFontSize > $minFontSize) &&
($rectangle->getHeight() > $this->box->getHeight() || $rectangle->getWidth() > $this->box->getWidth()));

$usedFontSize += $precision;
} else {
// Increment font size
do {
$this->setFontSize($usedFontSize);
$rectangle = $this->calculate($text);

$usedFontSize += $precision;
} while (($maxFontSize > 0 && $usedFontSize < $maxFontSize)
&& $rectangle->getHeight() < $this->box->getHeight()
&& $rectangle->getWidth() < $this->box->getWidth());

$usedFontSize -= $precision * 2;
}
$this->setFontSize($usedFontSize);

$rectangle = $this->drawText($text, true);

// Restore initial font size
$this->setFontSize($initialFontSize);

return $rectangle;
}

/**
* Get the area that will cover the given text
*
* @param string $text The text to calculate the rectangle for.
*
* @return Rectangle
*/
public function calculate(string $text)
{
return $this->drawText($text, false);
}

/**
* Draws the text on the picture.
*
* Modified from https://stackoverflow.com/a/52799317/4807235 to better fit the text if there are no spaces
*
* @param string $text Text to draw. May contain newline characters.
* @param bool $draw If we should draw the text on the canvas
*
* @return Rectangle
*/
public function draw($text)
public function drawText(string $text, bool $draw): Rectangle
{
if (!isset($this->fontFace)) {
throw new \InvalidArgumentException('No path to font file has been specified.');
}

switch ($this->textWrapping) {
case TextWrapping::NoWrap:
$lines = array($text);
$lines = [$text];
break;
case TextWrapping::WrapWithOverflow:
default:
Expand All @@ -246,7 +332,7 @@ public function draw($text)
}

$lineHeightPx = $this->lineHeight * $this->fontSize;
$textHeight = count($lines) * $lineHeightPx;
$textHeight = \count($lines) * $lineHeightPx;

switch ($this->alignY) {
case VerticalAlignment::Center:
Expand All @@ -261,6 +347,10 @@ public function draw($text)
}

$n = 0;

$drawnX = $drawnY = PHP_INT_MAX;
$drawnH = $drawnW = 0;

foreach ($lines as $line) {
$box = $this->calculateBox($line);
switch ($this->alignX) {
Expand All @@ -280,7 +370,7 @@ public function draw($text)
$xMOD = $this->box->getX() + $xAlign;
$yMOD = $this->box->getY() + $yAlign + $yShift + ($n * $lineHeightPx);

if ($line && $this->backgroundColor) {
if ($draw && $line && $this->backgroundColor) {
// Marks whole texbox area with given background-color
$backgroundHeight = $this->fontSize;

Expand All @@ -304,43 +394,54 @@ public function draw($text)
$box->getWidth(),
$lineHeightPx
),
new Color(rand(1, 180), rand(1, 180), rand(1, 180))
new Color(\rand(1, 180), \rand(1, 180), \rand(1, 180))
);
}

if ($this->textShadow !== false) {
if ($draw) {
if ($this->textShadow !== false) {
$this->drawInternal(
new Point(
$xMOD + $this->textShadow['offset']->getX(),
$yMOD + $this->textShadow['offset']->getY()
),
$this->textShadow['color'],
$line
);
}

$this->strokeText($xMOD, $yMOD, $line);
$this->drawInternal(
new Point(
$xMOD + $this->textShadow['offset']->getX(),
$yMOD + $this->textShadow['offset']->getY()
$xMOD,
$yMOD
),
$this->textShadow['color'],
$this->fontColor,
$line
);
}

$this->strokeText($xMOD, $yMOD, $line);
$this->drawInternal(
new Point(
$xMOD,
$yMOD
),
$this->fontColor,
$line
);
$drawnX = \min($xMOD, $drawnX);
$drawnY = \min($this->box->getY() + $yAlign + ($n * $lineHeightPx), $drawnY);
$drawnW = \max($drawnW, $box->getWidth());
$drawnH += $lineHeightPx;

$n++;
}

return new Rectangle($drawnX, $drawnY, $drawnW, $drawnH);
}

/**
* Splits overflowing text into array of strings.
*
* @param string $text
*
* @return string[]
*/
protected function wrapTextWithOverflow($text)
{
$lines = array();
$lines = [];
// Split text explicitly into lines by \n, \r\n and \r
$explicitLines = preg_split('/\n|\r\n?/', $text);
foreach ($explicitLines as $line) {
Expand All @@ -358,6 +459,7 @@ protected function wrapTextWithOverflow($text)
}
$lines[] = $line;
}

return $lines;
}

Expand All @@ -383,14 +485,16 @@ protected function drawFilledRectangle(Rectangle $rect, Color $color)

/**
* Returns the bounding box of a text.
*
* @param string $text
*
* @return Rectangle
*/
protected function calculateBox($text)
{
$bounds = imagettfbbox($this->getFontSizeInPoints(), 0, $this->fontFace, $text);

$xLeft = $bounds[0]; // (lower|upper) left corner, X position
$xLeft = $bounds[0]; // (lower|upper) left corner, X position
$xRight = $bounds[2]; // (lower|upper) right corner, X position
$yLower = $bounds[1]; // lower (left|right) corner, Y position
$yUpper = $bounds[5]; // upper (left|right) corner, Y position
Expand Down

0 comments on commit d8546e4

Please sign in to comment.