HotPDF renderira 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 pozivatelja pri razlučivosti koju odaberete, što je točno ono što cjevovodi za traku sličica (thumbnail strip), pregled ispisa ili izvoz PDF-a u sliku trebaju. Ovaj članak prolazi kroz API, a zatim kroz dio koji razlikuje upotrebljiv render od igračke: crtanje teksta iz samih ugrađenih programa fontova, a ne iz sličnih sustavnih 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 definiranom 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 transformacijsku matricu, stog grafičkih stanja za q/Q, stazu izrezivanja (clipping path), prostore boja za ispunu i potez — i rasterizirati rezultat. Zato je "samo prikaži stranicu 3 kao sliku" interpretator toka sadržaja, a ne pretvorba formata datoteke
Zašto je renderiranje PDF stranice teže od crtanja slike?
HotPDF-ov render, uveden u verziji v2.253.0, izgrađen je kao ove odvojenih jedinica koje zrcale taj model: jezgra afine matrice za algebru transformacije PDF-a [a b c d e f], stog grafičkih stanja, razrješivač prostora boja (DeviceRGB, DeviceGray, DeviceCMYK, Indexed), graditelj staza koji povezuje PDF operatore staza s GDI-jem, sloj metrike fontova koji čita nizove /Widths za točne pomake i interpretator koji šalje operatore i pokreće ostalih pet. Slikovni XObjecti prolaze kroz isti stog za dekodiranje koji knjižnica koristi za izdvajanje, pa se svaki filtar slika koji HotPDF može dekodirati za izdvajanje — uključujući JPEG 2000 slike komprimirane s JPXDecode — također pojavljuje u renderiranom izlazu
Renderiranje učitane stranice u TBitmap
RenderLoadedPageToBitmap uzima nulti indeks stranice i vrijednost DPI, pri čemu 72 DPI mapira jednu PDF jedinicu korisničkog prostora u jedan piksel. Vraća nil u slučaju neuspjeha (indeks izvan raspona, nedostajući resursi) radije nego da podiže iznimku, pa preglednik može preskočiti lošu stranicu i nastaviti dalje. Pozivatelj 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 scenarij. Traka sličica renderira se na 36 ili 48 DPI i dobiva male, brze bitmape; pregled na zaslonu na 96 ili 144 DPI odgovara tipičnoj gustoći zaslona; put izvoza na 300 DPI proizvodi slike visoke kvalitete za ispis. Rotacija stranice iz unosa /Rotate i okretanje ishodišta /MediaBox (PDF stavlja ishodište dolje-lijevo, GDI gore-lijevo) rješavaju se unutar matrice stranica-uređaj, pa se US Letter stranica na 72 DPI vraća točno kao 612×792 piksela ispravno okrenuta
Zašto renderirane PDF sličice prikazuju pogrešne glifove?
Pogrešni ili približni glifovi u renderiranom PDF izlazu gotovo uvijek znače da render zamjenjuje sustavni font umjesto 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 sustavni font s tim nazivom i nacrtao tekst s njim. Za dokument koji koristi Arial ili Times New Roman sa standardnim kodiranjem, rezultat izgleda slično. Ali to je aproksimacija i ne uspijeva na jasno definiranim mjestima
Ugrađeni podskupovi fontova su najgori slučaj. Podskup fonta može nositi samo četrdeset glifova koje dokument stvarno koristi, s kodovima znakova dodijeljenim redoslijedom koji je privatan za tu datoteku — kod 1 može biti "T", kod 2 "h" i tako dalje. Sustavni font ne zna ništa o tom privatnom dodjeljivanju, pa tekst ili nestaje ili ispada kao potpuno pogrešan znak. Korisnička kodiranja, simbolički fontovi, fontovi s bar kodom i bilo koje pismo koje nije instalirano na stroju za renderiranje ne uspijevaju na isti način. Render koji se zaustavlja na zamjeni sustavnog fonta proizvodi sličice koje su prepoznatljive kao stranica — sve dok stranica ne koristi fontove zbog kojih je ugradnja uopće bila nužna
Renderiranje 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 renderiranoj stranici sada dolazi iz istih podataka o obrisima koje koristi sukladan preglednik, što znači da se podskupovi fontova, korisnička kodiranja i neinstalirana pisma renderiraju u svojim točnim oblicima. Pokrivenost je izgrađena prema vrstama fontova:
Za Type0/CIDFontType2 fontove s ugrađenim TrueType programom (FontFile2), render izravno analizira tablice glyf i loca: kvadratne konture pretvaraju se u kubične Bézierove krivulje koje GDI razumije, implicirane točke na krivulji (on-curve) između uzastopnih točaka izvan krivulje (off-curve) se rekonstruiraju, a kompozitni glifovi se rekurzivno iscrtavaju. Podržani su i Identity i eksplicitni tokovi izgleda CIDToGIDMap, a CID pomaci poštuju unose širine /W i /DW unose širine, pa se dvobajti Identity-H tekst ispravno pomiče
CFF programi (FontFile3, bilo da se radi o CIDFontType0C, Type1C ili OpenType omotu) dobivaju potpuni interpreter Type 2 charstringa: linije, krivulje, obitelj flex, maske savjeta (hints) i lokalne/globalne pozive podprograma s ispravnim odstupanjem podprograma. CID-kodirani CFF programi mapiraju kodove znakova kroz skup znakova fonta (charset), što je važno za podskupove fontova čiji se redoslijed glifova razlikuje od redoslijeda CID-a, a poštuje se i odabir font-DICT-a po glifu kroz FDArray/FDSelect. Jednostavni (non-CID) TrueType fontovi razrješavaju jednobajtne kodove kroz vlastitu tablicu cmap ugrađenog fonta s robusnim lancem podtablica — najprije Unicode formati 4 i 12, zatim simboličke podtablice s zrcalom privatne uporabe F000, potom naslijeđeni Macintosh formati — dok se jednostavni Type1 fontovi razrješavaju kroz ugrađeno kodiranje CFF programa
Dvije pojedinosti upotpunjuju sliku. Prvo, rječnici /Encoding jednostavnih fontova razrješavaju se prema prioritetu koji propisuje ISO 32000-1 §9.6.6: nizovi /Differences nadjačavaju osnovno kodiranje, koje nadjačava vlastitu kartu programa fonta — staza o kojoj ovise TeX i PostScript izvedeni alati, s nazivima glifova koji se razrješ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 s komponiranom matricom fonta, veličinom fonta i tekstualnom matricom; /Widths prostora glifa interpretiraju se kroz /FontMatrix kako zahtijeva ISO 32000-1 §9.6.5, a procedure glifova koje deklariraju okvir ograničenja d1 izrezuju se na njega, tako da loše oblikovani glif bar koda ne može crtati izvan svoje ćelije. Kada se kod ne može mapirati — oštećen program, nemapirani znak — render se vraća na crtanje sustavnim fontom za taj glif, umjesto da ispusti cijeli niz teksta
Kako ponovljena renderiranja učiniti brzim?
Odgovor koji isporučuje HotPDF je najnovije korištena predmemorija stranica (MRU cache): RenderLoadedPageToBitmapCached čuva do RenderCacheCapacity renderiranih stranica (zadano 8) ključanih prema indeksu stranice i DPI-ju, a pogodak u predmemoriju vraća novu kopiju u vlasništvu pozivatelja bez diranja toka sadržaja — što je obično tisućama puta brže od ponovnog interpretiranja stranice. Taj obrazac točno odgovara preglednicima: korisnik koji prelazi s jedne stranice na drugu ili događaj promjene veličine (resize) koji ponovno traži istu stranicu pri istom DPI-ju, svaki put pogađa predmemoriju
// 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 prije povećanja kapaciteta. Stranica US Letter na 300 DPI iznosi 2550×3300 piksela, oko 25 MB kao 24-bitna bitmapa, pa osam predmemoriranih stranica u razlučivosti 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 kojem stvarno predmemorirate i pozovite InvalidateRenderedPageCache nakon bilo kakvog uređivanja na licu mjesta — predmemorija je ključana samo prema stranici i DPI-ju te ne može vidjeti da se temeljni sadržaj promijenio. Učitavanje novog dokumenta automatski je čisti
Druga predmemorija radi ispod predmemorije stranica: dekodirani slikovni XObjecti čuvaju se u spremištu s ograničenom količinom bajtova omeđenom s ImageCacheMaxBytes (zadano 32 MB) s izbacivanjem najstarije korištenih. Logotip ili slika zaglavlja ponovljena na svakoj stranici dekodira se jednom po učitavanju dokumenta umjesto jednom po operatoru Do, što otprilike prepolovljuje vrijeme renderiranja za stranice sa zajedničkim slikama i ubrzava izvoz višestranog TIFF-a u istoj mjeri. InvalidateRenderedPageCache čisti i ovu predmemoriju
Što se i dalje renderira približno
Render cilja na uobičajeni podskup dokumenta PDF i važno je znati gdje 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 namjere renderiranja neće biti kolorimetrijski točna. Obrasci sjenčanja (sh) i načini miješanja (blend modes) izvan jednostavne alfe također su izvan opsega, a rekurzija Form XObjecta je dubinski ograničena kao zaštita od petlje. Za račune, izvješća, ugovore i obrasce — stranice sastavljene od teksta, staza i slika — izlaz je vjeran; za dizajn koji je pun gradijenata i grupa prozirnosti, tretirajte bitmapu kao pregled, a ne kao dokaz (proof)
Praktično objašnjenje: ako vaš cjevovod generira dokumente s HotPDF-om ili troši tipične poslovne PDF-ove, RenderLoadedPageToBitmap ih vraća u ciklus s točnim oblicima ugrađenih glifova, točnim CID pomacima i točnom geometrijom stranice. Aproksimacije žive u kutovima grafičkog modela koje poslovni dokumenti rijetko posjećuju
RenderLoadedPageToBitmap, njegova predmemorirana varijanta i cjevovod za renderiranje ugrađenih glifova koji je ovdje opisan dolaze kao dio komponente HotPDF Component za Delphi i C++Builder — izvorne VCL knjižnice bez vanjskih DLL ovisnosti, koja pokriva stvaranje PDF-a, uređivanje, izdvajanje teksta i renderiranje stranica u jednom paketu