HotPDF tekent vectorafbeeldingen door een pad op te bouwen op de huidige pagina en dit vervolgens te laten inkleuren. Er is geen tussentijdse bitmapstap. Een lijn die u tekent met MoveTo en LineTo eindigt als PDF-padoperatoren in de contentstream, waardoor het een echte vector blijft: haarscherp bij 50% zoom, haarscherp bij 1600% zoom, en een fractie van de bestandsgrootte die een gerasterde versie zou kosten. Voor diagrammen, tabelranden, grafiekassen en formulierversieringen is dat precies wat u wilt, en de onderliggende API is compact genoeg om in één keer te leren.
Het gehele tekenoppervlak bevindt zich op THotPDF.CurrentPage. Tussen BeginDoc en EndDoc stelt u de kleur en lijndikte in op dit pagina-object, tekent u de geometrie en roept u een tekenoperator aan om deze door te voeren. De vier primitieven die u het meest zult gebruiken zijn MoveTo en LineTo voor willekeurige paden, Rectangle voor rechthoeken, Circle voor cirkels, en de twee tekenoperatoren Stroke en Fill.
Het coördinatensysteem is linksonder
Dit is het punt waar iedereen die overstapt van VCL over struikelt. De TCanvas waarmee u controls tekent, plaatst de oorsprong in de linkerbovenhoek waarbij Y naar beneden toe groeit. PDF doet het tegenovergestelde. HotPDF meet vanaf de linkerbenedenhoek van de pagina in punten (1/72 inch), waarbij Y toeneemt naarmate u omhoog beweegt. Een punt op Y := 720 bevindt zich dicht bij de bovenkant van een US Letter-pagina (die 792 punten hoog is), en Y := 50 bevindt zich dicht bij de onderkant. Als uw eerste tekening verticaal gespiegeld is, is dit de reden: code die is overgezet van schermgraphics gaat uit van de verkeerde richting en valt buiten de onderkant van de pagina.
Dezelfde conventie geldt voor TextOut, zodat tekst en vormen hetzelfde mentale model delen zodra u dit eenmaal onder de knie hebt. Plan een lay-out door te bepalen waar de onderkant van elk element zich bevindt in plaats van de bovenkant, en de rest volgt vanzelf.
Paden: MoveTo, LineTo, Stroke
Een omlijnd pad (stroke) is als een pen die wordt opgetild, neergezet en versleept. MoveTo tilt de pen op en stelt het startpunt in zonder iets te tekenen. Elke LineTo trekt het huidige pad door naar een nieuw punt. Er verschijnt niets op de pagina totdat u Stroke aanroept. Dit tekent het opgebouwde pad met de huidige stroke-kleur en lijndikte, en wist het pad vervolgens zodat de volgende MoveTo met een schone lei begint.
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;
Twee details besparen veel zoektijd bij het debuggen. De lijndikte is een status en geen argument: SetLineWidth stelt deze eenmalig in en elke opeenvolgende Stroke gebruikt die waarde totdat u deze weer wijzigt. Dit is waarom de polylijn hierboven dikker is dan de eerste lijn. Daarnaast wordt het pad na elke Stroke gewist. Een vergeten Stroke betekent dus dat de geometrie die u zo zorgvuldig hebt uitgezet, nooit wordt gerenderd. Als er een vorm ontbreekt in de uitvoer, is de tekenaanroep de eerste plek om te controleren.
De coördinaten zijn punten, en punten kunnen breuken bevatten. MoveTo en LineTo accepteren Single-waarden, dus een haarlijn van 0.5 punten of een positie op 72.25 is geldig en betekenisvol, en wordt niet afgerond naar de dichtstbijzijnde gehele eenheid. Die precisie is in twee tegengestelde richtingen van belang. Een lijndikte van minder dan ongeveer 0.5 kan worden gerenderd als een apparaatafhankelijke dunst mogelijke lijn die op het scherm verdwijnt en bij het afdrukken weer verschijnt. Een zichtbare lijn vereist dus een breedte die u bewust instelt in plaats van de standaardwaarde te gebruiken. Aan de andere kant zorgt het uitlijnen van tabelranden en rasterlijnen op hele coördinaten in punten ervoor dat een dicht raster er niet ongelijkmatig uitziet doordat aangrenzende lijnen anders worden afgerond. Bepaal vooraf de rasterafstand in punten en laat de rest van de lay-out daarvan overerven.
Gevulde vormen en kleur
Gesloten primitieven kunnen worden gevuld in plaats van omlijnd. Rectangle heeft een positie en een grootte nodig, Circle een middelpunt en een straal, en beide worden getekend met Fill (waarmee de binnenkant met de huidige vulkleur wordt ingekleurd) of met Stroke (voor alleen een omlijning). Vulkleur en omlijningskleur zijn afzonderlijke statussen, ingesteld met SetRGBFillColor en SetRGBStrokeColor, die beide een enkele TColor accepteren. Dit betekent dat u de kleurconstanten van Delphi en de RGB-helper rechtstreeks kunt hergebruiken.
// 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;
Let op de argumentvolgorde bij Rectangle. Deze is positie plus grootte, dus X, Y, Breedte, Hoogte, en niet twee tegenoverliggende hoeken. De TCanvas.Rectangle die Delphi-ontwikkelaars gewend zijn, verwacht (Left, Top, Right, Bottom). Door spiergeheugen zou u HotPDF een tweede hoek kunnen meegeven waar het een breedte en hoogte verwacht, waardoor de rechthoek de verkeerde grootte krijgt. Het paar (X, Y) is de linkerbenedenhoek, in overeenstemming met de oorsprong van de pagina. Voor een cirkel is (X, Y) het middelpunt en is het derde argument de straal in punten.
Een kleurkeuze die in het oorspronkelijke voorbeeld verkeerd was
Een oudere versie van dit voorbeeld bepaalde de kleuren van elke vorm met Random($FFFFFF). Dat ziet er levendig uit, maar het is de verkeerde benadering voor gegenereerde documenten. Een PDF die u vanuit code opbouwt, wilt u meestal ook kunnen testen. Willekeurige vulkleuren maken het onmogelijk om de uitvoer van verschillende sessies met elkaar te vergelijken: een byte-voor-byte vergelijking (diff) met een bestand waarvan bekend is dat het correct is, mislukt dan telkens zonder geldige reden. Kies voor expliciete kleuren. Als u variatie in een reeks vormen wilt, stuur dit dan aan vanuit uw data of een vaste array met een kleurenpalet, zodat dezelfde invoer altijd exact hetzelfde bestand oplevert. Determinisme is meer waard dan vernieuwing wanneer het bestand door een release-pipeline gaat.
Waar vectortekening loont, en waar niet
Kies voor deze pad- en vorm-aanroepen wanneer de geometrie dynamisch wordt gegenereerd: rasterlijnen en balken van grafieken, de lijnen van een factuurtabel, tekstballonnen op een diagram of een logo dat is opgebouwd uit een handvol paden. Dit alles schaalt zonder kwaliteitsverlies en voegt vrijwel niets toe aan de bestandsgrootte, omdat een rechthoek slechts uit enkele getallen bestaat in plaats van duizenden pixels. De keerzijde is eveneens waar: als u in werkelijkheid een foto of een schermafbeelding hebt, teken deze dan als een afbeelding met AddImage en ShowImage. Het natekenen van een bitmap met vector-aanroepen levert u niets op. Complexe curven vallen hier eveneens buiten het bestek. De bovenstaande primitieven zijn rechte segmenten, rechthoeken en cirkels, waarmee het overgrote deel van het rapportagewerk kan worden uitgevoerd. Alles wat vrije Béziercurven vereist, bevindt zich in een ander deel van de API.
Een andere gewoonte die de moeite waard is, is verificatie. Gegenereerde geometrie kan probleemloos werken op uw eigen machine, maar falen bij een klant, meestal door lettertypevervanging in teksten die u toevoegt of door aannames over de paginagrootte die niet kloppen. Open het voltooide bestand op verschillende zoomniveaus om te controleren of de randen strak blijven, en controleer of elke vorm binnen het beoogde margekader valt. Met een deterministisch kleurenschema kan die controle worden geautomatiseerd tegen een referentie-PDF in plaats van dit handmatig te moeten beoordelen.
De hier getoonde aanroepen voor MoveTo, LineTo, Stroke, Fill en kleur maken deel uit van de HotPDF Component voor Delphi en C++Builder.