Teknik Makale

PDF Meta Verileri, Ana Hatları ve Ek Açıklamaları Açıklandı

Sayfa açıklamalarını çıkardığınızda, geriye kimsenin yazdırmadığı ancak her okuyucunun, dizinleyicinin ve arşiv sisteminin bağlı olduğu ince bir yapı katmanı kalır. Bir sayfa nesnesi ait olduğu bölüm, onu yazan yazar veya başka bir yere bağlanan dipnot hakkında hiçbir şey bilmez. Bu bilgi bir üst seviyede, belge kataloğuna eklenmiş üç yapıda bulunur: meta veri akışları (metadata streams), ana hat ağacı (outline tree) ve sayfa başına ek açıklama dizileri (annotation arrays). Bu yapılar, yanlış yapılmalarını kolaylaştıran bir özelliği paylaşırlar. Hiçbiri sayfada görünür işaretler taşımaz; bu nedenle bir dosya kusursuz bir şekilde oluşturulabilir ancak yine de yer imleri (bookmarks) eksik olabilir, kendi yazar alanıyla çelişebilir veya artık var olmayan bir sayfa nesnesine bağlantı işaret edebilir

Bu, bir PDF kütüphanesinin belge özellikleri, yer imi API'leri ve bağlantı veya ek açıklama çağrıları olarak sunduğu katmandır; aynı zamanda bir arama tarayıcısının belgenizin ne hakkında olduğuna karar vermek için okuduğu katmandır. Altındaki nesne modeli, PDF belge yapısı incelemesi bölümünde ele alınmıştır. Burada odak noktası kesinlikle kataloğa nelerin bağlı olduğudur

Her üç yapı da kataloğa bağlanır. Bunları birbirine bağlayan eksiksiz bir katalog şöyle görünür:

1 0 obj
<< /Type /Catalog
   /Pages 2 0 R
   /Outlines 3 0 R
   /Names << /EmbeddedFiles 4 0 R >>
   /Metadata 5 0 R
>>
endobj

Dört girdi, dört bağımsız alt sistem. /Pages görünür belgedir; /Outlines yer imi ağacıdır; /Metadata XMP akışını işaret eder; /Names ise diğer şeylerin yanı sıra gömülü dosya eklerini tutan belge çapındaki ad sözlüğüne (name dictionary) ulaşır. Her biri isteğe bağlıdır ve hiçbirini bulamayan bir okuyucu yine de sayfaları gösterir. Bu isteğe bağlılık, bir dosya yalnızca sayfaları anlayan araçlar tarafından düzenlendiğinde gezinme katmanının ilk çürüyen şey olmasının tam olarak nedenidir

Anlaşmazlığa düşen iki meta veri deposu

PDF, belge meta verilerini aynı anda iki yerde taşır ve sorunlar farklı şeyler söylediklerinde başlar. Orijinal mekanizma, fragmanda (trailer) /Info tarafından referans verilen belge bilgi sözlüğüdür: /Title, /Author, /Subject, /Keywords, /Creator, /Producer ve iki tarih için düz bir anahtar-değer çifti seti. Basittir ve her görüntüleyici (viewer) bunu okur. PDF 2.0, ikinci mekanizma olan XMP meta veri akışı lehine bunun çoğunu kullanımdan kaldırmıştır

XMP, RDF dilinde yazılmış, kataloğun /Metadata üzerinden ulaştığı ve /Type /Metadata /Subtype /XML olarak işaretlenmiş bir akış olarak depolanan, bağımsız (self-contained) bir XML belgesidir. PDF nesne yapısının içine gömülmüş Info sözlüğünün aksine, bir XMP paketi PDF hakkında hiçbir şey bilmeyen araçlar tarafından tek başına çıkarılıp ayrıştırılacak şekilde tasarlanmıştır. İşte temsil edici bir paket:

5 0 obj
<< /Type /Metadata /Subtype /XML /Length 1235 >>
stream
<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
<x:xmpmeta xmlns:x="adobe:ns:meta/">
  <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
    <rdf:Description rdf:about=""
        xmlns:dc="http://purl.org/dc/elements/1.1/"
        xmlns:xmp="http://ns.adobe.com/xap/1.0/"
        xmlns:pdf="http://ns.adobe.com/pdf/1.3/">
      <dc:title><rdf:Alt><rdf:li xml:lang="x-default">Quarterly Report</rdf:li></rdf:Alt></dc:title>
      <dc:creator><rdf:Seq><rdf:li>A. Author</rdf:li></rdf:Seq></dc:creator>
      <xmp:CreateDate>2026-06-16T10:46:27+08:00</xmp:CreateDate>
      <xmp:CreatorTool>Reporting Service 4.2</xmp:CreatorTool>
      <pdf:Producer>losLab PDF Library</pdf:Producer>
    </rdf:Description>
  </rdf:RDF>
</x:xmpmeta>
<?xpacket end="w"?>
endstream
endobj

Bu bloktaki üç ayrıntı, meta verilerin gerçek araçlarla temasta hayatta kalıp kalmayacağını belirler. xpacket işleme talimatları bir dekorasyon değildir: paketi çerçevelerler, böylece bir çıkarıcı (extractor) onu daha büyük bir bayt akışında bulabilir ve kapanış <?xpacket end="w"?> etiketini atlayan bir yazıcı, sorunsuz açılan ancak katı doğrulayıcıları tetikleyen bir dosya üretir. Özellik veri türleri de önemlidir. dc:title rdf:Alt içine sarılmış bir dil alternatifiyken, dc:creator sıralı bir listedir ve rdf:Seq alır; bunlardan herhangi birini çıplak bir metin düğümü olarak yayınlamak, bunu tolere etmeyen görüntüleyiciye rastlayana kadar çoğu görüntüleyici tarafından tolere edilen en yaygın XMP hatasıdır. Ad alanı ön ekleri (namespace prefixes) gelenekseldir, ancak bağlandıkları URI'ler kuralcıdır: bir ayrıştırıcı ön eke değil, URI'ye göre anahtar belirler

İki depo ile ilgili kesin kural, bunların aynı fikirde olmaları gerektiğidir. Eğer /Info yazarın bir kişi olduğunu söyler ve dc:creator başka birini adlandırırsa, aynı soruya iki farklı şekilde cevap veren bir belge göndermiş olursunuz ve hangi cevabın kazanacağı, tüketen aracın hangi alanı okuduğuna bağlıdır. Bir kütüphane genellikle her ikisini de sizin için yazar, ancak birini elle düzenlediğiniz veya farklı oluşturuculardan dosyaları birleştirdiğiniz an, bu ikisi birbirinden uzaklaşır. Info sözlüğünü eski uyumluluk (legacy compatibility) ve XMP'yi de doğruluk kaynağı (source of truth) olarak değerlendirin ve ikisini bağımsız olarak yamalamak yerine tek bir değerler kümesinden yeniden oluşturun. PDF/A için bu bir uygunluk gereksinimi haline gelir: ISO 19005, XMP'yi zorunlu kılar ve XMP karşılığıyla çelişen herhangi bir Info özelliğini yasaklar

Yer imi panelinin arkasındaki ana hat ağacı

Bir görüntüleyicinin yer imleri (bookmarks) paneli olarak gösterdiği şey, dosyada, belge ana hattı (document outline) adı verilen çift bağlantılı bir sözlük ağacıdır. Katalog, /Outlines aracılığıyla bir kök ana hat sözlüğüne (root outline dictionary) işaret eder; kök, ilk ve son üst düzey öğelerine işaret eder; ve her öğe komşularına ve ebeveynine (parent) bağlanır. Hiçbir yerde bir yer imi dizisi yoktur. Tüm yapı referansları takip ederek yeniden oluşturulur, bu da tam olarak tek bir bozuk bağlantının herhangi bir hata vermeden tüm bir dalın panelden kaybolmasına neden olmasının nedenidir

8 0 obj                                    % the outline root
<< /Type /Outlines /Count 4 /First 9 0 R /Last 9 0 R >>
endobj
9 0 obj                                    % top-level: a chapter
<< /Title (Chapter 1: Results)
   /Parent 8 0 R /Count 2
   /First 12 0 R /Last 15 0 R >>
endobj
12 0 obj                                   % first child
<< /Title (Introduction)
   /Parent 9 0 R /Next 15 0 R
   /Dest [3 0 R /XYZ 72 720 0] >>
endobj
15 0 obj                                   % second child, last sibling
<< /Title (Methodology)
   /Parent 9 0 R /Prev 12 0 R
   /Dest [3 0 R /Fit] >>
endobj

Bağlantıları okuduğunuzda değişmezler açıkça görülür. Her öğe kendi /Parent öğesini işaret eder. Kardeşler (siblings), /Prev ve /Next yoluyla bir zincir oluşturur; ilk öğe /Prev öğesini, son öğe ise /Next öğesini atlar. Bir ebeveyn, ilk ve son çocuklarını /First ve /Last yoluyla adlandırır ve aradaki çocuklara yalnızca kardeş zincirini yürüyerek ulaşılabilir. Birini yanlış yaparsanız hata sessizdir: bayat bir /Next bir bölümü keser, zinciri sonlandırmayan /Last değerine sahip bir ebeveyn öğeleri öksüz bırakır ve görüntüleyici ulaşabildiği her şeyi oluşturur

/Count alanı, insanları şaşırtan bir durum parçası taşır. Kök üzerinde ve genişletilmiş (expanded) herhangi bir öğede şu anda görünür olan soy (descendant) sayısını tutar; daraltılmış (collapsed) bir öğede ise genişletme durumunda kaç soy görüneceğinin büyüklüğünü temsil eden negatif bir sayıdır. Yani /Count ağaç hakkında sabit bir yapısal gerçek değildir, panelin kaydedilmiş açık veya kapalı durumudur ve bunu pozitif bir toplam olarak sabit kodlayan bir oluşturucu, yazarın kapalı bırakmak istediği her dalı yeniden açar

Her öğe bir yeri işaret ederek yerini kazanır. /Title panelin gösterdiği şeydir; /Dest ise bir tıklamanın ineceği yerdir. Bir varış noktası (destination), yukarıdaki gibi öğenin içinde yer alabilir (inline) veya belgenin ad sözlüğü aracılığıyla çözümlenen bir ad olabilir; bu, birçok yer imi ve bağlantı aynı noktaları hedeflediğinde daha iyi bir seçimdir çünkü taşınan bir hedefi tek bir yerden düzeltirsiniz. Bir kütüphane genellikle bu ağacı bir ana hat kökü (outline-root) tutamacı ve alt girdiler ekleyen yöntemlerin arkasına gizler; HotPDF'te belge, THPDFDocOutlineObject türünde bir OutlineRoot sunar ve öğeler ekledikçe sizin için /Prev, /Next, /Parent ve /Count bağlantılarını bağlar. Bundan yararlanmaya değer, çünkü bu değişmezleri düzenlemeler boyunca elle korumak, ana hatların bozulduğu yerdir

Varış Noktaları: Bir tıklamanın nereye gideceğinin grameri

Hem yer imleri hem de bağlantı ek açıklamaları varış noktalarını (destinations) işaret eder ve bir varış noktası sayfa numarasından daha fazlasıdır. Bir sayfa nesnesini adlandıran ve ardından ikinci yuvadaki bir fiil aracılığıyla görüntüleyicinin onu nasıl çerçevelemesi gerektiğini belirten bir dizidir. En yaygın ve en çok kötüye kullanılanı, [page /XYZ left top zoom] formatındaki /XYZ'dir. Üç işleneni bağımsızdır ve herhangi biri "bunu okuyucunun bıraktığı gibi bırak" anlamına gelen null olabilir. Dolayısıyla, [page /XYZ null null null] genellikle "sayfaya git" bağlantısından isteyeceğiniz gibi kaydırma (scroll) konumuna veya yakınlaştırmaya dokunmadan sayfaya atlar. Sayılar, sayfa içeriğinin kullandığı aynı koordinat sistemi olan, sol alttan ölçülen ve y yukarı doğru artan varsayılan kullanıcı alanındadır (default user space). Ekran düzeninden gelen yazarlar refleks olarak üstten ölçüm yapar ve okuyucuyu sayfanın yanlış ucuna gönderirler

/Fit ailesi kesin konumlandırmayı esneklikle (resilience) takas eder. [page /Fit] tüm sayfayı pencereye sığacak şekilde ölçeklendirir, [page /FitH top] sayfa genişliğini belirli bir üst kenara (top edge) sığdırır ve [page /FitR l b r t] bir dikdörtgeni görünümü dolduracak şekilde yakınlaştırır. Bunlar ölçeği sabit koordinatlar yerine sayfa geometrisinden hesapladığı için, sayfa yeniden boyutlandırıldıktan sonra bir /Fit varış noktası hala mantıklı olanı yaparken, kalıplaşmış bir yakınlaştırmaya sahip bir /XYZ varış noktası okuyucuyu boşluğa bakarken bırakabilir. İçindekiler tablosu (table of contents) için, bölümün üst koordinatına sahip bir /FitH, tahmini bir yakınlaştırmaya sahip /XYZ'den daha iyi yaşlanır

Ek Açıklamalar: Sayfa içeriği olmayan tüm etkileşimli öğeler

Bir ek açıklama (annotation), içerik akışının bir parçası olmadan sayfanın üzerine binen (overlay) bir nesnedir. Bağlantılar (Links), yapışkan notlar (sticky notes), vurgulamalar (highlights), form bileşenleri, dosya eki simgeleri, damgalar (stamps): hepsi, üzerinde bulundukları sayfanın /Annots dizisinde listelenen ek açıklamalardır. Bir ek açıklamayı bu diziden kaldırmak, alttaki içerik dokunulmamış olsa bile onu sayfadan kaldırır. Bütün mesele budur: ek açıklamalar, üzerinde bulundukları işaretlerden ayrı bir düzenleme katmanıdır

Her ek açıklama küçük bir omurgayı paylaşır. /Subtype türü adlandırır, /Rect sayfa koordinatlarındaki sınırlayıcı kutusunu verir ve /Contents erişilebilir açıklama olarak ikiye katlanan metni tutar. Bağlantı ek açıklaması incelenmeye değer bir durumdur, çünkü iki biçimde gelir: çıplak bir varış noktası (bare destination) ve bir eylem (action)

12 0 obj                                    % link to a destination
<< /Type /Annot /Subtype /Link
   /Rect [100 200 300 250]
   /Border [0 0 0]
   /Dest [5 0 R /XYZ null null null] >>
endobj
13 0 obj                                    % link that runs an action
<< /Type /Annot /Subtype /Link
   /Rect [50 50 200 100]
   /Border [0 0 0]
   /A << /Type /Action /S /URI /URI (https://www.example.com) >> >>
endobj

/Rect bir etkin noktadır (hotspot); içine tıklamak okuyucuyu varış noktasına göndererek ana hattın kullandığı gramerin aynısını yeniden kullanır. /Border [0 0 0] asıl işi yapar, görüntüleyicilerin bağlantıların etrafına çizdiği çirkin varsayılan dikdörtgeni bastırır. İkinci biçim, çıplak /Dest'i, /S alt türünün davranışı seçtiği bir /A eylemiyle değiştirir: bu dosya içinde /GoTo, başka bir dosya için /GoToR, bir web adresi için /URI, harici bir programı çalıştırmak için /Launch. O sonuncusu şüpheyi hak ediyor. Bir çalıştırılabilir dosyayı başlatan /Launch, PDF'leri bir kötü amaçlı yazılım (malware) vektörü yapan davranıştır, bu nedenle uyumlu görüntüleyiciler bunu engeller veya yüksek sesle uyarır ve bağlantı çoğu okuyucu için başarısız olur. /URI ve /GoTo komutlarına uzanın ve /Launch'ı kendi haline bırakın

Vurgulamalar (highlights) ve yapışkan notlar (sticky notes) gibi işaretleme (markup) ek açıklamaları ile /Square gibi şekil ek açıklamaları bir pürüz ekler: ekrandaki görünümleri türleri tarafından ima edilmez. Çizim operatörlerini tutan bir XObject formuna referans veren bir görünüm akışı (appearance stream) olan /AP girişiyle görünümü sabitlemediğiniz sürece, bir görüntüleyici kendi versiyonunu oluşturur. Bunu atlarsanız aynı vurgulama iki okuyucuda veya bir düzenleyici gidiş-dönüşünden önce ve sonra farklı görünebilir. Tam görünümü belgenin bir parçası olan her şey için /AP sağlayın. Dosya ekleri (file attachments), tesadüfen, aynı mekanizmayı yeniden kullanır: gömülü bir dosya akışı ve /FileAttachment ek açıklaması olarak veya kataloğun /Names düğümü altındaki /EmbeddedFiles ad ağacı aracılığıyla yüzeye çıkan bir dosya spesifikasyon sözlüğü

Bu katman nerede bozulur ve nasıl yakalanır?

Tüm bunlardaki tekrarlayan başarısızlık, havada asılı kalan referanstır (dangling reference). Katalogda hiçbir /Outlines girişi olmadığında veya bir kardeş zinciri (sibling chain) ağacın ortasında koptuğunda yer imleri (bookmarks) görünmeyi bırakır; XMP akışında /Type /Metadata /Subtype /XML işareti eksikse veya xpacket sarıcısı bozuksa meta veriler yoksayılır. Her durumda sayfa içeriği iyidir, bu nedenle sıradan bir açılış doğru görünür ve kusur yalnızca kimsenin kontrol etmediği panelde ortaya çıkar

İki ucuz alışkanlık bunların çoğunu yakalar. Biten dosyayı gerçek bir görüntüleyicide açın ve referans grafiğini bir okuyucunun yapacağı gibi çalıştıran yer imleri paneline ve örnek bağlantılara tıklayın. Ardından meta verileri ayrı bir araçla geri okuyun ve Info sözlüğü ile XMP'nin uyuştuğunu doğrulayın; tıklama sayısının ne kadar olursa olsun ortaya çıkarmayacağı tek anlaşmazlık budur. Bu katmanı, bağlantı defter tutma (bookkeeping) işlemlerine sahip bir kütüphane aracılığıyla oluşturduğunuzda, bu tuzakların çoğu asla açılmaz. Delphi ve C++Builder için HotPDF Bileşeni (HotPDF Component), belge düzeyindeki API'ler aracılığıyla ana hat, ek açıklama ve meta veri yapılarını sunar, böylece yer imi hiyerarşisini ve bağlantıları tanımlarsınız ve referansları bağlamasına izin verirsiniz. Bu yapıların eklendiği nesne modeli için, PDF dosya yapısına teknik genel bakış (technical overview of PDF file structure), bağlı oldukları kataloğu ve çapraz referans tablosunu (cross-reference table) kapsar