Ekonomi ukuran berkas PDF
Spec: ISO 32000-2, §7.5.7ISO 32000-2 §7.5.7
Sekilas pandang
Bagian berjudul “Sekilas pandang”Dua PDF dapat tampak identik piksel-demi-piksel di layar dan berbeda sepuluh kali lipat di disk. Perbedaannya hampir tidak pernah konten yang Anda lihat; ia adalah bagaimana berkas itu dirakit di baliknya. Halaman ini adalah sebuah tur ekonomi-ukuran: ke mana byte sebuah PDF sebenarnya pergi, dan empat tuas yang dibelanjakan seorang penulis dari anggaran byte.
Ia adalah pendamping mengapa berkas besar untuk Streams and filters, yang membahas bagaimana sebuah filter men-decode. Yang ini tetap pada anggarannya.
Mengapa ini penting
Bagian berjudul “Mengapa ini penting”Ukuran berkas jarang merupakan metrik kesombongan. Ia adalah bandwidth pada setiap unduhan, penyimpanan pada setiap arsip, dan latensi pada setiap pratinjau. Sebuah faktur 12 MB yang seharusnya 400 KB bukanlah masalah kosmetik ketika Anda menghasilkan sejuta darinya sebulan — ia adalah tagihan tiga puluh kali lipat.
Bagian yang menjengkelkan adalah bahwa kembung biasanya tak terlihat. Dokumen merender dengan benar, terbuka dengan baik, mencetak dengan baik. Tidak ada yang memberi tahu Anda bahwa artefak yang sama dapat menjadi pecahan dari ukurannya, karena byte yang terbuang bersifat struktural, bukan visual. Untuk menemukannya Anda harus melihat anggarannya, bukan halamannya.
Versi singkatnya
Bagian berjudul “Versi singkatnya”Bayangkan sebuah PDF sebagai sebuah anggaran yang Anda belanjakan pada empat butir baris.
- Overhead per-objek. Setiap objek tak langsung membawa sebuah amplop
N G obj/endobj, dan dilacak oleh satu cross-reference entry. Sebuah dokumen yang berat-halaman memiliki ribuan objek kecil, dan amplop-amplop itu bertumpuk. Object stream membuang amplop itu untuk satu grup objek penuh; setiap objek yang dikemas tetap menyimpan cross-reference entry-nya sendiri, tetapi sebagai sebuah compact type-2 entry. - Byte gambar. Untuk dokumen apa pun dengan foto atau pindaian, gambar-gambar mendominasi, dan tuas tunggal terbesar adalah pilihan filter — sebuah codec lossless versus sebuah codec gambar lossy adalah perbedaan antara megabyte dan kilobyte.
- Byte font. Sebuah font tersemat penuh adalah ratusan kilobyte glif yang tidak pernah Anda gunakan. Subsetting hanya menyimpan glif yang sebenarnya digambar dokumen.
- Indeks. Cross-reference table yang membiarkan seorang pembaca menemukan setiap objek itu sendiri dapat menjadi sebuah compressed stream alih-alih teks-polos.
Buat keempatnya benar dan berkasnya kecil. Lewatkan satu dan ia mendominasi segala sesuatu lain yang Anda lakukan dengan baik.
Bagaimana NextPDF menanganinya
Bagian berjudul “Bagaimana NextPDF menanganinya”Writer NextPDF adalah sebuah serializer streaming single-pass: ia menambahkan byte setiap objek begitu mereka diproduksi dan merekam sebuah cross-reference entry in-use klasik untuk masing-masing. Default itu cepat, dapat diprediksi, dan menghasilkan sebuah berkas yang stabil-byte — tetapi ia bukan tata letak terkecil yang mungkin, dan NextPDF jujur tentang itu.
Tuas 1 — object stream (ObjStm)
Bagian berjudul “Tuas 1 — object stream (ObjStm)”Sebuah PDF adalah sebuah graf objek tak langsung. Sebagian besar dari mereka
adalah dictionary kecil: node halaman, dictionary anotasi, elemen structure-tree,
entri outline. Masing-masing membayar sebuah pajak tetap — keyword obj /
endobj, nomor objek dan generasi, dan sebuah cross-reference entry yang
menempatkannya. Pada sebuah dokumen dengan ribuan objek kecil, pajak itu adalah
sebuah iris yang bermakna dari berkasnya.
Sebuah object stream mengumpulkan banyak dari objek non-stream kecil itu ke
dalam satu stream dan mengompresinya bersama
(Spec: ISO 32000-2, §7.5.7ISO 32000-2 §7.5.7). Amplop obj / endobj
dibuang untuk grup penuhnya; nilai-nilai di dalamnya disimpan
saling-membelakangi tanpa keyword per-objek, lalu di-deflate sebagai sebuah blok
tunggal — yang juga mengompresi lebih baik, karena kompresor yang
men-deduplikasi sekarang melihat semua dictionary serupa itu sekaligus.
Cross-reference entry tidak hilang — setiap objek yang dikemas masih
membutuhkannya — tetapi ia menyusut menjadi sebuah compact binary type-2 entry di
cross-reference stream (lebih lanjut tentang itu di Tuas 2).
Di NextPDF ini disajikan oleh ObjectStreamPacker, sebuah post-processor
mandiri yang mengambil sebuah PDF cross-reference-stream yang selesai dan menulis
ulang objek yang memenuhi syarat ke dalam sebuah /Type /ObjStm tunggal. Aturan
yang ia ikuti datang langsung dari standar: sebuah objek yang memenuhi syarat
adalah sebuah objek generation-zero, non-stream, setelah mengecualikan objek
khusus yang harus tetap dapat dialamatkan secara langsung. §7.5.7 melarang
menyimpan sebuah objek stream di dalam sebuah object stream, sehingga objek
stream — konten, font, gambar — menyimpan entri mereka sendiri; dan
ObjectStreamPacker selain itu menolak objek cross-reference stream dokumen itu
sendiri (ia ditulis ulang) dan dictionary /Encrypt, keduanya harus tetap dapat
dialamatkan secara langsung. Segala sesuatu lainnya yang generation-zero dan
non-stream dikemas.
| Edition | Availability |
|---|---|
| Core | Dukungan penuh dalam core open-source via ObjectStreamPacker. Ia bersifat opt-in: default writer single-pass memancarkan entri in-use klasik, sehingga keluaran tetap identik per byte kecuali Anda mengaktifkan packing. Packer-nya deterministik, dengan golden baseline-nya sendiri yang dapat direproduksi. |
| Pro | Not in this edition |
| Enterprise | Not in this edition |
Opt-in adalah sebuah sikap yang disengaja, bukan sebuah keterbatasan yang disembunyikan. Keluaran default bersifat stabil-byte dan cocok dengan golden baseline yang ada; menyalakan packing memilih masuk ke sebuah tata letak yang berbeda, lebih kecil, dan sama-sama deterministik. Anda memilih trade-nya, dan mesin tidak pernah membuatnya di belakang Anda.
Tuas 2 — indeks juga dapat menjadi sebuah stream
Bagian berjudul “Tuas 2 — indeks juga dapat menjadi sebuah stream”Begitu objek hidup di dalam sebuah object stream, indeks yang menunjuk ke mereka
berubah bentuk. Seorang pembaca menemukan sebuah objek yang dikemas melalui
sebuah compressed cross-reference entry — sebuah type-2 entry yang menamai
object stream dan indeks di dalamnya
(Spec: ISO 32000-2, §7.5.8.3ISO 32000-2 §7.5.8.3). Karena seluruh
cross-reference itu sendiri adalah sebuah /Type /XRef stream, indeks untuk
ribuan objek di-binary-pack dan di-deflate alih-alih ditulis sebagai baris
teks-polos. Peta menyusut bersama wilayahnya.
ObjectStreamPacker membangun ulang persis ini: ia memancarkan object stream
tunggal, lalu sebuah cross-reference stream yang ditulis ulang yang membawa
sebuah compact type-1 entry untuk setiap objek yang dipertahankan dan sebuah
type-2 entry untuk setiap yang dikemas, mempertahankan setiap nomor objek
sehingga referensi yang ada tetap valid.
Tuas 3 — pilihan filter gambar
Bagian berjudul “Tuas 3 — pilihan filter gambar”Untuk dokumen apa pun dengan gambar sungguhan, tuas ini mengerdilkan yang lainnya. Byte-nya adalah gambar yang sama; codec-nya adalah anggarannya. Nama filter hidup di standard filter set (Spec: ISO 32000-2, §7.4ISO 32000-2 §7.4), dan pilihan di antara mereka adalah sebuah keputusan ukuran:
- FlateDecode bersifat lossless. Sempurna untuk line art, screenshot, dan apa pun dengan warna datar — dan menghancurkan untuk sebuah foto, di mana lossless berarti setiap byte dari aslinya.
- DCTDecode adalah JPEG: lossy, dan untuk foto adalah pilihan yang tepat dengan margin lebar, sering kali sebuah pengurangan sepuluh kali lipat untuk sebuah penurunan kualitas yang tidak diperhatikan siapa pun.
- JPXDecode adalah JPEG 2000: kompresi wavelet dengan sebuah kurva kualitas/ukuran yang berbeda, tetapi dukungan yang tidak merata dan dilarang oleh beberapa profil arsip.
Ini persis di mana bagaimana sebuah filter men-decode penting, dan itu adalah tugas artikel Streams and filters. Poin ekonominya lebih sempit: sebuah foto yang disimpan lossless adalah penyebab tunggal paling umum dari sebuah PDF yang besar tanpa perlu, dan tidak ada jumlah object-stream packing yang akan menyelamatkan sebuah berkas yang bobot sesungguhnya adalah satu pindaian yang tidak di-JPEG.
Tuas 4 — font subsetting
Bagian berjudul “Tuas 4 — font subsetting”Sebuah font tersemat adalah sebuah program. Yang penuh dapat beberapa ratus kilobyte, karena ia membawa setiap glif yang pernah digambar perancang typeface — ribuan karakter melintasi skrip yang tidak akan pernah Anda gunakan di dokumen ini. Subsetting hanya menyematkan glif yang sebenarnya digambar dokumen, mengubah program itu menjadi sebuah pecahan kecil dari dirinya. Sebuah surat satu halaman tidak membutuhkan seluruh sebuah font yang berkemampuan-CJK; ia membutuhkan beberapa lusin glif yang ia set. Mekanika bagaimana glif dipilih dan diindeks-ulang adalah subjeknya sendiri — lihat Fonts: the hard part.
- Image bytesFor media-heavy files, the largest line item. The filter choice — lossless Flate vs a lossy image codec like DCT (or JPX in a lossy mode) — is the dominant size lever.
- Font bytesA full embedded font is mostly glyphs you never draw. Subsetting keeps only the used glyphs, often shrinking the program by an order of magnitude.
- Per-object overheadThousands of small dictionaries each pay an obj/endobj envelope plus a cross-reference entry. Object streams (ObjStm) drop the envelope for the whole group; each object keeps a compact type-2 cross-reference entry.
- The indexA compressed cross-reference stream with type-2 entries binary-packs and deflates the map of every object, replacing plaintext index rows.
Contoh praktis
Bagian berjudul “Contoh praktis”Tidak ada API yang dibuat-buat untuk ditunjukkan di sini, karena keputusan ukuran yang paling penting dibuat sebelum byte-nya mencapai writer — dan satu tuas struktural yang diekspos NextPDF adalah sebuah opt-in tunggal. Secara konseptual, anggarannya terbaca seperti ini:
- Berikan foto sebagai JPEG sehingga mereka mendarat di bawah
DCTDecode, bukan di-encode-ulang secara lossless. Kemenangan terbesar adalah sebuah pilihan tentang data sumber, bukan sebuah flag writer. - Biarkan writer men-subset font tersemat sehingga hanya glif yang digambar yang dikirim.
- Untuk sebuah dokumen dengan banyak objek kecil, memilih masuk ke object-stream
packing, yang merutekan berkas yang selesai melalui
ObjectStreamPackeruntuk mengelompokkan objek non-stream kecil dan menulis ulang cross-reference stream.
Jalur default — entri in-use klasik, tanpa ObjStm — adalah baseline yang tepat: deterministik, stabil-byte, dan mudah diverifikasi. Packing adalah peningkatan yang dipertimbangkan ketika jumlah objek, bukan bobot gambar, yang menggelembung berkasnya.
Kesalahpahaman umum
Bagian berjudul “Kesalahpahaman umum”Jebakannya adalah menjangkau sebuah tombol “kompres PDF” dan mengharapkannya
memperbaiki segalanya. Kompresi bukan satu tuas; ia empat, dan mereka tidak
saling menggantikan. Object-stream packing tidak dapat menyusutkan sebuah foto —
itu adalah tugas filter gambar. Sebuah JPEG yang sempurna tidak dapat
mengimbangi sebuah font yang lupa Anda subset. Dan tidak satu pun dari itu
membantu jika kembung sesungguhnya adalah sebuah pindaian 10 MB yang
disimpan lossless karena tidak ada yang memilih DCTDecode untuknya.
Kesalahpahaman kedua adalah bahwa lebih kecil selalu pasti lebih baik. Tidak. Object stream tidak kompatibel dengan linearization — tata letak fast-web-view yang mematok penempatan objek absolut sehingga halaman pertama mengalir masuk lebih awal. Dan beberapa profil arsip membatasi filter gambar mana yang bahkan diizinkan. Ukuran adalah satu sumbu. Ia bertukar terhadap streaming, konformansi arsip, dan reproduksibilitas, dan titik yang tepat pada kurva bergantung pada untuk apa dokumen itu.
Batas dan batasan
Bagian berjudul “Batas dan batasan”Keempat tuas itu adalah ekonomi struktural dari ukuran berkas. Mereka bukan sebuah jaminan “buat ia lebih kecil” yang universal, dan NextPDF tidak berpura- pura menjadi sebuah re-optimizer untuk PDF masuk yang sembarang.
ObjectStreamPacker adalah sebuah optimisasi upaya-terbaik yang tidak pernah
mempertaruhkan kebenaran. Ia menolak — mengembalikan input tanpa perubahan —
ketika berkasnya bukan sebuah PDF cross-reference-stream, ketika ia terenkripsi,
ketika ia membawa sebuah tanda tangan digital (menata-ulang objek akan menggeser
rentang byte yang dilindungi sebuah tanda tangan), ketika ia sudah berisi object
stream, atau ketika tidak ada objek yang memenuhi syarat untuk dikemas. Ia
memancarkan persis satu object stream untuk seluruh dokumen; ia tidak terpecah
menjadi sebuah koleksi /Extends, yang berada di luar cakupan dan konform untuk
ukuran dokumen yang dihasilkan NextPDF.
Tuas gambar dan font sebagian besar adalah keputusan tentang input-nya. Writer
NextPDF tidak secara implisit men-transcode sebuah bitmap lossless menjadi sebuah
stream gambar lossy — meng-encode-ulang sebuah foto menjadi DCTDecode atau
JPXDecode adalah sebuah keputusan image-encoding hulu yang eksplisit, bukan
sesuatu yang dilakukan serializer di belakang Anda — ataupun ia merebut kembali
glif dari sebuah font yang diminta pemanggil untuk disematkan secara penuh.
Kemenangan ukuran terbesar dibuat di hulu byte serializer; tugas mesin adalah
untuk tidak memboroskan anggaran yang Anda bawa kepadanya.
Dokumen terkait
Bagian berjudul “Dokumen terkait”- Streams and filters — pendamping bagaimana sebuah filter men-decode; halaman ini sengaja melengkapinya, bukan menduplikasinya.
- What a PDF actually is — model objek- tak-langsung yang overhead per-objek-nya dikurangi oleh tuas object-stream.
- The anatomy of a PDF file — struktur cross-reference yang menjadi sebuah compressed stream.
- Fonts: the hard part — bagaimana subsetting memilih dan mengindeks-ulang glif yang digambar sebuah dokumen.
Glosarium
Bagian berjudul “Glosarium”- Object stream (ObjStm) — sebuah stream tunggal yang menampung banyak objek
tak langsung non-stream kecil, dikompresi bersama, sehingga amplop
obj/endobjdibuang untuk grupnya. Setiap objek yang dikemas tetap menyimpan cross-reference entry-nya sendiri, sebagai sebuah compact type-2 entry. Opt-in di NextPDF. - Indirect object — sebuah objek bernomor di graf sebuah PDF, dibungkus
dalam sebuah amplop
obj/endobjdan dilacak oleh indeks cross-reference. Amplop itu adalah overhead per-objek. - Cross-reference stream —
/Type /XRefstream yang mengindeks setiap objek, di-binary-pack dan di-deflate alih-alih ditulis sebagai baris teks-polos. - Compressed (type-2) entry — sebuah cross-reference entry yang menunjuk ke sebuah objek yang hidup di dalam sebuah object stream, menamai stream dan indeks di dalamnya.
- Font subsetting — menyematkan hanya glif yang sebenarnya digambar sebuah dokumen, alih-alih typeface penuh, menyusutkan program font tersemat.
- Lossless vs lossy filter — sebuah codec lossless (FlateDecode) mereproduksi setiap byte; sebuah codec gambar lossy (DCTDecode, atau JPXDecode dalam sebuah mode lossy) membuang detail yang tidak terlihat untuk sebuah hasil yang jauh lebih kecil. (JPEG 2000 / JPX juga dapat dikonfigurasi lossless.) Pilihannya adalah tuas dominan pada sebuah berkas yang berat-media.