Apa sebenarnya PDF itu
ISO 32000-2 §7 Evidence: Standard-backed
Sekilas pandang
Bagian berjudul “Sekilas pandang”PDF bukan sekadar deskripsi halaman yang kebetulan disimpan dalam sebuah berkas. PDF adalah basis data graf kecil dengan pencetak yang terhubung padanya. Halaman ini menjelaskan empat bagian yang dimiliki setiap PDF — header, body, tabel rujukan-silang, trailer — serta cara NextPDF menuliskannya agar pembaca dapat menemukan setiap objek tanpa menebak.
Mengapa ini penting
Bagian berjudul “Mengapa ini penting”Sebagian besar bug PDF bukan bug rendering. Bug tersebut adalah bug struktur: offset byte yang menunjuk satu karakter setelah objek yang dimaksud, trailer yang menamai root yang salah, entri rujukan-silang yang tidak sesuai dengan letak objek yang sebenarnya. Tidak satu pun dari hal ini mengubah tampilan halaman, sampai sebuah pembaca menempuh jalur berbeda melalui berkas lalu gagal di ujungnya.
Jika Anda memperlakukan PDF sebagai kotak hitam, kegagalan-kegagalan itu tampak acak. Jika Anda memahami model objeknya, kegagalan itu tampak persis sebagaimana adanya: sebuah angka yang tidak cocok dengan suatu posisi. Memahami formatnya membedakan antara “PDF ini rusak” dan “offset objek 14 sudah usang karena writer mengukurnya sebelum menyelesaikan panjang stream.”
Versi singkatnya
Bagian berjudul “Versi singkatnya”PDF memiliki empat bagian, sesuai urutan dalam berkas:
- Sebuah header — satu baris yang menyebutkan versinya (
%PDF-2.0). - Sebuah body — jaringan objek tak langsung bernomor: kamus, stream, larik, angka, string, nama.
- Sebuah tabel rujukan-silang (atau, dalam PDF 2.0, sebuah stream rujukan-silang) — pemetaan dari nomor objek ke offset byte, sehingga objek mana pun dapat dijangkau tanpa memindai berkas.
- Sebuah trailer — kamus kecil yang menamai objek root dokumen dan menunjuk ke tempat bagian rujukan-silang dimulai.
Sebuah pembaca tidak membaca PDF dari depan ke belakang. Pembaca membaca baris terakhir lebih dahulu, menemukan startxref, melompat ke bagian rujukan-silang, dan menggunakannya sebagai indeks ke dalam body. Format ini dirancang untuk dibaca dari belakang. Satu fakta ini menjelaskan sebagian besar rancangannya.
Bagaimana NextPDF menanganinya
Bagian berjudul “Bagaimana NextPDF menanganinya”NextPDF membangun PDF sesuai cara format tersebut dibaca: objek lebih dahulu, offset dicatat setelahnya, tabel ditulis paling akhir.
Setiap objek tak langsung dialokasikan sebuah nomor oleh satu registry tunggal (src/Core/ObjectRegistry.php). Registry memberikan nomor berurutan melalui allocate() dan, setelah byte sebuah objek ditulis ke buffer keluaran, mencatat offset byte-nya melalui register(). Offset tidak pernah ditebak sebelumnya. Offset itu diambil dari BinaryBuffer::getOffset() saat header objek dipancarkan. Inilah sebabnya entri rujukan-silang NextPDF tidak dapat menyimpang dari objek yang dideskripsikannya: offset tersebut persis nilai posisi buffer yang sebenarnya.
Setelah body lengkap, sebuah strategi serialisasi khusus-versi (src/Writer/PdfSerializationStrategy.php) menulis bagian rujukan-silang dan trailer:
Pdf20StreamStrategymenghasilkan sebuah stream rujukan-silang terkompresi (/Type /XRef) — bawaan PDF 2.0.Pdf17TableStrategydanPdf14TableStrategymenghasilkan sebuah tabel rujukan-silang tradisional 20-byte beserta kamus trailer terpisah — diperlukan oleh profil PDF/A yang mengharuskan struktur berkas yang lebih lama.
Strategi dipilih oleh profil keluaran, bukan disimpulkan secara implisit. Apa pun strateginya, byte akhir memiliki bentuk yang sama: bagian rujukan-silang, lalu startxref, lalu offset byte, lalu %%EOF. Ekor itulah yang pertama kali ditemukan oleh pembaca.
- Step 1 of 4: ISO 32000-2 §7.5.5 — %%EOF and startxref at the file end
- Step 2 of 4: ISO 32000-2 §7.5.4 / §7.5.8 — the cross-reference section maps object number to offset
- Step 3 of 4: ISO 32000-2 §7.5.5 — the trailer names /Root, the document catalog
- Step 4 of 4: ISO 32000-2 §7.3.10 — each indirect object is reached at its recorded offset
Apa kata buktinya
Bagian berjudul “Apa kata buktinya”Struktur empat bagian ini bukan konvensi NextPDF, melainkan bagian dari klausa struktur berkas dalam Spec: ISO 32000-2, §7.5 ISO 32000-2 §7.5 . Standar ini mendefinisikan sebuah PDF sebagai header, body berisi objek, tabel rujukan-silang, dan trailer, serta menyatakan bahwa sebuah pembaca seharusnya mengurai berkas dari ujungnya. Baris terakhir adalah %%EOF, dan dua baris sebelumnya adalah kata kunci startxref dan offset byte menuju bagian rujukan-silang.
Sebuah objek tak langsung didefinisikan sebagai nomor objek dan nomor generasi, dipisahkan oleh spasi, lalu diikuti nilai objek yang diapit di antara kata kunci obj dan endobj. Kombinasi nomor objek dan nomor generasi mengidentifikasi objek secara unik; rujukan tak langsung ke objek tersebut ditulis sebagai nomor objek, nomor generasi, dan kata kunci R. ObjectRegistry milik NextPDF mencerminkan persis hal ini: nomor berurutan, generasi 0 untuk objek yang baru ditulis, dan offset yang dicatat.
PDF 1.5 dan yang lebih baru juga memungkinkan objek berada di dalam sebuah object stream, tempat objek-objek itu disimpan tanpa kata kunci obj/endobj dan harus memiliki generasi nol. Stream rujukan-silang (/Type /XRef,
Spec: ISO 32000-2, §7.5.8 ISO 32000-2 §7.5.8 ) adalah mekanisme PDF 2.0
yang mengindeks baik objek biasa maupun objek terkompresi ini.
CrossReferenceStream milik NextPDF membangunnya dengan larik lebar-medan /W dan
kompresi FlateDecode.
Contoh praktis
Bagian berjudul “Contoh praktis”Berikut bentuk body PDF minimal beserta trailer-nya. Angka-angka di bagian rujukan-silang adalah offset byte. Angka-angka itu harus benar-benar tepat; itulah sebabnya NextPDF mencatatnya dari buffer, bukan menghitungnya.
%PDF-2.01 0 obj<< /Type /Catalog /Pages 2 0 R >>endobj2 0 obj<< /Type /Pages /Kids [3 0 R] /Count 1 >>endobj3 0 obj<< /Type /Page /Parent 2 0 R /MediaBox [0 0 612 792] >>endobjxref0 40000000000 65535 f0000000009 00000 n0000000058 00000 n0000000122 00000 ntrailer<< /Size 4 /Root 1 0 R >>startxref196%%EOFSebuah pembaca membuka berkas ini dari bawah: %%EOF, lalu startxref 196, lalu melakukan seek ke byte 196 tempat xref dimulai, membaca bahwa objek 1 berada di byte 9, mengikuti /Root 1 0 R menuju katalog, dan menelusuri pohon halaman dari sana. Objek 0 selalu menjadi kepala daftar-bebas dengan generasi 65535 — keanehan yang diwariskan dari rancangan paling awal format ini, direproduksi dengan setia karena pembaca mengharapkannya.
Kesalahpahaman umum
Bagian berjudul “Kesalahpahaman umum”Jebakannya adalah mengira bahwa PDF dibaca dari atas ke bawah seperti kode sumber. Padahal tidak demikian. Body dapat berada dalam urutan objek apa pun. Nomor objek tidak harus berurutan di dalam berkas, dan sebuah pembaca tidak pernah bergantung pada urutan itu. Satu-satunya indeks yang otoritatif adalah bagian rujukan-silang, dan satu-satunya cara menemukannya adalah melalui trailer di ujung. Sebuah PDF dengan body yang sepenuhnya valid namun satu angka yang salah di startxref tidak dapat dibaca. Sebuah PDF dengan objek yang ditulis dalam urutan acak namun tabel rujukan-silang yang benar tetap valid. Posisi tidak berarti apa-apa; posisi yang dicatat-lah segalanya.
Batasan dan ruang lingkup
Bagian berjudul “Batasan dan ruang lingkup”Halaman ini menjelaskan struktur berkas, bukan konten halaman. Bagaimana tanda tampil di sebuah halaman — content stream, operator grafis, penampilan teks — merupakan topik tersendiri. Halaman ini juga tidak mencakup apa yang terjadi ketika sebuah berkas diubah setelah ditulis. Hal itu adalah ranah pembaruan inkremental, tempat writer menambahkan bagian rujukan-silang kedua dan trailer-nya merantai ke belakang.
NextPDF adalah sebuah writer. Perilaku yang dijelaskan di sini adalah cara ia menserialisasikan dokumen yang dibangunnya. Ia bukan parser PDF serbaguna ataupun alat perbaikan. Ia tidak menjanjikan untuk membaca, merekonstruksi, atau menyelamatkan sembarang berkas pihak ketiga dengan tabel rujukan-silang yang rusak. Jaminannya sempit dan disengaja. Berkas yang ditulis NextPDF memiliki offset yang cocok, karena offset itu diukur, bukan diprediksi.
Mini-FAQ
Bagian berjudul “Mini-FAQ”Mengapa ada nomor generasi jika berkas baru selalu menggunakan 0? Nomor generasi ada untuk penggunaan ulang objek lintas pembaruan. Dalam berkas yang baru ditulis, setiap objek berada pada generasi 0. Generasi non-nol hanya muncul ketika sebuah berkas telah diperbarui secara inkremental dan suatu nomor objek didaur ulang.
Dapatkah dua objek memiliki nomor yang sama? Dalam satu bagian rujukan-silang tunggal, tidak. Lintas pembaruan inkremental, sebuah berkas secara fisik dapat memuat beberapa salinan dari nomor objek yang sama. Entri rujukan-silang paling terkinilah yang berlaku. Itulah pokok bahasan halaman berikutnya.
Apakah urutan objek di dalam berkas berpengaruh terhadap keluaran? Tidak. NextPDF menulis objek dalam urutan deterministik demi build yang dapat direproduksi, tetapi sebuah pembaca menyelesaikan segalanya melalui bagian rujukan-silang, sehingga urutan fisiknya tidak bermakna secara semantik.
Dokumen terkait
Bagian berjudul “Dokumen terkait”- Pembaruan inkremental dan mengapa itu penting — apa yang terjadi ketika sebuah PDF yang sudah ditulis diubah: bagian yang ditambahkan dan trailer yang dirantai.
- Stream dan filter — bagaimana stream objek di body dikompresi dan dikodekan.
- PDF 2.0: apa yang berubah — bagaimana struktur berkas berbeda antara 1.7 dan baseline 2.0 yang dituju NextPDF.
Glosarium
Bagian berjudul “Glosarium”- Objek tak langsung — objek bernomor di dalam body, ditulis sebagai
N G obj … endobj, denganNsebagai nomor objek danGsebagai nomor generasi. - Rujukan tak langsung — penunjuk ke sebuah objek tak langsung, ditulis
N G R. - Tabel rujukan-silang (xref) — indeks dari nomor objek ke offset byte. Dalam PDF 2.0, ini biasanya berupa stream rujukan-silang (
/Type /XRef) alih-alih tabel teks klasik 20-byte-per-entri. - Trailer — kamus di ujung sebuah bagian rujukan-silang yang menamai
/Root(katalog dokumen) dan/Size, serta ditemukan melalui offsetstartxref. - Object stream — objek stream yang memuat objek tak langsung lain di dalam dirinya (terkompresi bersama-sama); anggotanya tidak memiliki
obj/endobjdan bergenerasi nol. - Katalog dokumen — objek yang dinamai oleh
/Root; titik masuk ke pohon halaman dan segala hal lainnya di dalam dokumen.