Teknisk artikkel

HotPDF TextOut i Delphi: størrelse, stil, rotasjon, avstand

Hver synlige streng i et HotPDF-dokument kommer gjennom ett kall: TextOut(X, Y, angle, Text). Hello World-eksempelet bruker det på sitt enkleste, med skriften satt én gang og fire argumenter latt stå på fornuftige standardverdier. Etter den første siden bærer de samme fire argumentene hele vekten av layouten. Det tredje argumentet roterer tekstsekvensen. Skriften som settes rett før, avgjør størrelse og stil. Og X, Y-paret, målt fra sidehjørnet i punkter, er det eneste som står mellom en ren rapport og tekst som overlapper, klippes eller driver en linje lavere på en annens skriver. Det er her TextOut gjør nytte for seg, og der standardverdiene slutter å strekke til

Signaturen er verdt å feste seg ved før noe annet: X og Y er Single i punkter, angle er en Extended i grader, og Text er en WideString, så Unicode går gjennom uten et eget kall. En andre overlast tar en PWORD pluss en lengde for de gangene du allerede har glyfkodene, men for vanlige strenger er WideString-formen den du griper til

Størrelse og stil kommer fra SetFont, ikke fra TextOut

TextOut har ingen størrelsesparameter. Størrelsen, vekten, hellingen, alt sammen ligger i SetFont-kallet som kommer foran sekvensen, og det gjelder til neste SetFont erstatter det. Det er det ene faktumet som forklarer mesteparten av forvirringen den første dagen: en linje kommer ut i fet skrift fordi noe tre kall tidligere satte [fsBold] og ingenting nullstilte det

Pdf.CurrentPage.SetFont('Times New Roman', [], 24);
Pdf.CurrentPage.TextOut(72, 740, 0, 'Quarterly Report');        // 24 pt vanlig

Pdf.CurrentPage.SetFont('Times New Roman', [fsBold], 12);
Pdf.CurrentPage.TextOut(72, 712, 0, 'Revenue');                 // 12 pt fet

Pdf.CurrentPage.SetFont('Times New Roman', [fsItalic], 11);
Pdf.CurrentPage.TextOut(72, 694, 0, 'figures in thousands');    // 11 pt kursiv

Pdf.CurrentPage.SetFont('Courier New', [fsBold, fsItalic], 10);
Pdf.CurrentPage.TextOut(72, 676, 0, '  +18.4% YoY');            // stiler kombineres

Det andre argumentet er et TFontStyles-sett, så [fsBold, fsItalic] er fet kursiv og [] er vanlig. Størrelsen er i punkter, den samme enheten som koordinatene, noe som gjør loddrett avstand lett å resonnere om: en linje på 12 punkter vil ha omtrent 14 til 16 punkter loddrett steg for å puste, så å senke Y med 14 per linje er et rimelig utgangspunkt for linjeavstanden. Det finnes ingen automatisk linjeframføring. Du regner ut hver grunnlinje selv, noe som er kjedelig for et avsnitt, men eksakt for et skjema, der hvert felt sitter på en fast koordinat

To praktiske merknader om skriftnavnet. Det løses opp mot skriftene som er installert på byggemaskinen, og det operativsystemet gir tilbake, er det som bygges inn, så et navn som løses opp på skrivebordet ditt og et navn som løses opp på en byggeserver er ikke garantert å være samme skriftsnitt. Og skriften må dekke skriftsystemene i strengen. En sekvens med kyrillisk eller CJK-tekst under et snitt som bare har latinske tegn, gjengis som bokser for manglende glyfer uten noen feilmelding, og det er grunnen til at Hello World-siden griper til et bredt Unicode-snitt når den blander språk

HotPDF TextOut-side som viser Arial, Times New Roman og Courier New gjengitt med vanlig, fet og kursiv stil på tvers av flere tegnsett

Vinkelargumentet roterer rundt ankeret

Det tredje argumentet er det de fleste lar stå på null for alltid. Send inn en verdi ulik null, og sekvensen roterer mot klokken om sitt eget (X, Y)-anker, nederst til venstre i teksten, med så mange grader. Selve ankeret flytter seg ikke, så den samme koordinaten som plasserte en vannrett etikett, plasserer den roterte tvillingen; bare retningen glyfene marsjerer i, endres

Diagram over rotasjonsgeometrien i HotPDF TextOut: sekvenser på 0, 45 og 90 grader som svinger mot klokken rundt et fast anker nederst til venstre, med eksempler på Delphi TextOut-kall for ryggetiketter, vannmerker og skråstilte kolonneoverskrifter
En vinkel ulik null vender sekvensen mot klokken om sitt urørlige anker nederst til venstre, og felles grunnlinjer stepper X akkurat slik vannrette linjer stepper Y
Pdf.CurrentPage.SetFont('Arial', [fsBold], 11);

// En loddrett akseetikett ned langs venstre marg: 90 grader leses nedenfra og opp.
Pdf.CurrentPage.TextOut(40, 300, 90, 'Units sold');

// Et diagonalt DRAFT-vannmerke tvers over sidekroppen.
Pdf.CurrentPage.SetFont('Arial', [fsBold], 60);
Pdf.CurrentPage.TextOut(150, 250, 45, 'DRAFT');

// Kolonneoverskrifter vippet 60 grader så lange etiketter får plass i en smal tabell.
Pdf.CurrentPage.SetFont('Arial', [], 9);
Pdf.CurrentPage.TextOut(120, 600, 60, 'Q1 actual');
Pdf.CurrentPage.TextOut(160, 600, 60, 'Q2 actual');

Nitti grader er det vanlige tilfellet, en etikett som går opp langs siden av et diagram eller en ryggtittel. Førtifem grader dekker skråstilte kolonneoverskrifter, trikset som lar en bred etikett sitte over en smal kolonne uten å søle inn i naboene. Rotasjon endrer ikke hvordan ankeret tolkes, og det snubler folk i: en sekvens på 90 grader starter fortsatt i (X, Y) og vokser oppover derfra, så for å sentrere en rotert etikett justerer du ankeret, ikke vinkelen. Når flere roterte sekvenser deler en grunnlinje, gir du dem samme Y og stepper X, akkurat som du ville steppet Y for stablede vannrette linjer

Plassere koordinater uten å gjette

Koordinatene er den delen som overlever en gjennomgang eller stille feiler den. HotPDF måler fra nedre venstre hjørne av siden, med Y som vokser oppover, i punkter à 72 per tomme. En US Letter-side er 612 ganger 792 punkter; A4 er 595 ganger 842. En toppmarg på én tomme på Letter legger derfor den første grunnlinjen nær Y = 792 minus 72 minus skriftstørrelsen, ikke på et lite tall nær toppen. Alle som kommer fra skjermkoordinater, der Y vokser nedover fra null, skriver den første linjen utenfor nedre kant og bruker ti minutter på å lure på hvor den ble av

HotPDF: Diagram av en US Letter-side som viser grunnlinjearitmetikk med LeftMargin 72, TopBaseline 720 og en fast Leading som stepper mot bunnmargens gulv ved Y 72, ved siden av layoutløkken med navngitte konstanter, dens manuelle AddPage-vakt og nullstilling av SetFont
Navngitte ankre gjør en kolonne med magiske tall om til aritmetikk: trekk Leading fra den løpende grunnlinjen for hver linje og vokt gulvet selv med AddPage

Behandle layout som aritmetikk mot navngitte ankre heller enn som en kolonne med magiske tall. En venstremarg, en løpende grunnlinje du trekker fra per linje, og en fast linjeavstand gjør en blokk med etiketter om til en kort løkke i stedet for en vegg av litteraler:

const
  LeftMargin = 72;        // 1 tomme inn
  TopBaseline = 720;       // første linje, ca. 1 tomme ned på Letter
  Leading = 16;            // loddrett steg mellom linjene
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            // bunnmargen er nådd
    begin
      Pdf.AddPage;
      Pdf.CurrentPage.SetFont('Arial', [], 11);  // skriften nullstilles på ny side
      Y := TopBaseline;
    end;
  end;
end;

Sidebruddsvakten er linjen alle glemmer først og som slår hardest ute i felten. Det finnes ingen flytlayout under TextOut. Trekk deg forbi bunnmargen, og teksten fortsetter å tegne ned i renna, utenfor siden, ut i ingenting, uten noen advarsel. Så du holder øye med Y selv, kaller AddPage når den krysser gulvet, og nullstiller grunnlinjen. SetFont etter AddPage er ikke overflødig fyll: den gjeldende skriften overlever ikke et sidebrudd, og den første sekvensen på den nye siden kommer ut i visningsprogrammets standardsnitt hvis du hopper over den

Tegn- og ordavstand for tilpasning og justering

Noen ganger er en streng riktig, men har feil bredde: en overskrift som skal spenne over en fast strek, en kode som bør leses med luftigere sifre, en kolonne som trenger verdiene dyttet på plass. PDF har to teksttilstandsoperatorer for dette, tegnavstand (Tc, ekstra plass lagt til etter hver glyf) og ordavstand (Tw, ekstra plass lagt til ved hvert mellomromstegn), og begge uttrykkes i uskalerte tekstromsenheter, i praksis punkter ved gjeldende skriftstørrelse. De er tilstand, ikke argumenter til TextOut, så du setter dem, tegner, og setter dem tilbake

HotPDF: Tegnavstand Tc som sprer ekstra plass jevnt etter hver glyf i SUMMARY, mot ordavstand Tw som samler den bare ved mellomromstegn, koblet inn i syklusen sett, tegn og nullstill som hindrer at avstandstilstand lekker inn i senere avsnitt
Tc sprer justeringen sin over hver glyf, mens Tw bare virker på mellomromstegnet, og en nullstilling på neste linje holder tegnetilstanden ren
// Sperr en kort overskrift så den strekker seg over en strek.
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);   // nullstill før vanlig brødtekst

// Åpne opp mellomrommene mellom ordene på én bred linje.
Pdf.CurrentPage.SetWordSpacing(6);
Pdf.CurrentPage.SetFont('Arial', [], 11);
Pdf.CurrentPage.TextOut(72, 712, 0, 'Name        Department        Extension');
Pdf.CurrentPage.SetWordSpacing(0);

Ordavstand virker bare på mellomromstegnet (kode 32), noe som har en konsekvens verdt å kjenne: den gjør ingenting inne i en CJK-sekvens uten ASCII-mellomrom, og den samvirker rart med tekst kodet som glyfindekser i stedet for byte. For latinsk tabelloppsett er den den billige måten å utvide mellomrom på uten å skrive strengen om. Tegnavstand er det bedre verktøyet for en overskrift som må nå en målbredde, siden den sprer justeringen jevnt over hver glyf i stedet for å samle den ved mellomrommene

Nullstillingen er hele disiplinen. Avstand er, som skriften, en del av sidens tegnetilstand, og tilstand varer til du endrer den. Sperr én overskrift og glem å nulle den, så arver hvert avsnitt under strekket, noe som leses som en subtil og vanskelig plasserbar skjevhet som overlever en rask korrektur og feller en grundig. Den pålitelige vanen er å sette en avstandsverdi, tegne sekvensen som trenger den, og sette den tilbake til null på neste linje, slik at ingen senere kode må vite hva en tidligere del gjorde

HotPDF TextOut-side som sammenligner vannrett tekstskalering, tegnavstand, ordavstand og gjengivelsesmoduser med fyll mot strek

Sjekke resultatet der det faktisk brekker

Tekstlayout feiler på den andre maskinen, ikke den første, så sjekkene som betyr noe skjer borte fra pulten din. Åpne den genererte filen på et system uten utviklerskriftene dine installert og bekreft at de innebygde snittene fortsatt gjengis, inkludert aksenterte latinske tegn, eventuelle ikke-latinske skriftsystemer og tegnsetting, i én omgang heller enn å stikkprøve de lette tegnene. Merk og kopier noen linjer for å bekrefte at teksten er ekte tekst og ikke omriss, noe som betyr noe i det øyeblikket søk eller uttrekk er i bildet. Mat layouten med representative data, den lengste tyske etiketten og det bredeste tallet, ikke et pent plassholderord, for sekvensen som flommer over et felt er alltid den du ikke skrev inn for hånd. Og skal siden lande på et forhåndstrykt skjema, skriv ut eller rastrer én prøve og legg den mot originalen; en grunnlinjeforskyvning på en kvart millimeter er usynlig på skjermen og åpenbar på papir

Har du ennå ikke skrevet en eneste side, start med Hello World-eksempelet for HotPDF, som setter opp dokumentet, skriften og koordinatsystemet med origo nederst til venstre som alt over hviler på. Kallene TextOut og SetFont og avstandskallene som er vist her, er en del av HotPDF Delphi Component for Delphi og C++Builder