Technical Article

Risanje na platno s HotPDF v Delphi: Vektorske poti in barve

HotPDF riše vektorsko grafiko tako, da zgradi pot na trenutni strani in nato zahteva njen izris. Vmes ni koraka bitne slike. Črta, ki jo narišete z MoveTo in LineTo, se v toku vsebine zaključi kot PDF operator poti, zato ostane pravi vektor: oster pri 50-odstotni in oster pri 1600-odstotni povečavi ter le delček velikosti, ki bi jo zahtevala rasterizirana različica. Za diagrame, mrežne črte tabel, osi grafikonov in okrasne elemente obrazcev je to natanko tisto, kar želite, in zaledni vmesnik API je dovolj majhen, da se ga naučite naenkrat.

Celotna risalna površina živi na THotPDF.CurrentPage. Med BeginDoc in EndDoc nastavite barvo in debelino črte na tem objektu strani, določite geometrijo in pokličete slikarski operator za njeno uveljavitev. Štiri osnovne oblike, ki jih boste najpogosteje uporabljali, so MoveTo in LineTo za poljubne poti, Rectangle za pravokotnike, Circle za kroge ter dva slikarska operatorja Stroke in Fill.

Koordinatni sistem je spodaj levo

To je tista stvar, ob katero se spotaknejo vsi, ki prihajajo iz okolja VCL. Razred TCanvas, s katerim izrisujete kontrolnike, postavi izhodišče v zgornji levi kot, pri čemer Y narašča navzdol. PDF počne nasprotno. HotPDF meri od spodnjega levega kota strani v točkah (1/72 palca), pri čemer Y narašča, ko se premikate navzgor. Točka pri Y := 720 se nahaja blizu vrha strani formata US Letter, ki je visoka 792 točk, točka Y := 50 pa je blizu dna. Če je vaša prva risba navpično zrcalna, je to razlog: koda, prenesena iz zaslonske grafike, predvideva napačno smer in se zaključi pod spodnjim robom.

Isto pravilo velja za TextOut, so besedilo in oblike delijo enak miselni model, ko ga enkrat usvojite. Načrtujte postavitev tako, da določite, kje leži dno posameznega elementa in ne vrh, vse ostalo pa bo sledilo samodejno.

Poti: MoveTo, LineTo, Stroke

Izrisana pot je kot dvignjeno, postavljeno in vlečeno pero. Metoda MoveTo dvigne pero in nastavi začetno točko, ne da bi karkoli označila. Vsak LineTo podaljša trenutno pot do nove točke. Na strani se ne pojavi nič, dokler ne pokličete Stroke, ki izriše nabrano pot z uporabo trenutne barve poteze in debeline črte, nato pa pot počisti, da naslednji MoveTo začne znova.

var
  Pdf: THotPDF;
begin
  Pdf := THotPDF.Create(nil);
  try
    Pdf.FileName := 'DrawPaths.pdf';
    Pdf.BeginDoc;

    // Line width is in points and applies until you change it.
    Pdf.CurrentPage.SetLineWidth(1.5);
    Pdf.CurrentPage.SetRGBStrokeColor(clBlack);

    // A horizontal rule near the top of the page (Y measured from bottom).
    Pdf.CurrentPage.MoveTo(72, 720);
    Pdf.CurrentPage.LineTo(523, 720);
    Pdf.CurrentPage.Stroke;          // commit the path; nothing drew before this

    // A thicker connected polyline: three segments in one path.
    Pdf.CurrentPage.SetLineWidth(3);
    Pdf.CurrentPage.SetRGBStrokeColor(RGB(30, 90, 200));
    Pdf.CurrentPage.MoveTo(72, 640);
    Pdf.CurrentPage.LineTo(172, 690);
    Pdf.CurrentPage.LineTo(272, 620);
    Pdf.CurrentPage.LineTo(372, 680);
    Pdf.CurrentPage.Stroke;

    Pdf.EndDoc;
  finally
    Pdf.Free;
  end;
end;

Dve podrobnosti prihranita veliko časa pri odpravljanju napak. Debelina črte je stanje in ne argument: SetLineWidth jo nastavi enkrat, vsak naslednji Stroke pa uporabi to vrednost, dokler je znova ne spremenite, zaradi česar je zgornja lomljena črta debelejša od ravne črte. Poleg tega se pot po vsakem klicu Stroke ponastavi, zato pozabljen Stroke pomeni, da se geometrija, ki ste jo tako skrbno načrtovali, sploh ne bo izrisala. Če v izhodnem dokumentu manjka oblika, je slikarski klic prvo mesto, ki ga morate preveriti.

Koordinate so točke, točke pa so lahko delna števila. MoveTo in LineTo sprejemata vrednosti Single, zato je izredno tanka črta z debelino 0.5 točke ali položaj pri 72.25 veljaven in smiseln ter se ne zaokroži na najbližjo celo enoto. Ta natančnost je pomembna v dveh nasprotnih smereh. Debelina črte pod približno 0.5 se lahko izriše kot od naprave odvisna najtanjša možna črta, ki izgine na zaslonu in se znova pojavi pri tiskanju, zato vidna črta zahteva debelino, ki jo nastavite namensko, in ne privzete. Po drugi strani pa poravnava robov tabel in mrežnih črt na celoštevilske koordinate točk preprečuje, da bi bila gosta mreža videti rahlo neenakomerna tam, kjer se sosednje črte različno zaokrožijo. Vnaprej se odločite za razmik mreže v točkah in preostala postavitev bo to podedovala.

Polnjene oblike in barve

Zaprte osnovne oblike so lahko polnjene namesto obrobljene. Rectangle sprejme položaj in velikost, Circle središče in polmer, kateri koli od njiju pa se uveljavi s Fill, ki zapolni notranjost s trenutno barvo polnila, ali s Stroke za samo obrobo. Barva polnila in barva poteze sta ločeni stanji, ki se nastavljata s SetRGBFillColor in SetRGBStrokeColor, pri čemer oba sprejemata eno vrednost TColor. To pomeni, da lahko neposredno uporabite Delphijeve barvne konstante in pomožno funkcijo RGB.

// Rectangle(X, Y, Width, Height): X and Y are the lower-left corner.
Pdf.CurrentPage.SetRGBFillColor(RGB(220, 60, 60));
Pdf.CurrentPage.Rectangle(72, 500, 160, 90);
Pdf.CurrentPage.Fill;

// Circle(X, Y, Radius): X and Y are the center.
Pdf.CurrentPage.SetRGBFillColor(clNavy);
Pdf.CurrentPage.Circle(420, 545, 45);
Pdf.CurrentPage.Fill;

// Outline only: set a stroke color and a width, then Stroke.
Pdf.CurrentPage.SetLineWidth(2);
Pdf.CurrentPage.SetRGBStrokeColor(clBlack);
Pdf.CurrentPage.Rectangle(72, 400, 160, 60);
Pdf.CurrentPage.Stroke;

Bodite pozorni na vrstni red argumentov pri Rectangle. Gre za položaj in velikost, X, Y, Width, Height, in ne za dva nasprotna kota. Metoda TCanvas.Rectangle, ki jo poznajo razvijalci v Delphiju, sprejme (Left, Top, Right, Bottom), zato bo mišični spomin metodi HotPDF predal drugi kot tam, kjer pričakuje širino in višino, pravokotnik pa bo napačne velikosti. Par (X, Y) predstavlja spodnji levi kot, kar je skladno z izhodiščem strani. Za krog je (X, Y) središče, tretji argument pa je polmer v točkah.

Ena izbira barve, ki je bila v prvotnem vzorcu napačna

Starejša različica tega primera je določala barve z vrednostjo Random($FFFFFF) za vsako obliko. Izgleda živahno, a je napačna odločitev za generirane dokumente. PDF, ki ga zgradite s kodo, običajno želite tudi testirati, naključne barve polnila pa onemogočajo primerjavo izhoda med zagoni: primerjava razlik bajt za bajtom (diff) z znano dobro datoteko bo vsakič spodletela brez pravega razloga. Izberite izrecne barve. Če želite raznolikost med serijo oblik, jo vodite iz svojih podatkov ali fiksnega polja palete, tako da isti vhod vedno ustvari isto datoteko. Determinizem je vreden več kot novost, ko se izdelek premika skozi cevovod izdaje.

Kje se vektorsko risanje obnese in kje ne

Po teh klicih poti in oblik posezite, ko je geometrija generirana: mrežne črte in stolpci grafikonov, črte tabele na računu, označevalni okvirčki na diagramu, logotip, izražen z nekaj potmi. Vse to se prilagaja brez zamegljenosti in skoraj ne vpliva na velikost datoteke, saj je pravokotnik le nekaj številk in ne na tisoče slikovnih pik. Po drugi strani pa, če dejansko imate fotografijo ali posnetek zaslona, jo narišite kot sliko z uporabo AddImage in ShowImage; sledenje bitni sliki z vektorskimi klici vam ne prinese ničesar. Kompleksne krivulje prav tako niso del te teme. Zgoraj opisane oblike so ravni segmenti, pravokotniki in krogi, ki opravijo veliko večino dejanskega dela pri poročanju; vse, karat zahteva poljubne Bezierjeve krivulje, je del drugega vmesnika API.

Zadnja navada, ki jo je vredno ohraniti, je preverjanje. Generirana geometrija lahko deluje na vašem računalniku in spodleti pri stranki, običajno zaradi zamenjave pisave v besedilu, ki ga vključite, ali zaradi napačne predpostavke o velikosti strani. Odrite končano datoteko pri nekaj stopnjah povečave, da se prepričate, da robovi ostajajo čisti, in preverite, ali vsaka oblika pristane znotraj načrtovanih robov strani. Z deterministično barvno shemo je mogoče to preverjanje avtomatizirati s primerjavo z referenčnim PDF-jem, namesto vizualnega ocenjevanja.

Tukaj prikazani klici MoveTo, LineTo, Stroke, Fill in nastavitve barv so del komponente HotPDF Component za Delphi in C++Builder.