Tekninen artikkeli

HotPDF TextOut: koko, tyyli, kierto ja välistys

Jokainen HotPDF-asiakirjan näkyvä merkkijono piirretään kutsulla TextOut(X, Y, angle, Text). Hello World -esimerkissä fontti asetetaan kerran ja neljä argumenttia saavat yksinkertaiset arvot, mutta myöhemmässä asettelussa kolmas argumentti kiertää tekstijaksoa, edeltävä SetFont määrää koon ja tyylin ja pisteinä mitattu X/Y-pari ratkaisee, pysyykö raportti kohdallaan myös toisella tulostimella. Tässä vaiheessa oletusarvot eivät enää riitä

Allekirjoitus (signature) on syytä painaa mieleen ennen mitään muuta: X ja Y ovat Single-tyyppisiä pisteinä, angle on Extended asteina ja Text on WideString, joten Unicode menee läpi ilman erillistä kutsua. Toinen ylikuormitus (overload) ottaa vastaan PWORD-osoittimen plus pituuden silloin, kun pidät jo hallussasi glyyfikoodit, mutta tavallisille merkkijonoille WideString-muoto on se, johon tartut

Koko ja tyyli tulevat SetFont-kutsusta, ei TextOutista

TextOutilla ei ole kokoparametria. Koko, paksuus, kallistus, kaikki tuo asuu ajoa edeltävässä SetFont-kutsussa, ja se pysyy voimassa, kunnes seuraava SetFont korvaa sen. Tuo on se ainoa tosiasia, joka selittää suurimman osan ensimmäisen päivän hämmennyksestä: rivi tulee ulos lihavoituna, koska kolme kutsua aiemmin jokin asetti [fsBold] eikä mikään tyhjentänyt sitä

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

Toinen argumentti on TFontStyles-joukko, joten [fsBold, fsItalic] on lihavoitu kursiivi ja [] on tavallinen. Koko on pisteinä, samassa yksikössä kuin koordinaatit, mikä tekee pystysuorasta välistyksestä helpon järkeillä: 12 pisteen rivi haluaa karkeasti 14–16 pistettä pystysuoraa askelta hengittääkseen, joten Y:n pudottaminen 14:llä riviä kohden on kohtuullinen aloitusriviväli (leading). Automaattista rivinsiirtoa ei ole. Lasket jokaisen perusviivan itse, mikä on työlästä kappaleelle, mutta tarkkaa lomakkeelle, jossa jokainen kenttä istuu kiinteässä koordinaatissa

Kaksi käytännön huomiota fontin nimestä. Se ratkaistaan käännöskoneelle asennettuja fontteja vasten, ja mitä tahansa käyttöjärjestelmä antaa takaisin, se on se, mikä upotetaan, joten työpöydälläsi ratkeava nimi ja käännöspalvelimella (build server) ratkeava nimi eivät takuulla ole sama kirjasin (face). Ja fontin on katettava merkkijonon kirjoitusjärjestelmät (scripts). Kyrillisen tai CJK-tekstin ajo vain latinalaisia merkkejä tukevalla kirjasimella renderöityy puuttuvan glyyfin laatikoiksi ilman virhettä, mikä on syy, miksi Hello World -sivu tarttuu laajaan Unicode-kirjasimeen kieliä sekoittaessaan

HotPDF TextOut -sivu, joka näyttää Arialin, Times New Romanin ja Courier New'n renderöitynä normaali-, lihavointi- ja kursiiviasetuksilla useissa merkistöissä

Kulma-argumentti (angle) kiertää ankkurin ympäri

Kolmas argumentti on se, jonka suurin osa koodista jättää nollaan ikuisesti. Välitä nollasta poikkeava arvo, ja ajo kiertyy vastapäivään oman (X, Y) -ankkurinsa – tekstin vasemman alakulman – ympäri kyseisen astemäärän verran. Itse ankkuri ei liiku, joten sama koordinaatti, joka asetti vaakasuoran nimikkeen, asettaa sen kierretyn kaksosen; vain suunta, johon glyyfit marssivat, muuttuu

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');

Yhdeksänkymmentä astetta on yleinen tapaus, kaavion kylkeä ylös kulkeva nimike tai selkämyksen otsikko. Neljäkymmentäviisi astetta käsittelee kallistetut sarakkeiden otsikot, tempun, joka antaa leveän nimikkeen istua kapean sarakkeen päällä läikkymättä naapureihinsa. Kierto ei muuta sitä, miten ankkuria tulkitaan, mikä kaataa ihmisiä: 90 asteen ajo alkaa yhä koordinaatista (X, Y) ja kasvaa siitä ylöspäin, joten kierretyn nimikkeen keskittämiseksi säädät ankkuria, et kulmaa. Kun useat kierretyt ajot jakavat perusviivan, anna niille sama Y ja askeleta X:ää, täsmälleen samalla tavalla kuin askeltaisit Y:tä pinotuille vaakasuorille riville

Koordinaattien sijoittaminen arvailematta

Koordinaatit ovat se osa, joka selviää katselmoinnista (review) tai hiljaisesti reputtaa sen. HotPDF mittaa sivun vasemmasta alakulmasta, Y:n kasvaessa ylöspäin, pisteinä 72 tuumaa kohden. US Letter -sivu on 612 kertaa 792 pistettä; A4 on 595 kertaa 842. Tuuman ylämarginaali Letterissä asettaa siten ensimmäisen perusviivasi lähelle arvoa Y = 792 miinus 72 miinus fontin koko, ei johonkin pieneen lukuun yläosan lähellä. Kuka tahansa, joka saapuu ruutukoordinaateista, missä Y kasvaa alaspäin nollasta, kirjoittaa ensimmäisen rivin alareunan yli ja viettää kymmenen minuuttia ihmetellen, minne se meni

Käsittele asettelua (layout) aritmetiikkana nimettyjä ankkureita vasten ennemmin kuin sarakkeena taikanumeroita. Vasen marginaali, juokseva perusviiva, jota vähennät riviä kohden, ja kiinteä riviväli (leading) muuttavat nimikkeiden lohkon lyhyeksi silmukaksi literaalien seinän sijaan:

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;

Sivunvaihdon suoja (page-break guard) on se rivi, jonka kaikki unohtavat ensimmäisenä ja johon kenttä (field) osuu kovimmin. TextOutin alla ei ole virtauksen asettelua (flow layout). Vähennä alareunan marginaalin ohi, ja teksti jatkaa piirtymistä kouruun, sivun ulkopuolelle, tyhjyyteen, ilman varoitusta. Joten vahdit Y:tä itse, kutsut menetelmää AddPage, kun se ylittää lattian, ja nollaat perusviivan. SetFont menetelmän AddPage jälkeen ei ole valinnaista pehmustetta: nykyinen fontti ei selviä sivunvaihdosta, ja uuden sivun ensimmäinen ajo tulee ulos katseluohjelman oletuskirjasimella, jos ohitat sen

Merkkien ja sanojen välistys istuvuutta ja kohdistusta varten

Toisinaan merkkijono on oikea mutta väärän levyinen: otsikko, jonka on ulotuttava kiinteän viivan yli, koodi, jota pitäisi lukea ilmavammilla numeroilla, sarake, joka tarvitsee arvojaan tönäistäväksi asettuakseen linjaan. PDF kantaa kaksi tekstitilan operaattoria tätä varten, merkkivälistys (character spacing, Tc, jokaisen glyyfin jälkeen lisätty ylimääräinen tila) ja sanavälistys (word spacing, Tw, jokaiseen välilyöntiin lisätty ylimääräinen tila), ja molemmat ilmaistaan skaalaamattomina tekstitilan yksikköinä, käytännössä pisteinä nykyisessä fonttikoossa. Ne ovat tilaa, eivät argumentteja TextOutille, joten asetat ne, piirrät, ja asetat ne takaisin

// 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);

Sanavälistys toimii vain välilyöntimerkkiin (koodi 32), millä on tietämisen arvoinen seuraus: se ei tee mitään CJK-ajon sisällä, jossa ei ole ASCII-välilyöntejä, ja se vuorovaikuttaa oudosti tekstin kanssa, joka on koodattu glyyfi-indekseinä tavujen sijaan. Latinalaiselle taulukkotulosteelle se on halpa tapa leventää aukkoja kirjoittamatta merkkijonoa uudelleen. Merkkivälistys on parempi työkalu otsikolle, jonka täytyy saavuttaa tavoiteleveys, koska se jakaa säädön tasaisesti jokaisen glyyfin yli sen sijaan, että se kerääntyisi välilyönteihin

Nollaus on koko kuri. Välistys, kuten fonttikin, on osa sivun piirtotilaa (drawing state), ja tila jatkuu, kunnes muutat sitä. Laita kirjainvälistys yhteen otsikkoon ja unohda nollata se, ja jokainen alla oleva kappale perii venytyksen, mikä luetaan hienovaraisena, vaikeasti paikannettavana vääryytenä, joka selviää rennosta oikoluvusta ja reputtaa huolellisen. Luotettava tapa on asettaa välistysarvo, piirtää sitä tarvitseva ajo, ja asettaa se takaisin nollaan seuraavalla rivillä, jotta minkään myöhemmän koodin ei tarvitse tietää, mitä aiempi osio teki

HotPDF TextOut -sivu, joka vertailee horisontaalista tekstin skaalausta, merkkivälistystä, sanavälistystä ja fill versus stroke -renderöintitiloja

Tulosteen tarkistaminen siellä, missä se oikeasti menee rikki

Tekstin asettelu epäonnistuu toisella koneella, ei ensimmäisellä, joten merkitykselliset tarkistukset tapahtuvat poissa työpöytäsi äärestä. Avaa generoitu tiedosto järjestelmässä, johon ei ole asennettu kehittäjän fonttijoukkoa, ja vahvista, että upotetut kirjasimet renderöityvät edelleen, mukaan lukien aksentillinen latina, kaikki ei-latinalaiset kirjoitusjärjestelmät ja välimerkit, yhdellä läpikäynnillä mieluummin kuin helpot merkit pistokoetarkistamalla. Valitse ja kopioi muutama rivi vahvistaaksesi, että teksti on aitoa tekstiä eikä ääriviivoja, millä on väliä sillä hetkellä, kun haku tai purku on kuvassa. Syötä asettelulle edustavaa dataa, pisin saksalainen nimike ja levein numero, ei siisti paikanvaraaja (placeholder), koska ajo, joka valuu kentän yli, on aina se, jota et kirjoittanut käsin. Ja jos sivun on laskeuduttava esipainetulle lomakkeelle, tulosta tai rasteroi yksi näyte ja aseta se alkuperäistä vasten; neljännesmillimetrin perusviivan ajelehtiminen on näkymätön näytöllä ja ilmiselvä paperilla

Jos et ole vielä kirjoittanut yhtäkään sivua, aloita HotPDF Hello World -esimerkistä, joka pystyttää asiakirjan, fontin ja vasemman alakulman koordinaatiston, johon kaikki yllä oleva nojaa. Tässä näytetyt TextOut-, SetFont- ja välistyskutsut ovat osa HotPDF-komponenttia Delphille ja C++Builderille