Мне нужно аннотировать изображение с помощью китайского текста, и я использую библиотеку Imagick прямо сейчас.
Примером китайского текста является
这 是 中文
Используемый китайский файл шрифтов
Файл изначально называется 华文 黑体 .ttf
его также можно найти в Mac OSX в разделе / Library / Font
Я переименовал его на английский STHeiTi.ttf, чтобы было проще вызвать файл в php-коде.
В частности, функция Imagick::annotateImage
Я также использую ответ из «Как я могу нарисовать завернутый текст с помощью Imagick в PHP?» ,
Причина, по которой я его использую, заключается в том, что для английского текста и приложения для успеха требуется аннотация как английского, так и китайского, хотя и не в одно и то же время.
Проблема в том, что когда я запускаю annotateImage с использованием китайского текста, я получаю аннотацию, которая выглядит как 罍
Включенный код
Проблема в том, что вы utf8_decode
вывод «разделителя строк» ( wordWrapAnnotation
), к которому вы используете utf8_decode
ввода текста. Это неверно, если вы имеете дело с китайским текстом. utf8_decode
может utf8_decode
только текст UTF-8, который может быть преобразован в ISO-8859-1 (наиболее распространенное 8-битное расширение ASCII).
Теперь я надеюсь, что вы кодируете текст UTF-8 . Если это не так, вы можете преобразовать его следующим образом:
$text = mb_convert_encoding($text, 'UTF-8', 'BIG-5');
или как это
$text = mb_convert_encoding($text, 'UTF-8', 'GB18030'); // only PHP >= 5.4.0
(в вашем коде $text
скорее $text1
и $text2
).
Тогда в вашем коде есть (по крайней мере) две вещи:
utf8_decode
) в wordWrapAnnotation
, setTextEncoding
с "utf-8"
на "UTF-8"
согласно спецификациям Я надеюсь, что все переменные в вашем коде инициализируются в какой-то пропавшей части. С этими двумя изменениями выше (второй может быть не нужен, но вы никогда не знаете …), и с отсутствующими частями на месте, я не вижу причин, по которым ваш код не должен работать, если ваш файл TTF не сломан или Библиотека Imagick
сломана ( imagemagick
, на котором основан Imagick
, – отличная библиотека, поэтому я считаю эту последнюю возможность весьма маловероятной).
РЕДАКТИРОВАТЬ:
Следуя вашему запросу, я обновляю свой ответ с помощью
а) тот факт, что установка mb_internal_encoding('utf-8')
очень важна для решения, как вы говорите в своем ответе , и
б) мое предложение о лучшем разветвителе линии, которое подходит для западных языков и для китайцев, и это, вероятно, хорошая отправная точка для других языков с использованием логограмм Хан (японский иероглиф и корейский ханджа):
function wordWrapAnnotation(&$image, &$draw, $text, $maxWidth) { $regex = '/( |(?=\p{Han})(?<!\p{Pi})(?<!\p{Ps})|(?=\p{Pi})|(?=\p{Ps}))/u'; $cleanText = trim(preg_replace('/[\s\v]+/', ' ', $text)); $strArr = preg_split($regex, $cleanText, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); $linesArr = array(); $lineHeight = 0; $goodLine = ''; $spacePending = false; foreach ($strArr as $str) { if ($str == ' ') { $spacePending = true; } else { if ($spacePending) { $spacePending = false; $line = $goodLine.' '.$str; } else { $line = $goodLine.$str; } $metrics = $image->queryFontMetrics($draw, $line); if ($metrics['textWidth'] > $maxWidth) { if ($goodLine != '') { $linesArr[] = $goodLine; } $goodLine = $str; } else { $goodLine = $line; } if ($metrics['textHeight'] > $lineHeight) { $lineHeight = $metrics['textHeight']; } } } if ($goodLine != '') { $linesArr[] = $goodLine; } return array($linesArr, $lineHeight); }
В словах: вход сначала очищается, заменяя все пробелы пробелами, включая строки новой строки, одним пробелом, за исключением ведущего и конечного пробелов, который удаляется. Затем он разбивается либо в пространствах, либо непосредственно перед символами Хана, которым не предшествуют «ведущие» символы (например, открывающие круглые скобки или открывающие кавычки) или прямо перед «ведущими» символами. Строки собраны для того, чтобы они не отображались более чем в $maxWidth
пикселей по горизонтали, за исключением случаев, когда это невозможно по правилам разделения (в этом случае окончательный рендеринг, вероятно, будет переполняться). Модификация для принудительного расщепления в случаях переполнения не составляет труда. Обратите внимание, что, например, китайская пунктуация не классифицируется как Хан в Юникоде, так что, за исключением «ведущей» пунктуации, до нее не может быть вставлен алгоритм.
Боюсь, вам придется выбирать TTF, который может поддерживать китайские кодовые точки. Для этого есть много источников, вот два:
Полное решение здесь:
https://gist.github.com/2971092/232adc3ebfc4b45f0e6e8bb5934308d9051450a4
Ключевые идеи:
Должен задавать кодировку html и внутреннюю кодировку в форме и на странице обработки
header('Content-Type: text/html; charset=utf-8'); mb_internal_encoding('utf-8');
Эти строки должны быть в верхних строках php-файлов.
Используйте эту функцию, чтобы определить, является ли текст китайским и использовать правильный файл шрифта
function isThisChineseText($text) { return preg_match("/\p{Han}+/u", $text); }
Для получения дополнительной информации посетите https://stackoverflow.com/a/11219301/80353
Правильно установите TextEncoding в объекте ImagickDraw
$draw = new ImagickDraw(); // set utf 8 format $draw->setTextEncoding('UTF-8');
Обратите внимание на обобщенную UTF. Это было полезно мне упомянуто Уолтером Троссом в его ответе здесь: https://stackoverflow.com/a/11207521/80353
Используйте preg_match_all, чтобы взорвать английские слова, китайские слова и пробелы
// separate the text by chinese characters or words or spaces preg_match_all('/([\w]+)|(.)/u', $text, $matches); $words = $matches[0];
Вдохновленный этим ответом https://stackoverflow.com/a/4113903/80353
Работает так же хорошо для английского текста