HotPDF renderuje učitanu PDF stranicu u Delphi TBitmap putem jednog poziva: RenderLoadedPageToBitmap(PageIndex, DPI). Funkcija interpretira tok sadržaja stranice (content stream) i vraća 24-bitnu RGB bitmapu u vlasništvu pozivaoca pri rezoluciji koju odaberete, što je tačno ono što pipeline-ovi za traku sličica (thumbnail strip), pregled štampe ili izvoz PDF-a u sliku trebaju. Ovaj članak prolazi kroz API, a zatim kroz deo koji razlikuje upotrebljiv render od igračke: crtanje teksta iz samih ugrađenih programa fontova, a ne iz sličnih sistemskih fontova
PDF stranica nije slika. To je program: tok operatora koji grade staze, biraju fontove, postavljaju boje i postavljaju glifove, koji se izvodi prema grafičkom modelu definisanom u ISO 32000-1 §8. Ništa u datoteci ne govori kako izgleda bilo koji piksel. Za izradu bitmape morate pokrenuti taj program — održavati trenutnu transformacionu matricu, stek grafičkih stanja za q/Q, stazu isecanja (clipping path), prostore boja za ispunu i potez — i rasterizovati rezultat. Zato je "samo prikaži stranicu 3 kao sliku" interpretator toka sadržaja, a ne pretvaranje formata datoteke
Zašto je renderovanje PDF stranice teže od crtanja slike?
HotPDF-ov render, uveden u verziji v2.253.0, izgrađen je kao šest odvojenih jedinica koje zrcale taj model: jezgro afine matrice za algebru transformacije PDF-a [a b c d e f], stek grafičkih stanja, razrešivač prostora boja (DeviceRGB, DeviceGray, DeviceCMYK, Indexed), graditelj staza koji povezuje PDF operatore staza sa GDI-jem, sloj metrike fontova koji čita nizove /Widths za tačne pomake i interpretator koji šalje operatore i pokreće ostalih pet. Slikovni XObjecti prolaze kroz isti stek za dekodiranje koji biblioteka koristi za izdvajanje, pa se svaki filter slika koji HotPDF može dekodirati za izdvajanje — uključujući JPEG 2000 slike komprimovane sa JPXDecode — takođe pojavljuje u renderovanom izlazu
Renderovanje učitane stranice u TBitmap
RenderLoadedPageToBitmap uzima nulti indeks stranice i vrednost DPI, pri čemu 72 DPI mapira jednu PDF jedinicu korisničkog prostora u jedan piksel. Vraća nil u slučaju neuspeha (indeks van opsega, nedostajući resursi) radije nego da podiže izuzetak, pa pregledač može preskočiti lošu stranicu i nastaviti dalje. Pozivalac je vlasnik vraćene bitmape i mora je osloboditi
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 obavlja posao skaliranja za svaki uobičajeni scenario. Traka sličica renderuje se na 36 ili 48 DPI i dobija male, brze bitmape; pregled na ekranu na 96 ili 144 DPI odgovara tipičnoj gustini ekrana; put izvoza na 300 DPI proizvodi slike visokog kvaliteta za štampu. Rotacija stranice iz unosa /Rotate i okretanje porekla /MediaBox (PDF stavlja poreklo dole-levo, GDI gore-levo) rešavaju se unutar matrice stranica-uređaj, pa se US Letter stranica na 72 DPI vraća tačno kao 612×792 piksela ispravno okrenuta
Zašto renderovane PDF sličice prikazuju pogrešne glifove?
Pogrešni ili približni glifovi u renderovanom PDF izlazu gotovo uvek znače da render zamenjuje sistemski font umesto da koristi font ugrađen u datoteku. Prvi HotPDF render radio je upravo to: uklonio je prefiks podskupa iz /BaseFont (pretvarajući ABCDEF+Arial u Arial), zatražio od GDI-ja sistemski font sa tim nazivom i nacrtao tekst sa njim. Za dokument koji koristi Arial ili Times New Roman sa standardnim kodiranjem, rezultat izgleda slično. Ali to je aproksimacija i ne uspeva na jasno definisanim mestima
Ugrađeni podskupi fontova su najgori slučaj. Podskup fonta može nositi samo četrdeset glifova koje dokument stvarno koristi, sa kodovima znakova dodeljenim redosledom koji je privatan za tu datoteku — kod 1 može biti "T", kod 2 "h" i tako dalje. Sistemski font ne zna ništa o tom privatnom dodeljivanju, pa tekst ili nestaje ili ispada kao potpuno pogrešan znak. Korisnička kodiranja, simbolički fontovi, fontovi sa bar kodom i bilo koje pismo koje nije instalirano na mašini za renderovanje ne uspevaju na isti način. Render koji se zaustavlja na zameni sistemskog fonta proizvodi sličice koje su prepoznatljive kao stranica — sve dok stranica ne koristi fontove zbog kojih je ugradnja uopšte bila neophodna
Renderovanje ugrađenih glifova: crtanje iz samog programa fonta
HotPDF je zatvorio taj jaz kroz pet izdanja (od v2.268.0 do v2.272.0) analiziranjem ugrađenih programa fontova i ponovnim iscrtavanjem obrisa njihovih glifova kao ispunjenih GDI vektorskih staza. Tekst na renderovanoj stranici sada dolazi iz istih podataka o obrisima koje koristi usaglašen pregledač, što znači da se podskupi fontova, korisnička kodiranja i neinstalirana pisma renderuju u svojim tačnim oblicima. Pokrivenost je izgrađena prema vrstama fontova:
Za Type0/CIDFontType2 fontove sa ugrađenim TrueType programom (FontFile2), render direktno analizira tablice glyf i loca: kvadratne konture pretvaraju se u kubične Bézierove krive koje GDI razume, implicirane tačke na krivi (on-curve) između uzastopnih tačaka van krive (off-curve) se rekonstruišu, a kompozitni glifovi se rekurzivno iscrtavaju. Podržani su i Identity i eksplicitni tokovi izgleda CIDToGIDMap, a CID pomaci poštuju unuse širine /W i /DW unuse širine, pa se dvobajtni Identity-H tekst ispravno pomera
CFF programi (FontFile3, bilo da se radi o CIDFontType0C, Type1C ili OpenType omotu) dobijaju potpuni interpreter Type 2 charstringa: linije, krive, porodica flex, maske saveta (hints) i lokalne/globalne pozive podprograma sa ispravnim odstupanjem podprograma. CID-kodirani CFF programi mapiraju kodove znakova kroz skup znakova fonta (charset), što je važno za podskupove fontova čiji se redosled glifova razlikuje od redosleda CID-a, a poštuje se i odabir font-DICT-a po glifu kroz FDArray/FDSelect. Jednostavni (non-CID) TrueType fontovi razrešavaju jednobajtne kodove kroz sopstvenu tablicu cmap ugrađenog fonta sa robusnim lancem podtablica — najpre Unicode formati 4 i 12, zatim simboličke podtablice sa zrcalom privatne upotrebe F000, potom nasleđeni Macintosh formati — dok se jednostavni Type1 fontovi razrešavaju kroz ugrađeno kodiranje CFF programa
Dve pojedinosti upotpunjuju sliku. Prvo, rečnici /Encoding jednostavnih fontova razrešavaju se prema prioritetu koji propisuje ISO 32000-1 §9.6.6: nizovi /Differences nadjačavaju osnovno kodiranje, koje nadjačava sopstvenu kartu programa fonta — staza o kojoj zavise TeX i PostScript izvedeni alati, sa nazivima glifova koji se razrešavaju kroz Adobe Glyph List, CFF charset ili TrueType cmap. Drugo, Type3 fontovi, čiji su glifovi i sami mali tokovi sadržaja, iscrtavaju se kroz render sa komponovanom matricom fonta, veličinom fonta i tekstualnom matricom; /Widths prostora glifa interpretiraju se kroz /FontMatrix kako zahteva ISO 32000-1 §9.6.5, a procedure glifova koje deklarišu okvir ograničenja d1 isecaju se na njega, tako da loše oblikovani glif bar koda ne može crtati van svoje ćelije. Kada se kod ne može mapirati — oštećen program, nemapirani znak — render se vraća na crtanje sistemsnim fontom za taj glif, umesto da ispusti ceo niz teksta
Kako ponovljena renderovanja učiniti brzim?
Odgovor koji isporučuje HotPDF je najnovije korišćena predmemorija stranica (MRU cache): RenderLoadedPageToBitmapCached čuva do RenderCacheCapacity renderovanih stranica (zadano 8) ključanih prema indeksu stranice i DPI-ju, a pogodak u keš vraća novu kopiju u vlasništvu pozivaoca bez diranja toka sadržaja — što je obično hiljadama puta brže od ponovnog interpretiranja stranice. Taj obrazac tačno odgovara pregledačima: korisnik koji prelazi sa jedne stranice na drugu ili događaj promene veličine (resize) koji ponovo traži istu stranicu pri istom DPI-ju, svaki put pogađa keš
// 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
Budite iskreni prema potrošnji memorije pre povećanja kapaciteta. Stranica US Letter na 300 DPI iznosi 2550×3300 piksela, oko 25 MB kao 24-bitna bitmapa, pa osam keširanih stranica u rezoluciji izvoza zauzima otprilike 200 MB. Pri DPI-ju sličica istih osam unosa košta znatno manje od megabajta. Prilagodite veličinu RenderCacheCapacity za DPI na kom stvarno keširate i pozovite InvalidateRenderedPageCache nakon bilo kakvog uređivanja na licu mesta — keš je ključan samo prema stranici i DPI-ju te ne može da vidi da se temeljni sadržaj promenio. Učitavanje novog dokumenta automatski ga čisti
Druga keš memorija radi ispod keša stranica: dekodirani slikovni XObjecti čuvaju se u spremištu sa ograničenom količinom bajtova omeđenom sa ImageCacheMaxBytes (zadano 32 MB) sa izbacivanjem najstarije korišćenih. Logotip ili slika zaglavlja ponovljena na svakoj stranici dekodira se jednom po učitavanju dokumenta umesto jednom po operatoru Do, što otprilike prepolovljuje vreme renderovanja za stranice sa zajedničkim slikama i ubrzava izvoz višestranog TIFF-a u istoj meri. InvalidateRenderedPageCache čisti i ovaj keš
Što se i dalje renderuje približno
Render cilja na uobičajeni podskup dokumenta PDF i važno je znati gde su granice. CalRGB, Lab i prostori boja temeljeni na ICC-u se aproksimiraju, a ne upravljaju se bojom — podržani su prostori boja uređaja, indeksirane palete i uzorkovana pretraživanja boja funkcije tipa 0, ali datoteka za tiskarsku produkciju koja se oslanja na ICC namere renderovanja neće biti kolorimetrijski tačna. Obrasci senčenja (sh) i načini mešanja (blend modes) van jednostavne alfe takođe su van opsega, a rekurzija Form XObjecta je dubinski ograničena kao zaštita od petlje. Za račune, izveštaje, ugovore i obrasce — stranice sastavljene od teksta, staza i slika — izlaz je veran; za dizajn koji je pun gradijenata i grupa prozirnosti, tretirajte bitmapu kao pregled, a ne kao dokaz (proof)
Praktično objašnjenje: ako vaš pipeline generiše dokumente sa HotPDF-om ili troši tipične poslovne PDF-ove, RenderLoadedPageToBitmap ih vraća u ciklus sa tačnim oblicima ugrađenih glifova, tačnim CID pomacima i tačnom geometrijom stranice. Aproksimacije žive u uglovima grafičkog modela koje poslovni dokumenti retko posećuju
RenderLoadedPageToBitmap, njegova keširana varijanta i pipeline za renderovanje ugrađenih glifova koji je ovde opisan dolaze kao deo komponente HotPDF Component za Delphi i C++Builder — izvorne VCL biblioteke bez spoljnih DLL zavisnosti, koja pokriva stvaranje PDF-a, uređivanje, izdvajanje teksta i renderovanje stranica u jednom paketu