Php 使用imagettftext()时,如何处理字体文件不支持的字符?

Php 使用imagettftext()时,如何处理字体文件不支持的字符?,php,utf-8,fonts,gd,imagettftext,Php,Utf 8,Fonts,Gd,Imagettftext,我在PHP GD库创建的图像中使用Verdana字体 imagettftext($image, $fontSize, 0, 70, $y, $color, $font, $username ); 大多数情况下,imagettftext对字符串非常有效。 但是我的一些用户在他们的名字中使用了奇怪的字符/符号。 所以当我试着把他们的名字印在图片上。例如: 此用户使用 符号。所以Verdana无法打印它们 我用了这个: $username=iconv('UTF-8', 'ASCII//TRANSL

我在PHP GD库创建的图像中使用Verdana字体

imagettftext($image, $fontSize, 0, 70, $y, $color, $font, $username );
大多数情况下,imagettftext对字符串非常有效。
但是我的一些用户在他们的名字中使用了奇怪的字符/符号。
所以当我试着把他们的名字印在图片上。例如:

此用户使用

符号。所以Verdana无法打印它们

我用了这个:

$username=iconv('UTF-8', 'ASCII//TRANSLIT', $username);
输出如下:

(当前语言环境在英语和德语之间发生变化。因此,可能当前语言环境无法处理以下字符:

似乎不可能将
ɦ
音译为
h
ɲ
音译为
n
而不编写一个非常大的
strɦu replace()
块。喜欢

  • 所以我想知道是否有可能检查字体(Verdana)是否能显示这些符号。如果其中一个字符不能显示在字符串中,那么我可以将一个空字符串传递给
    imagettftext
    方法。我可以检查字体中支持的字符吗?或者创建包含Verdana支持的符号的字符映射,并检查我的字符串是否包含不支持的符号?
    (我认为这是不可能的,因为)

  • 或者另一种解决方案,是否可以在
    imagettftext()
    中使用多种字体?
    例如,首先尝试Verdana,如果Verdana没有涵盖符号使用Arial sans serif等

  • 还是其他解决方案

编辑:
Verdana似乎不支持我文本中的这些unicode字符。
Verdana支持的字符:

Verdana未移植字符:

您是否设置了正确的区域设置?对于iconv,可能是必需的-

我的第一选择是切换到支持您希望能够处理的全部字符范围的字体。但不要指望一种字体就可以实现这个功能

现在,如果您想采用(lazy;)音译路线,我将参考:

  • PHP>=5.4:使用新的内置类
  • PHP<5.4:使用
我现在手头上没有v5.4版本,所以我无法说出
音译器
,但凯末尔·达ğ的
jTranslationPort
性能相当好:

<?php
    require 'transliteration/JTransliteration.php';

    $input = 'ɦɪɲɣƙƨєʌɾ';
    echo JTransliteration::transliterate($input); // output: hIngk2ie^r

    $input = 'Хეλлఒ Wओრলद';
    echo JTransliteration::transliterate($input);

您所描述的问题有多个地方可能会失败,对于您来说,首先要了解哪些地方对如何最好地解决这个问题做出正确的决定很重要

因为很多事情都可能出错,所以您需要尽早失败,以防输入不符合预期。因此,首先,在调用该函数之前,必须验证字符串的编码是否正确,以便与
imagettftext()
一起使用:

if (!preg_match('//u', $username)) {
    throw new Exception(
        sprintf(
            "Username string %s can not be used with imagettftext()"
            , var_export($username, true)
        )
    );
}
如果不这样做,首先就不会得到正确的结果。如果该检查失败,通过该检查的解决方案是确保字符串是UTF-8编码的。这或多或少是一个健全的检查,因为您说字符串已经是UTF-8编码的,所以它应该已经通过了。但是,为了防止您在编码时出错,并且编码无效(很容易发生),此检查可防止您查找错误的位置

正如您在问题中输入的输出所显示的,您很可能在编码方面出错,因为否则支持的字符至少会正确显示,但不仅会遗漏一些字符,甚至会显示不同的字符。错误编码的明确标志:

因此,不要跳过此步骤来实际验证字符串所需的编码

这对于下一件事尤为重要:

您需要确保fontface支持该字符串中的字母。Verdana字体支持794个Unicode字符()。如果您要查找的字符不是其中的一部分,则
imagettftext()
函数无法显示这些字符,因为字体缺少这些字符。在这种情况下,您需要选择一种支持您正在寻找的Unicode字符的字体。Wikipedia上提供了不同字体的概览表:

有关正确字体选择的更多指导,请参见Stackoverflow:

如果您在字符串变量中使用正确的编码,并且字体具有该字符串中编码的所有Unicode字符的字形,
imagettftext
确实满足您的需要


正如我在一开始所写的,有很多地方可能出错:如果您通过了编码检查,字体已经支持所有字符,那么还有一个地方会失败:字符串是UTF-8编码的,但它不包含您认为的字符。

只要您使用UTF-8,UTF-8 True Type字体没有理由显示这些字母(东亚字母免责声明!)

下面是我的简单示例,使用true type字体:

// utf-8 text
$text   = 'ɦɪɲɣƙƨєʌɾ';

// if text read from a file (for example)
// and the default locale (for most of western countries)
// is ISO-8859-1, you can simly convert it to
// utf-8 using:

//$text = utf8_encode($text);

$png    = imagecreatefrompng('/tmp/sample.png');
$color  = imagecolorallocate($png, 0, 0, 0);

// True type font that support UTF-8!!!!
$font   = '/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf';

imagettftext($png, 50, 0, 50, 50, $color, $font, $text);
imagepng($png, '/tmp/test.png');
结果是:


我编辑了标题和标签,如果您不喜欢,可以随意更改。您是否100%确定传入的数据是UTF-8?因为如果不是,iconv()就无法为您音译字符。您必须确保在第一个参数中指定了正确的编码。(也就是说,我不确定
ɦ
是否应该首先音译为
h
,所以这可能是预期的结果。)我确定UTF8。即使没有iconv,最好知道Verdana是否可以打印它。所以,如果字体不合适,我可以打印一个虚拟单词。当前的语言环境是英语或德语。我无法预测
在哪个地区存在。所以我认为在这种情况下不可能使用iconv。我还检查了dejavu。看起来dejavu支持这些奇怪的角色。大多数用户名都可以用Dejavu显示。但我不想失去Verdana。。。当我检查字符串时,我总是看到它是UTF8编码的。我正在考虑一个复合解决方案,它将使用Verdana实现安全的c
// utf-8 text
$text   = 'ɦɪɲɣƙƨєʌɾ';

// if text read from a file (for example)
// and the default locale (for most of western countries)
// is ISO-8859-1, you can simly convert it to
// utf-8 using:

//$text = utf8_encode($text);

$png    = imagecreatefrompng('/tmp/sample.png');
$color  = imagecolorallocate($png, 0, 0, 0);

// True type font that support UTF-8!!!!
$font   = '/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf';

imagettftext($png, 50, 0, 50, 50, $color, $font, $text);
imagepng($png, '/tmp/test.png');