2012-06-19 18 views
7

Necesito anotar una imagen con texto chino y estoy usando la biblioteca Imagick en este momento.cómo usar imagick annotateImage para texto en chino?

Un ejemplo de un texto chino es

这 是 中文

el archivo de fuente china usada es this

El archivo original se llama 华文 黑体 .ttf

también puede ser encontrado en Mac OSX en/Librería/Fuente

Lo he cambiado a inglés STHeiTi.ttf hace que sea más fácil llamar a th e archivo en código php.

En particular the Imagick::annotateImage function

También estoy using the answer from "How can I draw wrapped text using Imagick in PHP?".

La razón por la que lo estoy usando es porque es exitoso para el texto en inglés y la aplicación necesita hacer anotaciones tanto en inglés como en chino, aunque no al mismo tiempo.

El problema es que cuando ejecuto el annotateImage utilizando texto chino, consigo anotación que se parece a 罍

Código incluido here

+1

texto en chino? ¿Qué hay de crear primero un gráfico de los símbolos chinos y luego combinarlo en la imagen? – hakre

+0

¿Cómo puedo hacer eso? –

+1

Bueno, para cada personaje chino, crea una imagen que lo muestre. Luego, junte estas imágenes, por ejemplo. Puede que no sea el mejor método, pero podría ahorrarte el problema de usar alguna fuente china. – hakre

Respuesta

2

solución completa aquí:

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

Ideas clave:

debe establecer el juego de caracteres HTML y codificación interna en la forma y en la página de procesamiento de

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

Estos las líneas deben estar en las líneas superiores de los archivos php.

Utilice esta función para determinar si el texto es chino y utilizar el archivo fuente correcta

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

Para más detalles echa un vistazo a https://stackoverflow.com/a/11219301/80353

Conjunto TextEncoding correctamente en el objeto ImagickDraw

$draw = new ImagickDraw(); 

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

Tenga en cuenta la U en mayúscula TF. Este fue amablemente me señaló por Walter Tross en su respuesta aquí: https://stackoverflow.com/a/11207521/80353

Uso preg_match_all a explotar las palabras en inglés, chino palabras y espacios

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

Inspirado por esta respuesta https://stackoverflow.com/a/4113903/80353

funciona igual también para el texto en inglés

+1

La última expresión regular dividirá la cadena "UTF-8" en 3 "palabras" separadas. Su solución de wordWrapAnnotation es incorrecta, también porque ahora puede devolver un espacio o puntuación al comienzo de la segunda línea. 'explotar ('', ...)' era correcto, a menos que haya alguna peculiaridad de escritura china de la que no tenga conocimiento. También creo que podría haber aceptado mi solución, ya que usó las dos correcciones de código que contiene. Es cierto que ha agregado información, pero eso podría haber sucedido en los comentarios (y podría haber editado mi solución también). –

+0

OK, ahora veo cuál es el "capricho" de la escritura china: en general, no hay espacios entre las palabras. Una forma de dividir en "palabras", para sus propósitos, podría ser algo como: 'preg_split ("/((? <=) | (? = \ P {Han}) (? = \ PL))/u ", $ str, -1, PREG_SPLIT_NO_EMPTY) ', que" corta "la cadena después de espacios o antes de Han" letras "(palabras, de hecho), pero los espacios finales deben manejarse por separado (sacados y agregados solo si no hay división de líneas) ocurre). Nota: hay un espacio después de '? <='. –

+1

La expresión regular anterior debe mejorarse para no permitir que ciertos caracteres finalicen una línea (estos caracteres son equivalentes a caracteres occidentales que normalmente están precedidos por un espacio, como abrir paréntesis o abrir comillas, por ejemplo, ver [aquí] (http: //msdn.microsoft.com/en-us/goglobal/bb688158.aspx)) –

3

Me temo que tendrá que elegir un TTF que puede soportar china puntos de código Hay muchas fuentes para esto, aquí son dos:

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

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

+0

¿Qué quiere decir con puntos de código? –

+0

@kimsia http://inamidst.com/stuff/unidata/ –

+0

@kimsia: o [Unicode] (http://en.wikipedia.org/wiki/Unicode#Architecture_and_terminology) en Wikipedia –

5

El problema es que están alimentando ImageMagick la salida de un "divisor de línea" (wordWrapAnnotation), al que están utf8_decode ing la entrada de texto. Esto está mal, seguro, si está tratando con texto chino. utf8_decode solo puede tratar con texto UTF-8 que PUEDE convertirse a ISO-8859-1 (la extensión más común de 8 bits de ASCII).

Ahora, espero que su texto esté codificado en UTF-8. Si no es así, usted podría ser capaz de convertir de esta manera:

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

o como esto

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

(en su código $text es bastante $text1 y $text2).

Entonces hay (al menos) dos cosas que arreglar en el código:

  1. pasar el texto "tal cual" (sin utf8_decode) a wordWrapAnnotation,
  2. cambio el argumento de setTextEncoding de "utf-8" a "UTF-8" según specs

espero que todas las variables en su código se inicializan en alguna parte que falta de la misma. Con los dos cambios anteriores (el segundo puede no ser necesario, pero nunca se sabe ...), y con las partes faltantes en su lugar, no veo ninguna razón por la cual su código no debería funcionar, a menos que su archivo TTF se rompa o el Imagick biblioteca está rota (imagemagick, en la que se basa Imagick, es una gran biblioteca, por lo que considero que esta última posibilidad es bastante improbable).

EDIT:

Tras su solicitud, puedo actualizar mi respuesta con

a) el hecho de que la fijación de mb_internal_encoding('utf-8') es muy importante para la solución, como usted dice en su answer, y

b) mi propuesta de un mejor divisor de línea, que funciona aceptablemente para idiomas occidentales y para chino, y ese es probablemente un buen punto de partida para otros idiomas que usan logogramas Han (kanji japonés y hanja coreano):

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 palabras: la entrada se limpia primero reemplazando todas las ejecuciones de espacios en blanco, incluidas las líneas nuevas, con un solo espacio, excepto el espacio en blanco inicial y posterior, que se elimina. Luego se divide en espacios o justo antes de que los caracteres Han no vayan precedidos por caracteres "iniciales" (como abrir paréntesis o comillas de apertura), o justo antes de caracteres "iniciales". Las líneas se ensamblan para no renderizarse en más de $maxWidth píxeles horizontalmente, excepto cuando esto no sea posible con las reglas de división (en cuyo caso la representación final probablemente se desborde). Una modificación para forzar la división en casos de desbordamiento no es difícil. Tenga en cuenta que, por ejemplo, la puntuación china no se clasifica como Han en Unicode, por lo que, salvo la puntuación "inicial", el algoritmo no puede insertar ningún salto de línea.

+0

Esta es la razón más probable para la codificación rota. –

+0

Hola Walter, tu respuesta me ayudó a llegar a la solución final. Quiero agradecerle por su ayuda. –

+0

No utilicé la solución mb_convert_encoding por cierto. –

Cuestiones relacionadas