如何使用imagick annotateImage中文文本?

时间:2012-06-19 13:02:55

标签: php image imagick annotate

我需要使用中文文本注释图像,我现在正在使用Imagick库。

中文文本的一个例子是

这是中文

使用的中文字体文件为this

该文件最初名为华文黑体.ttf

它也可以在Mac OSX的/ Library / Font

下找到

我已将其重命名为英语STHeiTi.ttf,可以更轻松地在php代码中调用该文件。

特别是the Imagick::annotateImage function

我也是using the answer from "How can I draw wrapped text using Imagick in PHP?"

我使用它的原因是因为英语文本和应用程序的成功需要注释英文和中文,但不是同时注释。

问题是当我使用中文文本运行annotateImage时,我得到的注释看起来像罍

代码包括here

3 个答案:

答案 0 :(得分:6)

问题是你正在向imagemagick提供“行分割器”(wordWrapAnnotation)的输出,你要utf8_decode输入文本。如果您正在处理中文文本,这肯定是错误的。 utf8_decode只能处理可以转换为ISO-8859-1(最常见的8位ASCII扩展名)的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更像是$text1$text2)。

然后在您的代码中至少要修复两件事:

  1. 将文字“原样”(不含utf8_decode)传递给wordWrapAnnotation
  2. setTextEncoding的参数从"utf-8"更改为"UTF-8" 根据{{​​3}}
  3. 我希望代码中的所有变量都在其中缺少部分进行初始化。通过上面的两个更改(第二个可能没有必要,但你永远不知道......),并且缺少部分,我认为没有理由为什么你的代码不能工作,除非你的TTF文件被破坏或者Imagick库已损坏imagemagickImagick所基于的库是一个很棒的库,所以我认为最后一种可能性很小。)

    修改

    根据您的要求,我用

    更新我的回答

    a)设置mb_internal_encoding('utf-8')对解决方案非常重要,正如您在specs中所说的那样,

    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);
    }
    

    用文字表示:首先通过用一个空格替换所有空格(包括换行符)来清理输入,除了前导和尾随空格(删除)。然后它在空格处分开,或者在Han字符前面没有“前导”字符(例如打开括号或打开引号)之前,或者在“前导”字符之前。组合线是为了不在水平方向上以$maxWidth像素呈现,除非分割规则不可能(在这种情况下,最终渲染可能会溢出)。为了在溢出情况下强制分裂的修改并不困难。请注意,例如,中文标点符号在Unicode中未被归类为汉字,因此除了“前导”标点符号外,算法之前不能插入换行符。

答案 1 :(得分:3)

答案 2 :(得分:2)

完全解决方案:

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。 Walter Tross在答案中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

同样适用于英文文本