Pase la frase en árabe يوضح ملف PDF a TextOut y abra el resultado. Las letras van en la dirección incorrecta y cada una se ubica en su forma aislada con un espacio visible antes de la siguiente, como si alguien hubiera escrito inglés al revés y presionado la barra espaciadora entre cada carácter. No se produjo ninguna excepción. No se imprimió ninguna advertencia. La salida simplemente es incorrecta y es incorrecta porque nunca se produjeron dos transformaciones independientes de las que depende el árabe. Saber cuáles son esas dos transformaciones y qué llamada las realiza es la mayor parte del trabajo de la salida de PDF de script complejo
HotPDF es un componente PDF nativo de VCL para Delphi y C++Builder, y realiza el trabajo de derecha a izquierda (RTL) por usted mediante una llamada diferente. También se detiene en algunos lugares específicos que querrá conocer antes de comprometerse con una configuración regional, por lo que este artículo esquematiza los conceptos y los límites; la configuración práctica de la llamada en sí se encuentra en el artículo de referencia de RtLTextOut
Por qué una cadena correcta se imprime de forma incorrecta
Unicode mantiene el texto en orden lógico, el orden en el que lo escribe y lo lee en voz alta. Un renderizador tiene que colocar los glifos en orden visual. Para los scripts de izquierda a derecha, esos órdenes coinciden y nadie piensa en ello. Para el árabe y el hebreo no es así, y cuando una sola línea mezcla direcciones, por ejemplo, una oración en árabe que contiene la palabra latina "PDF" o un precio escrito en dígitos, el Algoritmo Bidireccional de Unicode (UAX #9) decide exactamente cómo se anidan los fragmentos de izquierda a derecha dentro de la línea de derecha a izquierda. Esa es la primera transformación, el reordenamiento, y omitirla es lo que invierte la línea
La segunda es la conformación contextual. Una letra árabe se dibuja de forma diferente en función de dónde recaiga dentro de una palabra: inicial, media, final o si está sola. El punto de código se mantiene igual a lo largo de toda la palabra; solo cambia el glifo. Una canalización que pasa cada punto de código directamente a su glifo predeterminado produce exactamente la salida de forma aislada y desconectada del párrafo de apertura. El hebreo omite este paso, dado que sus letras no se unen, pero sigue necesitando el reordenamiento. El árabe necesita ambas, y por eso el árabe, y no el hebreo, es la cadena con la que se prueba
En el escritorio, nada de esto es problema suyo. Cuando un formulario VCL pinta árabe en un TEdit, la pila de texto del sistema operativo lo reordena y lo conforma silenciosamente, que es precisamente el motivo por el que la cadena que se ve perfecta en pantalla sale rota en un PDF rudimentario. Un flujo de contenido no almacena texto editable. Almacena glifos posicionados, de modo que quien emita el flujo hereda el trabajo de conformación que solía gestionar el SO. RtLTextOut es la llamada que recupera ese trabajo
Qué conforma RtLTextOut por usted
HotPDF mantiene la ruta latina y la ruta de script complejo como dos métodos diferentes. TextOut imprime lo que le dé en el orden en que lo dé. RtLTextOut realiza ambas transformaciones primero (reordenamiento bidireccional a lo largo de toda la línea, análisis contextual para los scripts de unión) y luego imprime. Las reglas del script que se aplican se introducen a través del conjunto de caracteres de la fuente en lugar de a través de la propia llamada, de modo que la dirección sea una opción explícita en cada sitio de llamada en lugar de una suposición que se haga a partir de los caracteres. La configuración parámetro por parámetro, los valores del conjunto de caracteres, los pasos de registro de la fuente y un ejemplo compilable completo se encuentran en el artículo de referencia de RtLTextOut; esta pieza se mantiene con lo que significan las transformaciones, dónde se detienen y cómo demostrar que funcionaron
Una norma de uso importa incluso a esta altitud: la entrada debe estar en orden lógico, porque RtLTextOut realiza la inversión por sí mismo, y una cadena que usted ya haya invertido a mano saldrá invertida dos veces; el artículo de referencia aborda esta trampa y cómo solucionarla. Lo que hace que valga la pena mencionar la trampa aquí es la razón por la que sobrevive a las pruebas. Una cadena puramente árabe invertida dos veces puede parecer perfectamente correcta, y solo se desmorona cuando una línea lleva una palabra latina o un número, porque esas ejecuciones incrustadas ya no se anidan como lo indica el UAX #9. El error no radica en la representación; consiste en introducir en el algoritmo un texto que ya estaba procesado a medias
Ese mismo comportamiento de dirección mixta hace tropezar más a los revisores que al código. Dentro de una línea de derecha a izquierda, los dígitos y las palabras latinas incrustadas se siguen leyendo de izquierda a derecha. Alguien que no haya trabajado con el diseño bidireccional mirará una factura renderizada, verá el número de cuenta que se lee en la dirección "incorrecta" en relación con el árabe que lo rodea, y lo anotará como un error. Es el resultado correcto de la especificación. Una breve nota en sus criterios de aceptación, redactada antes del primer pase por parte de un hablante nativo, ahorra esa vuelta atrás
Cuándo el reordenamiento y la unión son suficientes, y cuándo no
Para el texto corrido en árabe y hebreo (informes, facturas, contratos, cartas), el reordenamiento y la unión contextual constituyen todo el trabajo, y RtLTextOut lo realiza en solitario. El límite aparece cuando la tipografía pide más que una simple unión. La respuesta de HotPDF en la parte del árabe es un conformador en el lado del productor al que hay que optar: establezca AutoShapeArabic := True y el componente reescribirá la ejecución del orden lógico a los Formularios de presentación de Unicode antes del pase bidireccional, para que se calculen los formularios de unión respecto de los vecinos lógicos y se integren los pliegues de ligadura en los puntos de código que el PDF realmente conlleva, en lugar de dejar que un visor los resuelva. El interruptor viene desactivado de forma predeterminada y la salida es estable en bytes cuando permanece desactivada, por lo que su activación es una decisión deliberada en cada canalización de documentos, no una mejora global. El mismo modelo en el que hay que optar se extiende a los demás scripts de derecha a izquierda que HotPDF conforma y que conllevan uniones: el siriaco, el n'ko, el adlam y el rohinyá hanifi tienen su propia marca de autoconformación que refleja la del árabe
Las características opcionales de OpenType vuelven a ser un mecanismo diferente. Las ligaduras discrecionales y las características de sustitución única similares pasan por GetSingleSubstituteGlyph(GID, 'liga'), que resuelve una sustitución cada vez (el identificador de glifo de entrada primero, la etiqueta de característica después) y devuelve el glifo de entrada sin cambios cuando no se aplica la característica. Eso basta para impulsar una lista de ligaduras conocida y finita que usted mismo mantenga. No es un motor de GSUB completo, y la diferencia es exactamente donde los planes de configuración regional ambiciosos fallan: una canalización de conformación que gestione el árabe de forma impecable habrá demostrado el reordenamiento y la unión, nada más
Cobertura en los scripts
El árabe ejerce ambas transformaciones, y por eso es la cadena con la que hay que probar, y por la que un pase por árabe es la pieza de evidencia más fuerte por sí sola de que la canalización funciona. El hebreo necesita el reordenamiento pero no la unión, porque sus letras se mantienen aisladas; si el hebreo se renderiza correctamente pero el árabe sale desconectado, la mitad bidireccional está bien y la contextual nunca se ejecutó. El persa y el urdu funcionan sobre el script del árabe y heredan su comportamiento, aunque la preferencia del urdu por el estilo Nastaliq es una decisión sobre la fuente con consecuencias relativas a la legibilidad que debe evaluar un lector nativo
El tailandés se ubica en el otro extremo de la línea. Va de izquierda a derecha, por lo que no requiere ningún trabajo bidireccional, y sus letras no se unen, por lo que no necesita análisis contextual; las cadenas en tailandés pasan por la ruta ordinaria de TextOut igual que las latinas. Lo que sí posee el tailandés son las marcas apiladas (vocales y tonos que se sitúan arriba y abajo de la consonante base), y el hecho de que se asienten correctamente dependerá de si la fuente construye sus marcas de combinación para que se apilen sin la ayuda del motor de conformación. La mayoría de fuentes para tailandés lo hacen. Realice las pruebas con la fuente exacta que va a incrustar, no con una que se le parezca
El devanagari y el resto de la familia índica suponen un duro freno. Sus signos vocálicos se reordenan alrededor de las agrupaciones de consonantes, y sus conjunciones se forman a través de cadenas de sustituciones que dependen del contexto, algo que corresponde totalmente al territorio de GSUB, más allá del reordenamiento y la unión. Si hay una configuración regional índica en la hoja de ruta, realice un programa piloto real con cadenas de clientes genuinas antes de prometerlo; que el árabe funcione no es prueba de que el devanagari lo vaya a hacer. Las cadenas de CJK, el vietnamita (con sus diacríticos apilados) y el texto europeo mixto toman la ruta ordinaria sin análisis bidireccional, y resulta rentable mantener las dos rutas separadas físicamente en el código del informe: una rutina para las ejecuciones de RTL y otra para el resto, para que la lógica de la configuración regional esté a la vista en el sitio de llamada en lugar de escondida tras una marca que alguien olvide establecer
La cobertura de glifos se decide antes de que se ejecute la conformación
La conformación toma los glifos de una fuente. Si la fuente no los posee, no hay nada que tomar, lo cual explica que el clásico fallo de implementación (impecable en el equipo del desarrollador pero con recuadros en blanco en el servidor del cliente después de una sustitución de fuente silenciosa) sea un problema de cobertura y no de conformación. La solución práctica (registrar una fuente que usted suministre en lugar de confiar en la que tenga instalada cualquier equipo) se explica paso a paso en el artículo de referencia. El punto conceptual es que la cobertura debe establecerse antes de que cualquier pregunta sobre la conformación tenga siquiera sentido, y que esto se puede establecer de manera programática en lugar de evaluarlo a simple vista
// After RegisterUnicodeTTF, audit coverage for the
// codepoints your data actually uses
GID := Pdf.GetUnicodeGlyphForCodepoint($0628); // U+0628 ARABIC LETTER BEH
LogGlyphAudit($0628, GID);
El propio registro conlleva dos restricciones (un requisito básico de PDF 1.5 para la gestión de texto Unicode incrustado y los bits de permiso de incrustación de la fuente), las cuales se abordan junto a los pasos de la configuración en el artículo de referencia de RtLTextOut. Lo que corresponde aquí es el hábito de la auditoría: GetUnicodeGlyphForCodepoint es su sistema de alerta temprana. Recorra los rangos de puntos de código que utilizan sus datos en la realidad cuando se inicia el servicio y registre qué identificadores de glifo regresan. La falta de cobertura aparecerá entonces como una línea en el registro de inicio durante la fase de implementación, en lugar de como caracteres faltantes en la factura que ya le llegó al cliente
El orden de lectura corresponde al documento, no a los glifos
Incluso si se logran corregir todos los glifos, sigue faltando algo. La norma ISO 32000-1 §12.2 define una preferencia del visor llamada /Direction que determina el orden de lectura general del documento. No afecta a ningún glifo. Lo que sí hace es indicarle a un visor cómo organizar las dobles páginas, desde qué lado debería comenzar un diseño con páginas enfrentadas y hacia dónde se debería inclinar la UI de lectura. Nada de esto se muestra en una sola página, y ese es precisamente el motivo por el que se olvida
// Declare right-to-left reading order at the document level
Pdf.Direction := RightToLeft; // adds vpDirection to ViewerPreferences
Configurar Direction abarca todo el trabajo: el definidor de la propiedad añade vpDirection a las ViewerPreferences del documento, por lo que una línea lleva la preferencia al archivo. Si el texto se emite por medio de RtLTextOut usted lo obtendrá de forma gratuita, ya que la llamada invierte la dirección del documento como un efecto secundario (el artículo de referencia aborda los casos en los que un documento mixto necesita que esto se deshaga). El caso en el que deberá configurarlo por sí mismo consiste en un documento de derecha a izquierda producido de cualquier otra manera; por ejemplo, a partir de una entrada que haya conformado previamente de forma preliminar y que haya dibujado mediante la ruta ordinaria. Si no lo incluye, la prueba de una sola página que está observando se verá igual de ambas maneras; pero después alguien imprimirá un folleto dúplex, las páginas enfrentadas saldrán en espejo y la causa será una única línea que omitió semanas atrás
Cómo verificar la salida conformada
Lleve a cabo una verificación de principio a fin, porque es posible que una página parezca correcta pero resulte inútil para todo lo demás. La mayoría de los problemas se hallan por medio de tres comprobaciones. Copie el texto de Acrobat y compare los puntos de código con la cadena de origen. Ejecute una búsqueda de una palabra que pueda ver en la página en el visor del documento. Finalmente, abra la salida en un equipo que no disponga de sus fuentes de desarrollo: es el que más probabilidades tiene de exponer una sustitución. Nada de ello sustituye al lector nativo que mira un documento real, ya que es el único capaz de detectar lo que no puede ningún corpus sintético. Ponga esa revisión en el calendario antes de enviar el formato
Seleccione las cadenas de prueba adrede en vez de reciclar lo que un traductor envió el año pasado. Un mínimo practicable por configuración regional: una frase de script puro, una oración con nombres de marcas latinos incrustados, una línea que lleve dígitos y divisas, y nombres con signos diacríticos o marcas de combinación. Los nombres de clientes reales derriban las suposiciones que el texto de relleno deja intactas; así, deje que el conjunto de regresión crezca en una cadena cada vez que un caso de soporte revele un patrón que no hubiera visto
El registro de fuentes, los subconjuntos y la API de dibujo de texto habitual se abordan en el artículo sobre la salida de informes, las fuentes y las imágenes con HotPDF. Cuando los mismos documentos también deben cumplir los perfiles de accesibilidad, el etiquetado de lenguaje y las reglas de estructura del artículo sobre la validación de PDF/A y PDF/UA se ubican por encima del trabajo de conformación detallado aquí
Las APIs de fuentes de Unicode y de derecha a izquierda (RTL) descritas arriba se suministran con el Componente HotPDF para Delphi y C++Builder; en la página del producto encontrará el enlace de toda la referencia de salida de texto