Teknik Makale

Delphi'de Tam PDF Sürümü Kayıtları: PDFiumPas Uyumluluğu

Google'ın PDFium motoru etrafındaki Delphi ve C++Builder sarmalayıcısı olan PDFiumPas, bir belgeyi TPdf.SaveAs metodunun PdfVersion parametresi aracılığıyla 1.3'ten 1.7'ye kadar tam bir PDF sürümünde kaydeder. PDFium'un kendi FPDF_SaveWithVersion çağrısı, belgenin gerçek içeriğinin o sürümde yasal olup olmadığını kontrol etmeden yalnızca %PDF-M.m başlığını yeniden yazar. PDFiumPas bu boşluğu, dosya metottan çıkmadan önce aktif çapraz referans revizyon zincirini dolaşan ve Adobe Extension Level bildirimlerini kontrol eden bir kayıt-sonrası uyumluluk geçişiyle kapatır

Bu ayrım en çok baskı üretiminde önemlidir; burada bir PDF/X profili tam bir PDF sürümü adlandırır ve bir önkontrol aracı veya RIP, kendi başlığıyla sessizce çelişen her şeyi reddeder; bu senaryo çıktı tarafından PDFiumPas ile baskıya hazır PDF/X belgelerini doğrulama makalesinde ele alınmıştır. SaveAs, hedefi TPdfVersion enum'u olarak sunar, eski pv10'dan pv12'ye kadar olan değerlerin yanında pv13'ten pv17'ye kadar, artı artımlı veya tam yeniden yazımlar için bağımsız bir TSaveOption. PdfVersion'ı geçirin ve PDFiumPas tek bir çağrıda iki iş yapar: PDFium'dan istenen başlığı damgalamasını ister, ardından yeni yazılan baytları yeniden okur ve aktif içeriği o sürümde yasal olarak var olamayacak bir dosyayı geri vermeyi reddeder

var
  Pdf: TPdf;
begin
  Pdf:= TPdf.Create(nil);
  try
    Pdf.FileName:= 'source.pdf';
    Pdf.Active:= True;
    try
      Pdf.SaveAs('press-ready.pdf', saNoIncremental, pv17);
    except
      on E: Exception do
        // E.Message names the offending feature and the version or
        // extension level it actually needs, for example:
        // "RichMedia annotations and RichMediaExecute actions require
        // /Extensions /ADBE with /BaseVersion /1.7 and /ExtensionLevel 3
        // or newer."
        raise;
    end;
  finally
    Pdf.Free;
  end;
end;

Dosyadaki son nesne tanımına güvenmek neden yanlış?

Bir PDF dosyasında belirli bir numaraya sahip son fiziksel nesne, bugün uyumlu bir okuyucunun o numara için çözeceği nesne olmak zorunda değildir. Birkaç artımlı güncellemeden geçmiş bir PDF'in tek bir nesne grafiği yoktur, tek bir dosya içinde katmanlanmış bir tarihçesi vardır ve her ekleme döngüsü bir nesneyi serbest bırakabilir, onu yeni bir nesil numarası altında yeniden tanımlayabilir veya artık ona işaret eden hiçbir çapraz referans girdisi olmadan iki endobj işaretçisi arasında eski fiziksel gövdesini bırakabilir

PDFiumPas, xref revizyonlarını açıkça izlemeden önce tam olarak bu başarısızlık moduna çarptı: daha sonraki bir sayfa nesnesi yeniden yazımı tarafından yetim bırakılan bir Redact açıklaması, veya ona işaret eden hiçbir xref girdisi olmadan fiziksel olarak var olmaya devam eden bir /MarkInfo sözlüğü, hâlâ bir bayt taramasında ortaya çıkabilir ve bir okuyucunun gerçekte açacağı belgeye artık uygulanmayan bir sürüm-özelliği kontrolünü hâlâ tetikleyebilirdi. Başarısızlık yönü yanlış reddetmeydi, yanlış kabul değil: mevcut revizyonunda gerçekten bir özelliğin ötesine geçmiş bir dosya, artık kimsenin ulaşamadığı içerik yüzünden yine de daha düşük bir sürümde kaydedilmekten engellenebilirdi

PDFiumPas hangi nesne tanımlarının gerçekten aktif olduğunu nasıl belirler?

PDFiumPas, nesne başlıkları için baytları taramak yerine çapraz referans zincirini dolaşarak aktif nesne kümesini uyumlu bir okuyucunun yaptığı gibi çözer. Çözücü, dosyadaki son startxref konumunda başlar ve klasik çapraz referans tablolarını, hibrit /XRefStm bağlantılı akışları ve saf çapraz referans akışlarını yol boyunca ayrıştırarak her /Prev bağlantısını geriye doğru daha eski revizyonlara takip eder. Dolaşım en yeniden en eskiye çalışır ve her nesne numarasını ilk görüldüğünde yerleştirir; bu yüzden daha sonraki bir revizyondaki serbest bir girdi, daha önceki bir revizyonda yazılan bir nesne gövdesini doğru şekilde gölgeler ve yeni bir konum veya nesil altındaki bir yeniden tanımlama her zaman değiştirdiği şeye karşı kazanır

Nesne akışı üyeleri, düz bir konum aramasının kendi başına sağlayamayacağı ekstra bir kontrol alır; bu mekanizma PDFiumPas ile nesne ve çapraz referans akışlarını doğrulama makalesinde daha derinlemesine ele alınmıştır. Bir /ObjStm'den kurtarılan sıkıştırılmış bir nesnenin, aynı dolaşımda ebeveyn akışının aktif olduğu doğrulanmış olması gerekir ve indeksinin, PDFiumPas onu canlı içerik olarak ele almadan önce üyenin o akışın başlığı içindeki kendi konumuyla uyuşması gerekir. ISO 32000-1 bölüm 7.5.8.4, klasik bir uyumluluk tablosunun bir nesneyi serbest olarak işaretlediği ve arka planın /XRefStm girdisinin aynı anda o aynı nesneyi başka bir yerde sıkıştırılmış bir üye olarak tanımladığı bir hibrit-referans durumunu bile tarif eder; PDFiumPas, klasik girdiler uygulanmadan önce tamamlayıcı xref akışını aynı revizyona birleştirir; bu yüzden sıkıştırılmış tanım, spesifikasyonun amaçladığı şekilde kazanır

Adobe Extension Level'ları: sürüm numarasının üzerindeki kapı

Bir %PDF-1.7 başlığı yalnızca ISO 32000-1'in 2008'de standartlaştırdığı özellik kümesini vaat eder; PDF üreticilerinin bugün dayandığı birkaç yetenek ise aynı sürüm numarasının üzerine katmanlanmış yalnızca Adobe'ye ait ekler olarak sonradan gönderildi. Adobe, her eki, geliştirici öneki altında belge katalogunun /Extensions sözlüğünde kaydedilen bir BaseVersion ve ExtensionLevel çifti olarak kaydetti; Adobe'nin kendi uzantıları için ADBE; bu yüzden bir okuyucu düz bir PDF 1.7 dosyasını numaralı bir uzantı düzeyini de uygulayan bir dosyadan ayırt edebilir. Bu bildirim olmadan pv17'de kaydetmek kendi başına bir hata değildir; yalnızca aktif içerik gerçekten bildirimin kapsaması gereken bir özelliğe bağımlı olduğu an bir hataya dönüşür

Hangi yüksek sürüm özellikleri açık-sürüm kapısını tetikler?

PDFiumPas, yalnızca sürüm numarasından tahmin etmek yerine belirli, spesifikasyon güdümlü bir listeyi kontrol eder. Açık bir /SMaskInData girdisi taşıyan görüntü sözlükleri veya 16'lık bir /BitsPerComponent değeri, ikisi de PDF 1.5 gerektirir; on altı bit durumu doğrudan PDF Reference 1.5 bölüm 4.8'in görüntü bileşeni kurallarını izler. RichMedia açıklamaları ve RichMediaExecute eylemleri, /ExtensionLevel 3 veya üzeri ile /BaseVersion /1.7 gerektirir. Hem /Type /3D hem de /Subtype /PRC taşıyan bir sözlükle tanımlanan PRC 3D akışları, aynı temel sürümü ama yalnızca /ExtensionLevel 1'i gerektirir. Coğrafi-uzamsal Measure sözlükleri ve Projection açıklamaları, RichMedia'nın bağımlı olduğu aynı Adobe eki olan /ExtensionLevel 3 ile /BaseVersion /1.7 gerektirir

Coğrafi-uzamsal kontrol, PDFiumPas üzerine kendi sürüm-kapılı mantığınızı kurarsanız bilmeye değer bir spesifikasyon-okuma ayrıntısı taşır. ISO 32000-1 Tablo 254, Measure sözlüğünün /Type girdisini isteğe bağlı olarak işaretler, yalnızca "mevcutsa, Measure olmalıdır" notunu düşer; Tablo 311 ise PRC içeriğinin yaşadığı 3D akış sözlüğü için /Type'ı zorunlu kılar. Haritalama araçlarından gelen gerçek dünya GeoPDF çıktısı, Measure sözlüğünde rutin olarak /Type'ı atlar ve yalnızca /Subtype /GEO'yu yazar; bu yüzden PDFiumPas'ın coğrafi-uzamsal dedektörü, PRC 3D dedektörünün güvenle yapabildiği şekilde her iki anahtarı da gerektirmek yerine yalnızca /Subtype üzerinde eşleşir. Her iki sözlükte de /Type'ı gerektirmek, uyumlu GeoPDF içeriğinin tespit edilmeden kapıdan kayıp geçmesine, arkasında hiçbir uzantı düzeyi bildirimi olmayan düz bir PDF 1.7 dosyasına inmesine izin verirdi

PDFiumPas desteklenmeyen özellikleri otomatik olarak alt sürüme mi indirir?

Genel bir yetenek olarak değil, ve aksini varsaymak burada kaçınılması gereken hatadır. SaveAs, hedef sürümü dahili bir rutin olan ValidatePdfVersionCompliance üzerinden yönlendirir ve bu rutin, hedef sürümün veya onun uzantı düzeyi bildiriminin destekleyemeyeceği bir özellik bulduğunda, SaveAs dosyayı yazmak yerine rutinin hata metnini taşıyan bir istisna fırlatır; çağıran, hiçbir zaman sessizce yeniden yazılmış bir belge değil, kesin, özellik adlı bir neden geri alır. PDFiumPas'ın içeriği otomatik olarak yeniden yazdığı tek yer bir PDF 1.3 hedefidir; burada PDFium'un hedef sürümden bağımsız olarak her zaman ExtGState sözlüklerine yazdığı anlamsal olarak nötr /BM /Normal, /CA 1 ve /ca 1 saydamlık varsayılanlarını soyar, çünkü bu belirli değerler hiçbir görsel anlam taşımaz ve PDF 1.3 anahtarlardan tamamen önce gelir

// PDF 1.3 targets rewrite the saved bytes to strip transparency
// defaults PDFium always emits, so incremental mode cannot apply
Pdf.SaveAs('legacy-archive.pdf', saIncremental, pv13);
// raises: PDF 1.3 normalization is incompatible with incremental
// save mode

Gerçek, varsayılan olmayan saydamlık ve görüntü yumuşak maskeleri, bir PDF 1.3 hedefinde yine de tamamen başarısız olur, çünkü bunları kaldırmak sayfanın gerçekte nasıl göründüğünü değiştirir ve PDFiumPas o kararı sizin adınıza vermez. Bir toplu iş boru hattına tam bir sürüm koymadan önce planlanmaya değer iki ilgili sınır daha vardır. Açık sürüm çıktısı hiçbir zaman bir /Encrypt sözlüğü taşımaz; kaynak korunuyorsa kayıt anında başarısız olur ki bu, zaten şifrelemeyi yasaklayan PDF/X ve PDF/A profilleriyle uyumlu olur, ama bu, şifre çözmenin SaveAs'ın sizin için yaptığı bir şey değil, iş akışınızda ayrı bir adım olduğu anlamına gelir. PDFiumPas'ın ayrıca bir kataloga /Extensions /ADBE bildirimi yazmak için kamuya açık bir metodu yoktur; bu yüzden RichMedia, PRC 3D veya coğrafi-uzamsal içerik içeren ama bu bildirimden yoksun bir kaynak dosya, hangi PdfVersion'ı isterseniz isteyin kapıdan geçmeyecektir; bildirim kaynakta zaten var olmak zorundadır, genellikle yazma aracının onu yazmış olması nedeniyle, ya da özellik kayıttan önce çıkarılmak zorundadır. Salt okunur TPdf.PdfVersion özelliği, tam bir sürüm kaydı denenmeden önce kontrol edilmeye değer, çünkü kayıt zamanı doğrulayıcısının kendisinin dayandığı aynı kataloga duyarlı etkin sürümü -başlık veya /Version geçersiz kılması, hangisi güncelse- çözer

Pdf.FileName:= 'incoming.pdf';
Pdf.Active:= True;
// PdfVersion resolves the same catalog-aware effective version the
// save-time validator uses, so a mismatch here is worth investigating
// before spending a full SaveAs attempt on it
LogSourceVersion('incoming.pdf', Pdf.PdfVersion);

Tam bir sürüm hedefinde bir SaveAs istisnasını bir hata değil bir önkontrol raporu olarak ele alın: mesaj, kaynak belgenin ihlal ettiği tam maddeyi adlandırır ki bu, bir dosya daha ileri gitmeden önce bir baskı atölyesinin veya arşiv boru hattının tam olarak ihtiyaç duyduğu bilgidir. Burada açıklanan açık-sürüm kayıt yolu, aktif xref revizyon çözücü ve Adobe Extension Level kontrolleri, Delphi ve C++Builder için PDFiumPas Bileşeni'nin standart bir parçası olarak gönderilir; ürün sayfası, uyumluluk ve form API'sinin geri kalanının yanında tam TPdf.SaveAs referansını taşır