Ogni stringa visibile in un documento HotPDF arriva attraverso una sola chiamata: TextOut(X, Y, angle, Text). L'esempio Hello World la usa nella sua forma più semplice, font impostato una volta e quattro argomenti lasciati a valori predefiniti sensati. Superata quella prima pagina, gli stessi quattro argomenti reggono l'intero peso del layout. Il terzo argomento ruota la sequenza di testo. Il font impostato appena prima decide dimensione e stile. E la coppia X, Y, misurata dall'angolo della pagina in punti, è l'unica cosa che separa un report pulito da testo che si sovrappone, si tronca o scivola una riga più in basso sulla stampante di qualcun altro. È qui che TextOut si guadagna il suo posto, ed è qui che i valori predefiniti smettono di bastare
Vale la pena fissare in mente la firma prima di ogni altra cosa: X e Y sono Single in punti, angle è un Extended in gradi e Text è una WideString, quindi l'Unicode passa senza bisogno di una chiamata separata. Un secondo overload accetta un PWORD più una lunghezza per quando avete già in mano codici glifo, ma per le stringhe ordinarie la forma WideString è quella da usare
Dimensione e stile arrivano da SetFont, non da TextOut
TextOut non ha un parametro di dimensione. La dimensione, il peso, l'inclinazione, tutto vive nella chiamata SetFont che precede la scrittura, e resta in vigore finché il SetFont successivo non la sostituisce. È questo il singolo fatto che spiega la maggior parte della confusione del primo giorno: una riga esce in grassetto perché tre chiamate prima qualcosa ha impostato [fsBold] e nulla lo ha azzerato
Pdf.CurrentPage.SetFont('Times New Roman', [], 24);
Pdf.CurrentPage.TextOut(72, 740, 0, 'Quarterly Report'); // 24pt regular
Pdf.CurrentPage.SetFont('Times New Roman', [fsBold], 12);
Pdf.CurrentPage.TextOut(72, 712, 0, 'Revenue'); // 12pt bold
Pdf.CurrentPage.SetFont('Times New Roman', [fsItalic], 11);
Pdf.CurrentPage.TextOut(72, 694, 0, 'figures in thousands'); // 11pt italic
Pdf.CurrentPage.SetFont('Courier New', [fsBold, fsItalic], 10);
Pdf.CurrentPage.TextOut(72, 676, 0, ' +18.4% YoY'); // styles combine
Il secondo argomento è un insieme TFontStyles, quindi [fsBold, fsItalic] è grassetto corsivo e [] è normale. La dimensione è in punti, la stessa unità delle coordinate, il che rende facile ragionare sulla spaziatura verticale: una riga da 12 punti vuole circa 14-16 punti di passo verticale per respirare, quindi decrementare Y di 14 per riga è un'interlinea di partenza ragionevole. Non c'è alcun avanzamento riga automatico. Ogni linea di base la calcolate voi, il che è tedioso per un paragrafo ma esatto per un modulo, dove ogni campo sta a una coordinata fissa
Due note pratiche sul nome del font. Viene risolto contro i font installati sulla macchina di build, e quello che il sistema operativo restituisce è ciò che viene incorporato, quindi un nome che si risolve sul vostro desktop e un nome che si risolve su un server di build non è garantito che siano lo stesso carattere. E il font deve coprire gli script presenti nella stringa. Una sequenza di testo cirillico o CJK sotto un font solo latino viene resa come riquadri di glifi mancanti senza alcun errore, ed è il motivo per cui la pagina Hello World ricorre a un font Unicode ampio quando mescola le lingue
L'argomento angle ruota attorno all'ancora
Il terzo argomento è quello che la maggior parte del codice lascia a zero per sempre. Passate un valore diverso da zero e la sequenza ruota in senso antiorario attorno alla propria ancora (X, Y), l'angolo inferiore sinistro del testo, di quel numero di gradi. L'ancora stessa non si sposta, quindi la stessa coordinata che posizionava un'etichetta orizzontale posiziona la sua gemella ruotata; cambia solo la direzione in cui marciano i glifi
Pdf.CurrentPage.SetFont('Arial', [fsBold], 11);
// A vertical axis label down the left margin: 90 degrees reads bottom-to-top.
Pdf.CurrentPage.TextOut(40, 300, 90, 'Units sold');
// A diagonal DRAFT watermark across the page body.
Pdf.CurrentPage.SetFont('Arial', [fsBold], 60);
Pdf.CurrentPage.TextOut(150, 250, 45, 'DRAFT');
// Column headers tilted 60 degrees so long labels fit a narrow table.
Pdf.CurrentPage.SetFont('Arial', [], 9);
Pdf.CurrentPage.TextOut(120, 600, 60, 'Q1 actual');
Pdf.CurrentPage.TextOut(160, 600, 60, 'Q2 actual');
Novanta gradi è il caso comune, un'etichetta che corre lungo il lato di un grafico o un titolo sul dorso. Quarantacinque gradi gestisce le intestazioni di colonna inclinate, il trucco che permette a un'etichetta larga di stare sopra una colonna stretta senza invadere le vicine. La rotazione non cambia come viene interpretata l'ancora, e questo inganna: una sequenza a 90 gradi parte comunque da (X, Y) e cresce verso l'alto da lì, quindi per centrare un'etichetta ruotata si regola l'ancora, non l'angolo. Quando più sequenze ruotate condividono una linea di base, date loro la stessa Y e fate avanzare X, esattamente come fareste avanzare Y per righe orizzontali impilate
Posizionare le coordinate senza andare a tentoni
Le coordinate sono la parte che supera la revisione o la fallisce in silenzio. HotPDF misura dall'angolo inferiore sinistro della pagina, con Y crescente verso l'alto, in punti a 72 per pollice. Una pagina US Letter è 612 per 792 punti; A4 è 595 per 842. Un margine superiore di un pollice su Letter mette quindi la vostra prima linea di base vicino a Y = 792 meno 72 meno la dimensione del font, non a qualche numero piccolo vicino alla cima. Chi arriva dalle coordinate dello schermo, dove Y cresce verso il basso da zero, scrive la prima riga oltre il bordo inferiore e passa dieci minuti a chiedersi dove sia finita
Trattate il layout come aritmetica su ancore con un nome anziché come una colonna di numeri magici. Un margine sinistro, una linea di base corrente che decrementate per riga e un'interlinea fissa trasformano un blocco di etichette in un breve ciclo invece che in un muro di letterali:
const
LeftMargin = 72; // 1 inch in
TopBaseline = 720; // first line, ~1 inch down on Letter
Leading = 16; // vertical step between lines
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 // bottom margin reached
begin
Pdf.AddPage;
Pdf.CurrentPage.SetFont('Arial', [], 11); // font resets on a new page
Y := TopBaseline;
end;
end;
end;
La guardia di cambio pagina è la riga che tutti dimenticano per prima e che sul campo colpisce più duro. Sotto TextOut non c'è alcun layout a flusso. Decrementate oltre il margine inferiore e il testo continua a disegnarsi nella rilegatura, fuori dalla pagina, nel nulla, senza alcun avviso. Quindi sorvegliate Y voi stessi, chiamate AddPage quando attraversa il pavimento e azzerate la linea di base. Il SetFont dopo AddPage non è riempitivo opzionale: il font corrente non sopravvive a un cambio pagina, e la prima scrittura sulla nuova pagina esce nel carattere predefinito del visualizzatore se lo saltate
Spaziatura di caratteri e parole per adattamento e allineamento
A volte una stringa è corretta ma della larghezza sbagliata: un'intestazione che deve coprire un filetto fisso, un codice che dovrebbe leggersi con cifre più ariose, una colonna che ha bisogno di valori spostati per allinearsi. Il PDF porta due operatori di stato del testo per questo, la spaziatura dei caratteri (Tc, spazio extra aggiunto dopo ogni glifo) e la spaziatura delle parole (Tw, spazio extra aggiunto a ogni carattere spazio), ed entrambi sono espressi in unità di spazio testo non scalate, di fatto punti alla dimensione font corrente. Sono stato, non argomenti di TextOut, quindi li impostate, disegnate e li rimettete a posto
// Letter-space a short heading so it stretches across a rule.
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); // reset before normal body text
// Open up the gaps between words on a single wide line.
Pdf.CurrentPage.SetWordSpacing(6);
Pdf.CurrentPage.SetFont('Arial', [], 11);
Pdf.CurrentPage.TextOut(72, 712, 0, 'Name Department Extension');
Pdf.CurrentPage.SetWordSpacing(0);
La spaziatura delle parole agisce solo sul carattere spazio (codice 32), il che ha una conseguenza che vale la pena conoscere: non fa nulla dentro una sequenza CJK priva di spazi ASCII, e interagisce in modo strano con il testo codificato come indici di glifo anziché come byte. Per l'output tabellare latino è il modo economico di allargare gli intervalli senza riscrivere la stringa. La spaziatura dei caratteri è lo strumento migliore per un'intestazione che deve raggiungere una larghezza obiettivo, perché distribuisce l'aggiustamento uniformemente su ogni glifo invece di concentrarlo negli spazi
Il reset è tutta la disciplina. La spaziatura, come il font, fa parte dello stato di disegno della pagina, e lo stato persiste finché non lo cambiate. Applicate la spaziatura a un'intestazione e dimenticate di azzerarla, e ogni paragrafo sottostante eredita lo stiramento, che si legge come una scorrettezza sottile e difficile da localizzare, che sopravvive a una rilettura distratta e fallisce una attenta. L'abitudine affidabile è impostare un valore di spaziatura, disegnare la sequenza che ne ha bisogno e riportarlo a zero nella riga successiva, in modo che nessun codice successivo debba sapere cosa ha fatto una sezione precedente
Controllare l'output dove si rompe davvero
Il layout del testo fallisce sulla seconda macchina, non sulla prima, quindi i controlli che contano avvengono lontano dalla vostra scrivania. Aprite il file generato su un sistema senza il vostro set di font da sviluppatore installato e confermate che i caratteri incorporati vengano ancora resi, inclusi il latino accentato, eventuali script non latini e la punteggiatura, in un solo passaggio anziché campionare i caratteri facili. Selezionate e copiate qualche riga per confermare che il testo sia vero testo e non contorni, cosa che conta nel momento in cui ricerca o estrazione entrano in gioco. Alimentate il layout con dati rappresentativi, l'etichetta tedesca più lunga e il numero più largo, non un segnaposto ordinato, perché la sequenza che trabocca da un campo è sempre quella che non avete digitato a mano. E se la pagina deve finire su un modulo prestampato, stampate o rasterizzate un campione e sovrapponetelo all'originale; una deriva della linea di base di un quarto di millimetro è invisibile sullo schermo e ovvia sulla carta
Se non avete ancora scritto una sola pagina, iniziate dall'esempio Hello World di HotPDF, che imposta il documento, il font e il sistema di coordinate dal basso a sinistra da cui dipende tutto quanto sopra. Le chiamate TextOut, SetFont e di spaziatura mostrate qui fanno parte del HotPDF Component per Delphi e C++Builder