Как использовать Imagick annotateImage для китайского текста?

Мне нужно аннотировать изображение с помощью китайского текста, и я сейчас использую библиотеку Imagick.

Пример китайского текста:

& # X8FD9; & # x662F; & # x4E2D; & # x6587;

Файл китайского шрифта используетсяэтот

Файл изначально называется & # x534E; & # x6587; & # x9ED1; & # x4F53; .ttf

его также можно найти в Mac OSX в / Library / Font

Я переименовал его в английский STHeiTi.ttf, чтобы облегчить вызов файла в коде php.

ОсобенноImagick::annotateImage function

Я тожеиспользуя ответ от"How can I draw wrapped text using Imagick in PHP?".

Причина, по которой я его использую, заключается в том, что он успешен для английского текста, и приложение должно аннотировать английский и китайский, но не одновременно.

Проблема в том, что когда я запускаю annotateImage с использованием текста на китайском языке, я получаю аннотацию, которая выглядит как & # x7F4D;

Код включенВот

 Kim Stacks19 июн. 2012 г., 15:14
Как мне это сделать?
 Kim Stacks20 июн. 2012 г., 07:33
Ваша точка зрения о кодировании привела меня к этому ответу.stackoverflow.com/a/10546631/80353 Я собираюсь дать этому шанс.
 hakre19 июн. 2012 г., 15:04
Китайский текст? Как насчет создания графического изображения китайских символов, а затем слияния его с изображением?
 hakre19 июн. 2012 г., 15:16
Ну, для каждого китайского символа создайте одно изображение, которое отображает его. Затем соедините эти изображения, например. Возможно, это не лучший метод, но он может избавить вас от проблемы, связанной с использованием какого-либо китайского шрифта.
 Salman A22 июн. 2012 г., 10:22
@kimsia: используяexplode на utf8 кодированные данные, вероятно, нарушат кодировку.

Ответы на вопрос(3)

вам придется выбрать TTF, который может поддерживать китайские кодовые точки. Есть много источников для этого, вот два:

http://www.wazu.jp/gallery/Fonts_ChineseTraditional.html

http://wildboar.net/multilingual/asian/chinese/language/fonts/unicode/non-microsoft/non-microsoft.html

 26 июн. 2012 г., 23:29
@kimsia: илиUnicode в википедии
 27 июн. 2012 г., 03:14
@waltertross hmm op, должно быть, обновил свой вопрос: - / рассмотрим позже
 26 июн. 2012 г., 23:33
Джек, почему ты считаешь, что TTF kimsia не поддерживает китайские кодовые точки? Кстати, ваша первая ссылка о традиционном китайском, в то время как kimsia использует упрощенный китайский.
 Kim Stacks22 июн. 2012 г., 18:23
Что вы подразумеваете под кодовыми точками?
 22 июн. 2012 г., 23:52
Решение Вопроса

https://gist.github.com/2971092/232adc3ebfc4b45f0e6e8bb5934308d905,1450a4

Ключевые идеи:

Must set the html charset and internal encoding on the form and on the processing page

header('Content-Type: text/html; charset=utf-8');
mb_internal_encoding('utf-8');

Эти строки должны быть в верхних строках файлов php.

Use this function to determine if text is Chinese and use the right font file

function isThisChineseText($text) {
    return preg_match("/\p{Han}+/u", $text);
}

Для более подробной информации проверьтеhttps://stackoverflow.com/a/11219301/80353

Set TextEncoding properly in ImagickDraw object

$draw = new ImagickDraw();

// set utf 8 format
$draw->setTextEncoding('UTF-8');

Обратите внимание на заглавные UTF. Это было любезно указано мнеУолтер Тросс в своем ответе здесь:https://stackoverflow.com/a/11207521/80353

Use preg_match_all to explode English words, Chinese Words and spaces

// 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

Работает так же хорошо для английского текста

 28 июн. 2012 г., 00:27
Хорошо, теперь я вижу, что такое "причуды" китайской письменности: вообще нет пробелов между словами. Один из способов разбить на «слова» для ваших целей может быть что-то вроде:preg_split("/((?<= )|(?=\p{Han})(?=\pL))/u", $str, -1, PREG_SPLIT_NO_EMPTY)который "режет" строка после пробелов или до буквы «Хан» (слова, фактически), но завершающие пробелы должны обрабатываться отдельно (вынимаются и добавляются обратно, только если не происходит разделение строк). Примечание: после пробела?<=.
 28 июн. 2012 г., 01:04
Приведенное выше регулярное выражение должно быть расширено, чтобы некоторые символы не заканчивались строкой (эти символы эквивалентны западным символам, которым обычно предшествует пробел, например открывающие скобки или открывающие кавычки - например, см.here)
 28 июн. 2012 г., 08:26
Я написал предыдущее регулярное выражение, которое я удалил, заменив его тем, которое вы упомянули, именно потому, что оно "сгорело". пространства. Я не пробовал этот последний, но он не должен ничего есть, так как это просто альтернатива взгляду назад.assertion и два прогнозных утверждения, без совпадающих символов.
 Kim Stacks28 июн. 2012 г., 02:28
@WalterTross Мне жаль, что я не смог принять ваш ответ. Ваш ответ был последним ключом, который мне нужен, чтобы разгадать тайну. Разбиение текста на две отдельные строки оказывается частью требований, поэтому я согласен с этим. Я попробую ваш предыдущий комментарий об использовании preg_split (& quot; / ((? & Lt; =) | (? = \ P {Han}) (? = \ PL)) / u & quot ;, $ str, -1, PREG_SPLIT_NO_EMPTY). Однако Я заметил, что это регулярное выражение удаляет пробелы. Мне нужны пробелы для английского текста, так как функция wordWrapAnnotation должна работать как для английского, так и для китайского языков для более короткого кода. Но тем не менее я дам этому шанс.
 27 июн. 2012 г., 09:42
Последнее регулярное выражение разделит строку «UTF-8». на 3 отдельных "слова". Ваше исправление wordWrapAnnotation является неправильным, в том числе и потому, что теперь он может возвращать пробел или пунктуацию в начале второй строки.explode(' ', ...) было правильно, если только не было какой-то особенности китайского письма, о котором я не знаю. Я также думаю, что вы могли бы принять мое решение, так как вы использовали два исправления кода, которые оно содержит. Это правда, что вы добавили информацию, но это могло произойти в комментариях (и я мог бы также отредактировать свое решение).

что вы используете imagemagick для вывода «разделителя строк»; (wordWrapAnnotation), к которой вы относитесь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).

Тогда есть (по крайней мере) две вещи, которые нужно исправить в вашем коде:

pass the text "as is" (without utf8_decode) to wordWrapAnnotation, change the argument of setTextEncoding from "utf-8" to "UTF-8" as per specs

Я надеюсь, что все переменные в вашем коде инициализируются в какой-то недостающей его части. С этими двумя изменениями (второе может быть необязательным, но вы никогда не знаете ...) и с отсутствующими частями на месте, я не вижу причин, почему ваш код не должен работать, если ваш файл TTF не поврежден илиImagick библиотека сломана (imagemagick, на которомImagick основана, является отличной библиотекой, поэтому я считаю, что эта последняя возможность довольно маловероятна).

EDIT:

По вашему запросу я обновляю свой ответ

а) тот факт, что установка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);
}

Другими словами: ввод сначала очищается путем замены всех пробелов, включая новые строки, одним пробелом, за исключением пробелов, идущих вперед и назад, которые удаляются. Затем он разделяется либо на пробелы, либо непосредственно перед символами ханьского алфавита, которым не предшествует «ведущий». символы (например, открывающие скобки или открывающие кавычки) или непосредственно перед "quot; ведущим" quot; персонажи. Линии собраны, чтобы не отображаться более чем$maxWidth пикселей по горизонтали, за исключением случаев, когда это невозможно по правилам разделения (в этом случае окончательный рендеринг, вероятно, будет переполнен). Модификация с целью принудительного расщепления в случаях переполнения не является сложной. Обратите внимание, что, например, китайская пунктуация не классифицируется как Хань в Юникоде, так что, за исключением «ведущего» пунктуация, перед ней не может быть вставлен перенос строки алгоритмом.

 26 июн. 2012 г., 14:56
Это наиболее вероятная причина неправильного кодирования.
 Kim Stacks27 июн. 2012 г., 06:28
Привет Уолтер, твой ответ помог мне прийти к окончательному решению. Хочу поблагодарить вас за вашу помощь.
 Kim Stacks28 июн. 2012 г., 11:33
Позвольте мне вручить вам награду в знак благодарности. Вы действительно помогли мне с вашим ответом.
 Kim Stacks27 июн. 2012 г., 06:30
Кстати, я не использовал решение mb_convert_encoding.
 28 июн. 2012 г., 12:11
@ kimsia: это очень мило с вашей стороны! Когда я найду время, которое я хотел бы исправить разделением строки, чтобы она работала определенно как для английского, так и для китайского (и, возможно, для других без пробелов языков ...).

Ваш ответ на вопрос