Skip to content

Commit 4426ae0

Browse files
authored
Merge pull request #6076 from LibreSign/backport/6074/stable32
[stable32] fix: multibyte text wrapping
2 parents 341f257 + 1c9cde7 commit 4426ae0

2 files changed

Lines changed: 91 additions & 1 deletion

File tree

lib/Service/SignatureTextService.php

Lines changed: 86 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ public function signerNameImage(
230230
$draw->setTextAlignment($align);
231231

232232
$maxCharsPerLine = $this->splitAndGetLongestHalfLength($text);
233-
$wrappedText = wordwrap($text, $maxCharsPerLine, "\n", true);
233+
$wrappedText = $this->mbWordwrap($text, $maxCharsPerLine, "\n", true);
234234

235235
$textMetrics = $image->queryFontMetrics($draw, $wrappedText);
236236
$lineCount = substr_count($wrappedText, "\n") + 1;
@@ -300,6 +300,91 @@ private function splitAndGetLongestHalfLength(string $text): int {
300300
return !empty($results) ? max($results) : $length;
301301
}
302302

303+
/**
304+
* Multibyte-safe version of wordwrap
305+
*
306+
* @param string $text The text to wrap
307+
* @param int $width The number of characters at which the string will be wrapped
308+
* @param string $break The line break character
309+
* @param bool $cut If true, words longer than $width will be broken
310+
* @return string The wrapped text
311+
*/
312+
private function mbWordwrap(string $text, int $width, string $break = "\n", bool $cut = false): string {
313+
if ($width <= 0) {
314+
return $text;
315+
}
316+
317+
$lines = [];
318+
$currentLine = '';
319+
$currentLength = 0;
320+
321+
$paragraphs = explode("\n", $text);
322+
323+
foreach ($paragraphs as $paragraphIndex => $paragraph) {
324+
if ($paragraph === '') {
325+
if ($currentLength > 0) {
326+
$lines[] = $currentLine;
327+
$currentLine = '';
328+
$currentLength = 0;
329+
}
330+
$lines[] = '';
331+
continue;
332+
}
333+
334+
$words = explode(' ', $paragraph);
335+
336+
foreach ($words as $word) {
337+
$wordLength = mb_strlen($word);
338+
339+
if ($cut && $wordLength > $width) {
340+
if ($currentLength > 0) {
341+
$lines[] = $currentLine;
342+
$currentLine = '';
343+
$currentLength = 0;
344+
}
345+
346+
while ($wordLength > $width) {
347+
$lines[] = mb_substr($word, 0, $width);
348+
$word = mb_substr($word, $width);
349+
$wordLength = mb_strlen($word);
350+
}
351+
352+
if ($wordLength > 0) {
353+
$currentLine = $word;
354+
$currentLength = $wordLength;
355+
}
356+
continue;
357+
}
358+
359+
$spaceLength = ($currentLength > 0) ? 1 : 0;
360+
if ($currentLength + $spaceLength + $wordLength > $width && $currentLength > 0) {
361+
$lines[] = $currentLine;
362+
$currentLine = $word;
363+
$currentLength = $wordLength;
364+
} else {
365+
if ($currentLength > 0) {
366+
$currentLine .= ' ';
367+
$currentLength++;
368+
}
369+
$currentLine .= $word;
370+
$currentLength += $wordLength;
371+
}
372+
}
373+
374+
if ($currentLength > 0 && $paragraphIndex < count($paragraphs) - 1) {
375+
$lines[] = $currentLine;
376+
$currentLine = '';
377+
$currentLength = 0;
378+
}
379+
}
380+
381+
if ($currentLength > 0) {
382+
$lines[] = $currentLine;
383+
}
384+
385+
return implode($break, $lines);
386+
}
387+
303388
public function getDefaultTemplate(): string {
304389
$collectMetadata = $this->appConfig->getValueBool(Application::APP_ID, 'collect_metadata', false);
305390
if ($collectMetadata) {

tests/php/Unit/Service/SignatureTextServiceTest.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,11 @@ public static function providerSignerNameImage(): array {
203203
'center 175x50 scale 2.5' => ['Secure ✔️', 175, 50, 'center', 2.5],
204204
'left 175x50 scale 3' => ['Sign now', 175, 50, 'left',3],
205205
'right 175x50 scale 4' => ['Signed 🔐', 175, 50, 'right', 4],
206+
207+
// Portuguese text with accents
208+
'center 175x101 portuguese' => ['Imagem da assinatura aqui', 175, 101, 'center', 5],
209+
'right 175x101 portuguese' => ['Imagem da assinatura aqui', 175, 101, 'right', 5],
210+
'left 350x100 portuguese long' => ['Assinado com LibreSign administrador', 350, 100, 'left', 5],
206211
];
207212
}
208213

0 commit comments

Comments
 (0)