Tehnični članak

Upodabljanje strani PDF v bitno sliko v Delphiju s HotPDF

HotPDF upodobi naloženo stran PDF v Delphi TBitmap z enim samim klicem: RenderLoadedPageToBitmap(PageIndex, DPI). Funkcija interpretira tok vsebine strani in vrne 24-bitno sliko RGB v lasti klicatelja pri ločljivosti, ki jo izberete, kar je natanko tisto, kar potrebujejo sličice (thumbnails), predogled tiskanja ali cevovod za izvoz PDF-ja v sliko. Ta članek obravnava API, nato pa tisti del, ki ločuje uporaben upodabljalnik od igrače: risanje besedila iz samih vgrajenih programov pisav namesto iz podobnih sistemskih pisav

Zakaj je upodabljanje strani PDF težje od risanja slike?

Stran PDF ni slika. Je program: tok operaterjev, ki gradijo poti, izbirajo pisave, nastavljajo barve in postavljajo glife, ki se izvajajo v skladu z grafičnim modelom, določenim v ISO 32000-1 §8. Nič v datoteki ne določa, kako je videti kateri koli slikovni pik (piksel). Da bi ustvarili bitno sliko, morate zagnati ta program — vzdrževati trenutno transformacijsko matriko, sklad grafičnega stanja za q/Q, pot obrezovanja, barvne prostore za polnjenje in poteze — ter rasterizirati rezultat. Zato je "preprosto prikazovanje strani 3 kot slike" interpreter toka vsebine, ne pa pretvorba formata datoteke

Upodabljalnik HotPDF, uveden v v2.253.0, je zgrajen iz šestih nepovezanih enot, ki zrcalijo ta model: jedro afine matrike za algebro transformacij PDF [a b c d e f], sklad grafičnega stanja, razreševalnik barvnih prostorov (DeviceRGB, DeviceGray, DeviceCMYK, Indexed), gradnik poti, ki povezuje operaterje poti PDF z GDI, plast metrike pisav, ki bere polja /Widths za pravilen napredek, in interpreter, ki pošilja operaterje in usmerja ostale štiri. Slikovni XObjecti gredo skozi isti sklad za dekodiranje, ki ga knjižnica uporablja za ekstrakcijo, tako da se vsak filter slik, ki ga HotPDF lahko dekodira za ekstrakcijo — vključno s slikami JPEG 2000, stisnjenimi z JPXDecode — pojavi tudi v upodobljenem izhodu

Upodabljanje naložene strani v TBitmap

Klic RenderLoadedPageToBitmap sprejme ničelni indeks strani in vrednost DPI, pri čemer 72 DPI preslika eno enoto uporabniškega prostora PDF v en slikovni pik. Vrne nil ob neuspehu (indeks izven obsega, manjkajoči viri), namesto da bi sprožil izjemo, tako da bralnik lahko preskoči slabo stran in nadaljuje. Klicatelj je lastnik vrnjene bitne slike in jo mora sprostiti

var
  Pdf: THotPDF;
  Bmp: TBitmap;
begin
  Pdf := THotPDF.Create(nil);
  try
    if Pdf.LoadFromFile('report.pdf') > 0 then
    begin
      Bmp := Pdf.RenderLoadedPageToBitmap(0, 144);  // page 1 at 144 DPI
      if Bmp <> nil then
      try
        Image1.Picture.Assign(Bmp);
      finally
        Bmp.Free;  // caller owns the bitmap
      end;
    end;
  finally
    Pdf.Free;
  end;
end;

Argument DPI opravi skaliranje za vsak običajen scenarij. Vrstica sličic se upodablja pri 36 ali 48 DPI in dobi majhne, hitre bitne slike; predogled na zaslonu pri 96 ali 144 DPI ustreza tipični gostoti zaslona; izvozna pot pri 300 DPI pa ustvari slike kakovosti tiskanja. Vrtenje strani iz vnosa /Rotate in obrat izhodišča /MediaBox (PDF postavi izhodišče levo spodaj, GDI pa levo zgoraj) se upravljata znotraj matrike stran-naprava, tako da se stran US Letter pri 72 DPI vrne kot natanko 612×792 slikovnih pik v pravilni orientaciji

Zakaj upodobljene sličice PDF prikazujejo napačne glife?

Napačni ali približni glifi v upodobljenem izhodu PDF skoraj vedno pomenijo, da upodabljalnik nadomešča pisavo s sistemsko pisavo, namesto da bi uporabil pisavo, vgrajeno v datoteki. Prvi upodabljalnik HotPDF je naredil natanko to: odstranil je predpono podnabora iz /BaseFont (spremenil je ABCDEF+Arial v Arial), zahteval od GDI sistemsko pisavo s tem imenom in z njo narisal besedilo. Za dokument, ki uporablja Arial or Times New Roman s standardnim kodiranjem, je rezultat videti blizu. Vendar je to le približek in ne deluje v določenih primerih

Pisave z vgrajenimi podnabori so najslabši primer. Podnaborna pisava lahko vsebuje le štirideset glifov, ki jih dokument dejansko uporablja, s kodami znakov, dodeljenimi v vrstnem redu, ki je zaseben za to datoteko — koda 1 je lahko "T", koda 2 "h" in tako naprej. Sistemska pisava ne ve ničesar o tej zasebni dodelitvi, zato besedilo bodisi izgine bodisi se izpiše kot povsem napačni znaki. Kodiranja po meri, pisave s simboli, pisave s črtno kodo in kateri koli slog, ki ni nameščen na upodabljalnem stroju, odpovejo na enak način. Upodabljalnik, ki se ustavi pri nadomeščanju s sistemsko pisavo, ustvari sličice, ki so prepoznavne kot stran — dokler stran ne uporabi pisav, zaradi katerih je bila vgradnja sploh nujna

Upodabljanje vgrajenih glifov: risanje iz samega programa pisave

HotPDF je to vrzel odpravil v petih izdajah (v2.268.0 do v2.272.0) z analiziranjem vgrajenih programov pisav in predvajanjem njihovih orisov glifov kot izpolnjenih vektorskih poti GDI. Besedilo na upodobljeni strani zdaj izhaja iz istih podatkov orisa, kot jih uporablja skladen bralnik, kar pomeni, da se podnaborne pisave, kodiranja po meri in nenameščene pisave upodabljajo s svojimi natančnimi oblikami. Pokritost je bila zgrajena po vrstah pisav:

Za pisave Type0/CIDFontType2 z vgrajenim programom TrueType (FontFile2) upodabljalnik neposredno analizira tabeli glyf in loca: kvadratne konture se pretvorijo v kubične krivulje Bézier, ki jih GDI razume, rekonstruirajo se implicitne točke na krivulji med zaporednimi točkami izven krivulje, sestavljeni glifi pa se rekurzivno predvajajo. Podprti sta tako postavitvi Identity kot eksplicitni tokovni CIDToGIDMap, napredovanja CID pa spoštujejo vnosa širine /W in /DW, tako da se dvobajtno besedilo Identity-H pravilno premika

Programi CFF (FontFile3, bodisi CIDFontType0C, Type1C ali vsebnik OpenType) dobijo popoln interpreter Type 2 charstring: črte, krivulje, družino flex, maske namigov (hints) in klic lokalnih/globalnih podprogramov s pravilnim odklonom podprogramov. Programi CFF z indeksom CID preslikajo kode znakov prek nabora znakov pisave, kar je pomembno za podnaborne pisave, katerih vrstni red glifov se razlikuje od vrstnega reda CID, prav tako pa se spoštuje izbira font-DICT za posamezen glif prek FDArray/FDSelect. Preproste (ne-CID) pisave TrueType razrešujejo enobajtne kode prek lastne tabele cmap vgrajene pisave z robustno verigo podtabel — najprej formata Unicode 4 in 12, nato tabele simbolov z zrcalom zasebne uporabe F000, nato starejši formati Macintosh —, medtem ko preproste pisave Type1 razrešujejo prek kodiranja, vgrajenega v program CFF

Slika se zaključi z dvema izboljšavama. Prvič, slovarji preprostih pisav /Encoding se razrešujejo v skladu s prednostnim vrstnim redom, ki ga predpisuje ISO 32000-1 §9.6.6: polja /Differences preglasijo osnovno kodiranje, ki preglasi lasten zemljevid programa pisave — pot, od katere so odvisne orodne verige, izpeljane iz TeX-a in PostScript-a, pri čelem se imena glifov razrešujejo prek Adobe Glyph List, nabora znakov CFF ali TrueType cmap. Drugič, pisave Type3, katerih glifi so sami po sebi majhni tokovi vsebine, se predvajajo prek upodabljalnika s sestavljeno matriko pisave, velikostjo pisave in matriko besedila; širine v prostoru glifov se interpretirajo prek /FontMatrix, kot zahteva ISO 32000-1 §9.6.5, postopki glifov, ki deklarirajo omejitveni okvir d1, pa so obrezani nanj, tako da napačno oblikovan glif črtne kode ne more slikati izven svoje celice. Ko kode ni mogoče preslikati — poškodovan program, nepreslikan znak —, se upodabljalnik za ta glif preusmeri na risanje s sistemsko pisavo, namesto da bi izpustil celoten tek besedila

Kako doseči hitro večkratno upodabljanje?

Odgovor, ki ga ponuja HotPDF, je predpomnilnik nazadnje uporabljenih strani: RenderLoadedPageToBitmapCached hrani do RenderCacheCapacity upodobljenih strani (privzeto 8), ključanih po indeksu strani in DPI, zadetek v predpomnilniku pa vrne svežo kopijo v lasti klicatelja brez dotikanja toka vsebine — običajno tisočkrat hitreje kot ponovna interpretacija strani. Ta vzorec natančno ustreza bralnikom: uporabnik, ki preklaplja med dvema stranema, ali dogodek spremembe velikosti, ki znova zahteva isto stran pri istem DPI, vsakič zadene predpomnilnik

// Thumbnail strip: first pass renders, scrolling back hits the cache
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;

// After editing a loaded page in place:
Pdf.InvalidateRenderedPageCache;  // next render reflects the change

Bodite pošteni glede porabe pomnilnika, preden povečate kapaciteto. Stran US Letter pri 300 DPI obsega 2550×3300 slikovnih pik, kar je približno 25 MB kot 24-bitna bitna slika, tako da osem predpomnjenih strani pri izvozni ločljivosti zadrži približno 200 MB pomnilnika. Pri ločljivosti sličic teh istih osem vnosov stane precej manj kot megabajt. Določite RenderCacheCapacity for ločljivost DPI, pri kateri dejansko predpomnite, in pokličite InvalidateRenderedPageCache po vsakem urejanju na mestu — predpomnilnik je ključan le po strani in DPI in ne more videti, da se je vsebina pod njim spremenila. Nalaganje novega dokumenta ga samodejno počisti

Pod predpomnilnikom strani deluje drugi predpomnilnik: dekodirani slikovni XObjecti se hranijo v pomnilniku, omejenem z ImageCacheMaxBytes (privzeto 32 MB), z izločanjem najmanj v zadnjem času uporabljenih (LRU). Logotip ali slika glave pisma, ki se ponovi na vsaki strani, se dekodira enkrat na nalaganje dokumenta namesto enkrat na operater Do, kar približno prepolovi čas upodabljanja za strani s skupnimi slikami in pospeši izvoz večstranskih TIFF-ov za enako mero. Klic InvalidateRenderedPageCache počisti tudi ta predpomnilnik

Kaj se še vedno upodablja približno

Upodabljalnik cilja na običajen podnabor dokumentov PDF in vredno je vedeti, kje so meje. Barvni prostori CalRGB, Lab in tisti na osnovi ICC so raje približani kot upravljani z barvami — barvni prostori naprav, indeksirane palete in vzorčena iskanja barv s funkcijami tipa 0 se upravljajo, vendar produkcijska datoteka za tisk, ki se zanaša na namene upodabljanja ICC, ne bo barvno natančna. Senčni vzorci (shading patterns, sh) in načini mešanja (blend modes) poleg preproste alfe so prav tako izven obsega, rekurzija Form XObject pa je globinsko omejena kot zaščita pred zankami. Za račune, poročila, pogodbe in obrazce — strani, sestavljene iz besedila, poti in slik — je izhod zvest; za oblikovalske osnutke, polne gradientov in skupin prosojnosti, pa obravnavajte bitno sliko kot predogled, ne pa kot končni dokaz

Praktično branje: če vaš cevovod ustvarja dokumente s HotPDF ali porablja običajne poslovne PDF-je, jih RenderLoadedPageToBitmap poustvari z natančnimi orisi vgrajenih glifov, pravilnimi napredovanji CID in pravilno geometrijo strani. Približki živijo v kotih grafičnega modela, ki jih poslovni dokumenti redko obiščejo

Klic RenderLoadedPageToBitmap, njegova predpomnjena različica in cevovod za upodabljanje vgrajenih glifov, opisan tukaj, so na voljo kot del standardne komponente HotPDF Component za Delphi in C++Builder — izvorne knjižnice VCL brez odvisnosti od zunanjih knjižnic DLL, ki pokriva ustvarjanje, urejanje, ekstrakcijo besedila in upodabljanje strani PDF v enem paketu