Teknik Makale

Sıkıştırılmış PDF'leri Doğrulama: Nesne ve XRef Akışları

Küçük bir doğrulayıcı (validator) yazarsınız. Bir PDF'i açar, sonuna atlar (seeks), startxref'i bulur, ofseti (offset) okur ve altında sabit genişlikli (fixed-width) bir çapraz referans tablosu (cross-reference table) bulunan xref anahtar sözcüğüne inmesini (land on) bekler. O tablodan nesne ofsetlerini (offsets) toplar, ardından /Root ve /Size değerlerini öğrenmek (learn) için geriye doğru (backward) tarayarak trailer anahtar sözcüğünü (keyword) arar (scans). Test etmek için oluşturduğunuz her dosyada mükemmel bir şekilde çalışır. Ardından, Word'ün güncel (current) bir sürümü (version) veya PDF 1.5'i hedefleyen bir kitaplık tarafından üretilen (produced) bir dosya gelir ve doğrulayıcı (validator) bu dosyanın bozuk olduğunu (broken) ilan eder. Ofsetin işaret ettiği yerde (where the offset points) hiçbir xref anahtar sözcüğü, hiçbir yerde hiçbir trailer sözlüğü yoktur ve doğrulayıcının (validator) oluşturduğu (built) nesne (object) tablosu (table) neredeyse (nearly) boştur (empty). Dosya geçerlidir. Doğrulayıcı (validator) dosyayı on beş (fifteen-year-old) yıllık bir mercekten (lens) okuyor

Klasik (classic) düzene (layout) karşı yazılan (written) bayt (byte) seviyesindeki (level) bir PDF kontrolünün (check) modern (modern) belgelerde başarısız olmasının en (most) yaygın (common) tek (single) nedeni (reason) budur (This is). Bağlı olduğu (depends on) yapı (structure), düz metin (plaintext) çapraz referans (cross-reference) tablosu (table) ve trailer anahtar sözcüğü (keyword), PDF 1.5'te isteğe bağlı (optional) hale getirildi (made) ve sıklıkla (frequently) mevcut değil (absent). İki özellik bunların yerini (replaced it) aldı (Two features): çapraz referans (cross-reference) akışı (stream) ve sıkıştırılmış (compressed) nesne (object) akışı (stream). Her ikisi de (Both) ISO 32000-1'de açıklanmıştır (described) ve (and) bunları bilmeyen (does not know about them) bir doğrulayıcı (validator) sağlıklı (healthy) bir dosyayı, eksik nesnelerden (missing objects) oluşan bir yığın (heap) olarak görür (sees)

PDF 1.5 dosyanın (file) kuyruğu (tail) hakkında (about) neyi (what) değiştirdi (changed)

ISO 32000-1 §7.5.8 çapraz referans (cross-reference) akışını (stream) tanımlar ve §7.5.7, /ObjStm tipi nesne akışını tanımlar. Bunlar (they) birlikte (Together), bir yazıcının (writer), klasik bir ayrıştırıcının (parser) odaklandığı (keys on) o iki yapıyı düşürmesine (drop) izin verir (let). Bir PDF 1.5 dosyası, hiçbir xref tablosu (table) olmadan sonlanabilir (end). Bunun (its) yerinde (place), startxref'in işaret ettiği (points to) nesne (object), sözlüğü (dictionary) /Type /XRef değerini taşıyan (carries) sıradan (ordinary) bir akış (stream) nesnesidir (object) ve (and) o akış (that stream), çapraz referans verilerini yoğun (compact) ikili (binary) bir biçimde (form) tutar (holds). Orada hiçbir trailer anahtar kelimesi (keyword) de (either) yoktur (There is), çünkü katar (trailer) artık akışın kendi (own) sözlüğüdür (dictionary). Klasik bir ayrıştırıcının avladığı (hunted for) anahtarlar (keys) olan /Root, /Size ve /ID, o sözlüğün (that dictionary) içinde (inside) yaşar

İkinci değişiklik (change) nesnelerin kendilerini (themselves) hareket ettirir (moves). Her dolaylı (indirect) nesneyi kendi bayt (byte) ofsetine (offset) yazmak (writing) yerine (Instead of), bir yazar (writer) sayfa sözlükleri (page dictionaries), açıklama (annotation) sözlükleri (dictionaries), yapı ağacı (structure tree) gibi birçok (many) küçük (small) nesneyi (objects) tek (single) bir nesne (object) akışına (stream) paketleyebilir (pack) ve tüm (whole) kapsayıcıyı (container) Flate ile sıkıştırabilir (compress). Bireysel (individual) nesnelerin artık dosyada bir bayt ofseti (byte offset) yoktur. Sıkıştırılmış bir blob (compressed blob) içinde bir pozisyonları vardır. 1 0 obj için ham (raw) baytları (bytes) tarayan (scanning) bir doğrulayıcı (validator) onları (them) asla (never) bulamaz, çünkü bu (that) metin (text) yalnızca şişirildikten (inflation) sonra var (exists) olur. Klasik (classic) bir (a) ayrıştırıcı (parser) için (To), belgenin yarısı (half) basitçe (simply) kaybolmuştur (vanished)

Sıkıştırılmış (compressed) bir (a) dosyada (file) bile katar anahtarları (trailer keys) düz metindir (plaintext)

Güven verici (reassuring) kısım (part), bir çapraz referans (cross-reference) akışının katarını okumanın (reading) hiçbir şeyi şişirmeyi (inflating) gerektirmemesidir (does not require). Bir akış nesnesi, bir sözlük, ardından (followed by) stream anahtar kelimesi (keyword) ve daha sonra (then) sıkıştırılmış (compressed) baytlar (bytes) olarak yazılır (is written). Sözlük düz metindir. Bu (So) nedenle, startxref bir çapraz referans akışına (cross-reference stream) işaret (points) ettiğinde, nesne numarasından (object number) hemen sonraki baytlar (bytes) sıradan (ordinary) bir sözlük (dictionary) gibi (like) görünür ve /Root, /Size ve /ID, stream anahtar (keyword) kelimesi (keyword) ve (and) Flate verileri (data) başlamadan (begin) önce (before) açıkça (in the clear) orada (there) oturur (sit)

Bu (That), bir (a) doğrulayıcının (validator), (it most needs) en çok ihtiyaç (needs) duyduğu (it most) üç gerçeği (facts), (where) kataloğun (catalog) nerede olduğunu (is), (how many) dosyanın (file) kaç tane nesne (objects) iddia ettiğini (claims) ve (and) dosya (file) tanımlayıcısını (identifier), yalnızca (only) akış sözlüğünü (stream dictionary) ayrıştırarak (parsing) öğrenebileceği (can learn) anlamına (means) gelir. Çapraz (cross-reference) referans verilerini açmak (decompress) zorunda değildir (does not have to) ve içindeki (inside it) ikili kayıtları (binary entries) yorumlamak (interpret) zorunda (have to) değildir (does not). Saf (naive) bir (a) ayrıştırıcıyı yenen iş katarı okumak (reading) değildir (not); nesneleri bulmaktır (finding). Bunlar ayrılabilir (separable) iki (two) problemdir ve (and) ilkini (first) çözmek (solving) ucuzdur (cheap)

Nesne (Object) akışları (streams): bir başlık (header), ardından (then) bir Flate blobu (blob)

Bir nesne akışı bir kapsayıcıdır (container). Sözlüğü, /Type /ObjStm değerini, içinde paketlenmiş (packed inside) nesne sayısını veren bir /N girişini (entry) ve şişirilmiş (inflated) veriler (data) içinde, ilk nesnenin gövdesinin (body starts) nerede başladığını veren (giving) bayt ofsetini (byte offset) veren bir /First girişini (entry) taşır (carries). Sıkıştırılmış (compressed) yük (payload), şişirildikten (inflated) sonra, /N tamsayı (integer) çiftinden (pairs) oluşan (of) küçük (small) bir (a) başlıkla (header) başlar (begins). Her (Each) çift (pair), bir nesne numarası ve o (that) nesnenin (object's) gövdesinin (body) /First değerine (relative to) göre ofsetidir (offset). Başlıktan sonra nesne gövdelerinin kendileri birleştirilmiş (concatenated) halde gelir (come)

Baytlar (bytes) şişirildikten (inflated) sonra (once), birini (one) genişletmek (Expanding) mekaniktir (mechanical). /N ve /First değerlerini almak (get) için sözlüğü okur (read), akışı (stream) bir Flate kod çözücüsü (decoder) ile şişirir (inflate), (learn) hangi (which) nesne numarasının (object number) hangi (which) ofsette (offset) yaşadığını (lives) öğrenmek için baştaki (leading) /N çiftleri dolaşır (walk) ve (and) ardından (then), her gövdeyi sıradan (ordinary) bir (an) dolaylı (indirect) nesneymiş (object) gibi (as if) dışarı (out) kaldırırsınız (lift). Tek (only) gerçek (real) bağımlılık (dependency) Flate kod çözücüsüdür (decoder) ve (and) zaten (already) bir tane (one) var (have): Delphi, System.ZLib birimi ile gönderilir (ships), Free Pascal zstream birimi (unit) ile gönderilir; her ikisi de (both of which) zlib'i sarar (wrap) ve herhangi bir üçüncü taraf (third-party) kodu olmadan (without) ham (raw) bir Flate akışını (stream) şişirir (inflate). Çıkarılan (extracted) her (every) nesneyi (object) doğrulayıcının (validator's) nesne tablosuna (object table) ekleyen (appends) bir rutin (routine), doğrulayıcının geri kalanını (rest), /Root değerini dolaşan (walks) ve sayfa ağacını (page tree) kontrol (checks) eden kısmı (part), tıpkı klasik (classic) bir dosyada (file) davranacağı gibi (exactly as it would) davranmasını (behave) sağlar (makes)

Ne (What) uygulamak (implement) zorunda (have to) değilsiniz (do not)

İşi (work) gözünüzde (It is) büyütmek (overestimate) kolaydır (easy). Sıkıştırılmış bir dosyadan (file) katar anahtarlarını (trailer keys) okumak (Reading), çapraz (cross-reference) referans (cross-reference) akışının (stream's) ikili (binary) girişlerini (entries) çözmeyi (decoding) gerektirmez (does not require). §7.5.8 çapraz referans akışı (stream) üç (three) giriş türü (types) kullanır ve (and), (says) bu (this) nesne, N nesne akışı içinde (inside) i (i) indeksinde (at index) yaşar (lives) diyen (the one that) tip (type) 2 girdisi (entry), tam (full) bir ofset eşlemesi (offset map) oluşturmak (build) için (to) çözeceğiniz (decode) şeydir (what you would). Sayı (number) bazında (by) rastgele (arbitrary) nesneleri (objects) çözümlemek (resolve) için o haritaya (map) ihtiyacınız (need) var. Düz metin (plaintext) sözlüğünde olan (which are) /Root, /Size ve /ID değerlerini okumak için ona (it) ihtiyacınız (need) yoktur ve onu nesne akışlarını genişletmek (expand) için ona ihtiyacınız yoktur, çünkü (because) her bir /ObjStm, /N ve /First değerleri üzerinden kendi (own) içeriğini (contents) duyurur (announces)

Sadece katar (trailer) anahtarlarını almak (get) için (just to) bir (a) çapraz (cross-reference) referans akışının kendi /DecodeParms üzerinden (through) uygulayabileceği (may apply) PNG ve TIFF öngörücü (predictor) işlevlerini de ele almak (handle) zorunda (have to) değilsiniz (do not). Öngörücüler (Predictors), daha iyi sıkıştırılmalarını (compress better) sağlamak (make) için (to) ikili (binary) çapraz referans (cross-reference) satırlarını (rows) filtreler (filter); akıştan (stream) önce gelen (precedes) sözlükle hiçbir (nothing) ilgileri (to do with) yoktur. Klasik bir (a) doğrulayıcıyı (validator) modern-PDF farkında (aware) yapan minimal (minimal) yükseltme (upgrade) bu (is) nedenle (therefore) küçüktür (small): startxref xref anahtar kelimesi (keyword) yerine (rather than) bir akışa indiğinde (lands on), akış (stream) sözlüğünü (dictionary) katar anahtarları (trailer keys) için ayrıştırın (parse) ve, (so) içeriklerinin (contents) nesne (object) tablosuna (table) girmesi (enter) için karşılaştığınız (encounter) tüm /ObjStm nesnelerini genişletin (expand). Tip 2 girdilerini ve tahmincileri (predictors) çözmek (Decoding), gerçekten rastgele (random) nesne çözünürlüğüne (resolution) ihtiyaç duyana kadar erteleyebileceğiniz (defer) ayrı, daha (larger) büyük bir görevdir

Uyumluluk (compliance) kontrolü neden önce akışları genişletmelidir

Bir (a) profil (profile) kontrolü (check) çalıştırdığınız an bu akademik (academic) olmayı bırakır (stops being). Bir PDF/A veya PDF/X doğrulayıcısı (validator), belirli nesneleri (objects) inceler (inspects): bir (an) /OutputIntents dizisi (array) için (for) belge kataloğu, doğru (right) tanımlayıcıya sahip bir XMP paketi için (for) /Metadata akışı (stream), gömülü bir yazı tipi dosyası için (for) her (every) yazı tipi (font) tanımlayıcısı, bir /ID için (for) katar (trailer). Sıkıştırılmış bir (a) dosyada (file), o (those) nesnelerin çoğu (most of) nesne (object) akışlarının (streams) içindedir (inside). Nesne akışlarını genişletmemiş (has not expanded) bir doğrulayıcı (validator), kataloğun (catalog's) anahtarlarını (keys) göremez (cannot see), meta verileri (metadata) bulamaz (cannot find) ve yazı tiplerini listeleyemez (cannot enumerate). Mükemmel derecede uyumlu (conformant) bir belgeyi, çıktı amacı (output intent) eksik (missing), XMP'si eksik ve (and) yapısının (structure) yarısı (half) eksik (missing) olarak bildirecektir, çünkü (because) ihtiyaç (needs) duyduğu kanıt, (evidence) hiç (never) şişirmediği (inflated) bir Flate blob'unda (blob) hala oturuyor (sitting)

Sıra (order) önemlidir (matters). Genişletme (Expansion), kontroller (checks) çalışmadan (run) önce gerçekleşmelidir (happen), onlarla birlikte (alongside them) değil (not), çünkü (because) her (every) kontrol (check) nesneye sayı bazında (by number) ulaşabileceğini varsayar (assumes). Eğer profil (profile) kontrolünü doğrudan (directly) ham (raw) bayt taramasına bağlarsanız (wire), klasik ayrıştırıcının (parser's) körlüğünü (blindness) miras alır (inherits) ve ilk (first) etapta (place) çapraz referans (cross-reference) akışları (streams) yazacak (write) kadar yeni (new enough) olan (to) araç zincirlerinden (toolchains) çıktıkları (came out of) için tam olarak (exactly the) iyi (well) biçimlendirilmiş (formed) olma olasılığı en yüksek (most likely to be) olan modern dosyalarda sahte (false) ihlaller (violations) üretir (produces)

Ayrıştırma (parsing) işini (do) PDFium'a bırakmak (Letting)

PDFium Bileşeni (Component), çapraz referans akışlarını ve nesne akışlarını belge yüklemenin (loading) bir parçası (part) olarak ayrıştırır; bu da (which is), şişir ve genişlet (inflate-and-expand) adımını (step) elle (hand-rolling) yazmaktan kaçınmanın (avoid) pratik (practical) yoludur (way). TPdf bileşeni (component) ile (with) bir dosya yüklediğinizde, /ObjStm kapsayıcılarına (containers) paketlenmiş (packed) nesneler (objects) halihazırda (already) çözümlenmiş (resolved) olur ve doğrulama (validation) giriş (entry) noktaları tamamen (fully) genişletilmiş (expanded) belgeyi (document) görür (see). ValidatePdfA, Conformance alanı (field) pac1b veya (or) pacNone gibi (such as) bir TPdfAConformance değeri (value) olan, Issues alanı (field) bulunan (found) belirli (specific) problemler (problems) seti (set) olan ve IsCompliant yöntemi yalnızca bir uyumluluk (conformance) seviyesi (level) algılandığında (detected) ve sorun kümesi (issue set) boş (empty) olduğunda (when) doğru (true) olan bir TPdfAValidationResult kaydı (record) döndürür (returns). Nesneler (objects) yükleme (load) sırasında (during) genişletildiğinden, (an) /OutputIntents dizisi veya nesne (object) akışı (stream) içinde (inside) yaşayan gömülü bir (an) yazı tipi bulunur (found), eksik bildirilmez (not reported missing)

uses
  PDFium, FPdfPdfa;

function CheckPdfA(const FileName: string): TPdfAValidationResult;
var
  Pdf: TPdf;
begin
  Pdf := TPdf.Create(nil);
  try
    Pdf.FileName := FileName;
    Pdf.Active := True;            // parses xref/object streams on load
    Result := Pdf.ValidatePdfA;    // sees the expanded object table
  finally
    Pdf.Free;
  end;
end;

Aynı (same) şey, aynı (same) şekle sahip (with) bir TPdfXValidationResult döndüren (returns) ValidatePdfX için de (to) geçerlidir (applies). PDFium üzerinden yönlendirmenin (routing) amacı (point of), yukarıda açıklanan (described) yapısal (structural) açma işleminin (decompression), yükleyicinin içinde (inside) bir kez (once) doğru (correctly) şekilde (that) gerçekleşmesidir (happens), böylece (so) doğrulama kodunuz klasik bir (a) dosya (file) ile tamamen sıkıştırılmış (compressed) bir dosya (one) arasındaki farkı (difference) asla görmez. Her ikisi de (Both) doğrulayıcıya (validator) çözümlenmiş (resolved) bir (a) nesne kümesi (set) olarak gelir

function PdfXConformanceName(C: TPdfXConformance): string;
begin
  case C of
    pxc1a: Result := 'PDF/X-1a';
    pxc3 : Result := 'PDF/X-3';
    pxc4 : Result := 'PDF/X-4';
  else
    Result := 'none';
  end;
end;

var
  Pdf: TPdf;
  R  : TPdfXValidationResult;
  Issue: TPdfXValidationIssue;
  IssueCount: Integer;
begin
  Pdf := TPdf.Create(nil);
  try
    Pdf.FileName := 'Press_Ready.pdf';
    Pdf.Active := True;
    R := Pdf.ValidatePdfX;
    if R.IsCompliant then
      Writeln('PDF/X conformance: ', PdfXConformanceName(R.Conformance))
    else
    begin
      IssueCount := 0;
      for Issue in R.Issues do   // Issues is a set: count its members
        Inc(IssueCount);
      Writeln('Not conformant; issue count = ', IssueCount);
    end;
  finally
    Pdf.Free;
  end;
end;

Baytlar diskin (disk) yerine (rather than) bellek içindeyse (memory), aynı yükle ve (load-then-validate) doğrula dizisi, ham (raw) dosya (file) içeriğini (content) alan (takes) ve (and) çapraz referans (cross-reference) ve (and) nesne akışlarını (streams) dosya yolunun (file path) yaptığı (does) gibi (same way) ayrıştıran (parses) LoadDocument(const Data: TBytes) aşırı (overload) yükü (overload) yoluyla (through) da işe (works) yarar (works). Elle yazılmış (hand-written) bir doğrulayıcı için ana fikir (takeaway) API (API) değil yapısal (structural) kuraldır (rule): akış (stream) sözlüğündeki (dictionary) katar anahtarlarını (trailer keys) düz (plaintext) metin (plaintext) olarak okuyun (read), belgeyi (document) dolaşmadan (walk) önce (before) her (every) /ObjStm'yi Flate kod (decoder) çözücüyle (decoder) genişletin (expand) ve (and) ikili çapraz referans girdilerini (entries) çözmeyi (decoding), (as) daha büyük (larger), isteğe (optional) bağlı bir (job) iş olarak değerlendirin (treat)

Yapı (structure) genişletildiğinde (expanded), bir doğrulayıcı (validator) üzerinden (over it) bir iş akışının geri kalanını yürütebilir (drive). Bir girdiler klasörü (folder) üzerinden (across) uyumluluğu raporlayan (reports) komut satırı (command-line) ön kontrol (preflight) donanımı için, toplu (batch) ön (preflight) uçuş raporu (report) CLI'si (CLI) oluşturmaya (building) ilişkin kılavuzumuza (walkthrough) bakın. Doğrulama (validation), büyük (large) bir (a) belgeyi parçalamadan (apart) önce (ahead of) bir kapı (gate) olduğunda (When), PDF belgelerini (documents) birden fazla (multiple) dosyaya bölme (splitting) kılavuzumuzdaki teknikler, burada gösterilen (shown here) yükle (load) ve kontrol et (check) modeliyle (pattern) doğal (naturally) olarak (with) eşleşir (pair). Her ikisi (Both) de (de) bu (this) blogda daha önce ele (covered) alınan (elsewhere) oluşturma (rendering), düzenleme (editing) ve belge (document) API'lerinin yanı (alongside) sıra Delphi (Delphi) ve (and) C++Builder için (for) PDFium Bileşeni'nin (Component) yükleme (loading) ve (and) doğrulama (validation) yüzeyi (surface) üzerinde oluşturulur (build on)