@@ -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 ) {
0 commit comments