Teknik Makale

Pages Sözlüğü Olmayan PDF: Ayrıştırma Etkileri

PDF Katalog sözlüğünün tam olarak bir gerekli gezinme anahtarı vardır: /Pages. Bu anahtar, /Pages türünde dolaylı bir nesneye işaret etmelidir ve bu nesne de sırasıyla /Kids dizisini ve toplam sayfa sayısını (/Count) tutar. Bu işaretçiyi kaldırırsanız, uyumlu hiçbir okuyucu dosyadaki tek bir sayfayı bile bulamaz. ISO 32000-1 §7.7.2 bu konuda çok nettir: Kataloğun bir /Pages girişi olmalı ve başvurulan nesnenin türü /Pages olmalıdır. Bu gereksinimi ihlal eden dosyalar yalnızca uyumsuz olmakla kalmaz; çoğu ayrıştırıcının kötü bir şekilde ele aldığı yapısal olarak bozuk bir hale gelirler

Spesifikasyon aslında ne diyor

Minimal düzeyde uyumlu bir PDF'in en az üç nesnesi vardır. Nesne 1 Katalog, nesne 2 Pages kökü ve nesne 3 ve sonrakiler tek tek Page sözlükleridir. Katalog, Pages köküne işaret eder; Pages kökü çocuklarını /Kids içinde listeler; her Page (Sayfa) bir /Parent geri başvurusu taşır. Tüm zincir tasarımsal olarak iki yönlüdür, bu nedenle bir ayrıştırıcı her iki uçtan da başlayabilir ve dengeli ağaçlar için O(log n) süresinde herhangi bir sayfaya geçiş yapabilir

% Minimal conforming structure (ISO 32000-1 §7.7.2)
1 0 obj
<< /Type /Catalog /Pages 2 0 R >>
endobj

2 0 obj
<< /Type /Pages /Kids [3 0 R 4 0 R] /Count 2 >>
endobj

3 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 612 792] /Contents 5 0 R /Resources << >> >>
endobj

4 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 612 792] /Contents 6 0 R /Resources << >> >>
endobj

Pages ağacı iç içe yerleştirilebilir. Binlerce sayfası olan bir belge genellikle sayfaları /Pages türünü taşıyan, her biri kendi /Kids değerine ve altındaki alt ağacı yansıtan bir /Count değerine sahip ara düğüm nesneleri halinde gruplandırır. Kök düğümün /Count değeri her zaman toplam sayfa sayısına eşittir. Bu sayı, görüntüleyicilerin tek bir sayfayı bile ayrıştırmadan önce sayfa numarası alanında gösterdikleri sayıdır, çünkü nesne 2'den bir tam sayı okumak tüm ağacı dolaşmaktan çok daha az maliyetlidir

Pages sözlüğü olmayan bir dosya neye benzer

Pages sözlüğü eksik olan dosyalar genellikle sayfa nesnelerini bir ağaçta birleştirmeden doğrudan yazan PDF oluşturuculardan veya yaprak Page nesnelerini sağlam bırakırken kök düğümü kaldıran bozulmalardan kaynaklanır. Böyle bir dosyadaki Katalog ya /Pages anahtarından tamamen yoksundur ya da çapraz başvuru tablosunda artık var olmayan bir nesneye başvuru tutar

% Non-conforming: Catalog with no /Pages reference
1 0 obj
<< /Type /Catalog >>
endobj

% Page objects exist but are unreachable from the Catalog
5 0 obj
<< /Type /Page /MediaBox [0 0 612 792] /Contents 6 0 R /Resources << >> >>
endobj

15 0 obj
<< /Type /Page /MediaBox [0 0 612 792] /Contents 16 0 R /Resources << >> >>
endobj

25 0 obj
<< /Type /Page /MediaBox [0 0 612 792] /Contents 26 0 R /Resources << >> >>
endobj

Spesifikasyonu takip eden bir ayrıştırıcı Kataloğu okur, /Pages referansını çözümlemeye çalışır, hiçbir şey (veya ölü bir başvuru) bulamaz ve ya bir hata verir ya da sıfır sayfa bildirir. Yapmaması gereken şey, sanki dosyada sıfır sayfa varmış gibi devam etmek ve sessizce başarılı olmaktır; bu, otomatik araçlara doğru ama onu açan her insana yanlış görünen boş bir çıktı üretir

Ayrıştırıcılar neden çöker

Çoğu PDF ayrıştırıcısı, dahili sayfa tablosunu yükleme sırasında Pages kökündeki /Count değerine göre tahsis eder. Bu kök bulunmadığında, ayrıştırıcı ya sıfır okur, hiçbir şey tahsis etmez ve ardından herhangi bir kod sayfa 1'i ilk istediğinde boş (null) bir işaretçiyi başvurudan çıkarır ya da çöp veri okur ve son derece yanlış bir arabellek tahsis eder. İki sonuç da iyi değildir. Böyle bir dosyayı işlemekten kaynaklanan çökme günlüklerinde görünen 0x008E5D78 adresindeki erişim ihlali tam olarak şudur: ayrıştırıcının her zaman orada olacağını varsaydığı yapının yokluğuyla tetiklenen, sayfa erişim yolu içindeki boş işaretçi başvurusunun kaldırılması

Bunun temelindeki tasarım varsayımı makuldür. Var olan PDF'lerin büyük çoğunluğunda bir Pages sözlüğü vardır. Birkaç komuttan tasarruf etmek için varlık kontrolünü atlayan ayrıştırıcılar pervasız değildir; onlar sadece yaygın durumlar için optimizasyon yaparlar. Bu optimizasyonu cezalandıran dosyalar o kadar nadirdir ki, üretim kodu bunlardan biriyle asla karşılaşmayabilir ve karşılaştığında, mühendis §7.7.2'yi okumamışsa çökme hem tekrarlanabilir hem de kafa karıştırıcı olur

Pages ağacı olmadan kurtarma

Eğer bir ayrıştırıcı bu dosyaları reddetmek yerine ele almak zorundaysa, kurtarma öngörülebilir bir yolu izler: çapraz başvuru tablosundaki her bir dolaylı nesneyi tarayın, /Type /Page olanları toplayın ve nesne numarasına göre sıralayın. Nesne numarası sırasının spesifikasyondaki okuma sırasıyla eşleşmesi garanti edilmez, ancak pratikte, Pages ağacını atlayan oluşturucular sayfaları sıralı olarak verme eğilimindedir, bu nedenle nesne numarası sırası genellikle doğrudur

Kontrolün kendisi ucuzdur. Kataloğun /Pages işaretçisinde gezinmeden önce, işaretçinin var olduğunu, gerçek bir nesneye çözümlendiğini ve çözümlenen nesnenin /Type değerinin /Pages'e eşit olduğunu doğrulayın. Bu üç koşuldan herhangi biri başarısız olursa, doğrusal taramaya geçin. Tarama, büyük belgeler için ağaç geçişinden daha yavaştır, çünkü dengeli bir yolu izlemek yerine her bir nesne başlığını okur, ancak işe yarar ve zaten bozuk olan bir dosya için doğruluk hızdan daha önemlidir

Doğrusal taramanın otomatik olarak çözmediği bir uç durum vardır: sayfa sıralaması. Sırayı tanımlayacak bir /Kids dizisi olmadan, "doğru" sıra spesifikasyona göre tanımsızdır. Nesne numarası sırası pragmatik varsayılandır; eğer dosya dikkatlice işlenecek kadar önemliyse, Page nesnelerinin açık bir /StructParents taşıyıp taşımadığını veya bir okuma sırasını ima eden ek açıklama referansları taşıyıp taşımadığını kontrol etmek ekstra çabaya değer

PDF oluşturucular için etkiler

Bir ayrıştırıcı yerine bir PDF oluşturucu yazan herkes için çıkarılacak ders çok nettir: dosyayı kapatmadan önce daima Pages kökünü ekleyin. /Pages girişi olmayan bir Katalog, spesifikasyonun hiçbir revizyonu altında geçerli bir PDF değildir. Sayfa nesnelerini anında oluşturan ve ağacı sonlandırma aşamasında birleştiren oluşturucular (çoğu akış (streaming) yazarının kullandığı yaklaşım), sonlandırma gerçekten çalıştığı sürece iyidir. Yaygın başarısızlık durumu, treyler tamamlanmadan önce yazmayı iptal eden bir istisna veya erken dönüştür; bu da arkasında bazı görüntüleyicilerde (kurtarma sezgisel yöntemleri olan) açılan ve diğerlerinde (olmayanlarda) başarısız olan bir dosya bırakır

PDF/A ve PDF/UA, sayfa ağacına temel spesifikasyonun gerektirdiğinin ötesinde ek kısıtlamalar getirir, ancak hiçbiri /Pages gereksinimini gevşetmez. ISO 19005 veya ISO 14289'a uygunluğu kontrol eden bir doğrulayıcı, eksik bir Pages sözlüğünü profile özgü kurallara ulaşmadan önce bile temel spesifikasyon ihlali olarak yakalayacaktır