Artikel Teknis

Model Objek Logis PDF: Tipe, Referensi, dan Struktur

File PDF, pada intinya, adalah kumpulan objek yang saling menunjuk satu sama lain. Buang kompresi, pembukuan referensi silang, dan offset byte, maka yang tersisa adalah grafik: sekumpulan nilai bertipe, dihubungkan oleh referensi, berakar pada satu objek yang cara menemukannya sudah diketahui reader. Semua yang bisa diekspresikan PDF, dari paragraf teks hingga font tertanam hingga tanda tangan digital, dibangun dari delapan tipe objek primitif dan aturan yang memungkinkan satu objek merujuk ke objek lain. Pelajari itu, dan seluruh format terbaca sebagai komposisi, bukan misteri

Ini adalah lapisan logis PDF, didefinisikan dalam ISO 32000-1 klausul 7.3, dan berada satu tingkat di atas tata letak file fisik (header, body, tabel referensi silang, dan trailer, yang merupakan subjek tersendiri dalam tinjauan teknis struktur file PDF). Model logis adalah apa yang dimaksud oleh byte-byte itu setelah diurai. Viewer membaca file dari belakang untuk menemukan trailer, mengikutinya ke root, dan dari sana dokumen terbuka sebagai objek yang mereferensikan objek. Ini adalah bagian yang Anda nalar ketika men-debug halaman yang salah bentuk, menulis parser, atau mempercayakan library untuk merakit dokumen

Delapan tipe objek, dan tidak ada lagi

PDF mendefinisikan tepat delapan tipe objek dasar. Setiap nilai dalam dokumen adalah salah satunya, itulah yang membuat format ini dapat dikelola meskipun jangkauannya luas

Boolean adalah kata kunci true dan false. Mereka mengaktifkan dan menonaktifkan flag, seperti apakah anotasi dicetak

Angka hadir dalam dua rasa yang diperlakukan spesifikasi sebagai satu tipe: bilangan bulat seperti 42 dan bilangan real seperti 3.14 atau -0.002. PDF tidak memiliki notasi eksponen, jadi Anda tidak akan pernah melihat 1e6 dalam file yang sesuai standar. Koordinat, ukuran font, dan sudut rotasi semuanya adalah angka

String menyimpan urutan byte, ditulis baik dalam tanda kurung, (Hello), atau dalam tanda kurung sudut sebagai heksadesimal, <48656C6C6F>. Kedua notasi mengkodekan konten yang identik; hex adalah jalan keluar untuk byte yang canggung di dalam tanda kurung. String membawa teks, tetapi mereka adalah byte pertama, yang penting begitu Anda menangani apa pun di luar ASCII

Nama adalah token atomik yang diawali dengan garis miring: /Type, /Pages, /MediaBox. Nama bukan string; itu adalah pengidentifikasi, digunakan sebagai kunci kamus atau nilai yang dijumlahkan, dan dua nama sama hanya jika cocok byte demi byte. Garis miring adalah sintaks, bukan bagian dari nama. Ini membingungkan pendatang baru yang memperlakukan /Times-Roman dan string (Times-Roman) sebagai hal yang dapat dipertukarkan; format ini tidak demikian

Array adalah daftar berurutan dan heterogen dalam tanda kurung siku: [0 0 612 792] adalah persegi panjang halaman, dan array dapat mencampur tipe secara bebas, termasuk referensi ke objek lain. Kamus adalah workhorse-nya. Ditulis di antara << dan >>, kamus memetakan kunci nama ke nilai dari tipe apa pun, dan hampir setiap struktur bermakna dalam PDF, halaman, catalog, font, anotasi, adalah kamus dengan kunci /Type yang mendeklarasikan apa adanya

Aliran adalah kamus dengan ekor berupa byte mentah di antara kata kunci stream dan endstream. Kamus mendeskripsikan byte (panjang mereka, dan filter apa pun seperti FlateDecode yang mengompresnya), dan byte membawa muatan besar: instruksi konten halaman, program font tertanam, gambar. Sebuah aliran adalah tempat PDF menempatkan apa pun yang terlalu besar atau terlalu biner untuk duduk secara inline

Tipe kedelapan adalah objek null, kata kunci null. Ini adalah nilai nyata, berbeda dari kunci yang tidak ada. Entri kamus yang diatur ke null diperlakukan seolah-olah tidak ada, dan referensi yang diselesaikan ke objek yang tidak ada juga menghasilkan null daripada kesalahan. Perilaku yang memaafkan itu disengaja: memungkinkan file yang rusak terdegradasi daripada menolak untuk dibuka. Tidak ada tipe kesembilan; semua yang diekspresikan PDF berasal dari bagaimana delapan ini dikombinasikan

Nilai langsung, objek tidak langsung, dan referensi

Salah satu dari delapan tipe tersebut dapat muncul dalam dua cara. Objek langsung ditulis di tempat, seperti 612 di dalam array MediaBox. Objek tidak langsung diberi identitas sehingga objek lain dapat menunjuknya: dua bilangan bulat, nomor objek dan nomor generasi, membungkus definisi dalam obj dan endobj:

12 0 obj
<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>
endobj

Ini adalah objek 12, generasi 0, sebuah kamus font. Di mana pun lain dalam file, objek lain merujuknya dengan referensi tidak langsung: dua angka yang sama diikuti oleh kata kunci R, 12 0 R. Referensi adalah penunjuk. Ketika kamus sumber daya halaman menyatakan /Font << /F1 12 0 R >>, ia menamai objek 12 sebagai font di balik nama sumber daya /F1, tanpa menyalin definisi font ke dalam halaman

Nomor generasi ada untuk penghapusan dan penggunaan kembali. Ketika sebuah objek dibebaskan dan slotnya digunakan kembali, generasi bertambah sehingga 12 0 R yang basi tidak dapat diselesaikan ke penghuni baru slot 12. File yang baru ditulis hampir semuanya generasi 0, tetapi file yang banyak diedit dapat membawa nomor yang lebih tinggi, dan parser yang mengabaikan generasi pada akhirnya akan membaca objek yang salah

Indiresi adalah yang membuat PDF efisien dan dapat diedit. Satu font, gambar, atau ruang warna dapat didefinisikan sekali dan direferensikan dari ratusan halaman. Perubahan kecil dapat ditambahkan sebagai revisi baru yang menggantikan satu objek daripada menulis ulang file. Tabel referensi silang adalah indeks yang mengubah nomor objek menjadi offset byte, sehingga reader langsung menuju 12 0 obj tanpa memindai, tetapi itu adalah optimasi fisik. Secara logis, yang perlu Anda ketahui hanyalah bahwa 12 0 R berarti "objek yang diidentifikasi sebagai 12 0."

Catalog: dari mana setiap dokumen dimulai

Menyelesaikan referensi harus dimulai dari suatu tempat, dan tempat itu adalah entri /Root trailer, yang menunjuk ke catalog dokumen: root dari grafik objek, sebuah kamus dengan /Type /Catalog. Reader menjangkaunya pertama kali karena trailer ditemukan pertama, dan dari sana setiap bagian lain dokumen dapat dijangkau dengan mengikuti referensi

Catalog hanya membawa dua entri yang mutlak diperlukan: /Type-nya, dan /Pages, referensi tidak langsung ke root pohon halaman. Sisanya bersifat opsional dan mendeskripsikan perilaku seluruh dokumen daripada konten: /Outlines menunjuk ke pohon bookmark, /Names menyimpan pohon nama yang dikunci oleh string, /Metadata mereferensikan aliran metadata XMP, dan /PageMode serta /PageLayout menyarankan cara viewer harus membuka dokumen. Tidak satu pun dari itu diperlukan untuk merender halaman; mereka mengonfigurasi pengalaman di sekitar halaman. Struktur bookmark, metadata, dan anotasi yang menggantung dari catalog dibahas dalam artikel tentang metadata PDF, bookmark, dan anotasi

Diagram di bawah menunjukkan di mana body objek berada dalam file sekitarnya. Catalog dan pohon halaman berada di dalam body itu sebagai objek tidak langsung biasa; header, tabel referensi silang, dan trailer di sekitarnya adalah perancah fisik yang memungkinkan reader menemukan mereka

Diagram empat bagian fisik file PDF: header versi, body yang menyimpan objek dokumen termasuk catalog dan pohon halaman, tabel referensi silang offset objek, dan trailer yang menunjuk ke root

Pohon halaman: hierarki halaman yang seimbang

Dari /Pages, dokumen bercabang ke pohon halaman, di mana pilihan PDF menggunakan grafik daripada daftar datar terbukti manfaatnya. Halaman tidak disimpan sebagai urutan sederhana; mereka menggantung dari pohon yang node internalnya adalah node pohon halaman (/Type /Pages) dan daunnya adalah objek halaman (/Type /Page). Node internal mencantumkan anaknya dalam array /Kids dan mencatat, dalam /Count, berapa banyak halaman daun yang berada di bawahnya. Setiap node kecuali root membawa referensi /Parent kembali ke atas, sehingga pohon berjalan di kedua arah

2 0 obj                                  % root of the page tree
<< /Type /Pages /Kids [3 0 R 4 0 R] /Count 3 >>
endobj

3 0 obj                                  % a leaf page
<< /Type /Page /Parent 2 0 R
   /MediaBox [0 0 612 792]
   /Resources << /Font << /F1 12 0 R >> >>
   /Contents 5 0 R >>
endobj

4 0 obj                                  % an interior node grouping two more pages
<< /Type /Pages /Parent 2 0 R /Kids [6 0 R 7 0 R] /Count 2 >>
endobj

Di sini objek 2 adalah root, dengan tiga halaman di bawahnya: halaman daun 3, ditambah dua lagi yang dapat dijangkau melalui node internal 4. /Count root sebesar 3 harus sama dengan total daun di bawahnya, dan hitungan yang tidak sesuai dengan struktur aktual adalah cara umum file yang diedit secara manual menjadi salah. Tujuan pohon adalah lokalitas akses. Reader yang membuka halaman 900 dari dokumen seribu halaman tidak melintasi 900 objek; ia turun beberapa node, karena pohon yang terbentuk dengan baik tetap dangkal dan seimbang. Membangun pohon semacam itu secara manual cukup rumit sehingga layak untuk dilihat dari ujung ke ujung, yang dilakukan oleh panduan langkah demi langkah tentang membangun dokumen PDF dari awal

Pohon mendapatkan manfaat keduanya melalui pewarisan. Sejumlah atribut halaman, /Resources, /MediaBox, /CropBox, dan /Rotate, dapat diatur pada node internal dan dibiarkan tidak ada pada halaman individual, yang kemudian mewarisi nilai leluhur terdekatnya. Atur /MediaBox sekali pada root dan setiap daun mendapatkan ukuran halaman yang sama tanpa mengulanginya; halaman yang perlu berbeda mendeklarasikan miliknya sendiri. Inilah satu-satunya tempat dalam model objek di mana makna nilai bergantung pada posisi objek dalam pohon, bukan hanya pada kontennya sendiri

Apa yang sebenarnya dimiliki halaman daun

Objek halaman adalah titik pertemuan antara model struktural dan konten yang terlihat. Entri /Contents-nya mereferensikan satu atau lebih content stream, operator gambar yang melukis teks dan grafis ke halaman. Kamus /Resources-nya menamai font, gambar, dan ruang warna yang diandalkan oleh operator tersebut, masing-masing entri adalah referensi tidak langsung ke objek yang dibagikan di seluruh halaman. /MediaBox memberikan persegi panjang halaman dalam poin (1/72 inci), dan entri seperti /Rotate dan /CropBox menyesuaikan cara presentasinya

Pembagian kerja itu adalah seluruh model dalam miniatur. Kamus halaman adalah struktur: entri bertipe dan referensi yang mengatakan apa halaman itu dan apa yang digambarnya. Content stream adalah instruksi: blob yang dapat dikompres secara terpisah yang mengatakan cara menggambar. Font di balik /F1 adalah sumber daya bersama, didefinisikan sekali dan ditunjuk ke mana pun digunakan. Kamus, aliran, dan referensi bekerja sama untuk merender satu halaman, dan pola yang sama berskala ke seluruh dokumen. Operator content stream di dalam blob tersebut dibahas secara terpisah untuk teks dan font serta untuk grafis dan elemen visual

Mengapa model ini layak diketahui

Sebagian besar pengembang bertemu model objek hanya ketika ada yang rusak: halaman merender kosong karena referensi /Contents-nya menggantung, teks keluar sebagai kotak karena sumber daya font tidak pernah disematkan, sebuah alat melaporkan /Count yang tidak cocok dengan halaman yang dapat ditemukannya. Masing-masing itu adalah pernyataan tentang grafik, dan membaca grafik secara langsung mengalahkan menebak. Delapan tipe dan aturan referensi adalah kosakata yang cukup kecil untuk disimpan di kepala Anda, dan begitu Anda melihat PDF sebagai objek yang menunjuk ke objek, file yang salah bentuk berhenti menjadi tidak jelas

Yang dikatakan, menulis model secara manual jarang menjadi pilihan yang tepat di luar pembelajaran. Menjaga offset referensi silang, nomor generasi, jumlah pohon halaman, dan panjang aliran tetap konsisten di seluruh pengeditan adalah jenis pembukuan yang ada library untuk menanganinya. Dalam produksi, library pengembangan PDF yang matang mengelola grafik objek sambil membiarkan Anda berpikir dalam halaman dan konten. Mengetahui modelnya tetap terbayar: Anda memahami apa yang dibangun library di bawahnya, dan mengapa