如何使用imagick annotateImage中文文本?

Kim*_*cks 7 php image annotate imagick

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

中文文本的一个例子是

这是中文

使用的中文字体文件是这个

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

它也可以在Mac OSX的/ Library/Font下找到

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

特别Imagick::annotateImage功能

我也在使用"如何在PHP中使用Imagick绘制包装文本?"的答案..

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

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

代码包含在这里

Wal*_*oss 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');
Run Code Online (Sandbox Code Playgroud)

或者像这样

$text = mb_convert_encoding($text, 'UTF-8', 'GB18030'); // only PHP >= 5.4.0
Run Code Online (Sandbox Code Playgroud)

(在你的代码$text是相当$text1$text2).

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

  1. 将文本"原样"(没有utf8_decode)传递给wordWrapAnnotation,
  2. 改变的参数setTextEncoding"utf-8""UTF-8"规格

我希望代码中的所有变量都在其中缺少的部分进行初始化.通过上面的两个更改(第二个可能没有必要,但你永远不知道......),并且缺少部分,我认为没有理由为什么你的代码不能工作,除非你的TTF文件被破坏或者Imagick库坏了(imagemagick上它Imagick是基础,是一个伟大的图书馆,所以我认为这是最后的可能性相当不可能的).

编辑:

根据您的要求,我更新了我的答案

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);
}
Run Code Online (Sandbox Code Playgroud)

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


Kim*_*cks 3

完整解决方案在这里:

https://gist.github.com/2971092/232adc3ebfc4b45f0e6e8bb5934308d9051450a4

主要想法:

必须在表单和处理页面上设置html字符集和内部编码

header('Content-Type: text/html; charset=utf-8');
mb_internal_encoding('utf-8');
Run Code Online (Sandbox Code Playgroud)

这些行必须位于 php 文件的顶行。

使用此功能确定文本是否为中文并使用正确的字体文件

function isThisChineseText($text) {
    return preg_match("/\p{Han}+/u", $text);
}
Run Code Online (Sandbox Code Playgroud)

有关更多详细信息,请查看/sf/answers/785351101/

在 ImagickDraw 对象中正确设置 TextEncoding

$draw = new ImagickDraw();

// set utf 8 format
$draw->setTextEncoding('UTF-8');
Run Code Online (Sandbox Code Playgroud)

请注意大写的 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];
Run Code Online (Sandbox Code Playgroud)

受到这个答案的启发/sf/answers/287973241/

适用于英文文本