Envíe la oración árabe يوضح ملف PDF هذا a un TextOut normal y la página que obtiene está mal de dos maneras a la vez. Las palabras corren de izquierda a derecha en lugar de derecha a izquierda, y las letras quedan separadas en sus formas aisladas en vez de unirse en palabras conectadas. Nada da error. El código Delphi compila, el archivo se abre, y un revisor que lee árabe le dice que el resultado es inutilizable. La solución es una llamada, no un cambio de biblioteca: HotPDF encamina el texto de derecha a izquierda por un método separado, RtLTextOut, que se encarga del reordenamiento que el TextOut normal no hace. Esta página es la referencia práctica de ese método: la firma y sus parámetros, el argumento de charset que selecciona la escritura, el efecto secundario a nivel de documento, la configuración de fuente que debe hacerse antes, y los fallos que de verdad llegan a soporte, cada uno con su solución
Firma y parámetros
procedure RtLTextOut(X, Y: Single; angle: Extended;
Text: WideString); overload;
procedure RtLTextOut(X, Y: Single; angle: Extended;
Text: PWORD; TextLength: Integer); overload;
X e Y anclan la secuencia en el sistema de coordenadas propio de la página, medido desde la esquina inferior izquierda con Y creciendo hacia arriba, el mismo origen que usa cada llamada a TextOut; RtLTextOut cambia el orden de los glifos, no el punto desde el que mide la página. angle rota la línea base exactamente igual que en TextOut, así que 0 dibuja una línea horizontal. Text es la cadena en orden lógico, el orden en que usted la escribiría, y la segunda sobrecarga recibe los mismos datos UTF-16 como un búfer PWORD sin procesar con un conteo explícito de unidades de código, que es la forma a usar cuando el texto llega desde una API y no desde una cadena de Delphi. En versiones antiguas de Delphi anteriores a la resolución de sobrecargas para estos tipos, la forma de cadena se expone con el nombre RtLTextOutStr con la lista de parámetros idéntica
La división de tareas entre las dos llamadas de salida es estricta. TextOut dibuja los puntos de código en el orden en que usted los pasa, lo cual es correcto para latín, cirílico y CJK e incorrecto para árabe y hebreo. RtLTextOut reordena primero cada línea en orden visual de derecha a izquierda y luego dibuja, manteniendo las palabras latinas y los dígitos incrustados leyéndose de izquierda a derecha dentro de la línea. HotPDF mantiene los dos métodos deliberadamente separados en lugar de adivinar la dirección a partir de los caracteres, así que elegir cuál llamar es elegir qué comportamiento de escritura obtiene; use RtLTextOut para las secuencias de derecha a izquierda, TextOut para todo lo demás, y nunca encamine uno a través del otro. Por qué existe el reordenamiento, qué hacen realmente el algoritmo bidireccional de Unicode y la unión contextual del árabe, y dónde se detiene la conformación de HotPDF son el tema del artículo complementario sobre conformación de texto árabe y RTL con HotPDF; todo lo que sigue es la configuración práctica

El argumento de charset decide la escritura
Lo que le indica a RtLTextOut si está componiendo árabe o hebreo no es el método, es la fuente. SetFont recibe un charset de Windows como cuarto argumento, y ese valor lleva las reglas de la escritura a la llamada de derecha a izquierda: 178 selecciona árabe, 177 selecciona hebreo. Fije el charset, luego dibuje, y las dos líneas de abajo salen en el orden de lectura correcto sin ninguna configuración adicional
// Árabe: el charset 178 indica a RtLTextOut que aplique las reglas del árabe
Pdf.CurrentPage.SetFont('Arial Unicode MS', [], 12, 178);
Pdf.CurrentPage.RtLTextOut(400, 700, 0, 'يوضح ملف PDF هذا');
// Hebreo: el charset 177 cambia las reglas al hebreo
Pdf.CurrentPage.SetFont('Arial Unicode MS', [], 12, 177);
Pdf.CurrentPage.RtLTextOut(400, 660, 0, 'קובץ PDF זה');
Un detalle de secuencia fácil de pasar por alto: el SetFont tiene que ir primero y tiene que repetirse después de cada AddPage, porque la fuente actual, charset incluido, no sobrevive a un salto de página. Olvide la repetición y la segunda página vuelve a la fuente que estuviera activa, lo que para el árabe suele significar cuadros vacíos
No invierte texto que usted ya invirtió
El único error que más tiempo de depuración consume aquí es alimentar a RtLTextOut con una cadena que ya invirtió a mano. La gente llega a este método después de que un primer intento con TextOut normal salió al revés, y un parche habitual es invertir los caracteres en código antes de dibujar. RtLTextOut invierte internamente por sí solo, así que una cadena previamente invertida se invierte una segunda vez y termina justo donde empezó. Pase el texto en orden lógico, el orden en que lo escribiría y lo leería en voz alta, y deje que la llamada haga el reordenamiento
La trampa es más dañina que una simple inversión porque una cadena doblemente invertida puede verse correcta para una frase de prueba toda en árabe y luego romperse en cuanto una línea lleva una palabra latina o un número. Dentro de una línea de derecha a izquierda esas secuencias incrustadas deben leerse de izquierda a derecha, y la inversión manual destroza ese anidamiento mientras el caso puramente árabe resulta sobrevivirlo. Así que el error pasa su primera prueba de humo y aparece más tarde en una factura real con un número de cuenta. Elimine toda inversión manual en el momento en que cambie a RtLTextOut
El efecto secundario de Direction que vale la pena conocer
Llamar a RtLTextOut cambia más que la línea que está dibujando. También cambia la preferencia de dirección de lectura del documento a derecha a izquierda, lo mismo que usted fijaría por su cuenta a través de la propiedad Direction. Ese setter agrega vpDirection a las ViewerPreferences del documento, lo que indica al visor cómo organizar las vistas de dos páginas y de qué lado empieza una disposición de páginas enfrentadas. Cuando todo el documento es árabe o hebreo esto es exactamente lo que quiere, y lo obtiene sin costo
Vale la pena saberlo precisamente porque es invisible en una sola página. Si el documento es mayormente de izquierda a derecha con un bloque de derecha a izquierda, la primera llamada a RtLTextOut igualmente volcará la preferencia de todo el archivo, y nada en su prueba de una página lo mostrará. El síntoma aparece semanas después cuando alguien imprime un folleto a doble cara y las páginas enfrentadas salen en espejo. Si no es lo que quiere, vuelva a fijar Direction explícitamente después de la secuencia de derecha a izquierda:
// RtLTextOut ya fijó la dirección del documento en RightToLeft;
// restaure izquierda a derecha si el documento es predominantemente LTR
Pdf.Direction := LeftToRight;
Para un documento que de verdad se lee de derecha a izquierda, déjelo como está. La cuestión es saber que la llamada tiene un efecto en todo el documento para que la sorpresa del folleto nunca ocurra
Registre la fuente que distribuye, no la que espera que esté instalada
Nada del reordenamiento importa si la fuente no tiene glifos que dibujar. El fallo clásico es un informe que se renderiza impecablemente en la computadora del desarrollador, donde Arial Unicode MS resulta estar presente, y sale como filas de cuadros vacíos en el servidor de un cliente donde Windows sustituyó silenciosamente una fuente sin ninguna cobertura de árabe. El remedio es dejar de confiar en las fuentes del sistema instaladas y registrar una que distribuya con la aplicación
// Distribuya una fuente árabe conocida y regístrela antes de dibujar
Pdf.RegisterUnicodeTTF('C:\Fonts\NotoSansArabic.ttf');
Pdf.CurrentPage.SetFont('NotoSansArabic', [], 12, 178);
Pdf.CurrentPage.RtLTextOut(400, 700, 0, 'يوضح ملف PDF هذا');
Dos límites acompañan al registro. Una fuente incorporada mediante RegisterUnicodeTTF se incrusta, y el manejo de Unicode incrustado de HotPDF necesita que el documento esté en PDF 1.5 o posterior; eso solo muerde si algo más adelante insiste en PDF 1.4, pero cuando ocurre el fallo es silencioso. El otro es legal más que técnico: los archivos TrueType llevan bits de permiso de incrustación, y una tipografía que se ve bien en pantalla puede tener una licencia que prohíbe distribuirla dentro de documentos de clientes. Confirme la licencia antes de incrustar, no después de una queja
Un ejemplo de consola completo
Juntando las piezas, aquí hay un programa autocontenido que escribe una página con una línea en árabe, una línea en hebreo y una línea mixta que lleva un nombre de producto latino. Cada bloque fija su charset y luego dibuja en orden lógico
program RtLTextOutDemo;
{$APPTYPE CONSOLE}
uses
HPDFDoc; // unidad principal de HotPDF
var
Pdf: THotPDF;
begin
Pdf := THotPDF.Create(nil);
try
Pdf.FileName := 'RtLTextOut.pdf';
Pdf.BeginDoc;
// Un encabezado latino pasa por la ruta ordinaria de TextOut
Pdf.CurrentPage.SetFont('Arial', [fsBold], 16);
Pdf.CurrentPage.TextOut(40, 780, 0, 'Right-to-left text with HotPDF');
// Árabe: charset 178, orden lógico, RtLTextOut hace el reordenamiento
Pdf.CurrentPage.SetFont('Arial Unicode MS', [], 12, 178);
Pdf.CurrentPage.RtLTextOut(400, 720, 0,
'يوضح ملف PDF هذا كيفية التعامل مع النص العربي.');
// Hebreo: charset 177
Pdf.CurrentPage.SetFont('Arial Unicode MS', [], 12, 177);
Pdf.CurrentPage.RtLTextOut(400, 680, 0,
'קובץ PDF זה מדגים טקסט עברי הזורם מימין לשמאל.');
// Línea mixta: la palabra latina incrustada sigue leyéndose de izquierda a derecha
Pdf.CurrentPage.SetFont('Arial Unicode MS', [], 12, 178);
Pdf.CurrentPage.RtLTextOut(400, 640, 0,
'مرحبا بالعالم! تم إنشاؤه بواسطة HotPDF');
Pdf.EndDoc;
Writeln('Wrote RtLTextOut.pdf');
finally
Pdf.Free;
end;
end.
Ejecútelo y abra el resultado. Las líneas en árabe y hebreo se leen de derecha a izquierda, las letras se unen donde la escritura las une, y en la última línea el token HotPDF queda de izquierda a derecha dentro de la secuencia árabe. Ese anidamiento es el resultado bidireccional correcto, no un error, aunque los revisores primerizos lo reportan como tal de forma rutinaria; el artículo de conformación enlazado arriba explica por qué las reglas de Unicode lo exigen y cómo redactar sus criterios de aceptación para que el reporte nunca se presente
Errores comunes y sus soluciones
Cada fallo de abajo ha aparecido en un hilo real de soporte, y cada uno se remonta a una de las secciones anteriores
- La salida se lee al revés o se mezcla en líneas mixtas — la cadena se invirtió a mano antes de la llamada, normalmente un remanente de una solución provisional para un intento con
TextOut. Elimine toda inversión manual y pase el orden lógico;RtLTextOutinvierte internamente - Las letras se imprimen desconectadas en formas aisladas — el texto pasó por un
TextOutnormal, o se llamó aSetFontsin un charset de derecha a izquierda. Dibuje conRtLTextOuty pase 178 para árabe o 177 para hebreo como cuarto argumento deSetFont - Cuadros vacíos en la computadora del cliente — Windows sustituyó una fuente sin cobertura de árabe o hebreo. Deje de nombrar fuentes instaladas; registre una tipografía que usted distribuya mediante
RegisterUnicodeTTFy selecciónela conSetFontpor ese nombre - La segunda página se renderiza con la fuente equivocada — la fuente actual no sobrevive a
AddPage. Repita la llamada aSetFont, charset incluido, después de cada salto de página - Las páginas enfrentadas a doble cara se imprimen en espejo en un documento mayormente LTR — la primera llamada a
RtLTextOutcambió laDirectiondel documento como efecto secundario. FijePdf.Direction := LeftToRightdespués de la secuencia de derecha a izquierda - El texto Unicode incrustado se degrada silenciosamente más adelante — algo en el pipeline fuerza PDF 1.4, y el manejo de Unicode incrustado de HotPDF necesita 1.5 o posterior. Suba la versión del documento o elimine la restricción posterior
Antes de que el formato se distribuya, verifique más allá de mirar a ojo: copie el texto de vuelta desde el visor, ejecute la búsqueda dentro del documento, abra el archivo en una computadora sin sus fuentes de desarrollo y ponga un documento genuino delante de un lector nativo. La lista de verificación completa, el mapa de cobertura por escritura y el corpus de cadenas de prueba que vale la pena construir están en el artículo complementario sobre conformación de texto árabe y RTL con HotPDF
Las llamadas RtLTextOut, SetFont y RegisterUnicodeTTF mostradas aquí forman parte de HotPDF Delphi Component para Delphi y C++Builder