Dajte za odkaz 80 MB skenovanú správu, otvorte ju v prehliadači a sledujte, čo sa stane: zobrazovač sedí nad prázdnou plochou dovtedy, kým nedorazí veľká časť tých bajtov, a potom vykreslí prvú stranu naraz. Skočte na stranu 40 a pri zle postavenom súbore sa môže celé sťahovanie začať odznova. Frustrujúce na tom je, že čitateľ chcel po celý čas iba prvú stranu. Linearizácia je štrukturálnou odpoveďou na tento problém. Preusporiada PDF tak, aby zobrazovač dokázal vykresliť úvodnú stranu z malej predpony súboru a zvyšok si dotiahol na požiadanie, a práve preto Adobe túto funkciu predáva pod názvom „Fast Web View“
Nič z toho nie je iný formát súboru. Linearizované PDF je obyčajné PDF, ktoré vyhovujúca čítačka otvorí bez akéhokoľvek zvláštneho zaobchádzania. Celý trik spočíva výhradne v tom, ako sú bajty usporiadané, a v dvoch štruktúrach navyše, ktoré súbor nesie. ISO 32000-1 celé toto usporiadanie špecifikuje v prílohe F a keď raz to rozloženie uvidíte, správanie prestane vyzerať ako mágia a začne vyzerať ako zámerná výmena poradia v súbore za latenciu prvého vykreslenia
Čo linearizácia v skutočnosti preusporiada
Bežné PDF môže svoje objekty rozhádzať takmer v ľubovoľnom poradí. Funguje to vďaka tabuľke krížových odkazov na konci súboru: čítačka sa presunie na koniec, prečíta ukazovateľ startxref, načíta xref a odtiaľ vie nájsť každý objekt podľa jeho offsetu. Tento návrh je vynikajúci pre lokálne súbory, kde presun na koniec nič nestojí, a slabý pre súbor prúdiaci cez sieť, kde je koniec presne tou časťou, ktorá dorazí posledná. Na vykreslenie prvej strany potrebuje konvenčná čítačka objekt strany, jej prúd obsahu, písma, na ktoré sa odkazuje, a všetky obrázky, ktoré kreslí, a v neusporiadanom súbore môžu tieto veci ležať kdekoľvek, aj v poslednom megabajte
Linearizácia poradie napraví. Objekty potrebné na zobrazenie prvej strany sú zhromaždené do súvislého bloku blízko začiatku, hneď za malou hlavičkovou sekciou, takže v prúde bajtov dorazia skoro. Všetko ostatné, teda zvyšné strany a prostriedky, ktoré zdieľajú, nasleduje v predvídateľnom slede. Druhá, úplná tabuľka krížových odkazov naďalej žije na konci pre čítačky, ktoré optimalizáciu ignorujú, ale linearizovaný súbor navyše umiestňuje krížové odkazy prvej strany a parametre potrebné pre streamujúcu čítačku dopredu. Čítačka sa už nemusí dostať k chvostu súboru skôr, než dokáže čokoľvek nakresliť
Množina objektov prvej strany 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. Práve ten streamujúca čítačka hľadá, aby rozhodla, či je optimalizácia prítomná a ako ju použiť. Slovník zaznamenáva dĺžku celého súboru, bajtový offset, kde sa začína hlavná sekcia krížových odkazov, číslo objektu prvej strany a umiestnenie aj dĺžku hint streamu, ktorý nasleduje. S týmito číslami čítačka už z úvodných kilobajtov vie, koľko musí stiahnuť na zobrazenie prvej strany a kde hľadať index, ktorý jej umožní skočiť inam
Príloha F je prísna v tom, čo tu znamená „prvá strana“. Sekcia prvej strany musí obsahovať samotný objekt strany, jej prúdy obsahu a prostriedky, na ktoré sa tieto prúdy odkazujú, aby bola strana sebestačná, len čo sa táto predpona stiahne. Zdieľané prostriedky, teda písmo použité na každej strane alebo logo opakujúce sa v hlavičke, sa riešia zvlášť: objavia sa dosť skoro na to, aby poslúžili prvej strane, ale sú označené ako zdieľané, takže ich čítačka nesťahuje znovu, keď neskôr vykresľuje stranu 30. Práve toto rozlíšenie medzi objektmi súkromnými pre stranu a zdieľanými sa domácky vyrobeným „optimalizátorom“ pokazí najčastejšie a práve tá chyba vyprodukuje súbor, ktorý o sebe tvrdí, že je linearizovaný, a napriek tomu zamŕza
Hint streamy: index, vďaka ktorému sú skoky po stranách lacné
Rýchle zobrazenie prvej strany je len polovica hodnoty. Druhou polovicou je skok na ľubovoľnú stranu bez sťahovania všetkého, čo je medzi tým, a to je práve to, čo hint streamy poskytujú. Linearizovaný súbor nesie tabuľku offsetov strán a tabuľku zdieľaných objektov, uložené ako prúd, na ktorý sa odkazuje slovník parametrov. Tabuľka offsetov strán zaznamenáva pre každú stranu, kde sa jej objekty v súbore začínajú a ako ďaleko siahajú. Tabuľka zdieľaných objektov robí to isté pre prostriedky používané naprieč viacerými stranami
S týmito tabuľkami čítačka, ktorá chce stranu 40, súbor neanalyzuje sekvenčne. Nazrie do hint tabuľky, aby zistila, ktorý rozsah bajtov strana 40 zaberá, vypýta si od servera presne tento rozsah a stranu vykreslí, len čo tieto bajty dorazia, pričom si tým istým mechanizmom dotiahne zdieľané prostriedky, ktoré ešte nemá. Hint stream je v podstate mapou náhodného prístupu položenou cez dokument a je dôvodom, prečo dobre linearizovaný 500-stranový súbor pôsobí na pomalej linke svižne, kým neoptimalizovaný súbor rovnakej veľkosti nie
Prečo musí spolupracovať aj server
Linearizácia predpokladá, že prenos dokáže doručiť ľubovoľné výseky súboru, a tento predpoklad sa oplatí overiť skôr, než za zlé výsledky obviníte formát. Mechanizmom je bajtové obsluhovanie cez HTTP: čítačka vydá rozsahové požiadavky a server na ne odpovie odpoveďami 206 Partial Content. Ak server neinzeruje Accept-Ranges: bytes alebo ak proxy či CDN pred ním zlúči rozsahové požiadavky do plných prenosov, čítačka nemá ako stiahnuť stranu 40 samostatne a vráti sa k sťahovaniu celého súboru. Štruktúra vnútri PDF je potom úplne správna a úplne premárnená
Toto je zlyhanie, ktoré sa najčastejšie mylne diagnostikuje ako „linearizácia nefunguje“. Súbor je v poriadku; cesta doručenia nie. Skôr než dokument prestaviate, potvrďte si podmienenou požiadavkou, že hostiteľ pre URL, na ktorú čítačka mieri, skutočne vracia čiastočný obsah. Mnohé statické hostingy to robia predvolene a mnohé zle nakonfigurované aplikačné servery a cachovacie vrstvy nie
Prírastkové aktualizácie linearizáciu potichu rozbijú
Tu je obmedzenie, ktoré prekvapí ľudí, čo linearizované súbory generujú správne a potom sa čudujú, prečo sa optimalizácia vyparila. Linearizácia stojí na jedinom, starostlivo usporiadanom rozložení s indexom vpredu. Prírastková aktualizácia to zo svojej podstaty porušuje. Keď nástroj pridá podpis, vyplní pole formulára alebo pripojí anotáciu prírastkovým uložením, súbor neprepisuje. Na koniec pripojí zmenené objekty, novú sekciu krížových odkazov a nový trailer, pričom pôvodné bajty nechá nedotknuté. Práve toto pripojenie je celým zmyslom prírastkových aktualizácií: je rýchle a zachováva staršiu revíziu pre audit alebo overenie podpisu
Vedľajším efektom je, že súbor má teraz najnovšie dáta krížových odkazov na chvoste, za starostlivo umiestneným blokom prvej strany, a slovník parametrov linearizácie vpredu opisuje rozloženie, ktoré už súboru nezodpovedá. Vyhovujúca čítačka nesúlad odhalí a s dokumentom zaobchádza ako s bežným, nelinearizovaným PDF. Fast Web View je preč, hoci pôvodná linearizovaná štruktúra stále leží v prvej polovici súboru. Ak pripojíte niekoľko aktualizácií, každá z nich navrší na koniec ďalšiu revíziu a priepasť medzi zastaraným predným indexom a skutočným stavom sa rozšíri
Ak váš pracovný postup potrebuje aj úpravy, aj Fast Web View, pravidlo vyplýva priamo zo štruktúry: kým je dokument v pohybe, upravujte prírastkovo a na konci raz linearizujte znovu. Rozloženie obnoví práve úplný prepis. V pojmoch HotPDF to znamená, že rozpracovaná úprava ide cez BeginIncrementalUpdate a SaveIncrementalUpdate, ktoré pripoja deltu, kým záverečný krok načíta celý dokument a čerstvo ho serializuje cez LoadFromFile nasledované SaveLoadedDocument, čo zahodí nakopené staré revízie a vydá jedno čisté rozloženie. Ten istý kompromis sa objavuje pri prúdoch objektov: zapnutie UseObjectStreams spolu s UseXRefStream skomprimuje krížové odkazy a objekty zabalí natesno, čo pomáha veľkosti súboru, ale ako každá štrukturálna voľba sa musí uplatniť počas tohto záverečného prepisu, nie prišiť na pripojenú revíziu
// Úpravy počas práce: pripojí deltu, staršie revízie zostanú nedotknuté.
// Súbor tým NIE JE linearizovaný.
Pdf.BeginIncrementalUpdate('report.pdf');
Pdf.AddPage;
Pdf.CurrentPage.TextOut(72, 760, 0, 'Addendum');
Pdf.SaveIncrementalUpdate('report.pdf');
// Záverečný krok: úplná reserializácia vytvorí jedno čisté rozloženie
// a zahodí nakopené revízie. Na výstup znovu spustite linearizér.
Pdf.LoadFromFile('report.pdf');
Pdf.SaveLoadedDocument('report-final.pdf');
HotPDF nesprístupňuje rutinu „linearizuj“ na jedno volanie, takže praktickým vzorom je vyrobiť čistý, úplne prepísaný súbor a prehnať cezeň špecializovaný optimalizátor. Preusporiadanie zvládnu priamo nástroje z príkazového riadka. qpdf prepíše súbor do linearizovanej podoby jediným prepínačom:
qpdf --linearize report-final.pdf report-web.pdf
Ako zistiť, či je súbor linearizovaný
Nedôverujte názvu súboru ani nástroju, ktorý tvrdí, že ho vyrobil; overte 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, nesúci kľúč /Linearized. Skratkou na strane čítačky je dialóg Vlastnosti dokumentu v Acrobate, ktorý hlási „Fast Web View: Yes“ iba vtedy, keď je štruktúra naozaj prítomná a aktuálna
Pre skriptované kontroly hlási qpdf prítomnosť aj celistvosť štruktúry, na čom záleží, pretože súbor môže niesť slovník linearizácie, ktorý už jeho rozloženiu nezodpovedá, čo je presne stav, aký po sebe zanechá prírastková aktualizácia:
# Vypíše "File is linearized" a overí hint tabuľky oproti rozloženiu
qpdf --check report-web.pdf
# Podrobne vypíše parametre linearizácie a hint dáta
qpdf --show-linearization report-web.pdf
Krok overenia je ten, ktorý si svoje miesto zaslúži. Prechod, ktorý iba potvrdí, že slovník existuje, ochotne požehná súboru, ktorého index ukazuje na nesprávne offsety; až kontrola, ktorá hint tabuľky porovná so skutočnými pozíciami objektov, vám povie, či optimalizácia obstojí pri rozsahových požiadavkách skutočnej čítačky
Linearizáciu sa naďalej oplatí uplatniť na každý veľký dokument doručovaný cez web, obzvlášť mobilným čitateľom na nerovnomerných pripojeniach, a stojí niekoľko percent veľkosti súboru za dopredu vyložený index. Dve veci si treba udržať v hlave: správna musí byť aj štruktúra vnútri PDF, aj bajtové obsluhovanie mimo neho, a akákoľvek neskoršia úprava optimalizáciu zruší, kým súbor neprepíšete. Opätovnú linearizáciu berte ako posledný krok linky, až keď je každá iná zmena hotová. Správanie krížových odkazov, prúdov objektov a prírastkových aktualizácií opísané tu je súčasťou štrukturálneho modelu, ktorý implementuje HotPDF Delphi Component pre Delphi a C++Builder; širší kontext rozloženia súboru nájdete v článku ako je PDF štruktúrované a prírastkové aktualizácie aj prácu s veľkými súbormi v kóde rozoberá spracovanie veľkých PDF z Delphi