8 votes

comment utiliser imagick annotateImage pour un texte en chinois ?

J'ai besoin d'annoter une image avec du texte chinois et j'utilise actuellement la bibliothèque Imagick.

Un exemple de texte chinois est

Le fichier de la police chinoise utilisé est este

Le fichier original est nommé .ttf

il peut également être trouvé dans Mac OSX sous /Bibliothèque/Fontes

Je l'ai renommé en anglais STHeiTi.ttf pour faciliter l'appel du fichier dans le code php.

En particulier el Imagick::annotateImage fonction

Je suis aussi en utilisant la réponse de "Comment puis-je dessiner du texte enveloppé en utilisant Imagick en PHP ?" .

La raison pour laquelle je l'utilise est qu'il est efficace pour le texte anglais et que l'application doit annoter à la fois l'anglais et le chinois, mais pas en même temps.

Le problème est que lorsque je lance l'annotation de l'image en utilisant du texte chinois, j'obtiens une annotation qui ressemble à 罍

Code inclus aquí

7voto

Walter Tross Points 3559

Le problème est que vous fournissez à imagemagick la sortie d'un "séparateur de ligne" ( wordWrapAnnotation ), à laquelle vous êtes utf8_decode la saisie du texte. C'est certainement une erreur, si vous avez affaire à du texte chinois. utf8_decode ne peut traiter que du texte UTF-8 qui PEUT être converti en ISO-8859-1 (l'extension 8 bits la plus courante de l'ASCII).

Maintenant, j'espère que votre texte est UTF-8 encodé. S'il ne l'est pas, vous pouvez peut-être le convertir comme suit :

$text = mb_convert_encoding($text, 'UTF-8', 'BIG-5');

ou comme ceci

$text = mb_convert_encoding($text, 'UTF-8', 'GB18030'); // only PHP >= 5.4.0

(dans votre code $text est plutôt $text1 y $text2 ).

Il y a alors (au moins) deux choses à corriger dans votre code :

  1. transmettre le texte "tel quel" (sans utf8_decode ) à wordWrapAnnotation ,
  2. changer l'argument de setTextEncoding de "utf-8" à "UTF-8" selon Spécifications

J'espère que toutes les variables de votre code sont initialisées dans une partie manquante de celui-ci. Avec les deux changements ci-dessus (le second pourrait ne pas être nécessaire, mais on ne sait jamais...), et avec les parties manquantes en place, je ne vois aucune raison pour laquelle votre code ne devrait pas fonctionner, à moins que votre fichier TTF ne soit cassé ou que la fonction Imagick est cassé ( imagemagick sur lequel Imagick est basé, est une grande bibliothèque, donc je considère cette dernière possibilité plutôt improbable).

EDITAR:

Suite à votre demande, je mets à jour ma réponse avec

a) le fait que la mise mb_internal_encoding('utf-8') est très important pour la solution, comme vous le dites dans votre réponse et

b) ma proposition pour un meilleur séparateur de ligne, qui fonctionne de manière acceptable pour les langues occidentales et pour le chinois, et qui est probablement un bon point de départ pour les autres langues utilisant les logogrammes Han (kanji japonais et hanja coréen) :

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

En d'autres termes : l'entrée est d'abord nettoyée en remplaçant tous les espaces, y compris les nouvelles lignes, par un espace unique, à l'exception des espaces de tête et de queue, qui sont supprimés. Ensuite, elle est coupée soit aux espaces, soit juste avant les caractères Han qui ne sont pas précédés de caractères "de tête" (comme les parenthèses ouvrantes ou les guillemets ouvrants), soit juste avant les caractères "de tête". Les lignes sont assemblées de manière à ne pas être rendues en plus d'une ligne. $maxWidth pixels horizontalement, sauf lorsque les règles de fractionnement ne le permettent pas (dans ce cas, le rendu final débordera probablement). Une modification visant à forcer le fractionnement dans les cas de débordement n'est pas difficile. Notez que, par exemple, la ponctuation chinoise n'est pas classée comme Han dans Unicode, de sorte que, à l'exception de la ponctuation "de tête", aucun saut de ligne ne peut être inséré avant elle par l'algorithme.

3voto

Jack Points 88446

Je crains que vous ne deviez choisir un TTF capable de prendre en charge les points de code chinois. Il existe de nombreuses sources pour cela, en voici deux :

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

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

3voto

Kim Stacks Points 1269

Solution complète ici :

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

Les idées clés :

Il faut définir le charset html et l'encodage interne sur le formulaire et sur la page de traitement.

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

Ces lignes doivent se trouver en haut des fichiers php.

Utilisez cette fonction pour déterminer si le texte est chinois et utiliser le bon fichier de police.

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

Pour plus de détails, consultez https://stackoverflow.com/a/11219301/80353

Définir correctement le TextEncoding dans l'objet ImagickDraw

$draw = new ImagickDraw();

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

Notez l'UTF en majuscules. Ceci m'a été utilement signalé par Walter Tross dans sa réponse ici : https://stackoverflow.com/a/11207521/80353

Utilisez preg_match_all pour exploser les mots anglais, les mots chinois et les espaces.

// separate the text by chinese characters or words or spaces
preg_match_all('/([\w]+)|(.)/u', $text, $matches);
$words = $matches[0];

Inspiré par cette réponse https://stackoverflow.com/a/4113903/80353

Fonctionne aussi bien pour le texte anglais

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X