Articol tehnic

TextOut HotPDF în Delphi: dimensiune, stil, rotație

Fiecare șir vizibil dintr-un document HotPDF sosește printr-un singur apel: TextOut(X, Y, angle, Text). Exemplul Hello World îl folosește în forma lui cea mai simplă, cu fontul setat o dată și cu patru argumente lăsate la valori implicite rezonabile. Dincolo de acea primă pagină, aceleași patru argumente duc toată greutatea aranjamentului. Al treilea argument rotește secvența de text. Fontul setat chiar înaintea ei hotărăște dimensiunea și stilul. Iar perechea X, Y, măsurată din colțul paginii în puncte, este singurul lucru care stă între un raport curat și un text care se suprapune, se taie sau alunecă un rând mai jos pe imprimanta altcuiva. Aici își merită TextOut locul și aici valorile implicite încetează să fie de ajuns

Merită fixată în minte semnătura, înainte de orice altceva: X și Y sunt Single în puncte, angle este un Extended în grade, iar Text este un WideString, deci Unicode trece fără vreun apel separat. O a doua supraîncărcare primește un PWORD plus o lungime, pentru cazul în care aveți deja coduri de glife, dar pentru șiruri obișnuite forma cu WideString este cea la care apelați

Dimensiunea și stilul vin din SetFont, nu din TextOut

TextOut nu are parametru de dimensiune. Dimensiunea, grosimea, înclinarea, toate stau în apelul SetFont care precedă secvența și rămân în vigoare până când următorul SetFont le înlocuiește. Acesta este faptul care explică cea mai mare parte a confuziei din prima zi: o linie iese aldină pentru că, cu trei apeluri mai devreme, ceva a setat [fsBold] și nimic nu a golit setarea

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

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

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

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

Al doilea argument este o mulțime TFontStyles, deci [fsBold, fsItalic] înseamnă aldin cursiv, iar [] înseamnă simplu. Dimensiunea este în puncte, aceeași unitate ca a coordonatelor, ceea ce face ușor de judecat distanțarea pe verticală: o linie de 12 puncte vrea cam 14 până la 16 puncte de pas vertical ca să respire, deci scăderea lui Y cu 14 pe linie este un interlinie de pornire rezonabil. Nu există niciun avans automat de linie. Fiecare linie de bază o calculați chiar dumneavoastră, ceea ce este obositor pentru un paragraf, dar exact pentru un formular, unde fiecare câmp stă la o coordonată fixă

Două note practice despre numele fontului. El este rezolvat față de fonturile instalate pe mașina de compilare, iar ce înapoiază sistemul de operare este ce se încorporează, deci un nume care se rezolvă pe desktopul dumneavoastră și un nume care se rezolvă pe un server de compilare nu sunt garantat același font. Iar fontul trebuie să acopere scrierile din șir. O secvență de text chirilic sau CJK cu un font doar latin se randează ca niște casete de glifă lipsă, fără nicio eroare, motiv pentru care pagina Hello World apelează la un font Unicode larg atunci când amestecă limbi

Pagină HotPDF TextOut care arată Arial, Times New Roman și Courier New randate cu stiluri normal, aldin și cursiv, pe mai multe seturi de caractere

Argumentul de unghi rotește în jurul ancorei

Al treilea argument este cel pe care mai tot codul îl lasă la zero pentru totdeauna. Transmiteți o valoare diferită de zero și secvența se rotește în sens trigonometric în jurul propriei ancore (X, Y), stânga jos a textului, cu atâtea grade. Ancora în sine nu se mișcă, deci aceeași coordonată care a plasat o etichetă orizontală plasează și geamăna ei rotită; se schimbă doar direcția în care mărșăluiesc glifele

Diagramă a geometriei de rotație TextOut din HotPDF: secvențe la 0, 45 și 90 de grade care pivotează în sens trigonometric în jurul unei ancore fixe din stânga jos, cu exemple de apeluri TextOut în Delphi pentru etichete de cotor, filigrane și antete de coloană înclinate
Un unghi diferit de zero întoarce secvența în sens trigonometric în jurul ancorei ei nemișcate din stânga jos, iar liniile de bază comune pășesc pe X exact cum liniile orizontale pășesc pe Y
Pdf.CurrentPage.SetFont('Arial', [fsBold], 11);

// O etichetă de axă verticală pe marginea din stânga: 90 de grade se citește de jos în sus.
Pdf.CurrentPage.TextOut(40, 300, 90, 'Units sold');

// Un filigran DRAFT diagonal peste corpul paginii.
Pdf.CurrentPage.SetFont('Arial', [fsBold], 60);
Pdf.CurrentPage.TextOut(150, 250, 45, 'DRAFT');

// Antete de coloană înclinate la 60 de grade, ca etichetele lungi să încapă într-un tabel îngust.
Pdf.CurrentPage.SetFont('Arial', [], 9);
Pdf.CurrentPage.TextOut(120, 600, 60, 'Q1 actual');
Pdf.CurrentPage.TextOut(160, 600, 60, 'Q2 actual');

Nouăzeci de grade este cazul obișnuit, o etichetă care urcă pe latura unui grafic sau un titlu de cotor. Patruzeci și cinci de grade rezolvă antetele de coloană înclinate, trucul care lasă o etichetă lată să stea peste o coloană îngustă fără să se reverse peste vecine. Rotația nu schimbă felul în care este interpretată ancora, ceea ce încurcă lumea: o secvență la 90 de grade tot începe la (X, Y) și crește de acolo în sus, deci, ca să centrați o etichetă rotită, ajustați ancora, nu unghiul. Când mai multe secvențe rotite împart o linie de bază, dați-le același Y și pășiți pe X, exact cum ați păși pe Y pentru linii orizontale stivuite

Plasarea coordonatelor fără să ghiciți

Coordonatele sunt partea care trece de o revizuire sau cade tăcut la ea. HotPDF măsoară din colțul din stânga jos al paginii, cu Y crescând în sus, în puncte, la 72 pe inch. O pagină US Letter are 612 pe 792 de puncte; A4 are 595 pe 842. O margine de sus de un inch pe Letter pune, prin urmare, prima linie de bază lângă Y = 792 minus 72 minus dimensiunea fontului, nu la vreun număr mic de lângă partea de sus. Oricine vine dinspre coordonatele de ecran, unde Y crește în jos de la zero, scrie prima linie dincolo de marginea de jos și pierde zece minute întrebându-se unde s-a dus

HotPDF: diagramă a unei pagini US Letter care arată aritmetica liniei de bază, cu LeftMargin 72, TopBaseline 720 și un Leading fix care coboară spre pragul marginii de jos la Y 72, alături de bucla de aranjare cu constante denumite, cu garda manuală AddPage și resetarea SetFont
Ancorele denumite transformă o coloană de numere magice în aritmetică: scădeți din linia de bază curentă câte un Leading la fiecare rând și păziți singur pragul de jos cu AddPage

Tratați aranjamentul ca pe o aritmetică față de ancore denumite, nu ca pe o coloană de numere magice. O margine stângă, o linie de bază curentă pe care o scădeți la fiecare rând și un interlinie fix transformă un bloc de etichete într-o buclă scurtă, în loc de un zid de literali:

const
  LeftMargin = 72;        // 1 inch de la margine
  TopBaseline = 720;       // primul rând, la ~1 inch de sus pe Letter
  Leading = 16;            // pasul vertical între rânduri
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            // s-a atins marginea de jos
    begin
      Pdf.AddPage;
      Pdf.CurrentPage.SetFont('Arial', [], 11);  // fontul se resetează pe o pagină nouă
      Y := TopBaseline;
    end;
  end;
end;

Garda de schimbare a paginii este linia pe care toată lumea o uită prima și pe care realitatea o lovește cel mai tare. Sub TextOut nu există niciun aranjament în flux. Coborâți dincolo de marginea de jos și textul continuă să se deseneze în jgheab, în afara paginii, în neant, fără niciun avertisment. Așa că îl urmăriți chiar dumneavoastră pe Y, apelați AddPage când trece de prag și resetați linia de bază. Apelul SetFont de după AddPage nu este umplutură opțională: fontul curent nu supraviețuiește unei schimbări de pagină, iar prima secvență de pe pagina nouă iese cu fontul implicit al vizualizatorului dacă îl omiteți

Spațierea între caractere și între cuvinte, pentru încadrare și aliniere

Uneori un șir este corect, dar are lățimea greșită: un antet care trebuie să acopere o linie fixă, un cod care ar trebui citit cu cifre mai aerisite, o coloană ale cărei valori trebuie împinse ca să se alinieze. PDF poartă doi operatori de stare a textului pentru asta, spațierea între caractere (Tc, spațiu suplimentar adăugat după fiecare glifă) și spațierea între cuvinte (Tw, spațiu suplimentar adăugat la fiecare caracter de spațiu), iar amândouă se exprimă în unități nescalate din spațiul textului, practic puncte la dimensiunea curentă a fontului. Ele sunt stare, nu argumente ale lui TextOut, deci le setați, desenați și le puneți la loc

HotPDF: spațierea între caractere Tc împrăștie spațiul suplimentar uniform după fiecare glifă a cuvântului SUMMARY, față de spațierea între cuvinte Tw, care îl adună doar la caracterele de spațiu, integrate în ciclul setare, desenare, resetare, care împiedică starea de spațiere să se scurgă în paragrafele următoare
Tc își împrăștie ajustarea peste fiecare glifă, în timp ce Tw acționează doar asupra caracterului de spațiu, iar resetarea pe rândul următor păstrează curată starea de desenare
// Spațiați literele unui antet scurt ca să se întindă peste o linie.
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);   // resetați înainte de textul normal

// Lărgiți spațiile dintre cuvinte pe un singur rând lat.
Pdf.CurrentPage.SetWordSpacing(6);
Pdf.CurrentPage.SetFont('Arial', [], 11);
Pdf.CurrentPage.TextOut(72, 712, 0, 'Name        Department        Extension');
Pdf.CurrentPage.SetWordSpacing(0);

Spațierea între cuvinte acționează doar asupra caracterului de spațiu (codul 32), ceea ce are o consecință pe care merită să o știți: nu face nimic într-o secvență CJK fără spații ASCII și interacționează ciudat cu textul codificat ca indici de glife, nu ca octeți. Pentru ieșiri tabelare latine este calea ieftină de a lărgi golurile fără să rescrieți șirul. Spațierea între caractere este instrumentul mai bun pentru un antet care trebuie să atingă o lățime țintă, de vreme ce împrăștie ajustarea uniform peste fiecare glifă, în loc să o adune la spații

Resetarea este toată disciplina. Spațierea, ca și fontul, face parte din starea de desenare a paginii, iar starea persistă până când o schimbați. Spațiați literele unui antet și uitați să duceți valoarea la zero, iar fiecare paragraf de dedesubt moștenește întinderea, ceea ce se citește ca o greșeală subtilă, greu de localizat, care supraviețuiește unei corecturi în fugă și pică la una atentă. Obiceiul de încredere este să setați o valoare de spațiere, să desenați secvența care are nevoie de ea și să o puneți înapoi la zero pe rândul următor, astfel încât niciun cod ulterior să nu fie nevoit să știe ce a făcut o secțiune anterioară

Pagină HotPDF TextOut care compară scalarea orizontală a textului, spațierea între caractere, spațierea între cuvinte și modurile de randare cu umplere față de contur

Verificarea rezultatului acolo unde chiar se strică

Aranjarea textului se strică pe a doua mașină, nu pe prima, așa că verificările care contează se petrec departe de biroul dumneavoastră. Deschideți fișierul generat pe un sistem fără setul dumneavoastră de fonturi de dezvoltare instalat și confirmați că fonturile încorporate se randează în continuare, inclusiv literele latine cu diacritice, orice scrieri nelatine și semnele de punctuație, dintr-o singură trecere, nu verificând la întâmplare caracterele ușoare. Selectați și copiați câteva rânduri ca să confirmați că textul este text adevărat, nu contururi, ceea ce contează din clipa în care căutarea sau extragerea intră în discuție. Dați aranjamentului date reprezentative, cea mai lungă etichetă germană și cel mai lat număr, nu un substituent îngrijit, pentru că secvența care revarsă un câmp este întotdeauna cea pe care nu ați tastat-o de mână. Iar dacă pagina trebuie să aterizeze pe un formular pretipărit, tipăriți sau rasterizați o mostră și așezați-o peste original; o deviere de un sfert de milimetru a liniei de bază este invizibilă pe ecran și evidentă pe hârtie

Dacă nu ați scris încă nicio pagină, începeți cu exemplul HotPDF Hello World, care pregătește documentul, fontul și sistemul de coordonate cu originea în stânga jos de care depinde tot ce este mai sus. Apelurile TextOut, SetFont și cele de spațiere prezentate aici fac parte din HotPDF Delphi Component pentru Delphi și C++Builder