Skip to content

Commit

Permalink
refactoring letter spacing in write text methods
Browse files Browse the repository at this point in the history
  • Loading branch information
Franck ALARY committed Nov 9, 2022
1 parent 9a6f48c commit b2bfa29
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 74 deletions.
28 changes: 15 additions & 13 deletions docs/classes/DantSu/PHPImageEditor/Image.md
Original file line number Diff line number Diff line change
Expand Up @@ -848,13 +848,14 @@ Write text on the image.
|-----------|------|-------------|
| `string` | **string** | Text to be added on the image |
| `fontPath` | **string** | Path to the TTF file |
| `fontSize` | **int** | Font size |
| `fontSize` | **float** | Font size |
| `color` | **string** | Hexadecimal string color |
| `posX` | **int|string** | Left position in pixel. You can use `Image::ALIGN_LEFT`, `Image::ALIGN_CENTER`, `Image::ALIGN_RIGHT` |
| `posY` | **int|string** | Top position in pixel. You can use `Image::ALIGN_TOP`, `Image::ALIGN_MIDDLE`, `Image::ALIGN_BOTTOM` |
| `anchorX` | **int|string** | Horizontal anchor of the text. You can use `Image::ALIGN_LEFT`, `Image::ALIGN_CENTER`, `Image::ALIGN_RIGHT` |
| `anchorY` | **int|string** | Vertical anchor of the text. You can use `Image::ALIGN_TOP`, `Image::ALIGN_MIDDLE`, `Image::ALIGN_BOTTOM` |
| `rotation` | **int** | Counterclockwise text rotation in degrees |
| `posX` | **float|string** | Left position in pixel. You can use `Image::ALIGN_LEFT`, `Image::ALIGN_CENTER`, `Image::ALIGN_RIGHT` |
| `posY` | **float|string** | Top position in pixel. You can use `Image::ALIGN_TOP`, `Image::ALIGN_MIDDLE`, `Image::ALIGN_BOTTOM` |
| `anchorX` | **float|string** | Horizontal anchor of the text. You can use `Image::ALIGN_LEFT`, `Image::ALIGN_CENTER`, `Image::ALIGN_RIGHT` |
| `anchorY` | **float|string** | Vertical anchor of the text. You can use `Image::ALIGN_TOP`, `Image::ALIGN_MIDDLE`, `Image::ALIGN_BOTTOM` |
| `rotation` | **float** | Counterclockwise text rotation in degrees |
| `letterSpacing` | **float** | add space between letters |


#### Return Value:
Expand All @@ -881,18 +882,19 @@ Write text on the image and get the bounding box of the text in the image.
|-----------|------|-------------|
| `string` | **string** | Text to be added on the image |
| `fontPath` | **string** | Path to the TTF file |
| `fontSize` | **int** | Font size |
| `fontSize` | **float** | Font size |
| `color` | **string** | Hexadecimal string color |
| `posX` | **int|string** | Left position in pixel. You can use `Image::ALIGN_LEFT`, `Image::ALIGN_CENTER`, `Image::ALIGN_RIGHT` |
| `posY` | **int|string** | Top position in pixel. You can use `Image::ALIGN_TOP`, `Image::ALIGN_MIDDLE`, `Image::ALIGN_BOTTOM` |
| `anchorX` | **int|string** | Horizontal anchor of the text. You can use `Image::ALIGN_LEFT`, `Image::ALIGN_CENTER`, `Image::ALIGN_RIGHT` |
| `anchorY` | **int|string** | Vertical anchor of the text. You can use `Image::ALIGN_TOP`, `Image::ALIGN_MIDDLE`, `Image::ALIGN_BOTTOM` |
| `rotation` | **int** | Counterclockwise text rotation in degrees |
| `posX` | **float|string** | Left position in pixel. You can use `Image::ALIGN_LEFT`, `Image::ALIGN_CENTER`, `Image::ALIGN_RIGHT` |
| `posY` | **float|string** | Top position in pixel. You can use `Image::ALIGN_TOP`, `Image::ALIGN_MIDDLE`, `Image::ALIGN_BOTTOM` |
| `anchorX` | **float|string** | Horizontal anchor of the text. You can use `Image::ALIGN_LEFT`, `Image::ALIGN_CENTER`, `Image::ALIGN_RIGHT` |
| `anchorY` | **float|string** | Vertical anchor of the text. You can use `Image::ALIGN_TOP`, `Image::ALIGN_MIDDLE`, `Image::ALIGN_BOTTOM` |
| `rotation` | **float** | Counterclockwise text rotation in degrees |
| `letterSpacing` | **float** | add space between letters |


#### Return Value:

**array** : Pixels positions of the
**array** : Bounding box positions of the text



Expand Down
149 changes: 88 additions & 61 deletions src/Image.php
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ public function curl(string $url, array $curlOptions = [], bool $failOnError = f

$image = \curl_exec($curl);

if($failOnError && \curl_errno($curl)){
if ($failOnError && \curl_errno($curl)) {
throw new \Exception(\curl_error($curl));
}

Expand Down Expand Up @@ -635,22 +635,22 @@ private static function formatColor(string $stringColor): string
* Allocate a new color to the image.
*
* @param string $color Hexadecimal string color
* @return int Color id
* @return int|false Color id
*/
private function colorAllocate(string $color): int
private function colorAllocate(string $color)
{
$color = static::formatColor($color);
$red = \hexdec(\substr($color, 0, 2));
$green = \hexdec(\substr($color, 2, 2));
$blue = \hexdec(\substr($color, 4, 2));
$alpha = \floor(\hexdec(\substr($color, 6, 2)) / 2);

$newColor = \imagecolorexactalpha($this->image, $red, $green, $blue, $alpha);
if ($newColor === -1) {
$newColor = \imagecolorallocatealpha($this->image, $red, $green, $blue, $alpha);
$colorId = \imagecolorexactalpha($this->image, $red, $green, $blue, $alpha);
if ($colorId === -1) {
$colorId = \imagecolorallocatealpha($this->image, $red, $green, $blue, $alpha);
}

return $newColor;
return $colorId;
}


Expand Down Expand Up @@ -801,18 +801,19 @@ public function grayscale(): Image
*
* @param string $string Text to be added on the image
* @param string $fontPath Path to the TTF file
* @param int $fontSize Font size
* @param float $fontSize Font size
* @param string $color Hexadecimal string color
* @param int|string $posX Left position in pixel. You can use `Image::ALIGN_LEFT`, `Image::ALIGN_CENTER`, `Image::ALIGN_RIGHT`
* @param int|string $posY Top position in pixel. You can use `Image::ALIGN_TOP`, `Image::ALIGN_MIDDLE`, `Image::ALIGN_BOTTOM`
* @param int|string $anchorX Horizontal anchor of the text. You can use `Image::ALIGN_LEFT`, `Image::ALIGN_CENTER`, `Image::ALIGN_RIGHT`
* @param int|string $anchorY Vertical anchor of the text. You can use `Image::ALIGN_TOP`, `Image::ALIGN_MIDDLE`, `Image::ALIGN_BOTTOM`
* @param int $rotation Counterclockwise text rotation in degrees
* @param float|string $posX Left position in pixel. You can use `Image::ALIGN_LEFT`, `Image::ALIGN_CENTER`, `Image::ALIGN_RIGHT`
* @param float|string $posY Top position in pixel. You can use `Image::ALIGN_TOP`, `Image::ALIGN_MIDDLE`, `Image::ALIGN_BOTTOM`
* @param float|string $anchorX Horizontal anchor of the text. You can use `Image::ALIGN_LEFT`, `Image::ALIGN_CENTER`, `Image::ALIGN_RIGHT`
* @param float|string $anchorY Vertical anchor of the text. You can use `Image::ALIGN_TOP`, `Image::ALIGN_MIDDLE`, `Image::ALIGN_BOTTOM`
* @param float $rotation Counterclockwise text rotation in degrees
* @param float $letterSpacing add space between letters
* @return $this Fluent interface
*/
public function writeText(string $string, string $fontPath, int $fontSize, string $color = '#ffffff', $posX = 0, $posY = 0, string $anchorX = Image::ALIGN_CENTER, string $anchorY = Image::ALIGN_MIDDLE, int $rotation = 0, int $letter_spacing = 0): Image
public function writeText(string $string, string $fontPath, float $fontSize, string $color = 'ffffff', $posX = 0, $posY = 0, $anchorX = Image::ALIGN_CENTER, $anchorY = Image::ALIGN_MIDDLE, float $rotation = 0, float $letterSpacing = 0): Image
{
$this->writeTextAndGetBoundingBox($string, $fontPath, $fontSize, $color, $posX, $posY, $anchorX, $anchorY, $rotation, $letter_spacing);
$this->writeTextAndGetBoundingBox($string, $fontPath, $fontSize, $color, $posX, $posY, $anchorX, $anchorY, $rotation, $letterSpacing);
return $this;
}

Expand All @@ -821,16 +822,17 @@ public function writeText(string $string, string $fontPath, int $fontSize, strin
*
* @param string $string Text to be added on the image
* @param string $fontPath Path to the TTF file
* @param int $fontSize Font size
* @param float $fontSize Font size
* @param string $color Hexadecimal string color
* @param int|string $posX Left position in pixel. You can use `Image::ALIGN_LEFT`, `Image::ALIGN_CENTER`, `Image::ALIGN_RIGHT`
* @param int|string $posY Top position in pixel. You can use `Image::ALIGN_TOP`, `Image::ALIGN_MIDDLE`, `Image::ALIGN_BOTTOM`
* @param int|string $anchorX Horizontal anchor of the text. You can use `Image::ALIGN_LEFT`, `Image::ALIGN_CENTER`, `Image::ALIGN_RIGHT`
* @param int|string $anchorY Vertical anchor of the text. You can use `Image::ALIGN_TOP`, `Image::ALIGN_MIDDLE`, `Image::ALIGN_BOTTOM`
* @param int $rotation Counterclockwise text rotation in degrees
* @return array Pixels positions of the
*/
public function writeTextAndGetBoundingBox(string $string, string $fontPath, int $fontSize, string $color = '#ffffff', $posX = 0, $posY = 0, string $anchorX = Image::ALIGN_CENTER, string $anchorY = Image::ALIGN_MIDDLE, int $rotation = 0, int $letter_spacing = 0): array
* @param float|string $posX Left position in pixel. You can use `Image::ALIGN_LEFT`, `Image::ALIGN_CENTER`, `Image::ALIGN_RIGHT`
* @param float|string $posY Top position in pixel. You can use `Image::ALIGN_TOP`, `Image::ALIGN_MIDDLE`, `Image::ALIGN_BOTTOM`
* @param float|string $anchorX Horizontal anchor of the text. You can use `Image::ALIGN_LEFT`, `Image::ALIGN_CENTER`, `Image::ALIGN_RIGHT`
* @param float|string $anchorY Vertical anchor of the text. You can use `Image::ALIGN_TOP`, `Image::ALIGN_MIDDLE`, `Image::ALIGN_BOTTOM`
* @param float $rotation Counterclockwise text rotation in degrees
* @param float $letterSpacing add space between letters
* @return array Bounding box positions of the text
*/
public function writeTextAndGetBoundingBox(string $string, string $fontPath, float $fontSize, string $color = 'ffffff', $posX = 0, $posY = 0, $anchorX = Image::ALIGN_CENTER, $anchorY = Image::ALIGN_MIDDLE, float $rotation = 0, float $letterSpacing = 0): array
{
if (!$this->isImageDefined()) {
return [];
Expand Down Expand Up @@ -858,7 +860,7 @@ public function writeTextAndGetBoundingBox(string $string, string $fontPath, int
) {
if (
($newImg = \imagecreatetruecolor(1, 1)) === false ||
($posText = $this->imagettftextWithSpacing($newImg, $fontSize, $rotation, 0, 0, $color, $fontPath, $string, $letter_spacing)) === false
($posText = $this->imagettftextWithSpacing($newImg, $fontSize, $rotation, 0, 0, $color, $fontPath, $string, $letterSpacing)) === false
) {
return [];
}
Expand All @@ -884,6 +886,7 @@ public function writeTextAndGetBoundingBox(string $string, string $fontPath, int
}

$sizeWidth = $xMax - $xMin;
$sizeHeight = $yMax - $yMin;

switch ($anchorX) {
case static::ALIGN_LEFT :
Expand All @@ -898,17 +901,18 @@ public function writeTextAndGetBoundingBox(string $string, string $fontPath, int
}
switch ($anchorY) {
case static::ALIGN_TOP :
$posY = $posY + $fontSize;
$posY = $posY - $yMin;
break;
case static::ALIGN_MIDDLE :
$posY = $posY + $fontSize / 2;
$posY = $posY - $sizeHeight / 2 - $yMin;
break;
case static::ALIGN_BOTTOM :
$posY = $posY - $sizeHeight - $yMin;
break;
}
}

$posText = $this->imagettftextWithSpacing($this->image, $fontSize, $rotation, $posX, $posY, $color, $fontPath, $string, $letter_spacing);
$posText = $this->imagettftextWithSpacing($this->image, $fontSize, $rotation, $posX, $posY, $color, $fontPath, $string, $letterSpacing);

if ($posText === false) {
return [];
Expand Down Expand Up @@ -943,35 +947,52 @@ public function writeTextAndGetBoundingBox(string $string, string $fontPath, int

/**
* @param $image
* @param $size
* @param $angle
* @param $x
* @param $y
* @param $color
* @param $font
* @param $text
* @param int $spacing
* @return array
*/
private function imagettftextWithSpacing($image, float $size, float $angle, float $x, float $y, int $color, string $font, string $text, int $spacing = 0)
* @param float $size
* @param float $angle
* @param float $x
* @param float $y
* @param int $color
* @param string $font
* @param string $text
* @param float $spacing
* @return array|false
*/
private function imagettftextWithSpacing($image, float $size, float $angle, float $x, float $y, int $color, string $font, string $text, float $spacing = 0)
{
if ($spacing == 0)
{
if ($spacing == 0) {
return \imagettftext($image, $size, $angle, $x, $y, $color, $font, $text);
}
else
{
$temp_x = $x;
$temp_y = $y;
$posText = [];
for ($i = 0; $i < \mb_strlen($text); ++$i)
{
$posText = \imagettftext($image, $size, $angle, $temp_x, $temp_y, $color, $font, $text[$i]);
} else {
$length = \mb_strlen($text);

if ($length == 0) {
return false;
}

$letterPos = ['x' => $x, 'y' => $y];
$textWidth = $spacing * ($length - 1);
$top = 0;
$bottom = 0;

for ($i = 0; $i < $length; ++$i) {
\imagettftext($image, $size, $angle, $letterPos['x'], $letterPos['y'], $color, $font, $text[$i]);
$bbox = \imagettfbbox($size, 0, $font, $text[$i]);
$temp_x += \cos(\deg2rad($angle)) * ($spacing + ($bbox[2] - $bbox[0]));
$temp_y -= \sin(\deg2rad($angle)) * ($spacing + ($bbox[2] - $bbox[0]));
$letterPos = Geometry2D::getDstXY($letterPos['x'], $letterPos['y'], $angle, $spacing + $bbox[2]);

$textWidth += $bbox[2];
if ($top > $bbox[5]) {
$top = $bbox[5];
}
if ($bottom < $bbox[1]) {
$bottom = $bbox[1];
}
}
return $posText;

$bottomLeft = Geometry2D::getDstXY($x, $y, $angle - 90, $bottom);
$bottomRight = Geometry2D::getDstXY($bottomLeft['x'], $bottomLeft['y'], $angle, $textWidth);
$topLeft = Geometry2D::getDstXY($x, $y, $angle + 90, \abs($top));
$topRight = Geometry2D::getDstXY($topLeft['x'], $topLeft['y'], $angle, $textWidth);

return [$bottomLeft['x'], $bottomLeft['y'], $bottomRight['x'], $bottomRight['y'], $topRight['x'], $topRight['y'], $topLeft['x'], $topLeft['y']];
}
}

Expand Down Expand Up @@ -1010,7 +1031,7 @@ public function drawRectangle(int $left, int $top, int $right, int $bottom, stri
* @param string $color Hexadecimal string color
* @return $this Fluent interface
*/
public function drawPolygon(array $points, string $color = '#000000', $antialias = false): Image
public function drawPolygon(array $points, string $color = '000000', $antialias = false): Image
{
if (!$this->isImageDefined()) {
return $this;
Expand All @@ -1022,14 +1043,14 @@ public function drawPolygon(array $points, string $color = '#000000', $antialias
return $this;
}

if($antialias) {
if ($antialias) {
\imageantialias($this->image, true);
\imagepolygon($this->image, $points, \count($points) / 2, $color);
}

\imagefilledpolygon($this->image, $points, \count($points) / 2, $color);

if($antialias) {
if ($antialias) {
\imageantialias($this->image, false);
}

Expand Down Expand Up @@ -1280,10 +1301,10 @@ private function getData(callable $imgFunction): string

\ob_start();
$imgFunction();
$image_data = \ob_get_contents();
$imageData = \ob_get_contents();
\ob_end_clean();

return $image_data;
return $imageData;
}

/**
Expand All @@ -1293,7 +1314,9 @@ private function getData(callable $imgFunction): string
*/
public function getDataPNG(): string
{
return $this->getData(function () {$this->displayPNG();});
return $this->getData(function () {
$this->displayPNG();
});
}

/**
Expand All @@ -1304,7 +1327,9 @@ public function getDataPNG(): string
*/
public function getDataJPG(int $quality = -1): string
{
return $this->getData(function () use ($quality) {$this->displayJPG($quality);});
return $this->getData(function () use ($quality) {
$this->displayJPG($quality);
});
}

/**
Expand All @@ -1314,7 +1339,9 @@ public function getDataJPG(int $quality = -1): string
*/
public function getDataGIF(): string
{
return $this->getData(function () {$this->displayGIF();});
return $this->getData(function () {
$this->displayGIF();
});
}

/**
Expand Down
24 changes: 24 additions & 0 deletions src/samples/sample6.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

require_once '../Geometry2D.php';
require_once '../Image.php';

use \DantSu\PHPImageEditor\Image;

\header('Content-type: image/png');

$image1 = Image::newCanvas(500, 500);
$bbox = $image1->writeTextAndGetBoundingBox('I got the power !', __DIR__ . '/resources/font.ttf', 40, '#FFFFFF', Image::ALIGN_RIGHT, Image::ALIGN_BOTTOM, Image::ALIGN_RIGHT, Image::ALIGN_BOTTOM, 0, 1);

Image::newCanvas(500, 500)
->drawPolygon(
[
$bbox['top-left']['x'], $bbox['top-left']['y'],
$bbox['top-right']['x'], $bbox['top-right']['y'],
$bbox['bottom-right']['x'], $bbox['bottom-right']['y'],
$bbox['bottom-left']['x'], $bbox['bottom-left']['y']
],
'00000088'
)
->pasteOn($image1)
->displayPNG();

0 comments on commit b2bfa29

Please sign in to comment.