İçeriğe geç
getnextpdf.com

PDF dosya boyutunun ekonomisi

Spec: ISO 32000-2, §7.5.7

İki PDF, ekranda piksel piksel özdeş görünebilir ve diskte on kat farklılaşabilir. Fark, neredeyse hiçbir zaman gördüğünüz içerik değildir; dosyanın altta nasıl monte edildiğidir. Bu sayfa bir boyut-ekonomisi turudur: bir PDF’nin byte’larının gerçekte nereye gittiği ve bir yazarın bir byte bütçesini harcadığı dört kol.

Bu, Akışlar ve filtreler sayfasının bir filtre nasıl çözer konusunu işleyen yanına karşı, dosyalar neden büyük yoldaşıdır. Bu sayfa bütçede kalır.

Dosya boyutu nadiren bir gösteriş metriğidir. Her indirmede bant genişliği, her arşivde depolama ve her önizlemede gecikmedir. 400 KB olması gereken 12 MB’lik bir fatura, ayda bir milyon tane ürettiğinizde kozmetik bir sorun değildir — otuz katlık bir faturadır.

Sinir bozucu kısım, şişkinliğin genellikle görünmez olmasıdır. Belge doğru oluşturulur, sorunsuz açılır, sorunsuz yazdırılır. Aynı eserin boyutun bir kesri olabileceğini size hiçbir şey söylemez; çünkü boşa harcanan byte’lar görsel değil, yapısaldır. Onları bulmak için sayfaya değil, bütçeye bakmanız gerekir.

Bir PDF’yi, dört kalem üzerinde harcadığınız bir bütçe olarak düşünün.

  • Nesne başına ek yük. Her dolaylı nesne bir N G obj / endobj zarfı taşır ve bir cross-reference girdisiyle izlenir. Sayfa-ağırlıklı bir belgede binlerce küçük nesne vardır ve zarflar birikir. Nesne akışları, bir grup nesnenin tümü için o zarfı düşürür; paketlenmiş her nesne kendi cross-reference girdisini hâlâ tutar, ama kompakt bir tip-2 girdisi olarak.
  • Görüntü byte’ları. Fotoğraf ya da taramaların olduğu herhangi bir belge için görüntüler baskındır ve en büyük tek kol filtre seçimidir — kayıpsız bir codec’e karşı kayıplı bir görüntü codec’i, megabyte ile kilobyte arasındaki farktır.
  • Font byte’ları. Tam gömülü bir font, hiç kullanmadığınız yüzlerce kilobyte gliftir. Alt kümeleme, yalnızca belgenin gerçekten çizdiği glifleri tutar.
  • Dizin. Bir okuyucunun her nesneyi bulmasını sağlayan cross-reference table, düz metin yerine kendisi bir sıkıştırılmış akış olabilir.

Dördünü de doğru yapın ve dosya küçük olur. Birini kaçırın ve o, iyi yaptığınız her şeye baskın gelir.

NextPDF’nin yazıcısı tek geçişli, akış tabanlı bir serileştiricidir: her nesnenin byte’larını üretildikçe ekler ve her biri için klasik bir kullanımda cross-reference girdisi kaydeder. O varsayılan hızlı, öngörülebilir ve byte-kararlı bir dosya üretir — ama olası en küçük düzen değildir ve NextPDF bunu dürüstçe söyler.

Bir PDF, dolaylı nesnelerden oluşan bir grafiktir. Çoğu küçük sözlüklerdir: sayfa düğümleri, açıklama sözlükleri, yapı-ağacı öğeleri, taslak girdileri. Her biri sabit bir vergi öder — obj / endobj anahtar sözcükleri, nesne ve nesil numaraları ve onu konumlandıran bir cross-reference girdisi. Binlerce küçük nesneli bir belgede, o vergi dosyanın anlamlı bir dilimidir.

Bir nesne akışı, o küçük akış-dışı nesnelerin çoğunu tek bir akışta toplar ve onları birlikte sıkıştırır (Spec: ISO 32000-2, §7.5.7). obj / endobj zarfı, tüm grup için düşürülür; içerideki değerler, nesne başına anahtar sözcük olmadan, art arda saklanır ve sonra tek bir blok olarak deflate edilir — bu da daha iyi sıkıştırır; çünkü yineleme-eleyen sıkıştırıcı artık o benzer sözlüklerin hepsini bir kerede görür. Cross-reference girdisi yok olmaz — paketlenmiş her nesnenin hâlâ birine ihtiyacı vardır — ama cross-reference akışında kompakt bir ikili tip-2 girdisine küçülür (bununla ilgili daha fazlası Kol 2’de).

NextPDF’de bu, ObjectStreamPacker tarafından sunulur; bitmiş bir cross-reference-akışlı PDF’yi alan ve uygun nesneleri tek bir /Type /ObjStm’e yeniden yazan, bağımsız bir sonradan işleyicidir. İzlediği kurallar doğrudan standarttan gelir: uygun bir nesne, doğrudan adreslenebilir kalması gereken özel nesneler dışlandıktan sonra, nesil-sıfır, akış-dışı bir nesnedir. §7.5.7, bir akış nesnesini bir nesne akışının içinde saklamayı yasaklar; bu yüzden akış nesneleri — içerik, fontlar, görüntüler — kendi girdilerini tutar; ve ObjectStreamPacker ek olarak belgenin kendi cross-reference akış nesnesini (o yeniden yazılır) ve /Encrypt sözlüğünü reddeder; ikisi de doğrudan adreslenebilir kalmalıdır. Nesil-sıfır ve akış-dışı olan diğer her şey paketlenir.

Object stream packing (ObjStm) — edition availability
EditionAvailability
CoreFull support in the open-source core via ObjectStreamPacker. It is opt-in: the single-pass writer’s default emits classic in-use entries, so output stays byte-identical unless you enable packing. The packer is deterministic, with its own reproducible golden baseline.
ProNot in this edition
EnterpriseNot in this edition

İsteğe bağlı olmak, bir kısıtlamanın saklanması değil, bilinçli bir duruştur. Varsayılan çıktı byte-kararlıdır ve mevcut golden temellerle eşleşir; paketlemeyi açmak, farklı, daha küçük, eşit derecede deterministik bir düzene geçmektir. Ödünleşmeyi siz seçersiniz ve motor onu asla arkanızdan yapmaz.

Nesneler bir nesne akışının içinde yaşamaya başladığında, onlara işaret eden dizin biçim değiştirir. Bir okuyucu, paketlenmiş bir nesneyi bir sıkıştırılmış cross-reference girdisi aracılığıyla bulur — nesne akışını ve içindeki dizini adlandıran bir tip-2 girdisi (Spec: ISO 32000-2, §7.5.8.3). Tüm cross-reference’ın kendisi bir /Type /XRef akışı olduğu için, binlerce nesne için olan dizin, düz metin satırları olarak yazılmak yerine ikili-paketlenir ve deflate edilir. Harita, arazinin yanı sıra küçülür.

ObjectStreamPacker tam olarak bunu yeniden inşa eder: tek nesne akışını yayımlar, sonra tutulan her nesne için kompakt bir tip-1 girdisi ve paketlenmiş her nesne için bir tip-2 girdisi taşıyan, yeniden yazılmış bir cross-reference akışı yayımlar; mevcut referansların geçerli kalması için her nesne numarasını korur.

Gerçek görüntülerin olduğu herhangi bir belge için, bu kol diğerlerini cüceleştirir. Byte’lar aynı resimdir; codec, bütçedir. Filtre adları, standart filtre kümesinde yaşar (Spec: ISO 32000-2, §7.4) ve aralarındaki seçim bir boyut kararıdır:

  • FlateDecode kayıpsızdır. Çizgi sanatı, ekran görüntüleri ve düz renkli her şey için kusursuz — ve bir fotoğraf için yıkıcı; orada kayıpsız, özgünün her byte’ı demektir.
  • DCTDecode JPEG’dir: kayıplı ve fotoğraflar için geniş bir farkla doğru tercih, çoğu zaman kimsenin fark etmediği bir kalite düşüşü için on katlık bir azalma.
  • JPXDecode JPEG 2000’dir: farklı bir kalite/boyut eğrisiyle dalgacık sıkıştırma, ama düzensiz destek ve bazı arşivleme profilleri tarafından izin verilmez.

Tam olarak burası, bir filtre nasıl çözerin önemli olduğu yerdir ve bu, Akışlar ve filtreler makalesinin işidir. Ekonomi noktası daha dardır: kayıpsız saklanan bir fotoğraf, gereksizce devasa bir PDF’nin en yaygın tek nedenidir ve hiçbir nesne-akışı paketleme miktarı, gerçek ağırlığı tek bir JPEG’lenmemiş tarama olan bir dosyayı kurtarmaz.

Gömülü bir font, bir programdır. Tam olanı birkaç yüz kilobyte olabilir; çünkü yazı tipi tasarımcısının çizdiği her glifi taşır — bu belgede hiç kullanmayacağınız betikler arasında binlerce karakter. Alt kümeleme, yalnızca belgenin gerçekten çizdiği glifleri gömer; o programı kendisinin küçük bir kesrine çevirir. Tek sayfalık bir mektup, CJK-yetenekli bir fontun tümüne ihtiyaç duymaz; dizdiği birkaç düzine glife ihtiyaç duyar. Gliflerin nasıl seçilip yeniden dizinlendiğinin mekanikleri kendi başına bir konudur — bkz. Fontlar: zor kısım.

  1. 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.
  2. 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.
  3. 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.
  4. The indexA compressed cross-reference stream with type-2 entries binary-packs and deflates the map of every object, replacing plaintext index rows.
Where the bytes go: the four levers an author spends a PDF's size budget on, in the order they typically dominate a real file.

Burada gösterilecek uydurma bir API yoktur; çünkü en önemli boyut kararları, byte’lar yazıcıya ulaşmadan önce verilir — ve NextPDF’nin açtığı tek yapısal kol, isteğe bağlı tek bir anahtardır. Kavramsal olarak bütçe şöyle okunur:

  • Fotoğrafları JPEG olarak besleyin ki DCTDecode altına insinler, kayıpsız yeniden kodlanmasın. En büyük kazanç, bir yazıcı bayrağı değil, kaynak veri hakkında bir seçimdir.
  • Yazıcının gömülü fontları alt kümelemesine izin verin ki yalnızca çizilen glifler gönderilsin.
  • Çok sayıda küçük nesnesi olan bir belge için, nesne-akışı paketlemeyi tercih edin; bu, bitmiş dosyayı ObjectStreamPacker üzerinden yönlendirir; küçük akış-dışı nesneleri gruplar ve cross-reference akışını yeniden yazar.

Varsayılan yol — klasik kullanımda girdiler, ObjStm yok — doğru temeldir: deterministik, byte-kararlı ve doğrulaması kolay. Paketleme, dosyayı şişiren şeyin görüntü ağırlığı değil, nesne sayısı olduğunda düşünülmüş yükseltmedir.

Tuzak, bir “PDF’yi sıkıştır” düğmesine uzanmak ve onun her şeyi düzelteceğini beklemektir. Sıkıştırma tek bir kol değildir; dörttür ve birbirlerinin yerine geçmezler. Nesne-akışı paketleme bir fotoğrafı küçültemez — o, görüntü filtresinin işidir. Kusursuz bir JPEG, alt kümelemeyi unuttuğunuz bir fontu telafi edemez. Ve gerçek şişkinlik, kimse onun için DCTDecode seçmediği için kayıpsız saklanan 10 MB’lik bir tarama ise, bunların hiçbiri yardımcı olmaz.

İkinci yanlış kanı, daha küçüğün her zaman kesinlikle daha iyi olduğudur. Değildir. Nesne akışları, linearization ile uyumsuzdur — ilk sayfanın erken akması için mutlak nesne yerleşimini sabitleyen fast-web-view düzeni. Ve bazı arşivleme profilleri, hangi görüntü filtrelerine izin verildiğini bile kısıtlar. Boyut bir eksendir. Akış, arşivleme uygunluğu ve yeniden üretilebilirlik ile takas eder ve eğri üzerindeki doğru nokta, belgenin ne için olduğuna bağlıdır.

Dört kol, dosya boyutunun yapısal ekonomisidir. Evrensel bir “küçült” garantisi değildir ve NextPDF, gelişigüzel gelen PDF’ler için bir yeniden-iyileştirici olmaya çalışmaz.

ObjectStreamPacker, doğruluğu asla tehlikeye atmayan, en-iyi-çaba bir iyileştirmedir. Reddeder — girdiyi değiştirmeden döndürür — şu durumlarda: dosya bir cross-reference-akışlı PDF olmadığında, şifreliyken, bir dijital imza taşıdığında (nesneleri yeniden yerleştirmek, bir imzanın koruduğu byte aralıklarını kaydırır), zaten nesne akışları içerdiğinde ya da paketlenecek uygun bir nesne olmadığında. Tüm belge için tam olarak bir nesne akışı yayımlar; bir /Extends koleksiyonuna bölmez; bu kapsam dışıdır ve NextPDF’nin ürettiği belge boyutları için uygundur.

Görüntü ve font kolları, büyük ölçüde girdi hakkında kararlardır. NextPDF’nin yazıcısı, kayıpsız bir bit eşlemi örtük olarak kayıplı bir görüntü akışına dönüştürmez — bir fotoğrafı DCTDecode ya da JPXDecode’a yeniden kodlamak, açık bir yukarı yön görüntü-kodlama kararıdır, serileştiricinin arkanızdan yaptığı bir şey değil — ne de çağıranın tam olarak gömmesini istediği bir fonttan glifleri geri kazanır. En büyük boyut kazançları, byte serileştiricisinin yukarısında verilir; motorun işi, ona getirdiğiniz bütçeyi boşa harcamamaktır.

  • Nesne akışı (ObjStm) — birçok küçük akış-dışı dolaylı nesneyi birlikte sıkıştırılmış olarak tutan tek bir akış; böylece obj / endobj zarfı grup için düşürülür. Paketlenmiş her nesne kendi cross-reference girdisini hâlâ tutar, kompakt bir tip-2 girdisi olarak. NextPDF’de isteğe bağlıdır.
  • Dolaylı nesne (indirect object) — bir PDF’nin grafiğinde numaralı bir nesne; bir obj / endobj zarfına sarılı ve cross-reference dizini tarafından izlenir. Zarf, nesne başına ek yüktür.
  • Cross-reference akışı — her nesneyi dizinleyen /Type /XRef akışı; düz metin satırları olarak yazılmak yerine ikili-paketlenir ve deflate edilir.
  • Sıkıştırılmış (tip-2) girdi — bir nesne akışının içinde yaşayan bir nesneye işaret eden, akışı ve içindeki dizini adlandıran bir cross-reference girdisi.
  • Font alt kümeleme (font subsetting) — tam yazı tipi yerine, bir belgenin gerçekten çizdiği yalnızca glifleri gömmek; gömülü font programını küçültür.
  • Kayıpsız ile kayıplı filtre — kayıpsız bir codec (FlateDecode) her byte’ı yeniden üretir; kayıplı bir görüntü codec’i (DCTDecode ya da kayıplı bir kipte JPXDecode), çok daha küçük bir sonuç için algılanamaz ayrıntıyı atar. (JPEG 2000 / JPX, kayıpsız da yapılandırılabilir.) Seçim, medya-ağırlıklı bir dosyada baskın koldur.