Artikel Teknis

Metadata, Outline, dan Anotasi PDF Dijelaskan

Buang deskripsi halaman dan Anda tersisa dengan lapisan tipis struktur yang tidak ada yang mencetak tetapi setiap reader, pengindeks, dan sistem pengarsipan bergantung padanya. Objek halaman tidak tahu apa-apa tentang bab yang dimilikinya, penulis yang menulisnya, atau catatan kaki yang menaut ke tempat lain. Pengetahuan itu berada satu tingkat di atas, dalam tiga struktur yang terpasang pada catalog dokumen: aliran metadata, pohon outline, dan array anotasi per halaman. Mereka berbagi ciri yang membuatnya mudah salah. Tidak satu pun membawa tanda yang terlihat di halaman, sehingga file dapat merender dengan sempurna dan masih kehilangan bookmark-nya, bertentangan dengan bidang penulisnya sendiri, atau menunjuk tautan ke objek halaman yang sudah tidak ada

Ini adalah lapisan yang diekspos library PDF sebagai properti dokumen, API bookmark, dan panggilan tautan atau anotasi, dan lapisan yang dibaca perayap pencarian untuk memutuskan tentang apa dokumen Anda. Model objek di bawahnya dibahas dalam panduan struktur dokumen PDF. Di sini fokusnya khusus pada apa yang menggantung dari catalog

Ketiga struktur tersebut terpasang pada catalog. Kabel catalog lengkap yang menghubungkan ketiganya terlihat seperti ini:

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

Empat entri, empat subsistem independen. /Pages adalah dokumen yang terlihat; /Outlines adalah pohon bookmark; /Metadata menunjuk ke aliran XMP; /Names menjangkau kamus nama seluruh dokumen, yang antara lain menyimpan lampiran file tertanam. Masing-masing bersifat opsional, dan reader yang tidak menemukan satu pun dari keduanya masih menampilkan halaman. Opsionalitas itulah tepatnya mengapa lapisan navigasi adalah hal pertama yang rusak ketika file diedit oleh alat yang hanya memahami halaman

Dua penyimpan metadata yang tidak sepakat

PDF membawa metadata dokumen di dua tempat sekaligus, dan masalah dimulai ketika keduanya mengatakan hal yang berbeda. Mekanisme aslinya adalah kamus informasi dokumen, direferensikan oleh /Info dalam trailer: sekumpulan pasangan kunci-nilai datar untuk /Title, /Author, /Subject, /Keywords, /Creator, /Producer, dan dua tanggal. Ini sederhana dan setiap viewer membacanya. PDF 2.0 mendepresiasi sebagian besar itu demi mekanisme kedua, aliran metadata XMP

XMP adalah dokumen XML mandiri, ditulis dalam RDF, disimpan sebagai aliran yang dijangkau catalog melalui /Metadata dan ditandai /Type /Metadata /Subtype /XML. Tidak seperti kamus Info yang terkubur di dalam struktur objek PDF, paket XMP dirancang untuk diekstrak dan diurai sendiri oleh alat yang tidak mengetahui apa pun tentang PDF. Berikut adalah paket yang representatif:

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

Tiga detail dalam blok itu menentukan apakah metadata bertahan kontak dengan tooling nyata. Instruksi pemrosesan xpacket bukan dekorasi: mereka membingkai paket sehingga ekstraktor dapat menemukannya di dalam aliran byte yang lebih besar, dan penulis yang menghilangkan penutup <?xpacket end="w"?> menghasilkan file yang terbuka dengan baik tetapi memicu validator yang ketat. Tipe data properti juga penting. dc:title adalah alternatif bahasa yang dibungkus dalam rdf:Alt, sedangkan dc:creator adalah daftar berurutan dan mengambil rdf:Seq; memancarkan salah satunya sebagai node teks biasa adalah kesalahan XMP paling umum, ditoleransi oleh sebagian besar viewer tepat sampai yang tidak. Awalan namespace bersifat konvensional, tetapi URI yang diikatnya bersifat normatif: parser mengunci URI, bukan awalan

Aturan keras dengan dua penyimpan adalah bahwa keduanya harus sepakat. Jika /Info mengatakan penulisnya adalah satu orang dan dc:creator menamai yang lain, Anda telah mengirimkan dokumen yang menjawab pertanyaan yang sama dengan dua cara, dan jawaban mana yang menang bergantung pada bidang mana yang dibaca alat yang mengonsumsi. Library biasanya menulis keduanya untuk Anda, tetapi begitu Anda mengedit satu secara manual, atau menggabungkan file dari generator berbeda, keduanya akan berbeda. Perlakukan kamus Info sebagai kompatibilitas lama dan XMP sebagai sumber kebenaran, dan buat ulang keduanya dari satu set nilai daripada menambal keduanya secara independen. Untuk PDF/A ini menjadi persyaratan kesesuaian: ISO 19005 mewajibkan XMP dan melarang properti Info yang bertentangan dengan XMP-nya

Pohon outline di balik panel bookmark

Apa yang ditampilkan viewer sebagai panel bookmark adalah, dalam file, pohon kamus yang doubly-linked yang disebut outline dokumen. Catalog menunjuk ke kamus outline root melalui /Outlines; root menunjuk ke item tingkat atas pertama dan terakhirnya; dan setiap item dirangkai ke tetangganya dan induknya. Tidak ada array bookmark di mana pun. Seluruh struktur direkonstruksi dengan mengikuti referensi, itulah tepatnya mengapa satu tautan yang rusak dapat membuat seluruh cabang menghilang dari panel tanpa kesalahan apa pun

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

Baca tautannya dan invariannya menjadi jelas. Setiap item menunjuk kembali ke /Parent-nya. Saudara membentuk rantai melalui /Prev dan /Next, item pertama menghilangkan /Prev dan item terakhir menghilangkan /Next. Induk menamai anak pertama dan terakhirnya melalui /First dan /Last, dan anak-anak di antaranya hanya dapat dijangkau dengan berjalan rantai saudara. Salah satu dan kegagalannya diam: /Next yang basi memotong bab, induk yang /Last-nya tidak mengakhiri rantai membiarkan item yatim piatu, dan viewer merender apa pun yang dapat dijangkaunya

Bidang /Count membawa bagian state yang mengejutkan orang. Pada root dan pada item yang diperluas, itu menyimpan jumlah turunan yang saat ini terlihat; pada item yang diciutkan, itu adalah angka negatif yang besarnya adalah berapa banyak turunan yang akan muncul saat diperluas. Jadi /Count bukan fakta struktural tetap tentang pohon, ini adalah state panel terbuka atau tertutup yang disimpan, dan generator yang mengodekan keras itu sebagai total positif membuka kembali setiap cabang yang dimaksudkan penulis untuk dibiarkan tertutup

Setiap item mendapat tempatnya dengan menunjuk ke suatu tempat. /Title adalah yang ditampilkan panel; /Dest adalah di mana klik mendarat. Tujuan dapat inline dalam item, seperti di atas, atau nama yang diselesaikan melalui kamus nama dokumen, yang merupakan pilihan lebih baik ketika banyak bookmark dan tautan menargetkan tempat yang sama, karena Anda memperbaiki target yang dipindahkan di satu tempat. Library umumnya menyembunyikan pohon ini di balik handle outline-root dan metode yang menambahkan entri anak; di HotPDF dokumen mengekspos OutlineRoot bertipe THPDFDocOutlineObject dan menghubungkan tautan /Prev, /Next, /Parent, dan /Count untuk Anda saat Anda menambahkan item. Itu layak untuk dimanfaatkan, karena mempertahankan invarian tersebut secara manual di seluruh pengeditan adalah tempat outline rusak

Tujuan: tata bahasa ke mana klik pergi

Baik bookmark maupun anotasi tautan menunjuk ke tujuan, dan tujuan lebih dari sekadar nomor halaman. Ini adalah array yang menamai objek halaman dan kemudian menetapkan, melalui kata kerja di slot kedua, cara viewer harus membingkainya. Yang paling umum dan paling sering disalahgunakan adalah /XYZ, berbentuk [page /XYZ left top zoom]. Tiga operandnya independen, dan mana pun bisa null berarti "biarkan ini seperti yang dimiliki reader." Jadi [page /XYZ null null null] melompat ke halaman tanpa menyentuh posisi gulir atau zoom, biasanya apa yang Anda inginkan dari tautan "buka halaman." Angkanya dalam ruang pengguna default, diukur dari kiri bawah dengan y meningkat ke atas, sistem koordinat yang sama yang digunakan konten halaman. Penulis yang datang dari tata letak layar secara refleks mengukur dari atas dan mengirim reader ke ujung halaman yang salah

Keluarga /Fit menukar posisi yang tepat dengan ketahanan. [page /Fit] menskalakan seluruh halaman ke dalam jendela, [page /FitH top] menyesuaikan lebar halaman dengan tepi atas yang diberikan, dan [page /FitR l b r t] memperbesar persegi panjang untuk mengisi tampilan. Karena ini menghitung skala dari geometri halaman daripada koordinat tetap, tujuan /Fit masih melakukan hal yang masuk akal setelah halaman diubah ukurannya, sedangkan tujuan /XYZ dengan zoom yang dipanggang dapat membiarkan reader menatap margin. Untuk daftar isi, /FitH dengan koordinat atas bagian lebih tahan lama daripada /XYZ dengan zoom yang ditebak

Anotasi: semua yang interaktif yang bukan konten halaman

Anotasi adalah objek yang melapisi halaman tanpa menjadi bagian dari content stream-nya. Tautan, sticky note, sorotan, widget formulir, ikon lampiran file, stempel: semuanya adalah anotasi, tercantum dalam array /Annots halaman yang ditempatinya. Menghapus anotasi dari array tersebut menghapusnya dari halaman meskipun konten yang mendasarinya tidak tersentuh. Itulah seluruh intinya: anotasi adalah lapisan pengeditan, terpisah dari tanda yang didudukinya

Setiap anotasi berbagi tulang belakang kecil. /Subtype menamai jenisnya, /Rect memberikan kotak pembatasnya dalam koordinat halaman, dan /Contents menyimpan teks yang berfungsi ganda sebagai deskripsi yang dapat diakses. Anotasi tautan adalah kasus yang layak dipelajari, karena hadir dalam dua bentuk: tujuan biasa, dan tindakan

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 adalah hotspot; mengklik di dalamnya mengirim reader ke tujuan, menggunakan tata bahasa yang sama yang digunakan outline. /Border [0 0 0] melakukan pekerjaan nyata, menekan persegi panjang jelek default yang digambar viewer di sekitar tautan. Bentuk kedua menukar /Dest biasa dengan tindakan /A, yang subtipe /S-nya memilih perilaku: /GoTo dalam file ini, /GoToR untuk file lain, /URI untuk alamat web, /Launch untuk menjalankan program eksternal. Yang terakhir itu layak dicurigai. /Launch yang memulai executable adalah perilaku yang membuat PDF menjadi vektor malware, sehingga viewer yang sesuai membloknya atau meminta keras dan tautan gagal untuk sebagian besar reader. Gunakan /URI dan /GoTo dan tinggalkan /Launch

Anotasi markup seperti sorotan dan sticky note, dan anotasi bentuk seperti /Square, menambahkan kerutan: tampilan layar mereka tidak tersirat oleh tipenya. Viewer merender versinya sendiri kecuali Anda menyematkan tampilan dengan aliran tampilan, entri /AP, yang mereferensikan form XObject yang menyimpan operator gambar. Lewati itu dan sorotan yang sama dapat terlihat berbeda di dua reader, atau sebelum dan sesudah perputaran editor. Untuk apa pun yang tampilan pastinya merupakan bagian dari dokumen, sediakan /AP. Lampiran file, ngomong-ngomong, menggunakan mekanisme yang sama ini: aliran file tertanam dan kamus spesifikasi file, disajikan baik sebagai anotasi /FileAttachment atau melalui pohon nama /EmbeddedFiles di bawah /Names catalog

Di mana lapisan ini rusak, dan cara menangkapnya

Kegagalan berulang di semua ini adalah referensi yang menggantung. Bookmark berhenti muncul ketika catalog tidak memiliki entri /Outlines atau rantai saudara terputus di tengah pohon; metadata diabaikan ketika aliran XMP tidak memiliki penandaan /Type /Metadata /Subtype /XML atau pembungkus xpacket salah bentuk. Dalam setiap kasus konten halaman baik-baik saja, sehingga pembukaan biasa terlihat benar dan cacat hanya muncul di panel yang tidak diperiksa siapa pun

Dua kebiasaan murah menangkap sebagian besar masalah itu. Buka file yang sudah selesai di viewer nyata dan klik melalui panel bookmark dan sampel tautan, yang menggunakan grafik referensi dengan cara yang dilakukan reader. Kemudian baca kembali metadata dengan alat terpisah dan konfirmasi kamus Info dan XMP sepakat, ketidaksepakatan satu-satunya yang tidak diungkapkan oleh klik apa pun. Buat lapisan ini melalui library yang memiliki pembukuan tautan dan sebagian besar jebakan ini tidak pernah terbuka. HotPDF Component untuk Delphi dan C++Builder mengekspos struktur outline, anotasi, dan metadata melalui API tingkat dokumen, sehingga Anda mendeskripsikan hierarki bookmark dan tautan dan membiarkannya menghubungkan referensi. Untuk model objek tempat struktur ini terpasang, tinjauan teknis struktur file PDF mencakup catalog dan tabel referensi silang yang mereka andalkan