Pon una novela japonesa sobre la página y lo primero que notas es que el texto discurre hacia abajo por la columna, no a lo largo de la línea, y que las columnas avanzan desde el borde derecho de la hoja hacia la izquierda. Un lector que creció con ese sistema encuentra el texto horizontal ligeramente clínico. El problema de ingeniería es que PDF, como prácticamente todos los sistemas de texto digital, se construyó alrededor de una línea base horizontal que crece de izquierda a derecha, y un flujo de contenido no tiene ninguna noción de «escribir este párrafo hacia abajo». Así que cuando una aplicación Delphi tiene que producir un certificado, un poema, una pieza de señalización o un documento legal en formato tradicional para un lector taiwanés, japonés o coreano, la maquetación debe ensamblarse a mano: un carácter debajo del siguiente, una columna a la izquierda de la anterior.
HotPDF te proporciona un modificador que gestiona la contabilidad por carácter. La fuente que establezcas lleva un indicador IsVertical, y una vez activado, una única llamada TextOut apila toda una cadena en una columna vertical en lugar de extenderla a lo largo de una línea base. La colocación de columnas, el orden de derecha a izquierda y una importante sustitución de glifo son lo que desarrolla el resto de este artículo.

El modificador reside en SetFont
La maquetación vertical no es una propiedad de la página ni del documento. Es una propiedad de la fuente con la que dibujas, y se activa con el quinto argumento de SetFont:
// SetFont(FontName, FontStyle, Size, FontCharset, IsVertical)
// The 5th argument flips the current font into vertical mode.
Pdf.CurrentPage.SetFont('Arial Unicode MS', [], 12, DEFAULT_CHARSET, False); // horizontal
Pdf.CurrentPage.SetFont('Arial Unicode MS', [], 12, DEFAULT_CHARSET, True); // vertical
Como el indicador va asociado a la fuente, se alterna entre escritura horizontal y vertical simplemente llamando de nuevo a SetFont con un último argumento diferente. Una página puede tener un título horizontal en la parte superior y texto de cuerpo vertical debajo, y HotPDF mantiene los dos modos separados por objeto de fuente en lugar de por página. Eso es lo que hace posibles las maquetaciones mixtas sin ningún manejo especial de modo por tu parte: cada TextOut tras un SetFont vertical apila, cada TextOut tras uno horizontal discurre a lo largo de la línea base, y el último SetFont prevalece.
El cuarto argumento es el juego de caracteres de Windows, el mismo que acepta una llamada horizontal. Pasar DEFAULT_CHARSET permite al sistema resolver los glifos por cadena, lo que importa aquí porque un documento vertical a menudo mezcla sistemas de escritura. Todo lo demás sobre la fuente sigue aplicándose: debe estar instalada en la máquina de compilación, y casi siempre conviene activar FontEmbedding := True para que el fichero renderice los mismos glifos CJK en un lector que nunca tuvo Arial Unicode MS.
Una llamada TextOut es una columna
Con una fuente vertical activa, una llamada TextOut ya no extiende su cadena lateralmente desde el punto dado. Coloca el primer carácter en la parte superior y avanza el resto directamente hacia abajo, con un avance igual a la altura de línea de la fuente por cada glifo. La X que pasas fija la columna; la Y que pasas fija dónde comienza la parte superior de la columna. Para maquetar un pasaje real se emite por tanto un TextOut por columna y se decrementa X entre llamadas, porque las columnas CJK se leen de derecha a izquierda.
var
Pdf: THotPDF;
const
ColTop = 760; // y of the first glyph in every column (points)
ColGap = 28; // horizontal distance between columns
begin
Pdf := THotPDF.Create(nil);
try
Pdf.FileName := 'VerticalText.pdf';
Pdf.FontEmbedding := True; // embed the CJK face for portable rendering
Pdf.BeginDoc;
Pdf.CurrentPage.Size := psA4;
// A horizontal heading first, in the ordinary writing mode.
Pdf.CurrentPage.SetFont('Arial Unicode MS', [], 16, DEFAULT_CHARSET, False);
Pdf.CurrentPage.TextOut(60, 800, 0, 'Tang poem, vertical layout');
// Switch the font into vertical mode; every TextOut below now stacks.
Pdf.CurrentPage.SetFont('Arial Unicode MS', [], 18, DEFAULT_CHARSET, True);
// Columns advance right to left, so X decreases with each call.
Pdf.CurrentPage.TextOut(520, ColTop, 0, '床前明月光');
Pdf.CurrentPage.TextOut(520 - ColGap, ColTop, 0, '疑是地上霜');
Pdf.CurrentPage.TextOut(520 - ColGap * 2, ColTop, 0, '舉頭望明月');
Pdf.CurrentPage.TextOut(520 - ColGap * 3, ColTop, 0, '低頭思故鄉');
Pdf.EndDoc;
finally
Pdf.Free;
end;
end;
El poema se lee como debe: primero la columna de más a la derecha, de arriba abajo, luego el ojo salta a la izquierda hacia la siguiente columna. Nada en la propia cadena codifica ese orden. Lo codificas tú en las coordenadas X, disminuyéndolas llamada a llamada. Si inviertes la dirección, el verso sale al revés, que es el error más frecuente al portar una maquetación horizontal a vertical.
Coordenadas: hacia abajo en la página, de derecha a izquierda
Hay dos ejes en juego y tiran en direcciones opuestas, por lo que conviene ser preciso. HotPDF mide desde la esquina inferior izquierda de la página, con Y creciendo hacia arriba, en puntos. Una columna vertical, por tanto, comienza en una Y alta (cerca de la parte superior de la hoja) y los caracteres descienden desde ahí a medida que HotPDF resta una altura de línea por cada uno. Estableces esa Y de inicio una vez por columna y el componente gestiona el descenso.
El eje horizontal es el que controlas manualmente. Cada columna se sitúa en su propia X, y las columnas sucesivas pasan a valores X menores porque el orden de lectura es de derecha a izquierda. Un ritmo razonable es elegir la X de la columna más a la derecha y restar un espacio de columna fijo en cada llamada sucesiva, como hace el ejemplo con ColGap. El espacio es tuyo para elegir; demasiado ajustado y las columnas adyacentes se tocan, demasiado suelto y el bloque parece escaso. Para texto de cuerpo a 12 o 18 puntos, un espacio algo mayor que el tamaño de fuente se lee con comodidad.
Glifos que deben cambiar de forma
Algunos caracteres no son simplemente copias rotadas de su versión horizontal; deben sustituirse cuando el texto se vuelve vertical. El que HotPDF gestiona automáticamente es la marca de sonido prolongado japonesa ー (U+30FC), la barra de vocal larga que aparece en palabras katakana como コーヒー. Dibujada horizontalmente es un guión corto en la línea base. Si apilaras ese mismo glifo en una columna quedaría tendido a lo ancho de la columna, lo cual es incorrecto: en japonés vertical la marca se convierte en un trazo vertical que conecta los dos caracteres entre los que se sitúa. HotPDF detecta U+30FC en el trazado vertical y lo renderiza como una barra vertical (U+007C) para que la marca de vocal larga apunte en la dirección correcta sin ningún trabajo por tu parte.
Esa única sustitución cubre el caso que rompe la mayoría de las implementaciones ingenuas, pero vale la pena saber hasta dónde llega el problema general. La tipografía vertical completa también rota noventa grados las letras latinas y la puntuación occidental, desplaza las kana pequeñas y reposiciona corchetes y comas a sus formas verticales, y una implementación completa de eso reside en las características OpenType verticales de una fuente, no en reglas fijas. HotPDF puede aprovechar esas características cuando la fuente las incluye: las alternativas verticales (las características GSUB vert y vrt2) y el kerning vertical (las búsquedas GPOS vkrn y vpal) son opcionales y se aplican solo por la ruta vertical cuando la fuente activa realmente las define. Para texto CJK mixto en una tipografía de cobertura amplia como Arial Unicode MS, el manejo incorporado de U+30FC más un avance de altura de línea uniforme es suficiente para producir columnas correctas y legibles; las características OpenType importan cuando pasas a una fuente diseñada para composición vertical fina y quieres su posicionamiento nativo de kana y el espaciado entre glifos.
Mezclar sistemas de escritura y orientaciones en una misma página
Los documentos reales raramente son puros. Una página japonesa vertical puede llevar un pie de foto en inglés horizontal, un número de página en la parte inferior o un bloque de coreano compuesto verticalmente junto al japonés. Como el indicador vertical es un modificador a nivel de fuente, estos elementos se componen alternando llamadas SetFont en lugar de gestionar ningún estado a nivel de página. Establece una fuente horizontal, escribe el encabezado de página y el folio, establece una fuente vertical, coloca las columnas, establece de nuevo una fuente horizontal para el pie de página. Cada región recoge el modo del último SetFont, de modo que la única disciplina necesaria es llamarlo cada vez que cambias de dirección.
Un detalle a planificar cuando se mezclan sistemas de escritura: los ideogramas chinos, japoneses y coreanos son casi cuadrados y se apilan con un avance uniforme, pero los fragmentos en latín incrustados en una columna vertical no tienen ese avance uniforme. Si necesitas unas pocas palabras en latín dentro de texto que de otro modo es vertical, decide deliberadamente si deben rotarse para discurrir hacia abajo por la columna o colocarse en posición vertical como un inserto horizontal breve, y posiciona ese fragmento con su propio TextOut en lugar de dejarlo seguir el avance vertical destinado a los ideogramas. Tratar el fragmento mixto como su propio problema de colocación mantiene intacto el ritmo de las columnas.
Del ejemplo a la producción
Las piezas son pequeñas y se componen de forma predecible. Activa el indicador vertical en SetFont, emite un TextOut por columna desde una Y fija en la parte superior y disminuye X entre llamadas para que las columnas se lean de derecha a izquierda. Incrusta la fuente para que los glifos CJK sobrevivan el viaje a la máquina del lector, y deja que el componente gestione la marca de vocal larga U+30FC y, donde la fuente las admita, las características OpenType verticales. A partir de ahí, llevar la maquetación a producción es principalmente aritmética: derivar las posiciones X de las columnas a partir del ancho medido del bloque, dividir los pasajes largos en columnas que encajen en la altura de la página y reservar espacio para encabezados y folios horizontales.
Para la superficie más amplia de texto y fuentes sobre la que se construye esto, incluidas las convenciones de TextOut horizontal y el registro de fuentes Unicode, consulta el ejemplo Hello World multilingüe y el ejemplo de TextOut. El modificador vertical de SetFont y las llamadas TextOut mostradas aquí forman parte del HotPDF Component para Delphi y C++Builder.