Každý viditeľný reťazec v dokumente HotPDF sa vykresľuje prostredníctvom jedného volania: TextOut(X, Y, angle, Text). Príklad Hello World ho používa v najjednoduchšej forme, kde je písmo nastavené iba raz a štyri argumenty sú ponechané na rozumné predvolené hodnoty. Za touto prvou stranou však rovnaké štyri argumenty nesú celú váhu rozloženia. Tretí argument otáča textový beh. Písmo nastavené tesne pred ním určuje veľkosť a štýl. A dvojica X, Y, meraná od rohu stránky v bodoch, je to jediné, čo stojí medzi čistým reportom a textom, ktorý sa prekrýva, orezáva alebo sa na tlačiarni niekoho iného posunie o riadok nižšie. Tu TextOut dokazuje svoju dôležitosť a tu predvolené hodnoty prestávajú stačiť.
Predovšetkým je užitočné ujasniť si signatúru: X a Y sú typu Single v bodoch, angle (uhol) je Extended v stupňoch a Text je WideString, takže Unicode prechádza bez potreby samostatného volania. Druhé preťaženie prijíma PWORD a dĺžku pre prípady, keď už máte kódy glyfov, ale pre bežné reťazce je formát WideString ten, ktorý budete používať najčastejšie.
Veľkosť a štýl pochádzajú zo SetFont, nie z TextOut
TextOut nemá žiadny parameter veľkosti. Veľkosť, hrúbka, sklon, to všetko žije vo volaní SetFont, ktoré predchádza textovému behu, a zostáva v platnosti, kým ho nenahradí ďalšie volanie SetFont. To je ten hlavný fakt, ktorý vysvetľuje väčšinu zmätkov počas prvého dňa: riadok sa vykreslí tučne, pretože o tri volania skôr niečo nastavilo [fsBold] a nič to nevymazalo.
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
Druhým argumentom je množina TFontStyles, takže [fsBold, fsItalic] znamená tučnú kurzívu a [] je obyčajné písmo. Veľkosť je v bodoch, rovnakej jednotke ako súradnice, vďaka čomu sa o vertikálnych rozostupoch ľahko uvažuje: 12-bodový riadok potrebuje na dýchanie približne 14 až 16 bodov vertikálneho kroku, takže zníženie Y o 14 na riadok je rozumným začiatkom riadkovania (leading). Neexistuje žiadny automatický posun riadkov. Každé účaštie (baseline) si počítate sami, čo je pri odsekoch zdĺhavé, ale presné pri formulároch, kde každé pole sedí na pevnej súradnici.
Dve praktické poznámky k názvu písma. Názov sa vyhodnocuje podľa písiem nainštalovaných na zostavovacom stroji a to, čo operačný systém vráti, sa vloží do dokumentu. Preto nie je zaručené, že názov, ktorý funguje na vašom počítači, a názov na zostavovacom serveri budú predstavovať rovnaký typ písma. Písmo musí pokrývať znakové sady použité v reťazci. Behy cyriliky alebo CJK textu s písmom podporujúcim iba latinku sa vykreslia ako prázdne štvorčeky pre chýbajúce glyfy bez akejkoľvek chybovej správy, čo je dôvod, prečo stránka Hello World pri kombinovaní jazykov siaha po univerzálnom Unicode písme.
Argument uhla (angle) otáča text okolo kotvy
Tretí argument je ten, ktorý väčšina kódov ponecháva navždy na nule. Ak odovzdáte nenulovú hodnotu, textový beh sa otočí proti smeru hodinových ručičiek okolo svojej vlastnej kotvy (X, Y) na dolnom ľavom okraji textu o príslušný počet stupňov. Samotná kotva sa neposúva, takže rovnaká súradnica, ktorá umiestnila horizontálny štítok, umiestni aj jeho otočené dvojča; mení sa len smer, ktorým sa glyfy vykresľujú.
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');
Deväťdesiat stupňov je bežný prípad, napríklad štítok bežiaci po boku grafu alebo nadpis na chrbte knihy. Štyridsaťpäť stupňov rieši naklonené hlavičky stĺpcov, čo je trik, ktorý umožňuje umiestniť široký štítok nad úzky stĺpec bez toho, aby presahoval do susedných stĺpcov. Rotácia nemení spôsob interpretácie kotvy, čo môže zmiasť: 90-stupňový textový beh stále začína na súradniciach (X, Y) a rastie odtiaľ smerom nahor. Ak teda chcete otočený štítok vycentrovať, musíte upraviť kotvu, nie uhol. Keď niekoľko otočených behov zdieľa rovnaké účaštie, dajte im rovnaké Y a meňte X, presne tak, ako by ste menili Y pre horizontálne riadky nad sebou.
Umiestňovanie súradníc bez hádania
Súradnice sú tá časť kódu, ktorá prejde kontrolou, alebo potichu zlyhá. HotPDF meria od dolného ľavého rohu stránky, pričom Y rastie smerom nahor, v bodoch v pomere 72 bodov na palec. Stránka formátu US Letter má 612 x 792 bodov; A4 má 595 x 842 bodov. Jednopalcový horný okraj na formáte Letter preto umiestni vaše prvé účaštie približne na Y = 792 mínus 72 mínus veľkosť písma, a nie na nejaké malé číslo blízko vrchu. Každý, kto prichádza zo súradníc obrazovky, kde Y rastie smerom nadol od nuly, napíše prvý riadok pod dolný okraj stránky a potom strávi desať minút premýšľaním, kam zmizol.
Pristupujte k rozloženiu ako k aritmetike voči pomenovaným kotvám, a neberte ho ako stĺpec magických čísel. Ľavý okraj, priebežné účaštie, ktoré znižujete s každým riadkom, a fixné riadkovanie premenia blok štítkov na krátku slučku namiesto hromady literálov v kóde:
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;
Ochrana pred koncom stránky je riadok, na ktorý každý zabudne ako prvý a v reálnej prevádzke na to najviac doplatí. Pod funkciou TextOut nie je žiadne automatické rozloženie toku textu. Ak klesnete pod dolný okraj, text sa bude bez akéhokoľvek varovania vykresľovať ďalej mimo stránky do prázdna. Musíte teda sami sledovať súradnicu Y, zavolať AddPage, keď prekročí dolnú hranicu, a resetovať účaštie. Volanie SetFont po AddPage nie je len nepovinným doplnkom: aktuálne písmo neprežije prechod na novú stránku a prvý text na novej stránke sa bez tohto volania vykreslí predvoleným písmom prehliadača.
Rozostupy znakov a slov pre prispôsobenie a zarovnanie
Niekedy je reťazec správny, ale má nesprávnu šírku: hlavička, ktorá musí preklenúť pevnú šírku, kód, ktorý by sa mal čítať s väčšími rozostupmi medzi číslicami, alebo stĺpec, ktorého hodnoty je potrebné posunúť na zarovnanie. Formát PDF pre tieto účely obsahuje dva operátory stavu textu: rozostupy znakov (Tc, dodatočný priestor pridaný za každý glyf) a rozostupy slov (Tw, dodatočný priestor pridaný pri každom znaku medzery). Oba sa vyjadrujú v neškálovaných jednotkách textového priestoru, prakticky v bodoch pri aktuálnej veľkosti písma. Sú to stavy, nie argumenty pre TextOut, takže ich nastavíte, vykreslíte text a potom ich vrátite späť.
// 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);
Rozostup slov funguje iba na znak medzery (kód 32), čo má dôležitý dôsledok: nerobí nič v texte CJK, ktorý neobsahuje ASCII medzery, a správa sa zvláštne pri texte kódovanom ako indexy glyfov a nie bajty. Pre tabuľkový latinkový výstup je to rýchly spôsob, ako rozšíriť medzery bez prepisovania reťazca. Rozostup znakov je lepším nástrojom pre nadpis, ktorý musí dosiahnuť presnú šírku, pretože rozdelí úpravu rovnomerne na každý glyf namiesto toho, aby ju sústredil len na medzery.
Celé tajomstvo spočíva v resetovaní hodnôt. Rozostupy sú, podobne ako písmo, súčasťou stavu kreslenia stránky a tento stav pretrváva, kým ho nezmeníte. Ak zmeníte rozostupy znakov pre jeden nadpis a zabudnete ich vynulovať, každý odsek pod ním zdedí toto roztiahnutie. To potom pôsobí zvláštne a nesprávne, čo môže prejsť bežnou kontrolou, ale neprejde pozorným čítaním. Spoľahlivým zvykom je nastaviť hodnotu rozostupov, vykresliť potrebný text a hneď v nasledujúcom riadku ju nastaviť späť na nulu, aby žiadny neskorší kód nemusel riešiť, čo robila predchádzajúca sekcia.
Kontrola výstupu tam, kde sa naozaj láme chlieb
Rozloženie textu zvyčajne zlyhá na inom počítači, nie na vašom vývojárskom, takže dôležité kontroly musíte robiť mimo svojho pracovného stola. Otvorte vygenerovaný súbor v systéme, kde nie je nainštalované vaše vývojárske písmo, a overte, či sa vložené písma stále vykresľujú správne (vrátane latinky s diakritikou, iných písiem a interpunkcie) naraz, namiesto náhodnej kontroly jednoduchých znakov. Vyberte a skopírujte niekoľko riadkov, aby ste sa uistili, že ide o skutočný text a nie o krivky, čo je dôležité v momente, keď potrebujete vyhľadávanie alebo extrakciu textu. Naplňte rozloženie reprezentatívnymi údajmi (najdlhším nemeckým štítkom a najširším číslom, nie úhľadným zástupným symbolom), pretože text, ktorý pretečie cez pole, je vždy ten, ktorý ste nezadali ručne. A ak má stránka pasovať do predtlačeného formulára, vytlačte alebo rasterizujte jednu vzorku a priložte ju k originálu; odchýlka účaštia o štvrť milimetra je na obrazovke neviditeľná, ale na papieri okamžite udrie do očí.
Ak ste ešte nenapísali ani jednu stránku, začnite s príkladom HotPDF Hello World, ktorý nastavuje dokument, písmo a súradnicový systém s počiatkom vľavo dole, od ktorého závisí všetko vyššie uvedené. Volania TextOut, SetFont a nastavenia rozostupov zobrazené v tomto článku sú súčasťou komponentu HotPDF pre Delphi a C++Builder.