Raportin luonti tarkoittaa kolmen asian sijoittamista samalle sivulle: tekstin tunnetuille koordinaateille, palvelimella samalla tavalla renderöityvät fontit ja sopiviksi mitoitetut kuvat. HotPDF, losLabin PDF generation library Delphille ja C++Builderille, tarjoaa ne suorina page object -kutsuina. Keskeinen ero VCL canvas -malliin on vastakkaissuuntainen koordinaatisto
Tekstin sijoittaminen ja vasemman alakulman origo
PDF user space käyttää ISO 32000-1 §8.3:n mukaan vasenta alakulmaa origona ja kasvattaa Y-arvoa ylöspäin. GDI canvas aloittaa vasemmasta yläkulmasta ja kasvattaa Y-arvoa alaspäin. Siksi ensimmäisen raportin otsikko voi päätyä alareunaan ja seuraavat rivit nousta ylöspäin ilman ohjelmavirhettä
Page object -rajapinnan pääkutsu on TextOut(X, Y, Angle, Text). X ja Y ovat pisteitä vasemmasta alakulmasta, ja Angle kiertää tekstiä asteina esimerkiksi DRAFT- tai COPY-leimaa varten. VCL-ajattelua voi käyttää laskemalla Y-arvon sivun korkeudesta vähennettynä yläreunan etäisyydellä:
var
Pdf: THotPDF;
begin
Pdf := THotPDF.Create(nil);
try
Pdf.FileName := 'invoice-0001.pdf';
Pdf.BeginDoc;
Pdf.CurrentPage.SetFont('Arial', [fsBold], 16);
Pdf.CurrentPage.TextOut(50, 792 - 50, 0, 'INVOICE'); // 50pt from top of Letter
Pdf.CurrentPage.SetFont('Arial', [], 10);
Pdf.CurrentPage.TextOut(50, 792 - 70, 0, 'Date: 2026-06-11');
Pdf.CurrentPage.TextOut(300, 400, 45, 'COPY'); // rotated stamp
Pdf.AddPage; // CurrentPage now points here
Pdf.CurrentPage.SetFont('Arial', [], 10); // font state does not carry over
Pdf.CurrentPage.TextOut(50, 742, 0, 'Page 2 detail rows');
Pdf.EndDoc;
finally
Pdf.Free;
end;
end;
AddPage siirtää CurrentPage-viittauksen juuri luotuun sivuun, joten aiemmin välimuistiin tallennettu page reference ei enää piirrä odotettuun paikkaan. Fonttivalinta on sivukohtainen, ei asiakirjakohtainen. Ilman uutta SetFont-kutsua AddPage-kutsun jälkeen uuden sivun ensimmäinen TextOut käyttää sivun oletusta. Käsittele uuden sivun aloitusta ja tekstitilan palauttamista yhtenä report loop -vaiheena
Fontit palvelimella, eivät vain työpöydällä
Fonttiongelmat ovat usein deployment-ongelmia. Kehityskoneen corporate font puuttuu service account -tilillä ajavalta tuotantopalvelimelta, jolloin renderer korvaa sen toisella fontilla. Lataa fontti käyttöjärjestelmän fonttihakemiston sijasta tiedostosta, jonka installer sijoittaa levylle. HotPDFin Unicode-rekisteröinti ottaa suoraan polun:
Pdf.RegisterUnicodeTTF('C:\ProgramData\MyApp\Fonts\NotoSans.ttf');
Pdf.CurrentPage.SetFont('NotoSans', [], 12);
Pdf.CurrentPage.TextOut(50, 700, 0, WideString('Łódź - Ünïcode test ✓'));
TextOut hyväksyy WideString-arvon, joten aksentoidut nimet ja saksan- tai puolankieliset osoitteet kulkevat samalla kutsulla kuin ASCII-otsikot, kun rekisteröity fontti sisältää glyphs-merkit. Upotetut fontit vaativat PDF 1.5:n tai uudemman; vanhempaan versioon lukitseva vaatimus rikkoo tämän hiljaisesti. Arabic- ja Hebrew-kaltaiset right-to-left scripts vaativat shaping-prosessin suoran glyph lookup -toiminnon sijaan; katso HotPDFin complex script text shaping -artikkeli
Kun asennettu fontti ei sisällä tarvittavia MICR-merkkejä tai omaa symbolijoukkoa, Type 3 fonts täyttävät aukon. Jokainen glyph määritetään pienenä content stream -rakenteena kutsuilla RegisterType3Font ja AddType3Glyph. Tämä erikoistapaus on selkeämpi kuin satojen pienten symbolibittikarttojen sijoittaminen sivulle
Kuvat: keskimmäiset argumentit ovat leveys ja korkeus
AddImage ottaa TBitmap- tai TJPEGImage-kuvan, upottaa sen kerran ja palauttaa indeksin. PNG-kuva puretaan bitmap-muotoon ennen kutsua. ShowImage piirtää indeksin haluttuun paikkaan niin monta kertaa kuin tarvitaan. Tarkista seuraavan ShowImage-kutsun argumenttijärjestys:
var
Png: TPngImage;
Logo: TBitmap;
LogoIdx: Integer;
begin
Png := TPngImage.Create;
Logo := TBitmap.Create;
try
Png.LoadFromFile('brand-logo.png');
Logo.Assign(Png); // decode PNG to a bitmap
LogoIdx := Pdf.AddImage(Logo, icFlate); // lossless for flat-color art
finally
Logo.Free;
Png.Free;
end;
// (Index, X, Y, Width, Height, Angle): not (X1, Y1, X2, Y2)
Pdf.CurrentPage.ShowImage(LogoIdx, 50, 700, 120, 40, 0);
end;
Sijainnin jälkeiset arvot ovat width ja height, eivät vastakkaisen kulman koordinaatit, ja viimeinen argumentti on rotation angle asteina. X1/Y1/X2/Y2-tulkinta venyttää kohdassa (50, 700) olevan 120-by-40-logon lähes koko sivulle. KeepImageAspectRatio on oletuksena True, joten vääränmuotoinen laatikko letterbox-käsittelee kuvan venyttämisen sijaan. Aseta se False-arvoon vain tarkoituksellista venytystä varten
AddImage upottaa pikselit kerran ja kaikki saman indeksin ShowImage-kutsut viittaavat samaan objektiin. Jos AddImage kutsutaan 500 sivun loop-silmukan sisällä, sama logo upotetaan 500 kertaa. Rekisteröi se kerran ennen silmukkaa ja säilytä indeksi. Asset path -avaiminen pieni dictionary varmistaa, että kukin kuva rekisteröidään vain kerran
Photographic content ja scanned attachments kuuluvat JPEG-muotoon: välitä icJpeg AddImage-kutsulle ja laske oletusarvoltaan 100 oleva JpegQuality noin arvoon 85. Tulostuksessa eroa ei huomaa. Logos, charts ja line drawings kuuluvat häviöttömään icFlate-pakkaukseen, koska JPEG tekee koville reunoille ringing-virheitä. Täysilaatuinen kuva jokaisella sivulla voi kasvattaa raportin gigatavuihin; JPEG 85 voi pienentää sen noin kymmenesosaan
Viivat, laatikot ja varjostus path primitives -kutsuilla
Taulukko-otsikon viiva ja totals figure -taustan harmaa laatikko kannattaa piirtää vektoreina. Ne pysyvät terävinä kaikilla zoom-tasoilla, tulostuvat tarkasti ja lisäävät tiedostokokoa vain vähän. HotPDF käyttää raw PDF content streams -mallia: rakenna path ja kutsu sen maalaavaa operaattoria
// Horizontal rule under the table header
Pdf.CurrentPage.SetLineWidth(0.75);
Pdf.CurrentPage.MoveTo(50, 660);
Pdf.CurrentPage.LineTo(545, 660);
Pdf.CurrentPage.Stroke;
// Shaded totals box: X, Y, width, height
Pdf.CurrentPage.SetRGBFillColor(RGB(235, 235, 235));
Pdf.CurrentPage.Rectangle(395, 120, 150, 40);
Pdf.CurrentPage.Fill;
Järjestys on pakollinen: aseta paint state, rakenna path ja kutsu Stroke tai Fill. Maalaamaton path ei näy. SetRGBFillColor ottaa yhden TColor-arvon, joten VCL-vakiot kuten clNavy ja clBlack toimivat suoraan. Rectangle käyttää width- ja height-arvoja, ei kahta kulmaa. Alle noin puolen pisteen viiva voi kadota 600 dpi office printer -tulostuksessa, joten 0.75pt on järkevä minimi tulostettaville viivoille
Sivutus oikealla datalla, ei näytedatalla
Kohdista numerocolumns oikeasta reunasta mittaamalla kunkin renderöidyn arvon leveys ja sijoittamalla se column boundary -rajasta taaksepäin. Leading spaces toimii vain monospaced font -fontilla. Muotoile arvot ensin Delphin locale-aware-rutiinilla kuten FormatFloat, jotta mitattu thousands separator vastaa asiakkaalle näytettävää
Kymmenen lyhyen demorivin sivutus ei paljasta 140-merkkisen yritysnimen tai 4,000 line items -aineiston ongelmia. Käytä yhtä Y cursor -arvoa, josta vähennetään row height, ja aloita uusi sivu heti kun cursor ylittäisi bottom margin -rajan. Alaspäin tarkoittaa tässä pienenevää Y-arvoa. Pidä sivunvaihto, SetFont-tilan palautus ja running header -otsikon uudelleenpiirto samassa rutiinissa. Arkisto- ja saavutettavuusvaatimukset tarkistavat juuri tässä tehdyt font embedding-, tagging- ja color spaces -valinnat; lue HotPDF PDF/A-, PDF/X- ja PDF/UA -opas ennen templaten vakiinnuttamista
Kaikki esitetyt text positioning-, font registration-, image embedding- ja path drawing -kutsut sisältyvät Delphin ja C++Builderin HotPDF Component -tuotteeseen. Sen viite kuvaa koko output API -rajapinnan sekä rinnakkaiset forms-, encryption- ja signing-ominaisuudet