HotPDF gengiver en indlæst PDF-side til en Delphi-TBitmap gennem ét enkelt kald: RenderLoadedPageToBitmap(PageIndex, DPI). Funktionen fortolker sidens content stream og returnerer en 24-bit RGB-bitmap, som kalderen ejer, i den opløsning, du vælger, hvilket er præcis det, en miniaturestribe, en udskriftsvisning eller en PDF-til-billede-eksportpipeline har brug for. Denne artikel gennemgår API'en og derefter den del, der adskiller en brugbar renderer fra et legetøj: at tegne tekst ud fra selve de indlejrede skrifttypeprogrammer frem for fra lignende systemskrifttyper
Hvorfor er det sværere at gengive en PDF-side end at tegne et billede?
En PDF-side er ikke et billede. Den er et program: en strøm af operatorer, der bygger stier, vælger skrifttyper, sætter farver og placerer glyffer, udført mod den grafikmodel, der er defineret i ISO 32000-1 §8. Intet i filen siger, hvordan nogen pixel ser ud. For at producere en bitmap skal du køre det program — vedligeholde en aktuel transformationsmatrix, en grafiktilstandsstak til q/Q, en beskæringssti, fyld- og stregfarverum — og rasterisere resultatet. Derfor er "vis bare side 3 som et billede" en content stream-fortolker, ikke en filformatkonvertering
HotPDFs renderer, introduceret i v2.253.0, er bygget som seks afkoblede units, der afspejler den model: en affin matrixkerne til PDF-transformationsalgebraen [a b c d e f], en grafiktilstandsstak, en farverumsopløser (DeviceRGB, DeviceGray, DeviceCMYK, Indexed), en stibygger, der bygger bro fra PDF-stioperatorer til GDI, et skrifttypemetrik-lag, der læser /Widths-arrays for korrekte forskydninger, og fortolkeren, der dispatcher operatorer og driver de fem andre. Image XObjects går gennem den samme afkodningsstak, som biblioteket bruger til udtrækning, så hvert billedfilter, HotPDF kan afkode til udtrækning — herunder JPXDecode-komprimerede JPEG 2000-billeder — også optræder i det gengivne output
Gengivelse af en indlæst side til en TBitmap
RenderLoadedPageToBitmap tager et nulbaseret sideindeks og en DPI-værdi, hvor 72 DPI mapper én PDF-brugerrumsenhed til én pixel. Den returnerer nil ved fejl (indeks uden for intervallet, manglende ressourcer) i stedet for at kaste en undtagelse, så en fremviser kan springe en dårlig side over og fortsætte. Kalderen ejer den returnerede bitmap og skal frigive den
var
Pdf: THotPDF;
Bmp: TBitmap;
begin
Pdf := THotPDF.Create(nil);
try
if Pdf.LoadFromFile('report.pdf') > 0 then
begin
Bmp := Pdf.RenderLoadedPageToBitmap(0, 144); // side 1 ved 144 DPI
if Bmp <> nil then
try
Image1.Picture.Assign(Bmp);
finally
Bmp.Free; // kalderen ejer bitmappen
end;
end;
finally
Pdf.Free;
end;
end;
DPI-argumentet klarer skaleringsarbejdet i alle almindelige scenarier. En miniaturestribe gengives ved 36 eller 48 DPI og får små, hurtige bitmaps; en skærmvisning ved 96 eller 144 DPI matcher typisk skærmtæthed; en eksportsti ved 300 DPI producerer billeder i udskriftskvalitet. Siderotation fra /Rotate-posten og origo-spejlingen for /MediaBox (PDF placerer origo nederst til venstre, GDI øverst til venstre) håndteres inde i side-til-enhed-matricen, så en US Letter-side ved 72 DPI kommer tilbage som præcis 612×792 pixels med den rigtige side opad
Hvorfor viser gengivne PDF-miniaturer forkerte glyffer?
Forkerte eller omtrentlige glyffer i gengivet PDF-output betyder næsten altid, at rendereren erstatter med en systemskrifttype i stedet for at bruge den skrifttype, der er indlejret i filen. Den første HotPDF-renderer gjorde præcis det: den fjernede subset-præfikset fra /BaseFont (og forvandlede ABCDEF+Arial til Arial), bad GDI om en systemskrifttype med det navn og tegnede teksten med den. For et dokument, der bruger Arial eller Times New Roman med standardkodning, ser resultatet tæt på ud. Men det er en tilnærmelse, og den bryder sammen på veldefinerede måder
Subset-indlejrede skrifttyper er det værste tilfælde. En subset-skrifttype bærer måske kun de fyrre glyffer, et dokument faktisk bruger, med tegnkoder tildelt i en rækkefølge, der er privat for den fil — kode 1 kan være "T", kode 2 "h" og så videre. En systemskrifttype ved intet om den private tildeling, så teksten forsvinder enten eller kommer ud som helt forkerte tegn. Brugerdefinerede kodninger, symbolskrifttyper, stregkodeskrifttyper og enhver skrifttype, der ikke er installeret på gengivelsesmaskinen, fejler på samme måde. En renderer, der stopper ved systemskrifttype-erstatning, producerer miniaturer, der er genkendelige som siden — indtil siden bruger de skrifttyper, der gjorde indlejring nødvendig i første omgang
Indlejret glyfgengivelse: tegning ud fra selve skrifttypeprogrammet
HotPDF lukkede det hul over fem udgivelser (v2.268.0 til og med v2.272.0) ved at parse de indlejrede skrifttypeprogrammer og genafspille deres glyfkonturer som fyldte GDI-vektorstier. Tekst på en gengivet side kommer nu fra de samme konturdata, som en konform fremviser bruger, hvilket betyder, at subset-skrifttyper, brugerdefinerede kodninger og ikke-installerede skrifttyper gengives med deres præcise former. Dækningen blev bygget op efter skrifttypevariant:
For Type0/CIDFontType2-skrifttyper med et indlejret TrueType-program (FontFile2) parser rendereren tabellerne glyf og loca direkte: kvadratiske konturer konverteres til de kubiske Bézier-kurver, GDI forstår, implicitte on-curve-punkter mellem på hinanden følgende off-curve-punkter rekonstrueres, og sammensatte glyffer genafspilles rekursivt. Både Identity- og eksplicitte stream-CIDToGIDMap-layouts understøttes, og CID-forskydninger respekterer breddeposterne /W og /DW, så to-byte Identity-H-tekst rykker korrekt frem
CFF-programmer (FontFile3, hvad enten det er CIDFontType0C, Type1C eller en OpenType-wrapper) får en fuld Type 2-charstring-fortolker: linjer, kurver, flex-familien, hint masks og lokale/globale subrutinekald med den korrekte subrutine-bias. CID-nøglede CFF-programmer mapper tegnkoder gennem skrifttypens charset, hvilket betyder noget for subset-skrifttyper, hvis glyfrækkefølge afviger fra CID-rækkefølgen, og valg af font-DICT pr. glyf gennem FDArray/FDSelect respekteres. Simple (ikke-CID) TrueType-skrifttyper opløser én-byte-koder gennem den indlejrede skrifttypes egen cmap-tabel med en robust subtabelkæde — Unicode-format 4 og 12 først, derefter symbol-subtabeller med F000-spejlingen til privat brug, derefter ældre Macintosh-formater — mens simple Type1-skrifttyper opløser gennem CFF-programmets indbyggede kodning
To forfininger fuldender billedet. For det første opløses /Encoding-dictionaries for simple skrifttyper efter den prioritet, ISO 32000-1 §9.6.6 foreskriver: /Differences-arrays tilsidesætter basiskodningen, som tilsidesætter skrifttypeprogrammets eget kort — den sti, TeX- og PostScript-afledte værktøjskæder afhænger af, hvor glyfnavne opløses gennem Adobe Glyph List, CFF-charsettet eller TrueType-cmap. For det andet genafspilles Type3-skrifttyper, hvis glyffer selv er små content streams, gennem rendereren med skrifttypematricen, skriftstørrelsen og tekstmatricen sammensat; /Widths i glyfrum fortolkes gennem /FontMatrix, som ISO 32000-1 §9.6.5 kræver, og glyfprocedurer, der deklarerer en d1-afgrænsningsboks, beskæres til den, så en misdannet stregkodeglyf ikke kan male uden for sin celle. Når en kode ikke kan mappes — et beskadiget program, et ikke-mappet tegn — falder rendereren tilbage til systemskrifttype-tegning for den glyf i stedet for at droppe tekstkørslen
Hvordan gør man gentagne gengivelser hurtige?
Det svar, HotPDF leverer, er en most-recently-used-sidecache: RenderLoadedPageToBitmapCached beholder op til RenderCacheCapacity gengivne sider (standard 8) nøglet efter sideindeks og DPI, og et cache-hit returnerer en frisk kopi, som kalderen ejer, uden at røre content streamen — typisk tusindvis af gange hurtigere end at fortolke siden igen. Det mønster passer præcis til fremvisere: en bruger, der bladrer mellem to sider, eller en resize-hændelse, der anmoder om den samme side igen ved samme DPI, rammer cachen hver gang
// Miniaturestribe: første gennemløb gengiver, scrolling tilbage rammer cachen
for I := 0 to ThumbCount - 1 do
begin
Bmp := Pdf.RenderLoadedPageToBitmapCached(I, 48);
if Bmp <> nil then
try
ThumbList.AddThumbnail(I, Bmp);
finally
Bmp.Free;
end;
end;
// Efter redigering af en indlæst side på stedet:
Pdf.InvalidateRenderedPageCache; // næste gengivelse afspejler ændringen
Vær ærlig om hukommelsesregningen, før du hæver kapaciteten. En US Letter-side ved 300 DPI er 2550×3300 pixels, omkring 25 MB som 24-bit bitmap, så otte cachede sider i eksportopløsning fylder cirka 200 MB. Ved miniature-DPI koster de samme otte poster langt under en megabyte. Dimensionér RenderCacheCapacity efter den DPI, du faktisk cacher ved, og kald InvalidateRenderedPageCache efter enhver redigering på stedet — cachen er kun nøglet efter side og DPI, og den kan ikke se, at det underliggende indhold har ændret sig. Indlæsning af et nyt dokument rydder den automatisk
En anden cache arbejder under sidecachen: afkodede image XObjects opbevares i et bytebudgetteret lager begrænset af ImageCacheMaxBytes (standard 32 MB) med least-recently-used-udsmidning. Et logo eller brevhovedbillede, der gentages på hver side, afkodes én gang pr. dokumentindlæsning i stedet for én gang pr. Do-operator, hvilket cirka halverer gengivelsestiden for sider med delte billeder og fremskynder eksport af flersidet TIFF i samme grad. InvalidateRenderedPageCache rydder også denne cache
Hvad der stadig gengives omtrentligt
Rendereren sigter på den almindelige delmængde af dokument-PDF'er, og det er værd at vide, hvor grænserne går. CalRGB-, Lab- og ICC-baserede farverum tilnærmes frem for at farvestyres — enhedsfarverum, Indexed-paletter og samplede Type 0-funktionsfarveopslag håndteres, men en trykproduktionsfil, der forlader sig på ICC-gengivelseshensigter, vil ikke være kolorimetrisk præcis. Shading-mønstre (sh) og blandingstilstande ud over simpel alfa er ligeledes uden for rammerne, og Form XObject-rekursion er dybdebegrænset som en cyklusvagt. For fakturaer, rapporter, kontrakter og formularer — sider bestående af tekst, stier og billeder — er outputtet trofast; for en designprøve fuld af gradienter og transparensgrupper skal du betragte bitmappen som en forhåndsvisning, ikke en prøve
Den praktiske læsning: hvis din pipeline genererer dokumenter med HotPDF eller forbruger typiske forretnings-PDF'er, sender RenderLoadedPageToBitmap dem frem og tilbage med de præcise indlejrede glyfformer, korrekte CID-forskydninger og korrekt sidegeometri. Tilnærmelserne lever i de hjørner af grafikmodellen, som forretningsdokumenter sjældent besøger
RenderLoadedPageToBitmap, dens cachede variant og den pipeline til indlejret glyfgengivelse, der er beskrevet her, leveres som en del af HotPDF Delphi Component til Delphi og C++Builder — et native VCL-bibliotek uden eksterne DLL-afhængigheder, der dækker PDF-oprettelse, redigering, tekstudtrækning og sidegengivelse i én pakke