Technical Article

PDF Metadata, Outlines and Annotations Explained

Uklonite opise stranica i ostat će vam tanak sloj strukture koji nitko ne ispisuje, ali o kojem ovisi svaki preglednik, indeksator i arhivski sustav. Objekt stranice ne zna ništa o poglavlju kojem pripada, autoru koji ga je napisao ili bilješci koja vodi na drugo mjesto. To znanje živi jednu razinu više, u tri strukture pridružene katalogu dokumenta: tokovima metapodataka, stablu outlines (oznaka) i poljima bilješki (annotations) po stranici. Oni dijele osobinu zbog koje je lako pogriješiti. Nijedan ne nosi vidljive tragove na stranici, pa se datoteka može prikazati savršeno, a da joj i dalje nedostaju oznake, da proturječi vlastitom polju autora ili da povezuje na objekt stranice koji više ne postoji.

To je sloj koji PDF knjižnica izlaže kao svojstva dokumenta, API-je za oznake te pozive za veze ili bilješke, i sloj koji pretraživač weba čita kako bi odlučio o čemu se radi u vašem dokumentu. Model objekata ispod njega pokriven je u pregledu strukture PDF dokumenata. Ovdje je fokus isključivo na onome što visi s kataloga.

Sve tri strukture pridružuju se katalogu. Kompletan 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; /Metadata pokazuje na XMP tok; /Names doseže rječnik naziva na razini cijelog dokumenta, koji između ostalog sadrži ugrađene privitke datoteka. Svaki je neobavezan, a preglednik koji ne pronađe nijedan od njih i dalje prikazuje stranice. Ta neobaveznost je upravo razlog zašto navigacijski sloj prvi propada kada datoteku uređuju alati koji razumiju samo stranice.

Dva spremišta metapodataka koja se razlikuju

PDF nosi metapodatke dokumenta na dva mjesta istovremeno, a problem počinje kada oni govore različite stvari. Izvorni mehanizam je rječnik informacija o dokumentu (document information dictionary), na koji upućuje /Info u traileru: jednostavan skup parova ključ-vrijednost za /Title, /Author, /Subject, /Keywords, /Creator, /Producer i dva datuma. Jednostavan je i svaki ga preglednik čita. PDF 2.0 većinu toga proglašava zastarjelim u korist drugog mehanizma, XMP toka metapodataka.

XMP je samostalan XML dokument, napisan u RDF-u, pohranjen kao tok koji katalog doseže putem /Metadata i označen kao /Type /Metadata /Subtype /XML. Za razliku od rječnika Info zakopanog unutar PDF strukture objekata, XMP paket je dizajniran za samostalno izdvajanje i analiziranje od strane alata koji ne znaju ništa o PDF-u. Evo jednog reprezentativnog paketa:

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"?>
streamend
endobj

Tri detalja u tom bloku odlučuju hoće li metapodaci preživjeti susret sa stvarnim alatima. Upute za obradu xpacket nisu ukras: one uokviruju paket tako da ga ekstraktor može pronaći unutar većeg toka bajtova, a pisač koji izostavi zatvaranje <?xpacket end="w"?> proizvodi datoteku koja se otvara dobro, ali aktivira stroge validatore. Vrste podataka svojstava također su važne. dc:title je jezična alternativa omotana u rdf:Alt, dok je dc:creator uređeni popis i uzima rdf:Seq; emitiranje bilo kojeg od njih kao čistog tekstualnog čvora najčešća je pogreška u XMP-u, koju većina preglednika tolerira sve do onog koji to ne čini. Prefiksi imenskih prostora (namespaces) su konvencionalni, ali URI-ji s kojima se povezuju su normativni: parser se ravna prema URI-ju, a ne prema prefiksu.

Strogo pravilo kod dva spremišta jest da se moraju podudarati. Ako /Info kaže da je autor jedna osoba, a dc:creator imenuje drugu, isporučili ste dokument koji na isto pitanje odgovara na dva načina, a koji odgovor pobjeđuje ovisi o tome koje polje čita alat koji ga koristi. Knjižnica obično piše oba za vas, ali onog trenutka kada jedno uredite ručno, ili spojite datoteke iz različitih generatora, ta se dva spremišta razilaze. Tretirajte rječnik Info kao kompatibilnost s naslijeđenim sustavima, a XMP kao izvor istine, i regenerirajte oba iz jednog skupa vrijednosti umjesto da ih krpate zasebno. Za PDF/A to postaje zahtjev usklađenosti: norma ISO 19005 zahtijeva XMP i zabranjuje bilo koje svojstvo u Info koje proturječi njegovom XMP pandanu.

Stablo outlines iza ploče s oznakama

Ono što preglednik prikazuje kao ploču s oznakama (bookmarks panel) u datoteci je dvostruko povezano stablo rječnika koje se naziva obris dokumenta (document outline). Katalog pokazuje na korijenski rječnik outlines putem /Outlines; korijen pokazuje na svoju prvu i zadnju stavku gornje razine; a svaka je stavka povezana sa svojim susjedima i roditeljem. Nigdje ne postoji polje oznaka. Cijela se struktura rekonstruira praćenjem referenci, što je upravo razlog zašto jedna prekinuta veza može učiniti da cijela grana nestane s ploče 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 i invarijante postaju očigledne. Svaka stavka pokazuje natrag na svoj /Parent. Susjedne stavke na istoj razini (siblings) tvore lanac preko /Prev i /Next, pri čemu prva stavka izostavlja /Prev, a zadnja izostavlja /Next. Roditelj imenuje svoje prvo i zadnje dijete preko /First i /Last, a djeca između njih dostupna su samo prolaskom kroz lanac susjeda. Pogriješite li jednu vezu, neuspjeh je tih: zastarjeli /Next skraćuje poglavlje, roditelj čiji /Last ne završava lanac ostavlja stavke bez roditelja, a preglednik prikazuje ono što može dohvatiti.

Polje /Count nosi dio stanja koji iznenađuje ljude. Na korijenu i na bilo kojoj proširenoj stavci ono drži broj trenutno vidljivih potomaka; na skupljenoj stavci to je negativan broj čija veličina označava koliko bi se potomaka pojavilo pri proširenju. Dakle, /Count nije fiksna strukturna činjenica o stablu, to je spremljeno otvoreno ili zatvoreno stanje ploče, a generator koji ga tvrdo kodira kao pozitivan zbroj ponovno otvara svaku granu koju je autor namjeravao ostaviti zatvorenom.

Svaka stavka zaslužuje svoje mjesto pokazujući negdje. /Title je ono što ploča prikazuje; /Dest je mjesto gdje klik slijeće. Odredište može biti unutar same stavke (inline), kao gore, ili naziv koji se razrješava kroz rječnik naziva dokumenta, što je bolji izbor kada mnogo oznaka i veza cilja ista mjesta, jer promijenjeni cilj popravljate na jednom mjestu. Knjižnica općenito skriva ovo stablo iza korijenskog outlines rukovatelja i metoda koje dodaju podstavke; u HotPDF-u dokument izlaže OutlineRoot tipa THPDFDocOutlineObject i povezuje veze /Prev, /Next, /Parent i /Count umjesto vas dok dodajete stavke. To vrijedi iskoristiti, jer je ručno održavanje tih invarijanti tijekom uređivanja mjesto gdje se strukture outlines kvare.

Odredišta (Destinations): gramatika mjesta na koje klik vodi

I oznake i veze (link annotations) pokazuju na odredišta, a odredište je više od broja stranice. To je polje koje imenuje objekt stranice, a zatim specificira, preko glagola u drugom utoru, kako bi ga preglednik trebalo uokviriti. Najčešći i najčešće zloupotrebljavan je /XYZ, u obliku [page /XYZ left top zoom]. Njegova tri operanda su neovisna i bilo koji može biti null, što znači 'ostavi ovo kako je preglednik već imao'. Dakle, [page /XYZ null null null] skače na stranicu bez diranja položaja pomicanja (scroll) ili zumiranja, što je obično ono što želite od veze za odlazak na stranicu. Brojevi su u zadanom korisničkom prostoru (user space), mjereni od donjeg lijevog kuta s koordinatom Y koja raste prema gore, što je isti koordinatni sustav koji koristi sadržaj stranice. Autori koji dolaze iz dizajna ekrana refleksno mjere od vrha i šalju čitatelja na pogrešan kraj stranice.

Obitelj /Fit zamjenjuje precizno pozicioniranje otpornošću na promjene. [page /Fit] prilagođava cijelu stranicu prozoru, [page /FitH top] prilagođava širinu stranice s gornjim rubom, a [page /FitR l b r t] zumira pravokutnik kako bi ispunio prikaz. Budući da oni izračunavaju mjerilo iz geometrije stranice, a ne iz fiksnih koordinata, odredište /Fit i dalje radi ispravno nakon promjene veličine stranice, dok odredište /XYZ s ugrađenim zumiranjem može ostaviti čitatelja da gleda u marginu. Za tablicu sadržaja, /FitH s gornjom koordinatom odjeljka traje bolje od /XYZ s pretpostavljenim zumom.

Bilješke (Annotations): sve interaktivno što nije sadržaj stranice

Bilješka (Annotation) je objekt koji prekriva stranicu, a da nije dio njezina toka sadržaja. Veze (links), ljepljive bilješke, isticanja, widgeti obrazaca, ikone privitaka datoteka, pečati: sve su to bilješke, navedene u polju /Annots stranice na kojoj se nalaze. Uklanjanje bilješke iz tog polja uklanja je sa stranice iako je temeljni sadržaj nedirnut. To je i cijela poanta: bilješke su sloj za uređivanje, odvojen od oznaka preko kojih stoje.

Svaka bilješka dijeli mali kostur. /Subtype imenuje vrstu, /Rect daje njezin granični okvir u koordinatama stranice, a /Contents drži tekst koji služi kao pristupačan opis. Bilješka veze (link annotation) je slučaj koji vrijedi proučiti jer dolazi u dva oblika: kao golo odredište i kao radnja (action).

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 aktivno područje (hotspot); klik unutar njega šalje čitatelja na odredište, koristeći istu gramatiku koju koristi outline. /Border [0 0 0] obavlja stvarni posao, potiskujući ružan zadani pravokutnik koji preglednici crtaju oko veza. Drugi oblik zamjenjuje goli /Dest radnjom /A, čiji podtip /S bira ponašanje: /GoTo unutar ove datoteke, /GoToR za drugu datoteku, /URI za web adresu, /Launch za pokretanje vanjskog programa. Ovaj posljednji zaslužuje sumnju. /Launch koji pokreće izvršnu datoteku ponašanje je koje PDF-ove čini vektorom zlonamjernog softvera, pa ga usklađeni preglednici blokiraju ili glasno upozoravaju korisnika, pa veza ne uspijeva kod većine čitatelja. Koristite /URI i /GoTo, a /Launch ostavite po strani.

Označne bilješke (markup annotations) poput isticanja i ljepljivih bilješki te bilješke oblika (shape annotations) poput /Square, dodaju jednu pojedinost: njihov izgled na ekranu nije impliciran njihovom vrstom. Preglednik iscrtava vlastitu verziju osim ako ne učvrstite izgled pomoću toka izgleda (appearance stream), unosa /AP, koji upućuje na obrazac XObject koji drži operatore crtanja. Preskočite ga i isto isticanje može izgledati drugačije u dva različita preglednika, ili prije i nakon kruga uređivanja. Za sve čiji je točan izgled dio dokumenta, osigurajte /AP. Privitci datoteka, usput, ponovno koriste isti ovaj mehanizam: ugrađeni tok datoteke i rječnik specifikacije datoteke, koji se pojavljuju ili kao bilješka /FileAttachment ili kroz stablo naziva /EmbeddedFiles pod /Names kataloga.

Gdje ovaj sloj puca i kako to uočiti

Učestali problem u svemu ovome je viseća referenca. Oznake se prestaju pojavljivati kada katalog nema unos /Outlines ili kada se lanac susjednih stavki prekine na sredini stabla; metapodaci se zanemaruju kada XMP toku nedostaje oznaka /Type /Metadata /Subtype /XML ili kada je omot xpacket neispravan. U svakom slučaju, sadržaj stranice je u redu, pa povremeno otvaranje izgleda ispravno, a nedostatak ispliva na površinu tek na ploči koju nitko nije provjerio.

Dvije jednostavne navike hvataju većinu tih problema. Otvorite gotovu datoteku u stvarnom pregledniku i kliknite kroz ploču s oznakama i uzorak veza, što testira graf referenci na način na koji će to učiniti čitatelj. Zatim pročitajte metapodatke natrag zasebnim alatom i potvrdite da se rječnik Info i XMP podudaraju, što je nesuglasje koje nikakav klik ne otkriva. Generirajte ovaj sloj kroz knjižnicu koja vodi računa o vezama i većina ovih zamki nikada se neće otvoriti. Komponenta HotPDF za Delphi i C++Builder izlaže strukture outline, annotation i metadata preko API-ja na razini dokumenta, tako da vi opisujete hijerarhiju oznaka i veze, a prepuštate joj povezivanje referenci. Za model objekata na koji se ove strukture povezuju, tehnički pregled strukture PDF datoteka pokriva katalog i tablicu unakrsnih referenci o kojima ovise.