8

中国語のテキストで画像に注釈を付ける必要があり、現在 Imagick ライブラリを使用しています。

中国語のテキストの例は次のとおりです。

これは中文です

使用した中国語フォントファイルはこちら

ファイルはもともと华文黑体.ttfという名前です

Mac OSX の /Library/Font にもあります。

PHPコードでファイルを呼び出しやすくするために、英語のSTHEiTi.ttfに名前を変更しました。

特に機能_Imagick::annotateImage

また、 「PHP で Imagick を使用してラップされたテキストを描画するにはどうすればよいですか?」の回答も使用しています。.

私がこれを使用している理由は、英語のテキストで成功し、同時にではありませんが、アプリケーションで英語と中国語の両方に注釈を付ける必要があるためです。

問題は、中国語のテキストを使用して annotateImage を実行すると、罍のような注釈が表示されることです。

ここに含まれるコード

4

3 に答える 3

7

問題は、テキスト入力を行っている「ラインスプリッター」( wordWrapAnnotation)の出力をimagemagickに供給していることです。utf8_decode中国語のテキストを扱っている場合、これは確かに間違っています。utf8_decodeISO-8859-1 (ASCII の最も一般的な 8 ビット拡張) に変換できる UTF-8 テキストのみを処理できます。

さて、あなたのテキストが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ではむしろ$text1and$text2です)。

次に、コードで修正する必要がある (少なくとも) 2 つの点があります。

  1. テキストを「そのまま」(なしでutf8_decode) にwordWrapAnnotation渡します。
  2. 仕様 に従ってsetTextEncodingfromの引数を"utf-8"to に変更します"UTF-8"

コード内のすべての変数が、欠落している部分で初期化されることを願っています。上記の 2 つの変更 (2 番目の変更は必要ないかもしれませんが、わかりません...) と、欠落している部分があるため、TTF ファイルが壊れているか、Imagickライブラリが壊れています (imagemagickImagick基づいている は優れたライブラリであるため、この最後の可能性はかなり低いと思います)。

編集:

あなたのリクエストに続いて、私は私の答えを次のように更新します

a)mb_internal_encoding('utf-8')あなたの答えで言うように、設定はソリューションにとって非常に重要であるという事実、および

b) 西洋言語と中国語で問題なく機能する、より優れたライン スプリッターに関する私の提案です。これは、おそらく、漢語の表意文字 (日本語の漢字と韓国語の漢字) を使用する他の言語の出発​​点として適しています。

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。ただし、分割規則によってこれが不可能な場合を除きます (この場合、最終的なレンダリングはおそらくオーバーフローします)。オーバーフローの場合に強制的に分割するための変更は難しくありません。たとえば、中国語の句読点は Unicode では漢語として分類されないため、「先頭の」句読点を除いて、

于 2012-06-26T12:38:52.317 に答える
3

中国語のコードポイントをサポートできるTTFを選択する必要があります。これには多くの情報源があります。ここに2つあります。

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

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

于 2012-06-22T13:38:28.480 に答える
3

ここで完全なソリューション:

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をご覧ください。

ImagickDraw オブジェクトで TextEncoding を適切に設定する

$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

英語のテキストでも同様に機能します

于 2012-06-27T04:28:17.737 に答える