Bir PDF dosyası, özünde, birbirine işaret eden nesnelerden oluşan bir koleksiyondur. Sıkıştırmayı, çapraz başvuru kayıtlarını ve bayt ofsetlerini çıkardığınızda geriye kalan bir grafiktir: referanslarla birbirine bağlanmış, okuyucunun nasıl bulacağını bildiği tek bir nesnede köklenen küçük bir türlendirilmiş değerler kümesi. Bir paragraf metinden gömülü bir yazı tipine veya dijital bir imzaya kadar bir PDF'in ifade edebileceği her şey, sekiz temel nesne türünden ve bir nesnenin diğerine başvurmasına izin veren kuraldan oluşturulur. Bunları öğrendiğinizde, formatın geri kalanı bir gizemden ziyade bir kompozisyon olarak okunur
Bu, ISO 32000-1 madde 7.3'te tanımlanan PDF'in mantıksal katmanıdır ve fiziksel dosya düzeninin (başlık (header), gövde, çapraz başvuru tablosu ve PDF dosya yapısına teknik genel bakış makalesinde kendi başına bir konu olan treyler) bir seviye üzerinde yer alır. Mantıksal model, bu baytların ayrıştırıldıktan sonra ne anlama geldiğidir. Bir görüntüleyici treyleri bulmak için dosyayı geriye doğru okur, köke (root) kadar onu takip eder ve oradan belge, nesnelere başvuran nesneler olarak açılır. Bu, hatalı biçimlendirilmiş bir sayfada hata ayıklarken, bir ayrıştırıcı yazarken veya bir belgeyi birleştirmesi için bir kütüphaneye güvendiğinizde üzerinde düşündüğünüz kısımdır
Sekiz nesne türü ve başka hiçbir şey yok
PDF tam olarak sekiz temel nesne türü tanımlar. Bir belgedeki her değer bunlardan biridir ve formatın bu kadar kapsamlı olmasına rağmen yönetilebilir kalmasını sağlayan şey de budur
Boolean'lar true (doğru) ve false (yanlış) anahtar kelimeleridir. Bir ek açıklamanın (annotation) yazdırılıp yazdırılmayacağı gibi bayrakları (flag) açıp kapatırlar
Sayılar (Numbers) spesifikasyonun tek bir tür olarak ele aldığı iki çeşide sahiptir: 42 gibi tam sayılar (integer) ve 3.14 veya -0.002 gibi gerçek sayılar (real). PDF'in üslü gösterimi yoktur, bu nedenle uyumlu bir dosyada asla 1e6 göremezsiniz. Koordinatlar, yazı tipi boyutları ve döndürme açıları hep sayıdır
Dizeler (Strings), parantez içinde (Hello) veya açılı ayraçlar içinde onaltılık (hexadecimal) olarak <48656C6C6F> şeklinde yazılan bayt dizilerini tutar. Her iki gösterim de aynı içeriği kodlar; hex, parantez içinde tuhaf duran baytlar için bir kaçış yoludur. Dizeler metin taşır, ancak bunlar önce bayttır, ki ASCII'nin ötesinde bir şeyi işlediğiniz anda bu önem kazanır
İsimler (Names), eğik çizgi ile başlayan atomik belirteçlerdir: /Type, /Pages, /MediaBox. İsim bir dize değildir; bir sözlük anahtarı veya numaralandırılmış bir değer olarak kullanılan bir tanımlayıcıdır ve iki isim yalnızca bayt bayt eşleşirlerse eşittir. Eğik çizgi sözdizimidir (syntax), ismin bir parçası değildir. Bu, /Times-Roman ile (Times-Roman) dizesini birbirinin yerine kullanılabilirmiş gibi gören yeni başlayanları yanıltır; format bunu böyle görmez
Diziler (Arrays), köşeli parantezler içindeki sıralı, heterojen listelerdir: [0 0 612 792] bir sayfa dikdörtgenidir ve bir dizi, diğer nesnelere yapılan referanslar dahil olmak üzere türleri serbestçe karıştırabilir. Sözlükler (Dictionaries) ise işin yükünü çeken asıl kısımdır. << ve >> arasında yazılan bir sözlük, isim anahtarlarını herhangi bir türdeki değerlerle eşleştirir ve PDF'deki sayfa, katalog, yazı tipi, ek açıklama gibi hemen hemen her anlamlı yapı, ne olduğunu bildiren bir /Type anahtarına sahip bir sözlüktür
Akışlar (Streams), stream ve endstream anahtar kelimeleri arasında bir dizi ham bayt kuyruğuna sahip sözlüklerdir. Sözlük, baytları (uzunluklarını ve onları sıkıştıran FlateDecode gibi herhangi bir filtreyi) açıklar ve baytlar büyük boyutlu yükü taşır: sayfa içeriği talimatları, gömülü yazı tipi programları, görüntüler. Akış, PDF'in satır içi (inline) olarak yerleştirilemeyecek kadar büyük veya çok fazla ikili (binary) veriyi koyduğu yerdir
Sekizinci tür, null anahtar kelimesi olan boş nesnedir (null object). Bu, bir anahtarın eksik olmasından farklı olarak gerçek bir değerdir. null olarak ayarlanan bir sözlük girdisi hiç yokmuş gibi değerlendirilir ve var olmayan bir nesneye çözümlenen bir referans da bir hata yerine null verir. Bu affedici davranış kasıtlıdır: hasarlı bir dosyanın açılmayı reddetmek yerine işlevlerini kısıtlayarak açılabilmesini sağlar. Dokuzuncu bir tür yoktur; PDF'in ifade ettiği her şey bu sekizinin nasıl birleştiğinden kaynaklanır
Doğrudan değerler, dolaylı nesneler ve referanslar
Bu sekiz türden herhangi biri iki şekilde görünebilir. Doğrudan (direct) bir nesne, bir MediaBox dizisindeki 612 gibi yerinde yazılır. Dolaylı (indirect) bir nesneye, diğer nesnelerin ona işaret edebilmesi için bir kimlik verilir: bir nesne numarası ve bir nesil (generation) numarası olan iki tam sayı, tanımı obj ve endobj içine sarar:
12 0 obj
<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>
endobj
Bu, nesne 12, nesil 0 olan bir yazı tipi sözlüğüdür. Dosyanın başka bir yerinde, başka bir nesne ona dolaylı bir referansla (indirect reference) başvurur: aynı iki numarayı takiben R anahtar kelimesi, 12 0 R. Referans bir işaretçidir. Bir sayfanın kaynak (resource) sözlüğü /Font << /F1 12 0 R >> dediğinde, yazı tipinin tanımını sayfaya kopyalamadan, nesne 12'yi /F1 kaynak adının arkasındaki yazı tipi olarak adlandırır
Nesil numarası silme işlemleri ve yeniden kullanım için mevcuttur. Bir nesne serbest bırakıldığında ve yuvası (slot) yeniden kullanıldığında nesil artar, böylece eski bir 12 0 R referansı yuva 12'nin yeni kiracısına çözümlenemez. Yeni yazılmış dosyaların neredeyse tamamı 0. nesildir, ancak yoğun şekilde düzenlenmiş bir dosya daha yüksek numaralar taşıyabilir ve nesli görmezden gelen bir ayrıştırıcı eninde sonunda yanlış nesneyi okuyacaktır
Dolaylılık, PDF'i verimli ve düzenlenebilir kılan şeydir. Bir yazı tipi, görüntü veya renk uzayı bir kez tanımlanabilir ve yüz sayfadan referans gösterilebilir. Küçük bir değişiklik, dosyayı yeniden yazmak yerine tek bir nesnenin yerini alan yeni bir revizyon olarak eklenebilir. Çapraz başvuru tablosu, bir nesne numarasını bir bayt ofsetine dönüştüren dizindir, böylece okuyucu tarama yapmadan doğrudan 12 0 obj konumuna atlar, ancak bu fiziksel bir optimizasyondur. Mantıksal olarak tek bilmeniz gereken 12 0 R'nin "12 0 olarak tanımlanan nesne" anlamına geldiğidir
Katalog: her belgenin başladığı yer
Referansları çözümlemenin bir yerden başlaması gerekir ve o yer treylerin /Root girdisidir. Bu girdi belge kataloğuna (document catalog) işaret eder: nesne grafiğinin kökü, /Type /Catalog içeren bir sözlük. Okuyucu ona önce ulaşır çünkü önce treyler bulunur ve oradan referansları takip ederek belgenin diğer her yerine ulaşılabilir
Katalog kesinlikle gerekli sadece iki girdi taşır: /Type ve sayfa ağacının köküne dolaylı bir referans olan /Pages. Geri kalanı isteğe bağlıdır ve içerikten ziyade belge çapındaki davranışı açıklar: /Outlines yer işareti (bookmark) ağacına işaret eder, /Names dizelerle anahtarlanmış isim ağaçlarını tutar, /Metadata bir XMP meta veri akışına başvurur ve /PageMode ile /PageLayout bir görüntüleyicinin belgeyi nasıl açması gerektiğini önerir. Sayfayı oluşturmak için bunların hiçbirine ihtiyaç yoktur; bunlar sayfaların etrafındaki deneyimi yapılandırır. Kataloğa bağlı yer işareti, meta veriler ve ek açıklama (annotation) yapıları, PDF meta verileri, yer işaretleri ve ek açıklamaları hakkındaki makalede ele alınmaktadır
Aşağıdaki diyagram, nesne gövdesinin dosyanın neresinde yer aldığını göstermektedir. Katalog ve sayfa ağacı bu gövde içinde sıradan dolaylı nesneler olarak yaşar; etraflarındaki başlık, çapraz başvuru tablosu ve treyler, bir okuyucunun onları bulmasını sağlayan fiziksel yapı iskelesidir

Sayfa ağacı: sayfaların dengeli bir hiyerarşisi
/Pages'den belge, PDF'in düz bir liste yerine grafik (graph) tercihinin karşılığını verdiği sayfa ağacına dallanır. Sayfalar basit bir dizi olarak saklanmaz; iç düğümleri sayfa ağacı düğümleri (/Type /Pages) ve yaprakları sayfa nesneleri (/Type /Page) olan bir ağaçtan sarkarlar. Bir iç düğüm, çocuklarını /Kids dizisinde listeler ve altında kaç tane yaprak sayfa olduğunu /Count içine kaydeder. Kök hariç her düğüm geriye dönük bir /Parent referansı taşır, böylece ağaç her iki yönde de yürünebilir
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
Burada nesne 2 köktür ve altında üç sayfa vardır: yaprak sayfa 3, artı iç düğüm 4 aracılığıyla ulaşılabilen iki tane daha. Kökün 3 olan /Count değeri, altındaki toplam yapraklara eşit olmalıdır ve gerçek yapıyla uyuşmayan bir sayı, elle düzenlenmiş bir dosyanın yanlış gitmesinin yaygın bir yoludur. Ağacın amacı, erişimin lokalliğidir. Bin sayfalık bir belgenin 900. sayfasını açan bir okuyucu 900 nesne dolaşmaz; bir avuç düğüme iner, çünkü iyi oluşturulmuş bir ağaç sığ ve dengeli kalır. Böyle bir ağacı elle oluşturmak, baştan sona görmeye değecek kadar zahmetlidir, ki sıfırdan bir PDF belgesi oluşturma hakkındaki kılavuz tam olarak bunu yapmaktadır
Ağaç, ikinci önemli faydasını kalıtım (inheritance) yoluyla sağlar. Bir avuç sayfa özniteliği (/Resources, /MediaBox, /CropBox ve /Rotate) bir iç düğümde ayarlanabilir ve tek tek sayfalarından çıkarılabilir, ki bu sayfalar daha sonra en yakın atanın değerini devralır. Kök üzerinde /MediaBox'ı bir kez ayarlarsanız, her yaprak tekrarlamaya gerek kalmadan aynı sayfa boyutunu alır; farklı olması gereken bir sayfa kendi boyutunu bildirir. Bu, nesne modelinde bir değerin anlamının yalnızca kendi içeriğine değil, aynı zamanda nesnenin ağaçtaki konumuna bağlı olduğu tek yerdir
Bir yaprak sayfa aslında ne tutar
Bir sayfa nesnesi, yapısal model ile görünür içerik arasındaki birleşim noktasıdır. Onun /Contents girdisi, metni ve grafikleri sayfaya çizen çizim operatörleri olan bir veya daha fazla içerik akışına (content stream) başvurur. /Resources sözlüğü, o operatörlerin dayandığı yazı tiplerini, görüntüleri ve renk uzaylarını adlandırır ve her girdi sayfalar arasında paylaşılan bir nesneye yapılan dolaylı bir referanstır. /MediaBox, sayfa dikdörtgenini nokta (point) cinsinden (inçin 1/72'si) verir ve /Rotate ile /CropBox gibi girdiler sayfanın nasıl sunulacağını ayarlar
Bu işbölümü tüm modelin minyatür halidir. Sayfa sözlüğü yapıdır: sayfanın ne olduğunu ve neyle çizim yaptığını söyleyen türlendirilmiş girdiler ve referanslar. İçerik akışı talimatlardır: nasıl çizileceğini anlatan ayrı, sıkıştırılabilir bir yığın (blob). /F1 arkasındaki yazı tipi, bir kez tanımlanan ve kullanıldığı her yerde işaret edilen paylaşılan bir kaynaktır. Sözlük, akış ve referans bir sayfayı oluşturmak için işbirliği yapar ve aynı desenler (patterns) tüm belgeye ölçeklenir. O yığının içindeki içerik akışı operatörleri, metin ve yazı tipleri ile grafikler ve görsel öğeler için ayrı ayrı ele alınmaktadır
Bu modeli bilmeye neden değer
Çoğu geliştirici nesne modeliyle yalnızca bir şeyler bozulduğunda karşılaşır: bir sayfa boş görünür çünkü onun /Contents referansı boşlukta sallanıyordur (dangling), metin kutular (boxes) halinde çıkar çünkü bir yazı tipi kaynağı hiçbir zaman gömülmemiştir, bir araç bulabildiği sayfa sayısıyla uyuşmayan bir /Count bildirir. Bunların her biri grafik hakkında bir ifadedir ve grafiği doğrudan okumak tahminde bulunmaktan daha iyidir. Sekiz tür ve referans kuralı, akılda tutulacak kadar küçük bir kelime dağarcığıdır ve bir PDF'i nesnelere işaret eden nesneler olarak gördüğünüzde, hatalı oluşturulmuş dosyalar artık anlaşılmaz olmaktan çıkar
Bununla birlikte, öğrenme amacı dışında modeli elle yazmak nadiren doğru karardır. Çapraz başvuru ofsetlerini, nesil numaralarını, sayfa ağacı sayılarını ve akış uzunluklarını düzenlemeler boyunca tutarlı bir şekilde korumak, bir kütüphanenin üstesinden gelmek için var olduğu bir kayıt tutma türüdür. Üretimde (production), olgunlaşmış bir PDF geliştirme kütüphanesi sizin sayfalara ve içeriğe odaklanmanıza izin verirken nesne grafiğini yönetir. Ancak modeli bilmek yine de faydalıdır: kütüphanenin arka planda ne oluşturduğunu ve nedenini anlarsınız