Skip to content
Merged
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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 86 additions & 1 deletion lib/Service/SignatureTextService.php
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ public function signerNameImage(
$draw->setTextAlignment($align);

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

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

/**
* Multibyte-safe version of wordwrap
*
* @param string $text The text to wrap
* @param int $width The number of characters at which the string will be wrapped
* @param string $break The line break character
* @param bool $cut If true, words longer than $width will be broken
* @return string The wrapped text
*/
private function mbWordwrap(string $text, int $width, string $break = "\n", bool $cut = false): string {
if ($width <= 0) {
return $text;
}

$lines = [];
$currentLine = '';
$currentLength = 0;

$paragraphs = explode("\n", $text);

foreach ($paragraphs as $paragraphIndex => $paragraph) {
if ($paragraph === '') {
if ($currentLength > 0) {
$lines[] = $currentLine;
$currentLine = '';
$currentLength = 0;
}
$lines[] = '';
continue;
}

$words = explode(' ', $paragraph);

foreach ($words as $word) {
$wordLength = mb_strlen($word);

if ($cut && $wordLength > $width) {
if ($currentLength > 0) {
$lines[] = $currentLine;
$currentLine = '';
$currentLength = 0;
}

while ($wordLength > $width) {
$lines[] = mb_substr($word, 0, $width);
$word = mb_substr($word, $width);
$wordLength = mb_strlen($word);
}

if ($wordLength > 0) {
$currentLine = $word;
$currentLength = $wordLength;
}
continue;
}

$spaceLength = ($currentLength > 0) ? 1 : 0;
if ($currentLength + $spaceLength + $wordLength > $width && $currentLength > 0) {
$lines[] = $currentLine;
$currentLine = $word;
$currentLength = $wordLength;
} else {
if ($currentLength > 0) {
$currentLine .= ' ';
$currentLength++;
}
$currentLine .= $word;
$currentLength += $wordLength;
}
}

if ($currentLength > 0 && $paragraphIndex < count($paragraphs) - 1) {
$lines[] = $currentLine;
$currentLine = '';
$currentLength = 0;
}
}

if ($currentLength > 0) {
$lines[] = $currentLine;
}

return implode($break, $lines);
}

public function getDefaultTemplate(): string {
$collectMetadata = $this->appConfig->getValueBool(Application::APP_ID, 'collect_metadata', false);
if ($collectMetadata) {
Expand Down
5 changes: 5 additions & 0 deletions tests/php/Unit/Service/SignatureTextServiceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,11 @@ public static function providerSignerNameImage(): array {
'center 175x50 scale 2.5' => ['Secure ✔️', 175, 50, 'center', 2.5],
'left 175x50 scale 3' => ['Sign now', 175, 50, 'left',3],
'right 175x50 scale 4' => ['Signed 🔐', 175, 50, 'right', 4],

// Portuguese text with accents
'center 175x101 portuguese' => ['Imagem da assinatura aqui', 175, 101, 'center', 5],
'right 175x101 portuguese' => ['Imagem da assinatura aqui', 175, 101, 'right', 5],
'left 350x100 portuguese long' => ['Assinado com LibreSign administrador', 350, 100, 'left', 5],
];
}

Expand Down
Loading