Ao abrir um romance japonês, a primeira coisa que nota é que o texto se desenvolve ao longo de colunas verticais e não horizontalmente em linhas, e que as colunas progridem a partir da extremidade direita da folha em direção à esquerda. Um leitor habituado a este formato acha o texto horizontal um pouco impessoal. O desafio técnico reside no facto de o PDF, tal como quase todos os sistemas digitais de texto, ter sido estruturado em torno de uma linha de base horizontal que cresce da esquerda para a direita, não possuindo o fluxo de conteúdo (content stream) qualquer noção de "escrever este parágrafo para baixo". Por isso, quando uma aplicação Delphi necessita de gerar um certificado, um poema, um cartaz ou um documento legal em formato tradicional para leitores de Taiwan, Japão ou Coreia, o esquema tem de ser construído manualmente: um caractere por baixo do outro, uma coluna à esquerda da anterior.
HotPDF dá-lhe um parâmetro que faz o processamento individual dos caracteres por si. A fonte que define possui uma flag IsVertical e, assim que esta está ativa, uma única chamada TextOut dispõe toda a string numa coluna vertical, em vez de a estender ao longo de uma linha de base. O posicionamento das colunas, a ordem da direita para a esquerda e uma substituição de glifo discretamente importante constituem o foco do resto desta página.

O parâmetro de comutação reside em SetFont
O esquema vertical não é uma propriedade da página ou do documento. É uma propriedade da fonte com a qual desenha, e ativa-se com o quinto argumento do método 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 a flag reside na fonte, pode alternar entre a escrita horizontal e vertical simplesmente chamando de novo o método SetFont com um último argumento diferente. Uma página pode conter um título horizontal no topo e o corpo do texto na vertical abaixo deste, pois o HotPDF gere os dois modos individualmente por objeto de fonte e não por página. É isto que viabiliza esquemas mistos sem necessidade de processamento especial de modos da sua parte: cada TextOut efetuado após um SetFont vertical empilha o texto, ao passo que cada TextOut após um SetFont horizontal segue a linha de base, prevalecendo a última configuração do SetFont.
O quarto argumento é o character set do Windows, o mesmo utilizado numa chamada horizontal. Passar DEFAULT_CHARSET permite que o sistema resolva os glifos por string, o que é crucial aqui visto que um documento vertical mistura frequentemente escritas diferentes. Todos os restantes aspetos da fonte continuam a aplicar-se: esta tem de estar instalada na máquina de compilação e é quase sempre recomendável definir FontEmbedding := True para que o ficheiro desenhe os mesmos glifos CJK num leitor que não possua a fonte Arial Unicode MS instalada.
Uma chamada TextOut corresponde a uma coluna
Com uma fonte vertical activa, a chamada ao TextOut deixa de expandir a string horizontalmente a partir do ponto indicado. Posiciona o primeiro caractere no topo e alinha os seguintes verticalmente para baixo, avançando a altura de linha da fonte correspondente a cada glifo. O parâmetro X determina a coluna e o Y define o início do topo da coluna. Para organizar um texto real, deve efetuar um TextOut por coluna e decrementar o valor de X para a esquerda entre chamadas, dado que as colunas CJK se leem da direita para a esquerda.
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;
O poema lê-se da forma esperada: a coluna mais à direita primeiro, de cima para baixo, saltando depois o olhar para a coluna seguinte à esquerda. A string por si só não codifica essa ordenação; o programador define-a através das coordenadas X, decrescendo-as chamada a chamada. Se inverter o sentido, os versos surgirão invertidos, o que constitui o erro mais comum ao migrar um layout horizontal para vertical.
Coordenadas: para baixo na página, da direita para a esquerda
Estão dois eixos em jogo e atuam em direções opostas, pelo que convém ser rigoroso. O HotPDF mede a partir do canto inferior esquerdo da página, com o Y a crescer para cima, em pontos. Por conseguinte, uma coluna vertical inicia-se num Y elevado (perto do topo da página) e os caracteres descem à medida que o HotPDF subtrai a altura de linha para cada um deles. O programador define esse Y inicial uma vez por coluna e o componente encarrega-se do alinhamento descendente.
O eixo horizontal é controlado manualmente. Cada coluna situa-se no seu próprio X, e as colunas sucessivas avançam para valores de X menores porque a leitura se faz da direita para a esquerda. Uma lógica recomendável passa por escolher o X da coluna mais à direita e depois subtrair um intervalo de coluna fixo para cada chamada subsequente, tal como demonstrado no exemplo com o ColGap. A definição do intervalo fica ao seu critério: se for demasiado estreito, as colunas adjacentes tocam-se; se for muito largo, o bloco parecerá disperso. Para corpo de texto com 12 a 18 pontos, um intervalo ligeiramente maior do que o tamanho da fonte proporciona uma leitura confortável.
Glifos que necessitam de alterar a sua forma
Alguns caracteres não são meramente cópias rodadas da sua versão horizontal; requerem substituição quando o texto passa a vertical. Aquele que o HotPDF trata automaticamente por si é o sinal de prolongamento de som japonês ー (U+30FC), a barra de vogal longa comum em palavras katakana como コーヒー. Desenhado na horizontal, apresenta-se como um traço curto sobre a linha de base. Se empilhasse esse mesmo glifo numa coluna, ele ficaria disposto horizontalmente a atravessar a coluna, o que está incorreto: na escrita vertical japonesa, o sinal transforma-se num traço vertical que liga os dois caracteres adjacentes. O HotPDF deteta o U+30FC no fluxo vertical e renderiza-o como uma barra vertical (U+007C), garantindo que a marca da vogal longa aponta no sentido correto sem requerer intervenção manual.
Esta substituição simples resolve o problema que afeta a maioria das implementações mais básicas, mas convém estar ciente de que o desafio tipográfico é mais abrangente. A tipografia vertical completa também roda as letras latinas e a pontuação ocidental em noventa graus, desloca os caracteres kana pequenos e reposiciona parênteses e vírgulas para as suas formas verticais, residindo a implementação completa destas regras nos recursos verticais OpenType da própria fonte, e não em regras estáticas. O HotPDF consegue aceder a estes recursos quando a fonte os disponibiliza: as alternativas verticais (as funcionalidades GSUB vert e vrt2) e o kerning vertical (pesquisas GPOS vkrn e vpal) são ativados a nível do fluxo vertical apenas quando a fonte ativa os define. Para texto CJK misto com uma tipografia única de ampla cobertura como a Arial Unicode MS, o processamento integrado do U+30FC acompanhado de um avanço uniforme de altura de linha revela-se suficiente para gerar colunas corretas e legíveis; as funcionalidades OpenType assumem relevância quando se migra para uma fonte concebida especificamente para paginação vertical de qualidade, visando tirar partido do posicionamento nativo do kana e do espaçamento entre glifos.
Misturar escritas e orientações numa única página
Os documentos reais raramente são homogéneos. Uma página em japonês vertical pode conter uma legenda horizontal em inglês, a numeração da página no rodapé ou um bloco em coreano disposto verticalmente ao lado do japonês. Dado que a flag vertical é configurada ao nível da fonte, a composição destes elementos faz-se alternando chamadas ao SetFont, em vez de gerir um estado global da página. Defina uma fonte horizontal, escreva o cabeçalho e a paginação, configure uma fonte vertical, disponha as colunas e defina novamente uma fonte horizontal para o rodapé. Cada secção assume o modo da chamada SetFont mais recente, pelo que a única regra passa por invocar o método sempre que alterar a direção da escrita.
Um detalhe a ter em conta na mistura de escritas: os ideogramas em chinês, japonês e coreano são praticamente quadrados e empilham-se num avanço uniforme, mas os segmentos latinos inseridos numa coluna vertical não apresentam essa progressão regular. Se necessitar de introduzir algumas palavras em caracteres latinos num texto predominantemente vertical, decida conscientemente se estas devem ser rodadas para correr ao longo da coluna ou se devem surgir na vertical como uma pequena inserção horizontal, posicionando esse fragmento com o seu próprio TextOut, em vez de seguir o espaçamento vertical previsto para os ideogramas. Tratar o segmento misto como uma questão de posicionamento específica mantém a consistência rítmica da coluna.
Do exemplo para a produção
As peças são simples e articulam-se de forma previsível. Ative a flag vertical no SetFont, efetue um TextOut por coluna a partir de um Y superior fixo e decresça o valor de X entre chamadas para que as colunas se leiam da direita para a esquerda. Incorpore a fonte no documento para que os glifos CJK cheguem sem problemas à máquina do leitor, e deixe o componente processar a marca de vogal longa U+30FC e as funcionalidades OpenType verticais (se suportadas pela fonte). A partir daí, a adaptação do layout para produção resume-se essencialmente a aritmética: calcular as posições X das colunas a partir de uma largura de bloco medida, dividir textos longos em colunas que caibam na altura da página e reservar o espaço necessário para cabeçalhos e paginações horizontais.
Para obter informações sobre a API de fontes e texto geral em que esta lógica se baseia, incluindo as convenções do TextOut horizontal e o registo de fontes Unicode, consulte o exemplo multilíngue Hello World e o exemplo do TextOut. O parâmetro vertical de SetFont e as chamadas ao TextOut aqui demonstradas fazem parte do HotPDF Component para Delphi e C++Builder.