Toda a cadeia visível num documento HotPDF decorre de uma chamada: TextOut(X, Y, angle, Text). O exemplo Olá Mundo utiliza-a na sua forma mais simples, um tipo de letra que se define apenas uma vez com os quatro argumentos que se deixam perante as predefinições mais sensatas. Após essa primeira página, os mesmos quatro argumentos suportam todo o peso da disposição. O terceiro argumento roda a execução. O conjunto de carateres que o antecede determina o tamanho e o estilo. E o par X, Y medido a partir do canto da página em pontos, consiste no único obstáculo entre um relatório sem rasuras e um texto cujos caracteres se sobrepõem, são cortados, ou que numa outra impressora saia mais abaixo do estipulado. É aqui que o TextOut justifica a sua existência e as predefinições deixam de ser suficientes
A assinatura merece ser fixada antes de mais nada: X e Y são Single em pontos, o angle consiste num valor Extended em graus e Text corresponde a uma WideString, o que faz com que o Unicode passe sem necessidade de uma chamada em separado. Uma segunda sobrecarga aceita um PWORD e um comprimento perante um cenário em que já tem os códigos de glifos na sua posse, embora a forma WideString seja a que utilizará para a maioria das cadeias comuns
O tamanho e o estilo decorrem de SetFont, e não de TextOut
O TextOut não tem nenhum parâmetro de tamanho. O tamanho, a espessura, a inclinação, tudo isso reside na chamada SetFont que antecede a execução e mantém-se em vigor até que o próximo SetFont o substitua. Este é o único facto que explica a maior parte da confusão inicial: uma linha surge a negrito porque três chamadas antes algo definiu [fsBold] e nada o limpou
Pdf.CurrentPage.SetFont('Times New Roman', [], 24);
Pdf.CurrentPage.TextOut(72, 740, 0, 'Quarterly Report'); // 24pt normal
Pdf.CurrentPage.SetFont('Times New Roman', [fsBold], 12);
Pdf.CurrentPage.TextOut(72, 712, 0, 'Revenue'); // 12pt negrito
Pdf.CurrentPage.SetFont('Times New Roman', [fsItalic], 11);
Pdf.CurrentPage.TextOut(72, 694, 0, 'figures in thousands'); // 11pt itálico
Pdf.CurrentPage.SetFont('Courier New', [fsBold, fsItalic], 10);
Pdf.CurrentPage.TextOut(72, 676, 0, ' +18.4% YoY'); // os estilos combinam
O segundo argumento corresponde a um conjunto TFontStyles, pelo que o [fsBold, fsItalic] significa negrito e itálico, enquanto [] representa o normal. O tamanho é em pontos, exatamente a mesma unidade do que as coordenadas, razão pela qual o espaçamento vertical se torna muito mais simples de calcular: uma linha de 12 pontos exige um passo de 14 a 16 pontos no plano da vertical para respirar, motivo por que as reduções em 14 no Y por cada linha se traduz num ponto de partida razoável e inicial nas entrelinhas. Não há avanços automáticos a nível de linha. Fica ao seu encargo calcular, por si só, todas as linhas de base, facto capaz de ser entediante para a produção num parágrafo mas absolutamente exato em relação a um formulário perante o qual cada campo assenta, por si mesmo, numa coordenada estanque (fixa)
Duas notas práticas sobre o nome do tipo de letra. É resolvido com base nos tipos de letra instalados na máquina de compilação, e o que o SO devolver é o que fica incorporado, pelo que um nome resolvido no seu computador e um nome resolvido num servidor de compilação não são garantidamente o mesmo. E o tipo de letra tem de cobrir os scripts presentes na cadeia. Uma passagem de texto cirílico ou CJK sob um tipo de letra exclusivamente latino é renderizado como caixas de glifos em falta e sem qualquer erro, sendo esta a razão pela qual a página do Olá Mundo recorre a um tipo de letra Unicode alargado ao misturar idiomas
O argumento de ângulo roda em torno da âncora
O terceiro argumento é aquele que a maior parte do código deixa a zero para sempre. Passe um valor diferente de zero e a execução roda no sentido contrário aos ponteiros do relógio em torno da sua própria âncora (X, Y), o canto inferior esquerdo do texto, pelos referidos graus. A própria âncora não se move, pelo que a mesma coordenada que colocou uma etiqueta horizontal coloca a sua equivalente rodada; apenas muda a direção para a qual os glifos avançam
Pdf.CurrentPage.SetFont('Arial', [fsBold], 11);
// Uma etiqueta de eixo vertical na margem esquerda: 90 graus lê-se de baixo para cima.
Pdf.CurrentPage.TextOut(40, 300, 90, 'Units sold');
// Uma marca de água DRAFT diagonal no corpo da página.
Pdf.CurrentPage.SetFont('Arial', [fsBold], 60);
Pdf.CurrentPage.TextOut(150, 250, 45, 'DRAFT');
// Cabeçalhos de colunas inclinados em 60 graus para que as etiquetas longas caibam numa tabela estreita.
Pdf.CurrentPage.SetFont('Arial', [], 9);
Pdf.CurrentPage.TextOut(120, 600, 60, 'Q1 actual');
Pdf.CurrentPage.TextOut(160, 600, 60, 'Q2 actual');
Noventa graus é o caso habitual, como uma etiqueta que percorre o lado de um gráfico ou o título de uma lombada. Quarenta e cinco graus abrange cabeçalhos de colunas inclinados, o truque que permite a uma etiqueta larga posicionar-se sobre uma coluna estreita sem se derramar para os vizinhos. A rotação não altera a forma como a âncora é interpretada, o que costuma causar confusão: uma execução de 90 graus continua a ter o seu início em (X, Y) para a partir daí crescer no sentido ascendente, pelo que deverá, sempre que precisar de centralizar uma etiqueta rodada, proceder ao ajuste na e à sua âncora, prescindindo do ângulo para o efeito. Quando várias execuções rodadas partilharem uma mesma linha de base, conceda-lhes o mesmo Y e aplique um passo no X, exatamente como faria no Y caso se tratasse de linhas horizontais sobrepostas
Colocar coordenadas sem recorrer a conjeturas
As coordenadas são a parte que sobrevive à revisão ou que chumba silenciosamente na mesma. O HotPDF mede a partir do canto inferior esquerdo da página, com o Y a crescer no sentido ascendente, em pontos de 72 por polegada. Uma página de formato Letter norte-americana tem 612 por 792 pontos; um documento A4 assenta nos 595 por 842. Como tal, a existência de uma margem superior de uma polegada num formato Letter posicionará a sua primeira linha de base num ponto próximo a Y = 792 menos 72, para além de se lhe subtrair a dimensão associada do tamanho da fonte, não devendo figurar sobre um número pequeno próximo do topo. Quem vier das coordenadas de ecrã, onde Y cresce para baixo a partir do zero, acaba por escrever a primeira linha logo abaixo do limite inferior, passando de seguida dez minutos a pensar para onde ela terá ido
Encare a disposição (layout) como sendo aritmética aplicada em relação a âncoras nomeadas e não como uma coluna de números mágicos. Uma margem à esquerda, uma linha de base contínua que diminui a cada linha, bem como um entrelinhamento fixo (leading), transformam um bloco de etiquetas num ciclo curto e não numa imensidão e parede de literais:
const
LeftMargin = 72; // 1 polegada para dentro
TopBaseline = 720; // primeira linha, ~1 polegada para baixo em Letter
Leading = 16; // passo vertical entre linhas
var
Y: Single;
Line: string;
begin
Pdf.CurrentPage.SetFont('Arial', [], 11);
Y := TopBaseline;
for Line in ReportLines do
begin
Pdf.CurrentPage.TextOut(LeftMargin, Y, 0, Line);
Y := Y - Leading;
if Y < 72 then // margem inferior alcançada
begin
Pdf.AddPage;
Pdf.CurrentPage.SetFont('Arial', [], 11); // a fonte repõe-se numa nova página
Y := TopBaseline;
end;
end;
end;
A salvaguarda de quebra de página é a linha de que todos se esquecem primeiro e a que tem maior impacto no terreno. O TextOut não possui qualquer disposição de fluxo subjacente. Se efetuar reduções para além da margem inferior, o texto continuará a ser desenhado no limite exterior e para lá da página, indo para o vazio sem qualquer aviso. Deste modo, o utilizador deve vigiar o Y por si, chamando o AddPage no momento em que ultrapassar esse limite e repor, de seguida, a linha de base. O SetFont após o AddPage não é uma espécie de preenchimento facultativo: o tipo de letra atual não sobrevive à quebra da página, e a primeira passagem na nova página ficará pela predefinição do visualizador caso a omita
Espaçamento de carateres e palavras para ajustamento e alinhamento
Por vezes, a cadeia está correta mas a largura não: um cabeçalho que tem de se estender ao longo de uma regra fixa, um código que se deveria ler com algarismos mais arejados, uma coluna onde os valores necessitam de um pequeno ajustamento de modo a ficarem alinhados. O PDF possui dois operadores de estado de texto para esta finalidade, nomeadamente o espaçamento de carateres (Tc, espaço extra adicionado após cada glifo) bem como o espaçamento de palavras (Tw, espaço extra adicionado a cada caráter de espaço). Ambos exprimem-se em unidades de espaço de texto não escalonadas, efetivamente em pontos no tamanho de fonte atual. São estados e não argumentos para TextOut, pelo que tem de os definir, desenhar e repor de seguida
// Efetua o espaçamento de letras num cabeçalho curto para que se estenda ao longo de uma regra.
Pdf.CurrentPage.SetCharacterSpacing(4);
Pdf.CurrentPage.SetFont('Arial', [fsBold], 14);
Pdf.CurrentPage.TextOut(72, 740, 0, 'S U M M A R Y');
Pdf.CurrentPage.SetCharacterSpacing(0); // repõe antes do texto normal do corpo
// Abre as lacunas entre as palavras numa única linha larga.
Pdf.CurrentPage.SetWordSpacing(6);
Pdf.CurrentPage.SetFont('Arial', [], 11);
Pdf.CurrentPage.TextOut(72, 712, 0, 'Name Department Extension');
Pdf.CurrentPage.SetWordSpacing(0);
O espaçamento de palavras atua apenas no caráter de espaço (código 32), o que tem uma consequência que vale a pena conhecer: não tem qualquer efeito no interior de um texto CJK sem espaços ASCII, para além de interagir de forma estranha com texto codificado como índices de glifos em vez de bytes. Numa saída tabular latina, trata-se de um meio económico para alargar lacunas sem ser preciso voltar a redigitar a cadeia. O espaçamento de carateres assume-se como a ferramenta mais apta para a formatação de um cabeçalho cujo desígnio exija a adoção e a submissão aos rigores de uma dada largura definida como alvo, uma vez que distribui o ajuste de forma equitativa ao longo de cada glifo, em vez de o concentrar nos espaços
A reposição é toda a essência da disciplina. O espaçamento, tal como o tipo de letra, faz parte do estado de desenho da página e o estado persiste até que seja alterado. Se utilizar o espaçamento entre letras num cabeçalho e se esquecer de o repor a zero, todos os parágrafos subsequentes vão herdar esse alongamento, o que se assemelha a um erro subtil e de difícil perceção capaz de passar impune numa revisão casual para acabar a ser detetado na mais rigorosa das avaliações. O hábito mais seguro consiste em definir um valor de espaçamento, desenhar a sequência que dele necessita e repor o valor a zero na linha seguinte, para que o código posterior não precise de saber o que foi feito na secção anterior
Verificar a saída onde ela efetivamente falha
A disposição do texto falha na segunda máquina, não na primeira, pelo que as verificações que interessam acontecem longe da sua secretária. Abra o ficheiro gerado num sistema sem o seu conjunto de tipos de letra de programador instalado e confirme que os tipos incorporados continuam a renderizar, incluindo o latim acentuado, os scripts não latinos e a pontuação, de uma só vez, em vez de se limitar a efetuar verificações ocasionais apenas nos carateres mais fáceis. Selecione e copie algumas linhas para confirmar que o texto é texto real e não contornos, algo que se torna essencial a partir do momento em que uma pesquisa ou extração estejam em vista. Forneça dados representativos do esquema de disposição, a etiqueta alemã mais comprida e o número mais extenso, em vez de um texto de substituição perfeitamente arrumado, visto que a execução que faz transbordar os limites de um campo é quase sempre aquela que não digitou à mão. E caso a página tiver de ficar num formulário pré-impresso, trate de imprimir ou rasterizar uma amostra de modo a sobrepô-la face ao original; o desvio de um quarto de milímetro numa linha de base não se nota no ecrã mas no papel nota-se de imediato
Se ainda não escreveu uma única página, comece com o exemplo do Olá Mundo do HotPDF, que configura o documento, o tipo de letra e o sistema de coordenadas do canto inferior esquerdo dos quais tudo o que está acima depende. As chamadas TextOut, SetFont e o espaçamento aqui exibidos fazem parte do Componente HotPDF para Delphi e C++Builder