Tehnički članak

Objašnjenje PDF metapodataka, obrisa i napomena

Uklonite opise stranica i ostaje vam tanki sloj strukture koji nitko ne ispisuje, ali o kojem ovisi svaki čitač, indeksator i sustav za arhiviranje. Objekt stranice ne zna ništa o poglavlju kojem pripada, autoru koji ga je napisao ili fusnoti koja povezuje drugdje. To znanje živi jednu razinu iznad, u tri strukture pridružene katalogu dokumenata: tokovima metapodataka (metadata streams), stablu obrisa (outline tree) i nizovima napomena po stranici (per-page annotation arrays). Oni dijele osobinu zbog koje u njima lako može doći do pogreške. Nijedna ne nosi vidljive oznake na stranici, pa se datoteka može savršeno iscrtati, a da joj još uvijek nedostaju oznake, da proturječi vlastitom polju za autora ili usmjerava vezu na objekt stranice koji više ne postoji

Ovo je sloj koji PDF biblioteka izlaže kao svojstva dokumenta, bookmark API-je i pozive veza (linkova) ili napomena (annotations), te sloj koji pretraživač čita kako bi odlučio o čemu se u vašem dokumentu radi. Objektni model ispod njega pokriven je u pregledu strukture PDF dokumenta. Ovdje je fokus isključivo na onome što visi s kataloga

Sve tri strukture pričvršćene su za katalog. Cijeli katalog koji ih povezuje izgleda ovako:

1 0 obj
<< /Type /Catalog
   /Pages 2 0 R
   /Outlines 3 0 R
   /Names << /EmbeddedFiles 4 0 R >>
   /Metadata 5 0 R
>>
endobj

Četiri unosa, četiri neovisna podsustava. /Pages je vidljivi dokument; /Outlines je stablo oznaka (bookmark tree); /Metadata usmjerava na XMP stream; /Names dostiže u dokumentu opći rječnik imena, koji između ostalog sadrži ugrađene privitke datoteka (embedded file attachments). Svaki je neobavezan, a čitač koji ne pronađe nijedan i dalje prikazuje stranice. Ta neobaveznost upravo je razlog zašto navigacijski sloj prvi trune (rot) kada datoteku uređuju alati koji razumiju samo stranice

Dvije pohrane metapodataka koje se ne slažu

PDF prenosi metapodatke dokumenta na dva mjesta istovremeno, a nevolja počinje kada kažu različite stvari. Izvorni mehanizam je rječnik informacija o dokumentu (document information dictionary), na koji se referencira s /Info u traileru: ravni skup parova ključ-vrijednost za /Title, /Author, /Subject, /Keywords, /Creator, /Producer, i dva datuma. Jednostavno je i svaki ga preglednik čita. PDF 2.0 odbacuje većinu u korist drugog mehanizma, XMP toka (stream) metapodataka

XMP je samodostatan XML dokument, napisan u RDF-u, pohranjen kao stream do kojeg katalog dopire putem /Metadata i označen s /Type /Metadata /Subtype /XML. Za razliku od Info rječnika zakopanog unutar PDF objektne strukture, XMP paket je dizajniran da ga sami ekstrahiraju i raščlane alati koji ne znaju ništa o PDF-u. Ovdje je reprezentativan paket:

5 0 obj
<< /Type /Metadata /Subtype /XML /Length 1235 >>
stream
<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
<x:xmpmeta xmlns:x="adobe:ns:meta/">
  <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
    <rdf:Description rdf:about=""
        xmlns:dc="http://purl.org/dc/elements/1.1/"
        xmlns:xmp="http://ns.adobe.com/xap/1.0/"
        xmlns:pdf="http://ns.adobe.com/pdf/1.3/">
      <dc:title><rdf:Alt><rdf:li xml:lang="x-default">Quarterly Report</rdf:li></rdf:Alt></dc:title>
      <dc:creator><rdf:Seq><rdf:li>A. Author</rdf:li></rdf:Seq></dc:creator>
      <xmp:CreateDate>2026-06-16T10:46:27+08:00</xmp:CreateDate>
      <xmp:CreatorTool>Reporting Service 4.2</xmp:CreatorTool>
      <pdf:Producer>losLab PDF Library</pdf:Producer>
    </rdf:Description>
  </rdf:RDF>
</x:xmpmeta>
<?xpacket end="w"?>
endstream
endobj

Tri detalja u tom bloku odlučuju hoće li metapodaci preživjeti kontakt sa stvarnim alatima. xpacket instrukcije za obradu nisu ukras: one uokviruju paket tako da ga ekstraktor može pronaći unutar većeg toka (stream) bajtova, a pisac koji izostavi završni <?xpacket end="w"?> proizvodi datoteku koja se otvara u redu, ali sapliće stroge validatore. Vrste podataka svojstava (property datatypes) su također važne. dc:title je jezična alternativa (language alternative) omotana u rdf:Alt, dok je dc:creator naređeni popis i prima rdf:Seq; emitiranje bilo kojeg od njih kao golog tekstualnog čvora (bare text node) je jedna od najčešćih grešaka u XMP-u, koju većina preglednika tolerira sve do onog koji to ne radi. Prefiksi prostora imena (namespace) su konvencionalni, ali URI-ji (URIs) s kojima se vežu su normativni: parser se usmjerava prema URI-ju, a ne prefiksu

Tvrdo pravilo s dvije pohrane je da se one moraju slagati. Ako /Info kaže da je autor jedna osoba, a dc:creator imenuje drugu, isporučili ste dokument koji odgovara na isto pitanje na dva načina, a koji će odgovor pobijediti ovisi o tome koje polje alat koji konzumira pročita. Knjižnica (library) obično piše oboje umjesto vas, ali onog trenutka kada ga uredite ručno, ili spojite datoteke iz različitih generatora, to se dvoje razilazi. Info rječnik tretirajte kao naslijeđenu (legacy) kompatibilnost, a XMP kao izvor istine, te ponovno generirajte oboje iz jednog skupa vrijednosti, a ne da ih nezavisno krpate. Za PDF/A ovo postaje uvjet sukladnosti (conformance requirement): ISO 19005 propisuje XMP i zabranjuje bilo koje svojstvo informacija koje je u suprotnosti s njezinim XMP pandanom (counterpart)

Stablo obrisa (outline tree) iza ploče oznaka (bookmark panel)

Ono što preglednik (viewer) prikazuje kao ploču oznaka (bookmarks panel) u datoteci je dvostruko povezano stablo rječnika koje se zove obris (outline) dokumenta. Katalog usmjerava na rječnik obrisa korijena (root outline dictionary) putem /Outlines; korijen pokazuje na svoju prvu i posljednju stavku najviše razine (top-level); a svaka stavka je povezana sa svojim susjedima i roditeljem (parent). Nigdje ne postoji niz (array) oznaka. Cijela je struktura rekonstruirana slijedeći reference, što je upravo razlog zašto jedna prekinuta veza (link) može učiniti da cijela grana nestane s panela bez ikakve pogreške

8 0 obj                                    % the outline root
<< /Type /Outlines /Count 4 /First 9 0 R /Last 9 0 R >>
endobj
9 0 obj                                    % top-level: a chapter
<< /Title (Chapter 1: Results)
   /Parent 8 0 R /Count 2
   /First 12 0 R /Last 15 0 R >>
endobj
12 0 obj                                   % first child
<< /Title (Introduction)
   /Parent 9 0 R /Next 15 0 R
   /Dest [3 0 R /XYZ 72 720 0] >>
endobj
15 0 obj                                   % second child, last sibling
<< /Title (Methodology)
   /Parent 9 0 R /Prev 12 0 R
   /Dest [3 0 R /Fit] >>
endobj

Pročitajte veze (links) i invarijante postaju očite. Svaka stavka pokazuje natrag na svoj /Parent (roditelja). Braća (Siblings) čine lanac kroz /Prev i /Next, prva stavka izostavlja /Prev, a posljednja /Next. Roditelj (parent) imenuje svoje prvo i posljednje dijete pomoću /First i /Last, a do djece između može se doći samo hodajući po bratskom lancu (sibling chain). Ako samo jedno bude pogrešno, kvar je nečujan: stari /Next odsijeca (truncates) poglavlje, roditelj čiji /Last ne završava lanac ostavlja stavke bez roditelja (orphaned), a preglednik (viewer) prikazuje sve što može dosegnuti

Polje /Count nosi djelić stanja koje iznenađuje ljude. U korijenu i na svakoj proširenoj (expanded) stavci ono drži broj trenutačno vidljivih potomaka (descendants); na srušenoj (collapsed) stavci to je negativan broj čija je veličina koliko potomaka bi se pojavilo na ekspanziji. Dakle, /Count nije fiksna strukturna činjenica o drvetu, to je spremljeno otvoreno ili zatvoreno stanje panela, a generator koji ga hardkodira (hard-codes) kao pozitivan ukupni zbroj ponovno otvara svaku granu za koju je autor namjeravao da ostane zatvorena

Svaka stavka zaslužuje svoje mjesto pokazujući negdje. /Title je ono što panel pokazuje; /Dest je mjesto na koje klik slijeće (lands). Odredište može biti unutar stavke (inline), kao gore, ili naziv (name) koji se rješava kroz rječnik naziva dokumenta (name dictionary), što je bolji izbor kada su brojne oznake i poveznice usmjerene na ista mjesta, jer na jednom mjestu popravljate premješteni cilj. Knjižnica općenito skriva ovo stablo iza ručke korijena obrisa (outline-root handle) i metoda koje dodaju dječje unose (child entries); u HotPDF-u dokument izlaže OutlineRoot tipa THPDFDocOutlineObject i povezuje linkove /Prev, /Next, /Parent i /Count umjesto vas dok dodajete stavke. Vrijedi iskoristiti tu prednost, jer ručno održavanje tih invarijanti kroz izmjene predstavlja mjesto na kojem dolazi do lomova u obrisima

Odredišta: gramatika onoga kamo klik ide

I oznake (bookmarks) i bilješke veza (link annotations) upućuju na odredišta (destinations), a odredište je više od broja stranice. To je niz koji imenuje objekt stranice i zatim, pomoću glagola u drugom utoru (slot), navodi kako bi ga preglednik trebao uokviriti. Najčešće korišten i najviše zlouporabljivan je /XYZ, u obliku [stranica /XYZ left top zoom]. Njegova su tri operanda neovisna i svaki može biti null što znači "ostavite ovo onako kako je to čitatelj imao." Tako da [stranica /XYZ null null null] skače na stranicu bez dodirivanja pozicije pomicanja (scroll position) ili zumiranja, što je obično ono što želite od poveznice "idi na stranicu". Brojevi su u zadanom korisničkom prostoru, mjerenom od donjeg lijevog kuta, a y se povećava prema gore, u istom koordinatnom sustavu koji koristi sadržaj stranice. Autori koji dolaze sa izgleda zaslona (screen layout) refleksno mjere od vrha i šalju čitatelja na krivi kraj stranice

Obitelj /Fit zamjenjuje precizno pozicioniranje (precise positioning) za otpornost (resilience). [stranica /Fit] skalira cijelu stranicu unutar prozora, [stranica /FitH top] uklapa u širinu stranice sa zadanim gornjim rubom (top edge), i [stranica /FitR l b r t] zumira pravokutnik kako bi ispunio pogled (view). S obzirom da one izračunavaju (compute) omjer iz geometrije stranice (page geometry) umjesto iz fiksnih koordinata, /Fit odredište i dalje ima smisla nakon promjene veličine stranice, dok /XYZ odredište s ugrađenim zumiranjem može ostaviti čitača da zuri (staring) u marginu. Za tablicu sa sadržajem, /FitH s najvišom koordinatom sekcije ostari bolje od /XYZ s pretpostavljenim (guessed) zumiranjem

Napomene: sve interaktivno što nije sadržaj stranice

Napomena (annotation) je objekt koji preklapa stranicu bez da bude dio njenog content streama. Linkovi, ljepljive bilješke (sticky notes), istaknuto (highlights), widgeti obrasca (form widgets), ikone datoteka privitka (file-attachment icons), pečati: sve su napomene, izlistane u /Annots nizu stranice na kojoj sjede. Uklanjanje napomene iz tog niza uklanja je sa stranice iako temeljni (underlying) sadržaj ostaje netaknut. To je cijela bit: napomene su sloj za uređivanje (editing layer), odvojen od oznaka preko kojih se nalaze

Svaka napomena (annotation) dijeli malu kralježnicu (spine). /Subtype imenuje vrstu, /Rect daje njezin granični okvir (bounding box) u koordinatama stranice, a /Contents sadrži tekst koji ujedno služi kao dostupan opis. Vrijedno je proučiti vezu (link) napomene, jer dolazi u dva oblika: golo odredište (bare destination) i akcija

12 0 obj                                    % link to a destination
<< /Type /Annot /Subtype /Link
   /Rect [100 200 300 250]
   /Border [0 0 0]
   /Dest [5 0 R /XYZ null null null] >>
endobj
13 0 obj                                    % link that runs an action
<< /Type /Annot /Subtype /Link
   /Rect [50 50 200 100]
   /Border [0 0 0]
   /A << /Type /Action /S /URI /URI (https://www.example.com) >> >>
endobj

/Rect je žarišna točka (hotspot); klik unutar njega šalje čitatelja do odredišta (destination), ponovno upotrebljavajući istu gramatiku koju koristi obris (outline). /Border [0 0 0] radi pravi posao, potiskujući (suppressing) ružni zadani pravokutnik (default rectangle) koji preglednici (viewers) crtaju oko veza (links). Drugi oblik mijenja goli /Dest za radnju /A, čiji podtip (subtype) /S odabire ponašanje: /GoTo unutar ove datoteke, /GoToR za drugu datoteku, /URI za web-adresu, /Launch za pokretanje vanjskog programa. Ovo posljednje zaslužuje sumnju. /Launch koje pokreće izvršnu (executable) datoteku je ponašanje koje od PDF-ova radi vektor zloćudnog softvera (malware vector), tako da to sukladni (conforming) preglednici (viewers) blokiraju ili glasno upozoravaju, pa za većinu čitatelja veza ne uspijeva (link fails). Posegnite za /URI i /GoTo i ostavite /Launch na miru

Bilješke o označavanju (markup annotations) kao što su isticanja i ljepljive bilješke (highlights and sticky notes) te napomene o obliku (shape annotations) kao što je /Square, dodaju novost: njihov izgled (on-screen look) na zaslonu nije naznačen njihovim tipom. Preglednik prikazuje (renders) vlastitu verziju osim ako ne prikvačite pojavljivanje sa stream-om pojavljivanja (appearance stream), unosom /AP, koji upućuje na XObject obrasca s operatorima crtanja (drawing operators). Preskočite ga i isto isticanje (highlight) može izgledati različito u dva čitača ili prije i poslije povratne petlje u editoru (editor round-trip). Za sve čiji je točan izgled dio dokumenta, navedite /AP. Prilozi datoteka (file attachments), usput, ponovno koriste isti mehanizam: ugrađeni tijek (embedded file stream) datoteka i rječnik sa specifikacijom (file specification dictionary) datoteka, koji se pojavljuju ili kao napomena /FileAttachment ili kroz stablo imena /EmbeddedFiles ispod kataloga /Names

Gdje se ovaj sloj lomi i kako ga uhvatiti

Neuspjeh (failure) koji se ponavlja kroz sve ovo je viseća referenca (dangling reference). Oznake (bookmarks) prestaju se pojavljivati kada u katalogu ne postoji stavka /Outlines ili se sestrinski (sibling) lanac prekine u sredini stabla; metapodaci se zanemaruju ako XMP toku nedostaje oznaka /Type /Metadata /Subtype /XML ili ako je omotač (wrapper) xpacket neispravan (malformed). U svakom je slučaju sadržaj stranice u redu (fine), pa ležerno otvaranje (casual open) izgleda ispravno, a greška izlazi na površinu tek na ploči koju nitko nije provjerio

Dvije jeftine navike uhvate većinu toga. Otvorite dovršenu datoteku u stvarnom pregledniku i kliknite kroz ploču s oznakama i uzorak (sample) veza, čime se izvršava referentni grafikon onako kako će to učiniti čitač (reader). Zatim pročitajte metapodatke zasebnim alatom i provjerite slažu li se rječnik Info (Info dictionary) i XMP, jedno neslaganje koje nikakvo klikanje ne otkriva. Generirajte ovaj sloj preko biblioteke (library) koja drži u svojim rukama (owns) knjigovodstvo poveznica i većina se tih zamki (traps) nikad ne otvara. HotPDF Component za Delphi i C++Builder izlaže (exposes) strukture obrisa, napomena i metapodataka (metadata structures) putem API-ja na razini dokumenta, pa opišete hijerarhiju (bookmark hierarchy) označivača i veza i prepustite im nizati (thread) reference. Za model objekata s kojima se te strukture vežu (attach), tehnički pregled strukture PDF datoteke pokriva katalog (catalog) i tablicu unakrsnih referenci (cross-reference table) o kojima oni ovise