HotPDF Componentissa THotPDF.Resolution määrittelee piirtoyksikön: jokainen X- ja Y-koordinaatti, jokainen marginaali, SetFontille annettu koko sekä TextWidthin ja GetWideTextWidthin tulokset mitataan 1/Resolution tuumassa. THPDFPage.Width ja Height eivät noudata sitä ja pysyvät pisteinä, joten asettelun rajat on saatava vain luku -ominaisuuksista UserWidth ja UserHeight. Tavallinen syy koskettaa Resolutionia on porttaus: raporttimoottori, joka jo ajattelee 1/96 tai 1/144 tuumassa, on helpompi siirtää, kun PDF-puoli puhuu samaa yksikköä, kuin silloin, kun jokainen kutsukohta saa muunnoskertoimen. Se toimii hyvin, niin kauan kuin tiedät, mitkä luvut siirtyivät uuteen yksikköön ja mitkä jäivät taakse
Mitä THotPDF.Resolution oikeasti muuttaa?
THotPDF.Resolution muuttaa vain sen, miten HotPDF lukee antamasi luvut; kirjoitettava PDF on sama. Setterinä on kaksi riviä: SetResolution tallettaa arvon ja asettaa DocScale := Value / 72. Siitä lähtien XProjection ja YProjection jakavat jokaisen koordinaatin arvolla DocScale matkalla sisältöstreamiin, ja SetFont jakaa koon samalla tavalla ennen sen kirjaamista. PDF:n käyttäjätila olettaa 1/72 tuuman (ISO 32000-1 §8.3.2.3), joten oletus-Resolutionilla 72 projektointi on identiteetti ja arvolla 144 yksi piirtoyksikkö on puoli pistettä. /UserUnit-merkintää ei kirjoiteta. Kyseinen sivuattribuutti, lisätty PDF 1.6:ssa, on eri asia, jonka HotPDF näyttää metodina THPDFPage.SetUserUnit. Yksi yksityiskohta saa kiinni TextOut-oppaista tulevat: sivukoordinaatit kulkevat vasemmasta yläkulmasta, Y kasvaen alaspäin, koska YProjection laskee MediaBoxin yläosan miinus skaalatun Y:n, ja niin on joka Resolutionilla
var
Pdf: THotPDF;
Page: THPDFPage;
Margin: Single;
Title: WideString;
begin
Pdf := THotPDF.Create(nil);
try
Pdf.FileName := 'invoice.pdf';
Pdf.Resolution := 144; // 1 piirtoyksikkö = 1/144 tuumaa
Pdf.BeginDoc;
Page := Pdf.CurrentPage; // A4: Width = 595, UserWidth = 1190
Margin := 144; // yksi tuuma piirtoyksiköinä
Page.SetFont('Arial', [fsBold], 28); // 28/144 tuumaa, 14 pt fontti
Title := 'INVOICE 2026-0417';
// Tasaa oikealle sivun reunaan samassa yksikössä mitattuna
Page.TextOut(Page.UserWidth - Margin - Page.GetWideTextWidth(Title),
Margin, 0, Title);
Page.SetLineWidth(2); // 1 pt viiva
Page.MoveTo(Margin, Margin + 48);
Page.LineTo(Page.UserWidth - Margin, Margin + 48);
Page.Stroke;
Pdf.EndDoc;
finally
Pdf.Free;
end;
end;
Miksi Page.Width eriää koordinaattejani Resolutionilla 144?
THPDFPage.Width ja Height raportoivat sivun pisteinä riippumatta asiakirjan Resolutionista, kun taas koordinaattisi ovat 1/Resolution tuumassa, joten arvolla 144 sivu näyttää puolet niin leveältä kuin onkaan. A4-sivu lukee arvot Width = 595 ja Height = 842 Resolutionilla 72 ja yhä 595 ja 842 arvolla 144, missä oikea reuna on oikeasti kohdassa X = 1190. UserWidth ja UserHeight, lisättynä versiossa v2.766.0, palauttavat arvon Width * DocScale, eli sivukoon siinä yksikössä, jolla piirrät. Ennen niitä kirjasto sekoitti nämä kaksi keskenään sisällään, ja oireet Resolutionilla 144 olivat dramaattiset: kappaleet katkesivat rivin jokaisen merkin jälkeen, THPDFTable.Render työnsi jokaisen rivin uudelle sivulle, ja sekä HTML-tuoja että XFA-tasottaja piirsivät sisältönsä puolikokoisena, tasotettu lomake ahtautuneena vasempaan yläkulmaan. Kappaleasettelu, taulukoiden renderöinti, HTML-tuonti, EMF-keskitys, WMF-sivun leikkaus ja asetteludiagnostiikka lukevat nyt kaikki käyttäjäyksikkökoon. Sinun oman asettelukoodisi kannattaa lukea sekin: kaikki, mikä vertaa piirtoyksikkökoordinaattiin (oikea marginaali, sivunvaihtotesti, keskityslaskelma), kuuluu UserWidthille ja UserHeightille, ei koskaan Widthille ja Heightille
Ansa yksi: Widthin tai Heightin asettaminen vaihtaa sivun pisteisiin
Page.Widthin tai Page.Heightin asettaminen vaihtaa hiljaa sivun UserDefinediksi, ja UserDefined-sivu ohittaa DocScalen kokonaan, joten kaikki, minkä sille sen jälkeen piirrät, on pisteitä, eivät 1/Resolution tuumaa. Setteri on vanha ja ottaa pisteet suunnitellusti, minkä vuoksi sen merkitys jätettiin rauhaan. Projektointi UserDefined-sivulle on pelkkä X + MinX, ja SetFont tallettaa koon muuttumattomana. Resolutionilla 144 tulos on sivu, jonka sisältö yhtäkkiä tulee ulos kaksinkertaisena edelliseen sivuun verrattuna. Kirjasto teki täsmälleen tämän virheen itsekin: kappaleiden jatkosivut kopioivat aiemmin edellisen sivun koon kentän Width kautta, ja jokainen ylivuotosivu vaihtui pisteisiin. Kyseiset sivut kopioivat nyt arvot Size, Orientation ja sivun Resolutionin, ja palaavat arvoihin Width ja Height vain, jos alkuperäinen sivu oli jo UserDefined
Kaksi tieä ulos, tarpeen mukaan. Jos vakiopaperi kelpaa, aseta arvot Page.Size ja Page.Orientation ja jatka piirtämistä Resolution-yksikössäsi. Jos tarvitset oikeasti oman sivukoon, hyväksy, että se on pistesivu, ja piirrä pisteissä; UserWidth on silloin yhtä kuin Width, joten asettelukoodi, joka aina lukee UserWidthin, toimii molemmilla sivutyypeillä. Yksikkötesti lukitsee asian: Resolutionilla 144 A4-sivu raportoi UserWidthin arvon 1190, mutta arvojen Width := 500 ja Height := 400 jälkeen se raportoi 500 ja 400. Ladatut sivut käyttäytyvät samoin, koska olemassa olevasta PDF:stä rakennettu sivu tuntee vain MediaBoxinsa pisteinä ja piirtää pisteissä. Sivut, jotka tämä asiakirja loi, pitävät omat yksikkönsä, kun siirryt pois ja palaat CurrentPageNumberin kautta, kuten on ollut asia versiosta v2.766.26 alkaen
Ansa kaksi: miksi fonttikoot tulevat ulos puolikokoisina?
Pisteinä alkanut fonttikoko tulee ulos puolikokoisena Resolutionilla 144, koska SetFont käsittelee kokoparametriaan piirtoyksiköinä ja muuntaa sen pisteiksi ennen tallettamista. Sisäisesti SetFont tallettaa arvon ASize / DocScale * DPI nykyiseen fonttiobjektiin, joten talletettu arvo on aina pisteitä. Kirjasto komistui tähän kahdesti: fonttivaramaisuus funktiossa WideTextOutBoxEx ja kappaleiden jatkosivu antoivat molemmat kyseisen talletetun pistearvon takaisin funktiolle SetFont, joka skaalasi sen toisen kerran ja puolitti tekstin. Oma koodisi ei voi lukea talletettua kokoa, mutta sama vika ilmestyy aina, kun pistearvo jostain muualta päätyy funktiolle SetFont: TFont.Size VCL-lomakkeelta, koko raporttimäärittelyssä, CSS:n pt-pituus. Muunna se ensin, ja ota kerroimeen mukaan sivun oma Resolution ja UserDefined-tapaus, niin kuin metafilen toisto tekee toistaessaan sivun Canvasin (kyseinen polku on kerrottu kirjoituksessa miten HotPDF tuo EMF- ja WMF-vektorigrafiikkaa):
// Piirtoyksiköt pistettä kohti nykyisellä sivulla. Peilaa projektion,
// jota HotPDF käyttää: 1 sivulla, jonka koko on asetettu Width/Heightilla, muuten
// (document Resolution / 72) * (page Resolution / 72)
function UnitsPerPoint(Pdf: THotPDF): Single;
begin
if Pdf.CurrentPage.Size = UserDefined then
Result := 1
else
Result := (Pdf.Resolution / 72) * (Pdf.CurrentPage.Resolution / 72);
end;
procedure SetFontFromVcl(Pdf: THotPDF; Font: TFont);
begin
// TFont.Size on pisteissä; SetFont odottaa piirtoyksiköitä
Pdf.CurrentPage.SetFont(AnsiString(Font.Name), Font.Style,
Font.Size * UnitsPerPoint(Pdf));
end;
Kirjasto soveltaa samaa sääntöä omiin pistevakioihinsa. 12 pisteen fontti, jolla jokainen uusi sivu alkaa, kerrotaan nyt sisäisellä yksikköä-pistettä-kohti-kertoimella, joten se on 12 pistettä millä tahansa Resolutionilla. DrawChart, jonka marginaalit, leimakoot ja viivaleveydet ovat kaikki kovakoodattuja pisteitä, ajaa nyt skaalan ollessa väliaikaisesti 1. Mikä pysyy piirtoyksiköissä tahallaan, ovat julkisten parametrien oletukset kuten DrawQRCodein moduulikoko ja oletustaulukonfonttikoko: ne ovat osa API-sopimusta, joten Resolutionilla 144 ne merkitsevät puolet siitä, mitä ne merkitsevät arvolla 72. Jos kokoat raportteja mallipohjasta, opas raportin ulostulo fonteilla ja kuvilla HotPDF:ssä kertoo, mistä kyseiset arvot yleensä tulevat
Miten varmistat, että asettelu on riippumaton Resolutionista?
Luotettavin tarkistus on tavuvertailu: renderöi sama sivu Resolutionilla 72 ja uudelleen arvolla 144, jolloin jokainen koordinaatti ja koko on kaksinkertaistettu, ja pakaamattomien sisältöstreamien on oltava identtiset. Molemmat ajot laskeutuvat samoihin pistearvoihin projektoinnin jälkeen, joten jokainen ero on arvo, joka ohitti muunnoksen. Näin HotPDF:n testisarja tarkistaa kappaleet, taulukot, HTML-tuonnin, XFA-tasottamisen, kaaret, metafilet ja kuvat. Sama tekniikka toimii omalle raporttikoodillesi lähes ilman testinosturia:
procedure RenderPage(const FileName: string; Res: Integer; K: Single);
var
Pdf: THotPDF;
begin
Pdf := THotPDF.Create(nil);
try
Pdf.AutoLaunch := False;
Pdf.Compression := cmNone; // luettavat sisältöstreamit
Pdf.FileName := FileName;
Pdf.Resolution := Res;
Pdf.BeginDoc;
Pdf.CurrentPage.SetFont('Arial', [], 10 * K);
Pdf.CurrentPage.TextOut(36 * K, 36 * K, 0, 'Line 1');
Pdf.CurrentPage.Rectangle(36 * K, 60 * K, 200 * K, 40 * K);
Pdf.CurrentPage.Stroke;
Pdf.EndDoc;
finally
Pdf.Free;
end;
end;
// RenderPage('r72.pdf', 72, 1) ja RenderPage('r144.pdf', 144, 2)
// on tuotettava tavuiltaan identtiset sivujen sisältöstreamit
Tarkista operaattorit, jotka kantavat lukuja: Td, Tm, Tf, re, w ja TJ-taulukot. Tiedostotason tavut eroavat yhä luontipäivästä ja /IDstä, joten vertaa streameja, ei kokonaisia tiedostoja. Ero osoittaa lähes aina jompaan kumpaan yllä olevista ansaista: sivuun, joka oli koollestettu uudelleen kentän Width kautta, tai pistearvoon, joka annettiin suoraan funktiolle SetFont. Jos piirtokutsut itsessään ovat uusia, aloita oppaasta HotPDF TextOut -läpikäynti koolle, tyylille ja kierteelle, ja palaa sitten vaihtamaan Resolutionia, kun asettelusi lukee UserWidthin. Täydet API-yksityiskohdat ja kokeiluversiot ovat HotPDF Delphi PDF component -sivulla