Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New feature: textAligned #24

Open
wants to merge 17 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# IntelliJ project files
.idea
sami-cache/*
vendor
composer.lock
/.phpunit.result.cache
12 changes: 10 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,19 @@
}
],
"require": {
"php": ">=5.3"
"php": ">=7.3"
},
"suggest": {
"ext-gd": "*",
"ext-imagick": "*"
},
"autoload": {
"psr-4": {
"Grafika\\": "src/Grafika"
}
},
"require-dev": {
"phpunit/phpunit": "^9",
"symfony/var-dumper": "^5.0"
}
}
}
1 change: 0 additions & 1 deletion phpunit.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="false"
bootstrap="tests/bootstrap.php"
>
<testsuites>
Expand Down
30 changes: 27 additions & 3 deletions src/Grafika/EditorInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@
*/
interface EditorInterface {

const ALIGNMENT_X_LEFT = 'left';
const ALIGNMENT_X_CENTRE = 'centre';
const ALIGNMENT_X_RIGHT = 'right';

const ALIGNMENT_Y_TOP = 'top';
const ALIGNMENT_Y_MIDDLE = 'middle';
const ALIGNMENT_Y_BOTTOM = 'bottom';

/**
* Apply a filter to the image. See Filters section for a list of available filters.
*
Expand Down Expand Up @@ -77,7 +85,7 @@ public function draw( &$image, $drawingObject );
* @throws \Exception
*/
public function equal( $image1, $image2 );

/**
* Fill entire image with color.
*
Expand Down Expand Up @@ -144,7 +152,7 @@ public function opacity( &$image, $opacity );
* @return EditorInterface An instance of Editor.
*/
public function open( &$image, $imageFile );

/**
* Wrapper function for the resizeXXX family of functions. Resize an image to a given width, height and mode.
*
Expand Down Expand Up @@ -252,4 +260,20 @@ public function save( $image, $file, $type = null, $quality = null, $interlace =
*/
public function text( &$image, $text, $size = 12, $x = 0, $y = 12, $color = null, $font = '', $angle = 0 );

}
/**
* @param ImageInterface $image Instance of Image
* @param string $text The text to be written
* @param string $alignmentX One of EditorInterface::ALIGNMENT_X_*
* @param string $alignmentY One of EditorInterface::ALIGNMENT_Y_*
* @param int $paddingX Pixels to add to next to the text
* @param int $paddingY Pixels to add to above/below the text
* @param Color $color The Color object. Default text color is black.
* @param int $size The font size. Defaults to 12.
* @param string $font Full path to font file. If blank, will default to Liberation Sans font.
* @param int $angle Angle of text from 0 - 359. Defaults to 0.
* @return array With keys, textWidth int, textHeight int, boxWidth int, boxHeight int
* @throws \Exception
*/
public function textAligned(ImageInterface $image, string $text, string $alignmentX, string $alignmentY, int $paddingX = 0, int $paddingY = 0, ?Color $color = null, int $size = 12, string $font = '', int $angle = 0 ): array;

}
114 changes: 112 additions & 2 deletions src/Grafika/Gd/Editor.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Grafika\Gd;

use Grafika\Color;
use Grafika\DrawingObjectInterface;
use Grafika\EditorInterface;
use Grafika\FilterInterface;
Expand All @@ -10,8 +11,8 @@
use Grafika\Grafika;
use Grafika\ImageInterface;
use Grafika\ImageType;
use Grafika\Color;
use Grafika\Position;
use Grafika\Util\TTFBox;

/**
* GD Editor class. Uses the PHP GD library.
Expand Down Expand Up @@ -808,6 +809,115 @@ public function text(&$image, $text, $size = 12, $x = 0, $y = 0, $color = null,
return $this;
}

/**
* @inheritDoc
*/
public function textAligned(ImageInterface $image, string $text, string $alignmentX, string $alignmentY, int $paddingX = 0, int $paddingY = 0, ?Color $color = null, int $size = 12, string $font = '', int $angle = 0 ): array
{
if (!function_exists('imagettfbbox')) {
throw new \Exception('Freetype support is not available.');
}
$font = $this->getFont($font);

$ttfBoxZero = new TTFBox(imagettfbbox($size, 0, $font, $text));
if ($alignmentX === self::ALIGNMENT_X_CENTRE && $alignmentY === self::ALIGNMENT_Y_MIDDLE) {
// Remove chars with bits sticking out to so text centers at text body
$flatText = preg_replace('/[gjpqy]/', 'a', $text);
$ttfBoxV = new TTFBox(imagettfbbox($size, 0, $font, $flatText));
$ttfBoxZero = $ttfBoxZero->reduceHeight($ttfBoxV);
} else {
// Add chars with bits sticking out to ensure consistent height
$ttfBoxV = new TTFBox(imagettfbbox($size, 0, $font, $text . 'gjpqy'));
$ttfBoxZero = $ttfBoxZero->combineHeight($ttfBoxV);
}

if ($angle != 0) {
$ttfBox = $ttfBoxZero->rotate(0, 0, $angle * -1);
} else {
$ttfBox = $ttfBoxZero;
}

$x = $this->getTextXPosition($image, $alignmentX, $paddingX, $ttfBox);
$y = $this->getTextYPosition($image, $alignmentY, $paddingY, $ttfBox, $ttfBoxZero) - $size;

$this->text($image, $text, $size, $x, $y, $color, $font, $angle);

$xZeroValues = $ttfBoxZero->getXPoints();
$yZeroValues = $ttfBoxZero->getYPoints();

$xValues = $ttfBox->getXPoints();
$yValues = $ttfBox->getYPoints();

// dump(sprintf('A: %d X: %d Y: %d', $angle * -1, $x, $y), ''); // debug
return [
'textWidth' => max($xZeroValues) - min($xZeroValues),
'textHeight' => max($yZeroValues) - min($yZeroValues),
'boxWidth' => max($xValues) - min($xValues),
'boxHeight' => max($yValues) - min($yValues),
];
}

/**
* The coordinates given by x and y will define the basepoint of the first character (roughly the lower-left corner of the character).
* @param ImageInterface $image
* @param string $alignmentX
* @param int $paddingX
* @param TTFBox $ttfBox
* @return int
* @throws \Exception
*/
private function getTextXPosition(ImageInterface $image, string $alignmentX, int $paddingX, TTFBox $ttfBox): int
{
switch ($alignmentX) {
case self::ALIGNMENT_X_LEFT:
return abs(min($ttfBox->getXPoints())) + $paddingX;

case self::ALIGNMENT_X_CENTRE:
$middle = (abs(max($ttfBox->getXPoints())) - abs(min($ttfBox->getXPoints()))) / 2;
return ($image->getWidth() / 2) - $middle + $paddingX;

case self::ALIGNMENT_X_RIGHT:
return $image->getWidth() - abs(max($ttfBox->getXPoints())) - $paddingX;

default:
throw new \Exception('Invalid $alignmentX value');
}
}

/**
* The y-ordinate. This sets the position of the fonts baseline, not the very bottom of the character.
* @param ImageInterface $image
* @param string $alignmentY
* @param int $paddingY
* @param TTFBox $ttfBox
* @param TTFBox $ttfBoxZero
* @return int
* @throws \Exception
*/
private function getTextYPosition(ImageInterface $image, string $alignmentY, int $paddingY, TTFBox $ttfBox, TTFBox $ttfBoxZero): int
{
$textHeight = abs(min($ttfBoxZero->getYPoints())) - abs(max($ttfBoxZero->getYPoints()));
switch ($alignmentY) {
case self::ALIGNMENT_Y_TOP:
return abs(min($ttfBox->getYPoints())) + $paddingY;

case self::ALIGNMENT_Y_MIDDLE:
$middle = (($ttfBox->getLowerLeftY() - $ttfBox->getUpperRightY()) / 2) - $ttfBox->getLowerLeftY();
return ($image->getHeight() / 2) + $middle + $paddingY;

case self::ALIGNMENT_Y_BOTTOM:
return $image->getHeight() - abs(max($ttfBox->getYPoints())) - $paddingY;

default:
throw new \Exception('Invalid $alignmentY value');
}
}

private function getFont(string $font): string
{
return ($font !== '') ? $font : Grafika::fontsDir() . DIRECTORY_SEPARATOR . 'LiberationSans-Regular.ttf';
}

/**
* @param $canvas
* @param $gd1
Expand Down Expand Up @@ -1176,4 +1286,4 @@ private function _smartCrop($oldImage, $cropW, $cropH){

return array($x,$y);
}
}
}
Loading