From b73a7fbe152d62422919db532eb1b017005d8ea7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl=20van=20der=20Garde?= Date: Wed, 19 Feb 2025 11:52:08 +0100 Subject: [PATCH 1/4] Added: Text rotate [#80] --- src/Rasterization/Renderers/TextRenderer.php | 10 +++++++--- src/Rasterization/Transform/Transform.php | 14 ++++++++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/Rasterization/Renderers/TextRenderer.php b/src/Rasterization/Renderers/TextRenderer.php index 11e4c21..daea46e 100644 --- a/src/Rasterization/Renderers/TextRenderer.php +++ b/src/Rasterization/Renderers/TextRenderer.php @@ -25,7 +25,7 @@ class TextRenderer extends MultiPassRenderer */ protected function prepareRenderParams(array $options, Transform $transform, ?FontRegistry $fontRegistry): ?array { - // this assumes there is no rotation or skew, but that's fine, we can't deal with that anyway + // only the rotational impact of skew is used $size1 = $options['fontSize']; $size2 = $size1; $transform->resize($size1, $size2); @@ -55,12 +55,16 @@ protected function prepareRenderParams(array $options, Transform $transform, ?Fo $y = $options['y']; $transform->map($x, $y); + //get rotation result from transform matrix + $rotation = $transform->rotation(); + return [ 'x' => $x - $anchorOffset, 'y' => $y, 'size' => $size, 'fontPath' => $fontPath, 'text' => $options['text'], + 'rotation' => $rotation ]; } @@ -72,7 +76,7 @@ protected function renderFill($image, $params, int $color): void imagettftext( $image, $params['size'], - 0, + $params['rotation'], $params['x'], $params['y'], $color, @@ -92,7 +96,7 @@ protected function renderStroke($image, $params, int $color, float $strokeWidth) for ($c1 = ($x - abs($px)); $c1 <= ($x + abs($px)); $c1++) { for ($c2 = ($y - abs($px)); $c2 <= ($y + abs($px)); $c2++) { - imagettftext($image, $params['size'], 0, $c1, $c2, $color, $params['fontPath'], $params['text']); + imagettftext($image, $params['size'], $params['rotation'], $c1, $c2, $color, $params['fontPath'], $params['text']); } } } diff --git a/src/Rasterization/Transform/Transform.php b/src/Rasterization/Transform/Transform.php index e92af4a..af4e295 100644 --- a/src/Rasterization/Transform/Transform.php +++ b/src/Rasterization/Transform/Transform.php @@ -202,6 +202,20 @@ public function rotate(float $radians): void $this->matrix[3] = $d; } + /** + * Calculate the resulting rotation using the yaw rotation matrix + * + * @return float + */ + public function rotation(): float + { + $caRotation = atan2($this->matrix[2], $this->matrix[0]); + $bdRotation = atan2(-($this->matrix[1]), $this->matrix[3]); + $result = ($caRotation + $bdRotation) / 2 * 180 / M_PI; + + return $result; + } + /** * Apply a horizontal skew to this transform. This object will be mutated as a result of this operation. * This is the same as post-multiplying this transform with another transform representing a pure horizontal skew. From eb12616d98546fc4297b65535c187a065ad3bb7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl=20van=20der=20Garde?= Date: Wed, 19 Feb 2025 12:05:39 +0100 Subject: [PATCH 2/4] Added: Text rotate [#80] --- src/Rasterization/Renderers/TextRenderer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Rasterization/Renderers/TextRenderer.php b/src/Rasterization/Renderers/TextRenderer.php index daea46e..a96ea88 100644 --- a/src/Rasterization/Renderers/TextRenderer.php +++ b/src/Rasterization/Renderers/TextRenderer.php @@ -64,7 +64,7 @@ protected function prepareRenderParams(array $options, Transform $transform, ?Fo 'size' => $size, 'fontPath' => $fontPath, 'text' => $options['text'], - 'rotation' => $rotation + 'rotation' => $rotation ]; } From 895d9c6342cab89695913be43e27c45df03f2a6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl=20van=20der=20Garde?= Date: Wed, 19 Feb 2025 12:09:45 +0100 Subject: [PATCH 3/4] Added: Text rotate [#80] --- src/Rasterization/Transform/Transform.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Rasterization/Transform/Transform.php b/src/Rasterization/Transform/Transform.php index af4e295..977fe47 100644 --- a/src/Rasterization/Transform/Transform.php +++ b/src/Rasterization/Transform/Transform.php @@ -211,9 +211,7 @@ public function rotation(): float { $caRotation = atan2($this->matrix[2], $this->matrix[0]); $bdRotation = atan2(-($this->matrix[1]), $this->matrix[3]); - $result = ($caRotation + $bdRotation) / 2 * 180 / M_PI; - - return $result; + return ($caRotation + $bdRotation) / 2 * 180 / M_PI; } /** From 1cb95565f6ee44e34b4da4d4289d4b7dd3ad357a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl=20van=20der=20Garde?= Date: Wed, 19 Feb 2025 14:02:45 +0100 Subject: [PATCH 4/4] Added: Text rotate [#80] --- src/Rasterization/Renderers/TextRenderer.php | 15 +++++++++--- src/Rasterization/Transform/Transform.php | 24 ++++++++++++++++---- 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/src/Rasterization/Renderers/TextRenderer.php b/src/Rasterization/Renderers/TextRenderer.php index a96ea88..83d9c29 100644 --- a/src/Rasterization/Renderers/TextRenderer.php +++ b/src/Rasterization/Renderers/TextRenderer.php @@ -55,7 +55,7 @@ protected function prepareRenderParams(array $options, Transform $transform, ?Fo $y = $options['y']; $transform->map($x, $y); - //get rotation result from transform matrix + //get clockwise rotation result from transform matrix $rotation = $transform->rotation(); return [ @@ -76,7 +76,7 @@ protected function renderFill($image, $params, int $color): void imagettftext( $image, $params['size'], - $params['rotation'], + $params['rotation'] * -1, //counterclockwise $params['x'], $params['y'], $color, @@ -96,7 +96,16 @@ protected function renderStroke($image, $params, int $color, float $strokeWidth) for ($c1 = ($x - abs($px)); $c1 <= ($x + abs($px)); $c1++) { for ($c2 = ($y - abs($px)); $c2 <= ($y + abs($px)); $c2++) { - imagettftext($image, $params['size'], $params['rotation'], $c1, $c2, $color, $params['fontPath'], $params['text']); + imagettftext( + $image, + $params['size'], + $params['rotation'] * -1, //counterclockwise + $c1, + $c2, + $color, + $params['fontPath'], + $params['text'] + ); } } } diff --git a/src/Rasterization/Transform/Transform.php b/src/Rasterization/Transform/Transform.php index 977fe47..d03ba2a 100644 --- a/src/Rasterization/Transform/Transform.php +++ b/src/Rasterization/Transform/Transform.php @@ -205,13 +205,29 @@ public function rotate(float $radians): void /** * Calculate the resulting rotation using the yaw rotation matrix * - * @return float + * @return float clockwise rotation */ public function rotation(): float { - $caRotation = atan2($this->matrix[2], $this->matrix[0]); - $bdRotation = atan2(-($this->matrix[1]), $this->matrix[3]); - return ($caRotation + $bdRotation) / 2 * 180 / M_PI; + /* + * This is the counterclockwise rotation matrices, + * although the $radians in the function rotate() is a clockwise value, + * the matrix presents is counterclockwise, + * using these matrices, the result is clockwise. + * + * |cos(θ) -sin(θ) 0| |a -c 0| + * R = |sin(θ) cos(θ) 0| = |b d 0| + * |0 0 1| |0 0 1| + * + * Note: atan2(y, x) takes params in the y, x order. + * First we calculate the rotation effect of skewX/c and scaleX/a into radians: atan2(-c, a) + * Then we calculate the rotation effect of skewY/b and scaleY/d into radians: atan2(b, d) + * Last we average that and convert it to degree rotation: Ave(caRadian, bdRadian) * 180 / M_PI + */ + + $caRadian = atan2(-$this->matrix[2], $this->matrix[0]); + $bdRadian = atan2($this->matrix[1], $this->matrix[3]); + return ($caRadian + $bdRadian) / 2 * 180 / M_PI; } /**