V HotPDF Component THotPDF.Resolution definira risalno enoto: vsaka koordinata X in Y, vsak rob, velikost, podana k SetFont, in rezultati TextWidth ter GetWideTextWidth se merijo v 1/Resolution palca. THPDFPage.Width in Height ji ne sledita in ostajata v točkah, zato morajo meje postavitve prihajati iz read-only lastnosti UserWidth in UserHeight. Običajen razlog za dotikanje Resolution je prenos: motor poročil, ki že misli v 1/96 ali 1/144 palca, se lažje preseli, kadar PDF stran govori isto enoto, kot kadar vsako klicno mesto dobi pretvorbeni faktor. To dela dobro, dokler veste, katera števila so se preselila v novo enoto in katera so ostala za sabo
Kaj THotPDF.Resolution dejansko spremeni?
THotPDF.Resolution spremeni samo to, kako HotPDF bere števila, ki jih podate; PDF, ki ga zapiše, je isti. Nastavitelj sta dve vrstici: SetResolution shrani vrednost in nastavi DocScale := Value / 72. Od takrat naprej XProjection in YProjection delita vsako koordinato s DocScale na poti v tok vsebine, SetFont pa na enak način deli velikost, preden jo zabeleži. Uporabniški prostor PDF privzame 1/72 palca (ISO 32000-1 §8.3.2.3), zato je pri privzeti Resolution 72 projekcija identiteta, pri 144 pa je ena risalna enota pol točke. Vnos /UserUnit se ne zapiše. Ta atribut strani, dodan v PDF 1.6, je ločena zadeva, ki jo HotPDF izpostavi kot THPDFPage.SetUserUnit. Ena podrobnost, ki ujame ljudi, prišle iz vadnic TextOut: koordinate strani tečejo od zgornjega levega kota z Y, ki raste navzdol, ker YProjection izračuna zgornji rob MediaBox minus skalirani Y, in to ostane res pri vsaki Resolution
var
Pdf: THotPDF;
Page: THPDFPage;
Margin: Single;
Title: WideString;
begin
Pdf := THotPDF.Create(nil);
try
Pdf.FileName := 'invoice.pdf';
Pdf.Resolution := 144; // 1 risalna enota = 1/144 palca
Pdf.BeginDoc;
Page := Pdf.CurrentPage; // A4: Width = 595, UserWidth = 1190
Margin := 144; // en palec v risalnih enotah
Page.SetFont('Arial', [fsBold], 28); // 28/144 palca, pisava 14 pt
Title := 'INVOICE 2026-0417';
// Poravnajte desno na rob strani, merjen v isti enoti
Page.TextOut(Page.UserWidth - Margin - Page.GetWideTextWidth(Title),
Margin, 0, Title);
Page.SetLineWidth(2); // črta 1 pt
Page.MoveTo(Margin, Margin + 48);
Page.LineTo(Page.UserWidth - Margin, Margin + 48);
Page.Stroke;
Pdf.EndDoc;
finally
Pdf.Free;
end;
end;
Zakaj se Page.Width ne ujema z mojimi koordinatami pri Resolution 144?
THPDFPage.Width in Height poročata stran v točkah, ne glede na Resolution dokumenta, vaše koordinate pa so v 1/Resolution palca, zato pri 144 stran izgleda pol toliko široka, kot je res. Stran A4 bere Width = 595 in Height = 842 pri Resolution 72 in še vedno bere 595 in 842 pri 144, kjer je desni rob dejansko pri X = 1190. UserWidth in UserHeight, dodana v v2.766.0, vrneta Width * DocScale, kar je velikost strani v enoti, s katero rišete. Pred njima je knjižnica notranje mešala oboje, simptomi pri Resolution 144 pa so bili dramatični: odstavki so se lomili po vsakem znaku, THPDFTable.Render je vsako vrstico potisnil na novo stran, izvoznik HTML in izravnalnik XFA pa sta risala svojo vsebino na polovico velikosti, izravnani obrazec stisnjen v zgornji levi kot. Postavitev odstavkov, izrisovanje tabel, uvoz HTML, sredinjenje EMF, izrez strani WMF in diagnostika postavitve zdaj vsi berejo velikost v uporabniških enotah. Tudi vaša lastna koda postavitve bi morala: vse, kar primerja z risalno koordinato (desni rob, preizkus preloma strani, izračun sredinjenja), pripada na UserWidth in UserHeight, nikoli na Width in Height
Past ena: dodelitev Width ali Height preklopi stran na točke
Nastavitev Page.Width ali Page.Height tiho spremeni stran v UserDefined, stran UserDefined pa popolnoma spregleda DocScale, zato je vse, kar nanjo potem narišete, v točkah, ne v 1/Resolution palca. Nastavitelj je star in po zasnovi jemlje točke, zato je bil njegov pomen puščen pri miru. Projekcija za stran UserDefined je goli X + MinX, SetFont pa shrani velikost nespremenjeno. Pri Resolution 144 je rezultat stran, katere vsebina nenadoma izide dvakrat toliko velika kot stran pred njo. Knjižnica je naredila točno to napako sama: strani nadaljevanja odstavkov so kopirale velikost prejšnje strani skozi Width in vsaka stran preliva je prešla na točke. Te strani zdaj namesto tega kopirajo Size, Orientation in Resolution strani ter padejo nazaj na Width in Height samo, kadar je bila izvirna stran že UserDefined
Dva izhoda, odvisno od tega, kaj potrebujete. Če bo zadostoval standarden list, nastavite Page.Size in Page.Orientation in nadaljujte z risanjem v svoji enoti Resolution. Če res potrebujete velikost strani po meri, sprejmite, da je to stran v točkah, in rišite v točkah; UserWidth je tam enak Width, zato koda postavitve, ki vedno bere UserWidth, dela na obeh vrstah strani. Enotski preizkus to pribije: pri Resolution 144 stran A4 poroča UserWidth 1190, po Width := 500 in Height := 400 pa poroča 500 in 400. Naložene strani se obnašajo enako, ker stran, znova zgrajena iz obstoječega PDF, pozna samo svoj MediaBox v točkah in riše v točkah. Strani, ki jih je ta dokument ustvaril, obdržijo svoje enote, kadar odmaknete in se vrnete skozi CurrentPageNumber, kar velja od v2.766.26
Past dva: zakaj velikosti pisav izidejo na polovico?
Velikost pisave, ki je začela kot točke, izide na polovico pri Resolution 144, ker SetFont ravna s svojim argumentom velikosti kot z risalnimi enotami in ga pretvori v točke, preden ga shrani. Notranje SetFont shrani ASize / DocScale * DPI v trenutni objekt pisave, zato je shranjena vrednost vedno v točkah. Knjižnica se je na tem dvakrat spotaknila: pisavna rezerva v WideTextOutBoxEx in stran nadaljevanja odstavkov sta obe podali to shranjeno vrednost v točkah nazaj k SetFont, ki jo je skaliral drugič in prepolovil tekst. Vaša koda ne more brati shranjene velikosti, a isti hrošč se pokaže vsakič, ko vrednost v točkah od kje koli drugje doseže SetFont: TFont.Size iz obrazca VCL, velikost v definiciji poročila, dolžina CSS pt. Najprej jo pretvorite in v faktor vključite lastno Resolution strani ter primer UserDefined, kot to stori predvajanje metafile, ko znova predvaja Canvas strani (glejte kako HotPDF uvaža vektorsko grafiko EMF in WMF za to pot):
// Rislane enote na točko na trenutni strani. Zrcali projekcijo,
// ki jo uporablja HotPDF: 1 na strani, velikostni skozi Width/Height, sicer
// (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 je v točkah; SetFont pričakuje risalne enote
Pdf.CurrentPage.SetFont(AnsiString(Font.Name), Font.Style,
Font.Size * UnitsPerPoint(Pdf));
end;
Knjižnica uveljavi isto pravilo za svoje lastne konstante v točkah. Pisava 12 točk, s katero se začne vsaka nova stran, je zdaj pomnožena z notranjim faktorjem enot-na-točko, zato je 12 točk pri kateri koli Resolution. DrawChart, katerega robovi, velikosti oznak in širine črt so vsi trdo kodirane točke, zdaj teče s skalo, začasno nastavljeno na 1. Kar ostane v risalnih enotah, namerno, so privzete vrednosti javnih parametrov, kot sta velikost modula DrawQRCode in privzeta velikost pisave tabele: del so pogodbe API, zato pri Resolution 144 pomenijo polovico tega, kar pomenijo pri 72. Če velikost poročil jemljete iz predloge, vodnik po izpisu poročil s pisavami in slikami v HotPDF pokrije, od kod te vrednosti običajno pridejo
Kako preverite, da je postavitev neodvisna od Resolution?
Najbolj zanesljiv preizkus je bajtna primerjava: izrišite isto stran pri Resolution 72 in znova pri 144, z vsako koordinato in velikostjo podvojeno, tokova nestisnjene vsebine pa morata biti identična. Obe poganjanji pristaneta na istih vrednostih v točkah po projekciji, zato je vsaka razlika vrednost, ki je preskočila pretvorbo. Tako preizkusna zbirka HotPDF preverja odstavke, tabele, uvoz HTML, izravnavanje XFA, loka, metafile in slike. Ista tehnika dela za vašo lastno kodo poročil s skoraj nič opreme:
procedure RenderPage(const FileName: string; Res: Integer; K: Single);
var
Pdf: THotPDF;
begin
Pdf := THotPDF.Create(nil);
try
Pdf.AutoLaunch := False;
Pdf.Compression := cmNone; // berljivi tokovi vsebine
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) and RenderPage('r144.pdf', 144, 2)
// morata izdelati bajtno identična tokova vsebine strani
Preverite operatorje, ki nosijo števila: Td, Tm, Tf, re, w in polja TJ. Bajti na ravni datoteke se bodo še vedno razlikovali v datumu nastanka in /ID, zato primerjajte tokova, ne celih datotek. Neujemanje skoraj vedno kaže na eno od dveh pasti zgoraj: stran, spremenjeno v velikost skozi Width, ali vrednost v točkah, podano naravnost k SetFont. Če ste novi pri risalnih klicih samih, začnite z vodnikom po TextOut za velikost, stil in zasuk v HotPDF, nato se vrnite in preklopite Resolution, ko vaša postavitev bere UserWidth. Popolne podrobnosti API in preizkusni prenosi so na strani komponente HotPDF Delphi PDF