Technical Article

Linearizácia PDF a Fast Web View: Ako to funguje

Dajte 80 MB naskenovaný report za odkaz, otvorte ho v prehliadači a sledujte, čo sa stane: prehliadač zobrazuje prázdne okno, kým nedorazí veľká časť týchto bajtov, a potom naraz vykreslí prvú stranu. Skočte na stranu 40 a pri nesprávne vytvorenom súbore sa môže celé sťahovanie spustiť odznova. Frustrujúce na tom je, že čitateľ chcel iba prvú stranu. Linearizácia je štrukturálnou odpoveďou na tento problém. Usporiadava PDF tak, aby prehliadač mohol vykresliť úvodnú stránku z malej počiatočnej časti súboru a zvyšok sťahovať na požiadanie. Preto Adobe túto funkciu označuje ako „Fast Web View“ (rýchle zobrazenie na webe).

Nič z toho neznamená iný formát súboru. Linearizované PDF je obyčajné PDF, ktoré kompatibilná čítačka otvorí bez akéhokoľvek špeciálneho zaobchádzania. Trik spočíva výhradne v spôsobe usporiadania bajtov a v dvoch dodatočných štruktúrach, ktoré súbor obsahuje. Norma ISO 32000-1 špecifikuje celú túto schému v prílohe F. Akonáhle toto rozloženie uvidíte, správanie súboru vám prestane pripadať ako mágia a začne sa javiť ako premyslená výmena poradia súborov za zníženie latencie prvého vykreslenia.

Čo linearizácia v skutočnosti usporadúva

Bežné PDF môže ojedinele mať svoje objekty roztrúsené v takmer ľubovoľnom poradí. Tabuľka krížových odkazov na konci súboru je to, čo to umožňuje: čítačka prejde na koniec, prečíta ukazovateľ startxref, načíta tabuľku xref a odtiaľ vie nájsť každý objekt podľa jeho posunu (offsetu). Tento návrh je vynikajúci pre lokálne súbory, kde prechod na koniec nič nestojí. Je však nevhodný pre súbory prenášané cez sieť, kde je koniec práve tou časťou, ktorá dorazí ako posledná. Na vykreslenie prvej stránky potrebuje bežná čítačka objekt stránky, jeho obsahový prúd, písma, na ktoré odkazuje, a obrázky, ktoré kreslí. V neusporiadanom súbore sa tieto prvky môžu nachádzať kdekoľvek, vrátane posledného megabajtu.

Linearizácia toto poradie napravuje. Objekty potrebné na zobrazenie prvej stránky sú zhromaždené do súvislého bloku blízko začiatku, hneď za malou hlavičkou, so v bajtovom prúde dorazia ako prvé. Všetko ostatné (zostávajúce stránky a zdroje, ktoré zdieľajú) nasleduje v predvídateľnom poradí. Druhá, kompletná tabuľka krížových odkazov sa stále nachádza na konci pre čítačky, ktoré túto optimalizáciu ignorujú. Linearizovaný súbor však obsahuje aj tabuľku krížových odkazov pre prvú stránku a parametre, ktoré streamujúca čítačka potrebuje, hneď na začiatku. Čítačka už nemusí čakať na stiahnutie konca súboru, aby mohla niečo vykresliť.

Sada objektov prvej stránky a slovník parametrov linearizácie

Úplne prvým objektom v linearizovanom súbore, hneď za hlavičkou %PDF, je slovník parametrov linearizácie (linearization parameter dictionary). Práve ten streamujúca čítačka hľadá, aby zistila, či je optimalizácia prítomná a ako ju použiť. Slovník zaznamenáva dĺžku celého súboru, bajtový posun začiatku hlavnej časti krížových odkazov, číslo objektu prvej stránky a umiestnenie a dĺžku hint streamu (pomocného prúdu), ktorý nasleduje. Vďaka týmto číslam čítačka už z prvých kilobajtov vie, koľko dát musí stiahnuť na zobrazenie prvej strany a kde hľadať index, ktorý jej umožní skočiť inam.

Príloha F striktne definuje, čo v tomto kontexte znamená „prvá stránka“. Sekcia prvej stránky musí obsahovať samotný objekt stránky, jeho obsahové prúdy a zdroje, na ktoré tieto prúdy odkazujú, aby bola stránka po stiahnutí tejto počiatočnej časti samostatne vykresliteľná. So zdieľanými zdrojmi (písmo použité na každej strane, logo opakujúce sa v hlavičke) sa zaobchádza osobitne: objavujú sa dostatočne skoro na to, aby poslúžili prvej strane, no sú označené ako zdieľané, takže ich čítačka pri neskoršom vykresľovaní strany 30 nemusí sťahovať znova. Rozlišovanie medzi súkromnými objektmi stránky a zdieľanými objektmi je časťou, ktorú väčšina amatérskych „optimalizátorov“ robí chybne, čo vedie k tomu, že sa súbor síce tvári ako linearizovaný, no prehliadač pri ňom aj tak mrzne.

Hint streamy: index, vďaka ktorému sú skoky na stránky nenáročné

Rýchle zobrazenie prvej strany je iba polovicou úspechu. Druhou polovicou je možnosť skočiť na ľubovoľnú stránku bez nutnosti sťahovať všetko medzi tým. A to je presne to, čo poskytujú pomocné prúdy (hint streams). Linearizovaný súbor obsahuje tabuľku hintov posunu stránok (page offset hint table) a tabuľku hintov zdieľaných objektov (shared object hint table) uloženú ako prúd, na ktorý odkazuje slovník parametrov. Tabuľka posunu stránok zaznamenáva pre každú stranu, kde v súbore začínajú jej objekty a ako ďaleko siahajú. Tabuľka zdieľaných objektov robí to isté pre zdroje používané na viacerých stránkach.

Na základe týchto tabuliek čítačka, ktorá vyžaduje stranu 40, neanalyzuje súbor sekvenčne. Pozrie sa do tabuľky hintov, aby zistila, aký bajtový rozsah zaberá strana 40, požiada server presne o tento rozsah a po doručení týchto bajtov stranu vykreslí, pričom rovnakým mechanizmom stiahne všetky zdieľané zdroje, ktoré ešte nemá k dispozícii. Pomocný prúd (hint stream) je v podstate mapa náhodného prístupu položená nad dokumentom a je dôvodom, prečo dobre linearizovaný 500-stranový súbor reaguje na pomalom pripojení rýchlo, zatiaľ čo neoptimalizovaný súbor rovnakej veľkosti nie.

Prečo musí server spolupracovať

Linearizácia predpokladá, že prenosová cesta dokáže doručovať ľubovoľné časti súboru. Tento predpoklad sa oplatí overiť skôr, ako začnete zlé výsledky pripisovať samotnému formátu. Mechanizmom je HTTP byte-serving: čítačka posiela žiadosti o rozsahy (range requests) a server na ne odpovedá správami 206 Partial Content. Ak server neponúka hlavičku Accept-Ranges: bytes, alebo ak proxy či sieť CDN pred ním spájajú žiadosti o rozsahy do plných prenosov, čítačka nemá možnosť získať stranu 40 izoluovane a prejde k sťahovaniu celého súboru. Štruktúra vo vnútri PDF je potom síce úplne správna, no úplne zbytočná.

Toto je zlyhanie, ktoré sa najčastejšie nesprávne diagnostikuje ako „linearizácia nefunguje“. Súbor je v poriadku, doručovacia cesta nie. Pred prebudovaním dokumentu si pomocou podmienečnej žiadosti overte, či hostiteľ pre danú URL adresu skutočne vracia čiastočný obsah. Mnohé statické servery to robia predvolene, no mnohé nesprávne nakonfigurované aplikačné servery a vyrovnávacie pamäte nie.

Prírastkové aktualizácie ticho narúšajú linearizáciu

Tu narážame na obmedzenie, ktoré často prekvapí ľudí, ktorí správne generujú linearizované súbory a potom sa divia, prečo optimalizácia mizne. Linearizácia závisí od jediného, presne usporiadaného rozloženia s indexom na začiatku. Prírastková aktualizácia (incremental update) to z princípu narúša. Keď nástroj pridá podpis, vyplní pole formulára alebo pripojí anotáciu cez prírastkové ukladanie, neprepíše celý súbor. Upravené objekty, novú časť krížových odkazov a nový trailer iba pripojí na koniec súboru, pričom pôvodné bajty nechá nedotknuté. Toto pripojenie je zmyslom prírastkových aktualizácií: je rýchle a zachováva predchádzajúcu revíziu na účely auditu alebo overenia podpisu.

Vedľajším účinkom je, že súbor má teraz svoje najnovšie údaje o krížových odkazoch na konci (až za starostlivo umiestneným blokom prvej stránky) a slovník parametrov linearizácie na začiatku popisuje rozloženie, ktoré už neodpovedá súboru. Kompatibilná čítačka tento nesúlad deteguje a zaobchádza s dokumentom ako s bežným, nelinearizovaným PDF. Funkcia Fast Web View je preč, aj keď pôvodná linearizovaná štruktúra sa stále nachádza v prvej polovici súboru. Ak pripojíte niekoľko aktualizácií, každá z nich navrství ďalšiu revíziu na koniec a rozdiel medzi neaktuálnym indexom na začiatku a skutočným stavom sa zväčší.

Pracovný postup pri úpravách a zachovaní Fast Web View

Ak váš pracovný postup vyžaduje úpravy aj funkciu Fast Web View, pravidlo vyplýva priamo zo štruktúry: kým je dokument v procese úprav, upravujte ho prírastkovo a nakoniec ho jednorazovo preusporiadajte (re-linearize). Úplný prepis je to, čo obnoví správne rozloženie. V terminológii HotPDF to znamená, že prebiehajúce úpravy prechádzajú cez BeginIncrementalUpdate a SaveIncrementalUpdate, ktoré pripájajú zmeny, zatiaľ čo dokončovací krok načíta celý dokument a nanovo ho serializuje pomocou LoadFromFile a následne SaveLoadedDocument. Tým sa zahodia nahromadené staré revízie a vytvorí sa jedno čisté rozloženie. Rovnaký mechanizmus sa prejavuje pri prúdoch objektov (object streams): povolenie vlastností UseObjectStreams spolu s UseXRefStream skomprimuje krížové odkazy a tesne zabalí objekty. To si vyžaduje full rewrite namiesto delta ukladania.

// In-flight edits: append a delta, keep prior revisions intact.
// This leaves the file NOT linearized.
Pdf.BeginIncrementalUpdate('report.pdf');
Pdf.AddPage;
Pdf.CurrentPage.TextOut(72, 760, 0, 'Addendum');
Pdf.SaveIncrementalUpdate('report.pdf');

// Finishing step: full re-serialization produces one clean layout,
// dropping the stacked revisions. Re-run your linearizer on the output.
Pdf.LoadFromFile('report.pdf');
Pdf.SaveLoadedDocument('report-final.pdf');

Knižnica HotPDF neponúka volanie na linearizáciu na jeden klik. Praktickým postupom je preto vytvoriť čistý, plne prepísaný súbor a spustiť nad ním špecializovaný optimalizátor. Nástroje príkazového riadka to vyriešia priamo. Nástroj qpdf prepíše súbor do linearizovanej podoby pomocou jediného príznaku:

qpdf --linearize report-final.pdf report-web.pdf

Ako zistiť, či je súbor linearizovaný

Neverte názvu súboru ani nástroju, ktorý tvrdí, že ho vytvoril. Overte samotné bajty. Najpriamejšou kontrolou je začiatok súboru: otvorte ho a hľadajte slovník parametrov linearizácie ako prvý objekt za hlavičkou, ktorý obsahuje kľúč /Linearized. Pre používateľov je skratkou dialógové okno Vlastnosti dokumentu v programe Acrobat, ktoré hlási „Fast Web View: Áno“ iba vtedy, ak je táto štruktúra v súbore skutočne prítomná a aktuálna.

Pre skriptované kontroly vie nástroj qpdf overiť prítomnosť aj integritu štruktúry. To je dôležité, pretože súbor môže obsahovať slovník linearizácie, ktorý už nezodpovedá jeho rozloženiu (čo je presne stav, ktorý zanecháva prírastková aktualizácia):

# Reports "File is linearized" and validates hint tables against the layout
qpdf --check report-web.pdf

# Dumps the linearization parameters and hint data in detail
qpdf --show-linearization report-web.pdf

Krok overenia (validation) je tým, čo skutočne rozhoduje. Kontrola, ktorá iba potvrdí existenciu slovníka, pokojne schváli súbor, ktorého index ukazuje na nesprávne posuny. Až kontrola porovnávajúca tabuľky hintov so skutočnými pozíciami objektov vám potvrdí, že optimalizácia prežije reálne range requesty čítačky.

Linearizáciu sa stále oplatí aplikovať na akýkoľvek veľký dokument prenášaný cez web, najmä kvôli mobilným čítačkám na nestabilnom pripojení. Jej cenou je len niekoľko percent veľkosti súboru na index umiestnený na začiatku. Dve veci, ktoré treba mať na pamäti, sú: správna musí byť štruktúra vo vnútri PDF aj byte-serving na strane servera. A akákoľvek dodatočná úprava optimalizáciu zruší, kým súbor znova neprepíšete. Považujte opätovnú linearizáciu za posledný krok v reťazci spracovania po tom, čo sú všetky ostatné zmeny hotové. Správanie krížových odkazov, prúdov objektov a prírastkových aktualizácií, ktoré tu popisujeme, je súčasťou štrukturálneho modelu, ktorý implementuje komponent HotPDF pre Delphi a C++Builder. Širší prehľad o rozložení súborov nájdete v článku o štruktúre súborov PDF a prácu s prírastkovými aktualizáciami a veľkými súbormi v kóde nájdete v článku o spracovaní veľkých PDF v Delphi.