HotPDF iscrtava vektorsku grafiku tako da izgradi putanju na trenutnoj stranici, a zatim zatraži da se ona oboji. Između nema koraka s bitmapom. Linija koju nacrtate pomoću MoveTo i LineTo na kraju postaje PDF operatorima putanje u toku sadržaja, pa ostaje pravi vektor: oštra pri uvećanju 50%, oštra pri uvećanju 1600%, i tek djelić veličine koju bi koštala rasterizirana verzija. Za dijagrame, linije tablica, osi grafikona i ukrase obrazaca, to je upravo ono što želite, a API iza toga dovoljno je malen da se nauči u jednom sjedenju
Cijela ploha za crtanje živi na THotPDF.CurrentPage. Između BeginDoc i EndDoc postavljate boju i debljinu linije na tom objektu stranice, polažete geometriju, i pozivate operator bojenja kako biste je potvrdili. Četiri primitiva koje ćete najčešće koristiti su MoveTo i LineTo za proizvoljne putanje, Rectangle za pravokutnike, Circle za krugove, i dva operatora bojenja Stroke i Fill
Koordinatni sustav polazi od donjeg lijevog ruba
Ovo je jedina stvar koja spotakne svakoga tko dolazi iz VCL-a. TCanvas kojim bojite kontrole stavlja ishodište u gornji lijevi kut, a Y raste prema dolje. PDF radi suprotno. HotPDF mjeri od donjeg lijevog kuta stranice u točkama (1/72 inča), pri čemu Y raste kako idete prema gore. Točka na Y := 720 nalazi se blizu vrha stranice US Letter, koja je visoka 792 točke, a Y := 50 nalazi se blizu dna. Ako vam prvi crtež ispadne okomito zrcaljen, to je razlog: kod prenesen iz grafike zaslona pretpostavlja pogrešan smjer i otrči izvan donjeg ruba
Ista konvencija vrijedi za TextOut, pa tekst i oblici dijele jedan mentalni model čim ga usvojite. Planirajte raspored odlučujući gdje se nalazi dno svakog elementa, a ne vrh, i ostatak slijedi
Putanje: MoveTo, LineTo, Stroke
Putanja s obrisom je pero koje se podigne, postavi i povuče. MoveTo podiže pero i postavlja početnu točku bez crtanja ičega. Svaki LineTo produžuje trenutnu putanju do nove točke. Ništa se ne pojavljuje na stranici dok ne pozovete Stroke, koji crta akumuliranu putanju koristeći trenutnu boju obrisa i debljinu linije, a zatim briše putanju tako da sljedeći MoveTo počinje iznova
var
Pdf: THotPDF;
begin
Pdf := THotPDF.Create(nil);
try
Pdf.FileName := 'DrawPaths.pdf';
Pdf.BeginDoc;
// Debljina linije je u točkama i vrijedi dok je ne promijenite.
Pdf.CurrentPage.SetLineWidth(1.5);
Pdf.CurrentPage.SetRGBStrokeColor(clBlack);
// Vodoravna linija blizu vrha stranice (Y mjeren od dna).
Pdf.CurrentPage.MoveTo(72, 720);
Pdf.CurrentPage.LineTo(523, 720);
Pdf.CurrentPage.Stroke; // potvrdi putanju; ništa prije ovoga nije nacrtano
// Deblja povezana izlomljena linija: tri segmenta u jednoj putanji.
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;
Dva detalja štede stvarno vrijeme otklanjanja pogrešaka. Debljina linije je stanje, a ne argument: SetLineWidth je postavlja jednom, a svaki naredni Stroke koristi tu vrijednost dok je opet ne promijenite, zbog čega je gornja izlomljena linija deblja od ravne crte. A putanja se resetira nakon svakog Stroke, pa zaboravljeni Stroke znači da se geometrija koju ste tako pažljivo postavili uopće ne iscrtava. Ako neki oblik nedostaje u izlazu, poziv za bojenje prvo je mjesto za provjeru
Koordinate su u točkama, a točke su razlomljene. MoveTo i LineTo prihvaćaju vrijednosti tipa Single, pa je vlas od 0.5 točaka ili pozicija na 72.25 valjana i smislena, a ne zaokružena na najbliži cijeli broj. Ta preciznost je važna u dva suprotna smjera. Debljina linije ispod otprilike 0.5 može se iscrtati kao najtanja moguća linija ovisna o uređaju, koja nestane na zaslonu, a pojavi se pri ispisu, pa vidljiva crta treba širinu koju namjerno postavite umjesto zadane. Na drugom kraju, poravnavanje tabličnih linija i mrežnih linija na cjelobrojne koordinate u točkama sprječava da gusta mreža izgleda blago neravnomjerno tamo gdje se susjedne linije zaokružuju drugačije. Odlučite razmak mreže u točkama unaprijed i ostatak rasporeda ga nasljeđuje
Ispunjeni oblici i boja
Zatvoreni primitivi mogu se ispuniti umjesto ocrtati. Rectangle uzima poziciju i veličinu, Circle uzima središte i polumjer, a bilo koji od njih potvrđuje se pomoću Fill, koji boja unutrašnjost trenutnom bojom ispune, ili pomoću Stroke samo za obris. Boja ispune i boja obrisa odvojena su stanja, postavljaju se pomoću SetRGBFillColor i SetRGBStrokeColor, od kojih svaka uzima jedan TColor. To znači da možete izravno ponovno koristiti Delphijeve konstante boja i pomoćnu funkciju RGB
// Rectangle(X, Y, Width, Height): X i Y su donji lijevi kut.
Pdf.CurrentPage.SetRGBFillColor(RGB(220, 60, 60));
Pdf.CurrentPage.Rectangle(72, 500, 160, 90);
Pdf.CurrentPage.Fill;
// Circle(X, Y, Radius): X i Y su središte.
Pdf.CurrentPage.SetRGBFillColor(clNavy);
Pdf.CurrentPage.Circle(420, 545, 45);
Pdf.CurrentPage.Fill;
// Samo obris: postavi boju obrisa i širinu, zatim Stroke.
Pdf.CurrentPage.SetLineWidth(2);
Pdf.CurrentPage.SetRGBStrokeColor(clBlack);
Pdf.CurrentPage.Rectangle(72, 400, 160, 60);
Pdf.CurrentPage.Stroke;
Pripazite na oblik argumenata za Rectangle. To je pozicija-plus-veličina, X, Y, Width, Height, a ne dva suprotna kuta. TCanvas.Rectangle, koji poznaju Delphi razvijatelji, uzima (Left, Top, Right, Bottom), pa će mišićna memorija HotPDF-u predati drugi kut tamo gdje se očekuje širina i visina, i pravokutnik ispadne krive veličine. Par (X, Y) je donji lijevi kut, dosljedno ishodištu stranice. Za krug, (X, Y) je središte, a treći argument je polumjer u točkama
Jedan izbor boje koji je izvorni primjer pogrešno napravio
Starija verzija ovog primjera generirala je boje pomoću Random($FFFFFF) za svaki oblik. Izgleda živopisno, a to je pogrešan instinkt za generirane dokumente. PDF koji gradite iz koda obično je nešto što također želite testirati, a nasumične boje ispune čine izlaz neusporedivim iz pokretanja u pokretanje: usporedba bajt po bajt s poznato ispravnom datotekom svaki put ne uspije, bez pravog razloga. Birajte izričite boje. Kad želite raznolikost kroz niz oblika, izvedite je iz svojih podataka ili fiksnog niza palete, tako da isti ulaz uvijek proizvede istu datoteku. Determinizam vrijedi više od novosti kad artefakt prolazi kroz cjevovod izdavanja
Slaganje primitiva zajedno: okvir s oznakom
Svaki primitiv sam po sebi je jednostavan; isplativost se vidi kad se pregršt njih sastavi u nešto što izvještaj zaista treba. Oznaka (callout), okvir s napomenom koji pokazuje na sliku i objašnjava je, koristi sve dosad obrađeno: ispunjeni pravokutnik s obrubom, obrisanu liniju pokazivača, točku koja sidri pokazivač, i tekst postavljen unutar okvira koristeći iste koordinate donjeg lijevog kuta koje koriste oblici. FillAndStroke ovdje zaslužuje svoje mjesto, bojeći unutrašnjost i obris jedne putanje u jednoj potvrdi umjesto da se pravokutnik gradi dvaput
var
Pdf: THotPDF;
begin
Pdf := THotPDF.Create(nil);
try
Pdf.FileName := 'Callout.pdf';
Pdf.BeginDoc;
// 1. Okvir: blijeda ispuna plus vidljiv obrub, jedna putanja, jedna potvrda.
// Rectangle je donji lijevi kut plus veličina, Y mjeren od dna
Pdf.CurrentPage.SetRGBFillColor(RGB(255, 244, 214)); // blijedo jantarni panel
Pdf.CurrentPage.SetRGBStrokeColor(RGB(180, 130, 40)); // tamniji rub
Pdf.CurrentPage.SetLineWidth(1);
Pdf.CurrentPage.Rectangle(90, 600, 240, 70);
Pdf.CurrentPage.FillAndStroke;
// 2. Pokazivač: jedan obrisani segment od ruba okvira prema dolje
// prema onome što se napominje
Pdf.CurrentPage.SetLineWidth(1.5);
Pdf.CurrentPage.MoveTo(90, 615); // lijevi rub okvira
Pdf.CurrentPage.LineTo(66, 546);
Pdf.CurrentPage.Stroke;
// 3. Ispunjena točka sidri pokazivač na svom cilju
Pdf.CurrentPage.SetRGBFillColor(RGB(180, 130, 40));
Pdf.CurrentPage.Circle(64, 542, 3);
Pdf.CurrentPage.Fill;
// 4. Oznaka, pozicionirana u odnosu na donji lijevi kut okvira.
// Tekst i oblici dijele jedan koordinatni sustav, pa su pomaci
// obična aritmetika u odnosu na (90, 600)
Pdf.CurrentPage.SetFont('Arial', [fsBold], 10);
Pdf.CurrentPage.TextOut(102, 645, 0, 'Check this total');
Pdf.CurrentPage.SetFont('Arial', [], 9);
Pdf.CurrentPage.TextOut(102, 628, 0, 'The rounding rule changed in the');
Pdf.CurrentPage.TextOut(102, 616, 0, 'June release; verify against v2.1');
Pdf.EndDoc;
finally
Pdf.Free;
end;
end;
Primijetite koliko malo upravljanja stanjem ovaj sastav treba. Boja ispune, boja obrisa i debljina linije svaka se postavlja neposredno prije oblika koji je koristi, pa se svaki blok crteža čita kao samostalna cjelina i može se preurediti ili izdvojiti u pomoćnu funkciju bez povlačenja skrivenog stanja za sobom. Zamotajte ovo u proceduru koja uzima sidrenu točku i nizove znakova, i imate ponovno upotrebljivu napomenu za dijagram uz cijenu od svega četrdeset redaka
Gdje se vektorsko crtanje isplati, a gdje ne
Posegnite za ovim pozivima za putanje i oblike kad je geometrija generirana: mrežne linije i stupci grafikona, linije tablice računa, okviri s oznakama na dijagramu, znak logotipa izražen kao pregršt putanja. Sve se to skalira bez zamućenja i gotovo ništa ne dodaje veličini datoteke, jer je pravokutnik nekoliko brojeva, a ne tisuće piksela. I druga strana je poštena. Ako zapravo imate fotografiju ili snimku zaslona, umjesto toga to nacrtajte kao sliku pomoću AddImage i ShowImage; precrtavanje bitmape vektorskim pozivima ne donosi vam ništa. Ravni segmenti, pravokutnici i krugovi iznad nose veliku većinu stvarnog posla izvještavanja, a tri usavršavanja o kojima razvijatelji sljedeće pitaju, krivulje, uzorci crtkanja i prozirnost, nalaze se na istom objektu stranice
Ukratko o krivuljama, crtkanju i prozirnosti
Slobodne krivulje proširuju isti mehanizam putanja koji već imate. CurveToC(X1, Y1, X2, Y2, X3, Y3) dodaje kubični Bezierov segment od trenutne točke do (X3, Y3), savijajući se prema dvjema kontrolnim točkama, a skraćene varijante CurveToV i CurveToY pokrivaju slučajeve kad se jedna kontrolna točka poklapa s krajnjom točkom. Putanja može slobodno miješati segmente LineTo i CurveToC prije nego što ih jedan Stroke ili Fill potvrdi, i tako se grade zaobljeni kutovi i glatke linije grafikona
Crtkani obrisi su stanje, baš kao i debljina linije. SetDash([3, 3], 0) prebacuje svaki naredni obris na uzorak od tri točke uključeno, tri točke isključeno, pri čemu niz ispisuje duljine uključenih/isključenih segmenata u točkama, a drugi argument fazira gdje ciklus počinje; NoDash vraća pero na punu liniju. Postavite je, obrišite mrežne linije koje je trebaju, i vratite je prije sljedeće pune crte, inače crtkanje tiho zarazi sve što slijedi
Prozirnost prolazi kroz imenovano grafičko stanje, a ne kroz argument boje, jer je alfa u PDF-u svojstvo rječnika grafičkog stanja. Registrirajte ga u dokumentu pomoću RegisterExtGState, predajući alfu ispune i alfu obrisa između 0 i 1, zatim primijenite naziv koji vraća pomoću CurrentPage.SetGraphicsState; ispune i obrisi od te točke boje se s registriranom prozirnošću. To je teža ceremonija od postavljača boje, a isplati se prvi put kad traka za isticanje mora ležati preko teksta bez da ga sakrije
Preostala navika vrijedna zadržavanja je provjera. Generirana geometrija može proći na vašem stroju, a zakazati na korisnikovom, obično zbog zamjene fonta u bilo kojem tekstu koji umiješate, ili pretpostavke o veličini stranice koja ne vrijedi. Otvorite gotovu datoteku pri nekoliko razina zuma kako biste potvrdili da rubovi ostaju čisti, i provjerite da svaki oblik pada unutar okvira margine koji ste namjeravali. S determinističkom shemom boja, ta se provjera može automatizirati usporedbom s referentnim PDF-om umjesto procjenjivati okom
Pozivi MoveTo, LineTo, Stroke, Fill, i pozivi za boju prikazani ovdje dio su HotPDF Delphi komponente za Delphi i C++Builder