Tehnički članak

Stabla stranica u PDF-u: Zašto redoslijed stranica nije isto što i redoslijed objekata

Stranica 1 u PDF-u nije objekt 1. Ta je razlika najčešći izvor pogrešaka pri izdvajanju stranica, a rješenje je čitati specifikaciju umjesto sirovih bajtova datoteke

Razgranavanje je odluka o performansama

PDF datoteka zbirka je numeriranih objekata. Svaki ima broj objekta i broj generacije, zapisan kao N G obj, dok reference među objektima koriste oblik N G R. Trailer pokazuje na korijenski katalog, a njegov unos /Pages vodi do stabla stranica. Tablica unakrsnih referenci ili tok unakrsnih referenci u PDF-u 1.5 i novijem mapira brojeve objekata na pomake u datoteci. Ta mapa služi nasumičnom pristupu, a ne određivanju redoslijeda stranica

Stablo stranica može imati mnogo djece po čvoru ili samo nekoliko. Taj fan-out je odluka o performansama jer veći čvorovi smanjuju dubinu obilaska, ali povećavaju količinu podataka koju čitač mora obraditi odjednom. Inkrementalno ažurirana datoteka može dodati nove objekte na kraj s većim brojevima, dok njihov logički položaj i dalje određuje niz /Kids. Zato redoslijed brojeva objekata nije redoslijed stranica

Unutarnji čvorovi nose naslijeđene atribute

Korijenski katalog sadrži referencu /Pages na čvor tipa /Pages. Njegov niz /Kids navodi djecu redoslijedom čitanja, a svako dijete može biti list tipa /Page ili drugi međučvor /Pages. Prva stranica je prvi list do kojeg se dolazi obilaskom nizova /Kids dubinom, slijeva nadesno

Najčešće naslijeđene stavke su /MediaBox, /CropBox, /Resources i /Rotate. List koji izostavi /MediaBox nije neispravan; preuzima vrijednost od najbližeg pretka koji je definira. Ako je definira sam list, njegova vrijednost nadjačava roditeljsku samo za tu stranicu. Ispravan čitač prolazi lanac /Parent, prikuplja još neviđene atribute i zaustavlja se u korijenu

Unos /Count u međučvoru predmemorira ukupan broj podređenih listova, pa preglednik može preskočiti cijelo podstablo pri skoku na udaljenu stranicu. Defenzivni parser ipak provjerava /Count prema stvarnom broju listova jer ga stari uređivači nakon izmjena na mjestu nisu uvijek ponovno izračunali

Legalno, uobičajeno, povremeno skupo izravnavanje

Specifikacija ne ograničava stablo na jednu razinu. Velik dokument može grupirati stranice pod međučvorovima koji približno odgovaraju poglavljima, a algoritam obilaska ostaje isti: posjeti djecu redom, rekurzivno uđi u svaki čvor /Pages i prikupi listove /Page

5 0 obj   % document root
<< /Type /Pages /Count 6 /Kids [6 0 R  7 0 R] >>
endobj

6 0 obj   % report body: portrait A4, body font
<< /Type /Pages /Parent 5 0 R /Count 3
   /Kids [30 0 R  31 0 R  32 0 R]
   /MediaBox [0 0 595 842]
   /Resources << /Font << /F1 8 0 R >> >> >>
endobj

7 0 obj   % appendix: landscape A4, rotated, its own font
<< /Type /Pages /Parent 5 0 R /Count 3
   /Kids [40 0 R  41 0 R  42 0 R]
   /MediaBox [0 0 842 595] /Rotate 90
   /Resources << /Font << /F2 9 0 R >> >> >>
endobj

40 0 obj  % appendix page: inherits size, rotation, fonts
<< /Type /Page /Parent 7 0 R /Contents 43 0 R >>
endobj

Ovaj raspored pokazuje zašto su objektni brojevi loš izvor redoslijeda. Niz /Kids određuje da je objekt 20 prva logička stranica, objekt 1 druga, a objekt 4 treća, iako bi obilazak brojeva od 1 naviše proizveo 1, 4, 20. Rezultat bi imao stranice u pogrešnom redoslijedu iako se svaka pojedinačna stranica može normalno prikazati

% Original revision
12 0 obj
<< /Type /Pages /Count 9 /Kids [13 0 R  14 0 R  15 0 R] >>
endobj

14 0 obj
<< /Type /Pages /Parent 12 0 R /Count 3
   /Kids [50 0 R  51 0 R  52 0 R] >>
endobj

% Appended revision: one page inserted into the middle branch.
% Object 14 is superseded; object 12 is never rewritten
14 0 obj
<< /Type /Pages /Parent 12 0 R /Count 4
   /Kids [50 0 R  51 0 R  90 0 R  52 0 R] >>
endobj

Izravnavanje stabla može pojednostaviti čitanje, ali nije uvijek besplatno. Čvorovi s mnogo djece mogu smanjiti dubinu, dok očuvanje prirodnih grupa može pomoći alatima koji rade po poglavljima. Pravilo je zadržati strukturu koja odgovara dokumentu i potvrditi stvarni broj listova umjesto slijepog povjerenja u predmemorirane brojače

Kad je broj stranice pogrešan

Pogreške redoslijeda najčešće se pojavljuju u dva scenarija. Prvi je prilagođeni parser koji skenira objekte tipa /Page umjesto da prati stablo. On pronađe sve stranice, ali po broju objekta, a ne po redoslijedu čitanja. Ispravan postupak uvijek počinje trailerom, razrješava korijenski katalog, prati /Pages i obilazi nizove /Kids

Drugi je inkrementalno ažurirana datoteka. Urednik može zamijeniti stranicu 5 novim objektom 143, dok niz /Kids sada pokazuje na 143 na istom logičkom mjestu. Hodanje po brojevima objekata tada bi zamjensku stranicu stavilo na pogrešan položaj

Linearizirani PDF-ovi dodaju još jednu zamku: sadržaj prve stranice fizički je blizu početka radi brzog prikaza preko spore veze, ali stablo stranica i dalje određuje redoslijed, dok xref preslikava nove fizičke pomake. Parser koji se oslanja na položaj u datoteci umjesto na xref može pogrešno pročitati i prvu stranicu

HotPDF Component interno obrađuje obilazak stabla stranica, razrješavanje nasljeđivanja i spajanje xref podataka iz inkrementalnih ažuriranja. Kada radite s njegovim objektima stranica, redoslijed niza /Kids već je primijenjen, pa indeksi stranica označavaju logičke stranice, a ne brojeve objekata