Egy HotPDF dokumentum minden látható karakterlánca (string) egyetlen híváson keresztül érkezik: TextOut(X, Y, angle, Text). A Hello World példa a legegyszerűbb formájában használja, egyszer beállított betűtípussal és négy argumentummal, amelyeket ésszerű alapértelmezésen hagy. Túl az első oldalon ugyanez a négy argumentum hordozza az elrendezés (layout) teljes súlyát. A harmadik argumentum elforgatja a sorozatot (run). A közvetlenül előtte beállított betűtípus határozza meg a méretet és a stílust. És az X, Y pár, az oldal sarkától pontokban mérve, az egyetlen dolog, ami egy tiszta jelentés (report) és egy olyan szöveg között áll, amely átfed, levágódik, vagy egy sorral lejjebb csúszik valaki más nyomtatóján. Ez az a pont, ahol a TextOut megdolgozik a pénzéért, és ahol az alapértelmezések már nem elegendőek
A szignatúrát (signature) érdemes minden más előtt rögzíteni az emlékezetünkben: X és Y Single érték pontokban (points), az angle egy Extended fokokban (degrees), a Text pedig egy WideString, így a Unicode külön hívás nélkül megy keresztül. Egy második túlterhelés (overload) egy PWORD-öt és egy hosszt fogad arra az esetre, ha már rendelkezik glifakódokkal (glyph codes), de a hagyományos karakterláncok esetében a WideString formátum az, amelyhez nyúlni fog
A méret és a stílus a SetFont-ból származik, nem a TextOut-ból
A TextOut-nak nincs méret paramétere. A méret, a vastagság, a dőlés, mindez abban a SetFont hívásban él, amely megelőzi a sorozatot, és addig marad érvényben, amíg a következő SetFont le nem cseréli. Ez az egyetlen tény, amely megmagyarázza a legtöbb első napi zavart: egy sor azért lesz félkövér (bold), mert három hívással korábban valami beállította az [fsBold]-ot, és semmi sem törölte azt
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
A második argumentum egy TFontStyles halmaz (set), így az [fsBold, fsItalic] félkövér dőlt, a [] pedig normál (plain). A méret pontokban van megadva, ugyanabban a mértékegységben, mint a koordináták, ami megkönnyíti a függőleges térközök (vertical spacing) átgondolását: egy 12 pontos sornak nagyjából 14-16 pont függőleges lépésközzel kell rendelkeznie, hogy lélegezni tudjon, így az Y soronként 14-gyel történő csökkentése ésszerű kiindulási sortávolság (leading). Nincs automatikus soremelés. Minden alapvonalat (baseline) magának kell kiszámítania, ami egy bekezdésnél unalmas, de pontos egy űrlapnál (form), ahol minden mező (field) fix koordinátán helyezkedik el
Két gyakorlati megjegyzés a betűtípus nevével kapcsolatban. Ez a fordítógépen (build machine) telepített betűtípusokkal szemben kerül feloldásra (resolved), és amit az operációs rendszer visszaad, az ágyazódik be, így egy olyan név, amely az Ön asztali gépén feloldódik, és egy név, amely egy build szerveren feloldódik, nem garantált, hogy ugyanaz a betűkészlet lesz. És a betűtípusnak le kell fednie a karakterláncban szereplő írásmódokat (scripts). Egy cirill vagy CJK szövegsorozat egy kizárólag latin betűkészlet (Latin-only face) alatt hiányzó glifadobozokként (missing-glyph boxes) jelenik meg hiba nélkül, ami az oka annak, hogy a Hello World oldal egy széles Unicode betűkészlethez nyúl, amikor nyelveket kever
Az angle argumentum a horgony (anchor) körül forgat
A harmadik argumentum az, amelyet a legtöbb kód örökre nullán hagy. Adjon át egy nem nulla értéket, és a sorozat az óramutató járásával ellentétes irányban elfordul a saját (X, Y) horgonya (anchor), a szöveg bal alsó sarka körül annyi fokkal (degrees). Maga a horgony nem mozog, így ugyanaz a koordináta, amely egy vízszintes címkét (label) elhelyezett, elhelyezi az elforgatott ikertestvérét is; csak a glifák haladási iránya változik
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');
A kilencven fok a gyakori eset, egy címke, amely egy diagram (chart) oldalán vagy egy gerinccímen (spine title) fut felfelé. A negyvenöt fok a megdöntött oszlopfejléceket (column headers) kezeli, az a trükk, amely lehetővé teszi, hogy egy széles címke egy keskeny oszlop felett üljön anélkül, hogy átfolyna a szomszédaira. A forgatás nem változtatja meg a horgony értelmezését, ami sokakat megzavar: egy 90 fokos sorozat továbbra is az (X, Y) koordinátától kezdődik, és onnan nő felfelé, tehát egy elforgatott címke középre igazításához (center) a horgonyt kell beállítania, nem a szöget. Amikor több elforgatott sorozat megoszt egy alapvonalat, adja meg nekik ugyanazt az Y-t, és léptesse az X-et, pontosan úgy, ahogy az Y-t léptetné az egymásra rakott vízszintes soroknál
Koordináták elhelyezése találgatás nélkül
A koordináták az a rész, amely túléli az ellenőrzést, vagy csendben megbukik rajta. A HotPDF az oldal bal alsó sarkától mér, az Y felfelé növekszik, hüvelykenként 72 pontos (points) felbontásban. Egy US Letter oldal 612x792 pont; az A4 595x842. Egy egyhüvelykes (one-inch) felső margó a Letter-en ezért az első alapvonalat az Y = 792 mínusz 72 mínusz a betűméret közelébe helyezi, nem pedig egy kis számhoz a teteje közelében. Bárki, aki a képernyőkoordináták felől érkezik, ahol az Y nullától lefelé növekszik, az első sort az alsó peremen (bottom edge) kívülre írja, és tíz percet tölt azzal, hogy azon tűnődik, hová lett
Kezelje az elrendezést (layout) úgy, mint nevesített horgonyokkal végzett aritmetikát, nem pedig mágikus számok (magic numbers) oszlopaként. Egy bal margó, egy futó alapvonal (running baseline), amelyet soronként csökkent, és egy rögzített sortávolság (fixed leading) egy címkeblokkot egy rövid ciklussá változtat egy falnyi literál (literals) helyett:
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;
Az oldaltörés védelme (page-break guard) az a sor, amelyet mindenki először felejt el, és amelyet a gyakorlat a leginkább megbüntet. A TextOut alatt nincs folytonos elrendezés (flow layout). Csökkentse az értéket az alsó margón túlra, és a szöveg továbbra is a kötésmargóba (gutter), az oldalról lefelé, a semmibe rajzolódik, mindenféle figyelmeztetés nélkül. Tehát magának kell figyelnie az Y-t, hívja meg az AddPage-t, amikor átlépi a padlót (floor), és állítsa alaphelyzetbe az alapvonalat (baseline). Az AddPage utáni SetFont nem opcionális kitöltés (padding): az aktuális betűtípus nem éli túl az oldaltörést, és az új oldalon az első sorozat a nézegető (viewer) alapértelmezett betűtípusával jelenik meg, ha kihagyja
Karakter- és szóköz a megfelelő illeszkedéshez és igazításhoz
Néha egy karakterlánc helyes, de nem megfelelő a szélessége: egy fejléc, amelynek egy rögzített vonalat (rule) kell átfognia, egy kód, amelyet szellősebb számjegyekkel (digits) kellene olvasni, egy oszlop, amelynek az értékeit az igazításhoz mozgatni (nudged) kell. A PDF két szövegállapot-operátort (text-state operators) hordoz ehhez, a karakterközt (Tc, extra szóköz (space) minden glifa után) és a szóközt (Tw, extra szóköz (space) minden szóköz (space character) karakternél), és mindkettő skálázatlan (unscaled) szövegtér-egységekben (text-space units) van kifejezve, gyakorlatilag pontokban az aktuális betűméretnél. Ezek állapotok (state), nem argumentumok a TextOut-hoz, így beállítja őket, rajzol, majd visszaállítja őket
// 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);
A szóköz (word spacing) csak a szóköz (space) karakterre (32-es kód) hat, aminek van egy olyan következménye, amit érdemes tudni: nem csinál semmit egy olyan CJK sorozat (run) belsejében, amelynek nincsenek ASCII szóközei, és furcsán lép interakcióba az olyan szöveggel, amely nem bájtokként (bytes), hanem glifaindexekként van kódolva. Latin táblázatos (tabular) kimenet esetén ez az olcsó módja a rések (gaps) kiszélesítésének a karakterlánc (string) újragépelése nélkül. A karaktertérköz (character spacing) a jobb eszköz egy olyan fejléc (heading) esetében, amelynek el kell érnie egy cél szélességet (target width), mivel a beállítást egyenletesen elosztja az összes glifán (glyph), ahelyett, hogy a szóközöknél gyűjtené össze (pooling)
A visszaállítás az egész fegyelem. A térköz, akárcsak a betűtípus, az oldal rajzolási állapotának (drawing state) része, és az állapot mindaddig fennmarad, amíg meg nem változtatja. Ha betűközzel (letter-space) lát el egy fejlécet, és elfelejti kinullázni, minden alatta lévő bekezdés örökli a nyújtást (stretch), ami olyan finom, nehezen elhelyezhető hibaként (wrongness) olvasható, amely túléli a felületes korrektúrát (proofread), de megbukik az alaposon. A megbízható szokás az, hogy beállít egy térközértéket (spacing value), megrajzolja azt a sorozatot (run), amelynek szüksége van rá, és a következő sorban visszaállítja nullára, így egyetlen későbbi kódnak sem kell tudnia, hogy mit csinált egy korábbi szakasz
A kimenet ellenőrzése ott, ahol az valóban megbukik
A szöveg elrendezése a második gépen vall kudarcot, nem az elsőn, így a számottevő ellenőrzések az Ön asztalától távol történnek. Nyissa meg a generált fájlt egy olyan rendszeren, amelyen nincs telepítve a fejlesztői betűkészlete (developer font set), és győződjön meg arról, hogy a beágyazott betűtípusok továbbra is renderelődnek, beleértve az ékezetes latint, minden nem latin írásmódot (scripts) és az írásjeleket (punctuation), mindezt egy menetben (one pass), ahelyett, hogy szúrópróbaszerűen ellenőrizné (spot-checking) az egyszerű karaktereket. Jelöljön ki és másoljon le néhány sort, hogy megbizonyosodjon arról, hogy a szöveg valódi szöveg, nem pedig körvonalak (outlines), ami attól a pillanattól kezdve számít, amint a keresés vagy a kinyerés (extraction) képbe kerül. Tápláljon be az elrendezésbe reprezentatív adatokat, a leghosszabb német címkét és a legszélesebb számot, ne pedig egy rendezett helyőrzőt (placeholder), mert mindig az a sorozat (run) fog túlcsordulni (overflows) egy mezőn (field), amelyet nem Ön gépelt be kézzel. Ha pedig az oldalnak egy előre nyomtatott (preprinted) űrlapra kell kerülnie, nyomtasson ki vagy raszterizáljon (rasterize) egy mintát, és tegye az eredetire; egy negyed milliméteres alapvonal-eltolódás (baseline drift) a képernyőn láthatatlan, papíron viszont egyértelmű
Ha még egyetlen oldalt sem írt, kezdje a HotPDF Hello World példával, amely beállítja a dokumentumot, a betűtípust és azt a bal alsó koordináta-rendszert, amelytől a fentiek mindegyike függ. A TextOut, a SetFont és az itt bemutatott térközhívások (spacing calls) a HotPDF Component részét képezik Delphi-hez és C++Builder-hez