From 5d88492b971d635af78d45dc646fd764af73f695 Mon Sep 17 00:00:00 2001 From: Miguel Martinez Date: Sat, 13 May 2023 10:08:18 +0200 Subject: [PATCH 1/5] Added some source code documentation --- src/Cpdf.php | 96 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 91 insertions(+), 5 deletions(-) diff --git a/src/Cpdf.php b/src/Cpdf.php index daf710d..0cf831b 100644 --- a/src/Cpdf.php +++ b/src/Cpdf.php @@ -2812,7 +2812,52 @@ protected function filterText($text, $bom = true, $convert_encoding = true) return $text; } - + + + /** + * Prepares the text with directives for later processing in text addition. + * + * This function prepares text with directives at the specified coordinates and + * with the specified font size and style. The function also allows for text justification and + * rotation, and returns an array of text and formatting information. + * + * @param string &$text The text to add to the PDF document + * @param float $x The x coordinate of the starting point of the text + * @param float $y The y coordinate of the starting point of the text + * @param float $size The font size of the text + * @param float &$width The maximum width available for the text + * @param string $justification The justification of the text: "left", "center", or "right" + * @param float $angle The angle of rotation for the text + * @param float $wordSpaceAdjust The space between words in the text + * + * @return array An array of text and formatting information + * + * Example of returned array for: + * $text = "HelloWorld! extra text" + * $width = 100 + * + * [ + * 0 => [ + * 'text' => "Hello ", + * 'nspaces' => 1, + * 'callback' => ['func' => 'b', 'status' => 'start', ... ] + * ], + * 1 => [ + * 'text': "World", + * 'nspaces': 0, + * 'callback': ['func' => 'b', 'status' => 'end', ... ] + * ], + * 2 => [ + * 'text' => "!", + * 'nspaces' => 1, + * 'callback' => null + * ] + * ] + * + * With the next resulting output values: + * $text = "extra text" (will be processed in next call) + * $width = 17.489 + */ private function addTextWithDirectives(&$text, $x, $y, $size, &$width, $justification = 'left', $angle = 0, $wordSpaceAdjust = 0) { $result = []; @@ -2980,7 +3025,17 @@ protected function defaultFormatting($info) } /** - * add text to the document, at a specified location, size and angle on the page. + * Add text to the document, at a specified location, size and angle on the page. + * @param float $x The x-coordinate of the starting point of the text + * @param float $y The y-coordinate of the starting point of the text + * @param float $size The size of the text + * @param string $text The text to be added + * @param float $width The maximum width allowed for the text (default: 0) + * @param string $justification The type of text justification ('left', 'right', 'center', 'full') (default: 'left') + * @param float $angle The angle in degrees by which the text should be rotated (default: 0) + * @param float $wordSpaceAdjust The amount of space between words (default: 0) + * @param bool $test Flag indicating whether the function is being used for testing purposes (default: 0) + * @return string The text that was added to the document */ public function addText($x, $y, $size, $text, $width = 0, $justification = 'left', $angle = 0, $wordSpaceAdjust = 0, $test = 0) { @@ -3077,8 +3132,22 @@ public function addText($x, $y, $size, $text, $width = 0, $justification = 'left return $text; } + /** + * Add wrapped text to the document at the given coordinates. + * @param float $x The x-coordinate of the starting point of the text. + * @param float $y The y-coordinate of the starting point of the text. + * @param int $size The font size to use for the text. + * @param string $text The text to add to the document. + * @param float $width The width of the area in which the text should wrap. + * @param string $justification The type of justification to use for the text. Can be 'left', 'right', 'center', or 'full'. + * @param int $angle The angle at which to draw the text, measured in degrees. + * @param float $wordSpaceAdjust The space between words in the text + * @param bool $test Whether to just return the calculated height without actually adding the text to the PDF. + * @return void + */ public function addTextWrap($x, $y, $size, $text, $width = 0, $justification = 'left', $angle = 0, $wordSpaceAdjust = 0, $test = 0) { + // Split the input text into an array of lines based on line breaks and wrap the lines as necessary $parts = preg_split('/$\R?^/m', $text); foreach ($parts as $v) { $text = $this->addText($x, $y, $size, $v, $width, $justification, $angle, $wordSpaceAdjust, $test); @@ -3122,6 +3191,23 @@ public function getTextWidth($size, $text) return $tmp[0]; } + /** + * Calculates the width and height of a given text string in the current + * font and size, taking into account any rotation angle and a maximum width + * (in page units) for line wrapping + * + * @param float $size The font size to use for the text. + * @param string $text The text string for which to calculate the length. + * @param float $maxWidth The maximum width of the text string. If the text string exceeds this width, it will be truncated. + * @param float $angle The angle at which to draw the text, in degrees. + * @param float $wa word spacing (0 will use default spacing) + * @return array an array with five elements: + * [0] => The width of the text string in the current font and size, taking into account the font size and angle. + * [1] => The height of the text string in the current font and size, taking into account the font size and angle. + * [2] => The index of the character at which the text string should be truncated, if it exceeds the maximum width, or -1 if no line wrapping occurs. + * [3] => A boolean value indicating whether a space character should be added at the truncation point. + * [4] => The number of spaces in the text string. + */ private function getTextLength($size, $text, $maxWidth = 0, $angle = 0, $wa = 0) { if (!$this->numFonts) { @@ -3132,9 +3218,9 @@ private function getTextLength($size, $text, $maxWidth = 0, $angle = 0, $wa = 0) // get length of its unicode string $len = mb_strlen($text, 'UTF-8'); $cf = $this->currentFont; - $tw = $maxWidth / $size * 1000; + $tw = $maxWidth / $size * 1000; // maximum width of the text in glyph units $break = -1; - $w = 0; + $w = 0; // accumulated total length of the string $nspaces = 0; for ($i = 0; $i < $len; ++$i) { @@ -3144,7 +3230,7 @@ private function getTextLength($size, $text, $maxWidth = 0, $angle = 0, $wa = 0) continue; } - // verify if the charactor is a valid space (unicode supported, see $this->spaces) + // verify if the character is a valid space (unicode supported, see $this->spaces) $isSpace = in_array($cOrd, $this->spaces); if (isset($this->fonts[$cf]['differences'][$cOrd])) { From 8eeada605bc2f41c188131f99ae17b000fa73948 Mon Sep 17 00:00:00 2001 From: Miguel Martinez Date: Sat, 13 May 2023 10:15:49 +0200 Subject: [PATCH 2/5] Re-added adjustWrapText precondition from commit 00db904 rospdf#175 justification broken in tables --- src/Cpdf.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Cpdf.php b/src/Cpdf.php index 0cf831b..c132491 100644 --- a/src/Cpdf.php +++ b/src/Cpdf.php @@ -2884,6 +2884,7 @@ private function addTextWithDirectives(&$text, $x, $y, $size, &$width, $justific $x += $textLength[0]; $y += $textLength[1]; + // text must be truncated if ($textLength[2] >= 0) { if (isset($result[count($result) - 1])) { $prev = &$result[count($result) - 1]; @@ -3060,7 +3061,9 @@ public function addText($x, $y, $size, $text, $width = 0, $justification = 'left return $v['text']; }, $parts)); - $this->adjustWrapText($parsedText, $orgWidth - $width, $orgWidth, $x, $wordSpaceAdjust, $justification); + if (($justification == 'full' && ($orgWidth / 100 * 90) < ($orgWidth - $width)) || $justification != 'full'){ + $this->adjustWrapText($parsedText, $orgWidth - $width, $orgWidth, $x, $wordSpaceAdjust, $justification); + } if ($test) { return $text; From 6e773002cd29f536b966a85c957b7e50b36a4479 Mon Sep 17 00:00:00 2001 From: Miguel Martinez Date: Sat, 13 May 2023 10:19:22 +0200 Subject: [PATCH 3/5] addTextWithDirectives make sure we always advance position when generating parts to avoid infinite loops --- src/Cpdf.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Cpdf.php b/src/Cpdf.php index c132491..94017b2 100644 --- a/src/Cpdf.php +++ b/src/Cpdf.php @@ -2909,7 +2909,9 @@ private function addTextWithDirectives(&$text, $x, $y, $size, &$width, $justific $text = mb_substr($text, $offset, null, 'UTF-8'); } else { - $text = mb_substr($text, $offset + $textLength[2] + $textLength[3], null, 'UTF-8'); + // make sure we advance at least 1 character + $textOff = max(1, $offset + $textLength[2] + $textLength[3]); + $text = mb_substr($text, $textOff, null, 'UTF-8'); array_push($result, ['text' => mb_substr($part, 0, $textLength[2], 'UTF-8'), 'nspaces' => $textLength[4], 'callback' => $info]); } From bfa830bd50439551bba0036a7543d3c8fd6c4a25 Mon Sep 17 00:00:00 2001 From: Miguel Martinez Date: Sun, 18 Jun 2023 11:14:45 +0200 Subject: [PATCH 4/5] Reverted #8eeada6 added in ezTable same check as ezText if very last line force left justification --- src/Cezpdf.php | 10 +++++++++- src/Cpdf.php | 4 +--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/Cezpdf.php b/src/Cezpdf.php index 44a4e41..3f87472 100644 --- a/src/Cezpdf.php +++ b/src/Cezpdf.php @@ -1687,7 +1687,7 @@ public function ezTable(&$data, $cols = '', $title = '', $options = '') $lines = []; } $this->y -= $options['rowGap']; - foreach ($lines as $line) { + foreach ($lines as $i => $line) { $line = $this->ezProcessText($line); // set the text color // grab the defined colors for this cell @@ -1720,6 +1720,14 @@ public function ezTable(&$data, $cols = '', $title = '', $options = '') } else { if (isset($options['cols'][$colName]) && isset($options['cols'][$colName]['justification'])) { $just = $options['cols'][$colName]['justification']; + + if ($just == 'full' && (empty($lines[$i + 1]) || count($lines) == $i + 1)) { + // do not fully justify if its the absolute last line (taking line breaks into account) + $tmp = $this->addText($pos[$colName], $this->y, $options['fontSize'], $line, $maxWidth[$colName], $just, 0,0,1); + if (!strlen($tmp)) { + $just = "left"; + } + } } else { $just = 'left'; } diff --git a/src/Cpdf.php b/src/Cpdf.php index 94017b2..4fe86da 100644 --- a/src/Cpdf.php +++ b/src/Cpdf.php @@ -3063,9 +3063,7 @@ public function addText($x, $y, $size, $text, $width = 0, $justification = 'left return $v['text']; }, $parts)); - if (($justification == 'full' && ($orgWidth / 100 * 90) < ($orgWidth - $width)) || $justification != 'full'){ - $this->adjustWrapText($parsedText, $orgWidth - $width, $orgWidth, $x, $wordSpaceAdjust, $justification); - } + $this->adjustWrapText($parsedText, $orgWidth - $width, $orgWidth, $x, $wordSpaceAdjust, $justification); if ($test) { return $text; From b69c3a7574adead079cae5ee795134d252cec6f3 Mon Sep 17 00:00:00 2001 From: Miguel Martinez Date: Sun, 2 Jul 2023 17:52:25 +0200 Subject: [PATCH 5/5] Unfortunately current conditions were not covering all cases --- src/Cezpdf.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Cezpdf.php b/src/Cezpdf.php index 3f87472..51a7657 100644 --- a/src/Cezpdf.php +++ b/src/Cezpdf.php @@ -1721,7 +1721,7 @@ public function ezTable(&$data, $cols = '', $title = '', $options = '') if (isset($options['cols'][$colName]) && isset($options['cols'][$colName]['justification'])) { $just = $options['cols'][$colName]['justification']; - if ($just == 'full' && (empty($lines[$i + 1]) || count($lines) == $i + 1)) { + if ($just == 'full') { // do not fully justify if its the absolute last line (taking line breaks into account) $tmp = $this->addText($pos[$colName], $this->y, $options['fontSize'], $line, $maxWidth[$colName], $just, 0,0,1); if (!strlen($tmp)) { @@ -1977,7 +1977,7 @@ public function ezText($text, $size = 0, $options = [], $test = 0) $right = $this->ez['pageWidth'] - $this->ez['rightMargin'] - ((is_array($options) && isset($options['right'])) ? $options['right'] : 0); } - if ($just == 'full' && (empty($lines[$i + 1]) || $c == $i + 1)) { + if ($just == 'full') { // do not fully justify if its the absolute last line (taking line breaks into account) $tmp = $this->addText($left, $this->y, $size, $line, $right - $left, $just, 0, 0, 1); if (!strlen($tmp)) {