PDFium Component, PDF optional content katmanlarını (OCG'leri) Delphi'de iki TPdf yöntemiyle kontrol eder: InspectOptionalContent her katmanı, PDFium'un gerçekte render edeceği görünürlükle birlikte listeler; SaveAsOptionalContentConfigured ise seçtiğiniz katmanların açılıp kapatıldığı doğrulanmış bir kopya yazar. İkinci yöntem ayrıca, aksi hâlde düzenlemenizi sessizce geri alan Usage ve /AS kurallarını etkisizleştirir. İkisi de TPdf içinde zaten açık olan belge üzerinde çalışır; görüntüleyicinin gösterdiğiyle eşit tutulacak ikinci bir parser yoktur
Talep genellikle bir CAD ya da GIS atölyesinden gelir: çizim takımı, ölçüler, notlar ve başlık bloğu ayrı katmanlarda dağıtılır ve müşteri, tedarikçiye gitmeden önce ölçüleri gizlenmiş bir kopya ister. PDFium optional content'i doğru render eder ama genel ABI'sinde OCG'leri listelemeye, bir konfigürasyon seçmeye ya da katman durumunu çevirmeye yarayan bir fonksiyon yoktur. O yüzden nesne düzeyine iner, /OCProperties'i düzenler, kaydeder, yeniden yüklersiniz ve katman hâlâ oradadır. Neden, PDFium'un görünürlük mantığıdır ve hiçbir bayta dokunmadan önce anlamaya değer
PDFium'un render ettiğini değiştirmek için /ON ve /OFF'u düzenlemek neden yetmez?
Konfigürasyon sözlüğünün /ON ve /OFF dizilerini düzenlemek yetmez, çünkü PDFium, OCG'nin kendi /Usage sözlüğünün içindeki açık bir durumun o dizileri geçmesine izin verir ve bir /AS otomatik-durum kuralı ardından ikisini de ezebilir. ISO 32000-1 §8.11.4, konfigürasyonları ve usage sözlüklerini ayrı mekanizmalar olarak tanımlar; PDFium'un renderer'ı onları tek bir karara katlar ve InspectOptionalContent bu kararı şu sırayla yeniden üretir:
- Konfigürasyonun
/BaseState'inden başlayın;/ONile/Unchangedgörünür sayılır, yalnızca/OFFgizler - Konfigürasyonun
/ONdizisini, sonra/OFFdizisini uygulayın; ikisinde de listelenen bir grup gizlenmiş kalır - İstenen kullanım için grubun açık Usage durumunu uygulayın — örneğin
/Usage << /View << /ViewState /OFF >> >>— bu, yukarıdakilerin hepsini ezer /Intent'inde ne/Viewne de/Allbulunan bir grubu görünür sayın; view-intent görünürlüğüne katılmaz- Son olarak seçili konfigürasyonun
/ASdizisini işletin; eşleşen event için girdileri, listeledikleri grupların durumunu belirler
Üçüncü adım, insanları yakan adımdır. Bir layout aracının kaydettiği dosya çoğu zaman her OCG üzerinde /ViewState /ON taşır ve PDFium o zaman özenle düzenlediğiniz /OFF dizisini yok sayar: kaydetme başarılı olur, dosya temizce yeniden açılır ve katman yine çizilir. Print ve Export için OcExplicitUsageState önce PrintState'i ya da ExportState'i okur ve ilgili girdi yoksa ViewState'e düşer; tek başına bir ViewState /ON katmanı yazdırmak için de sabitler. Bir OCMD'ye (§8.11.2.2) başvuran marked content sonra bu grup-başı sonuçlara karşı, /P politikası üzerinden ya da varsa /VE görünürlük ifadesiyle çözümlenir
PDFium'un gerçekte göstereceği katmanları nasıl listelersiniz?
TPdf.InspectOptionalContent, Groups dizisinde her OCG'nin nesne numarasını, adını, intent'lerini, üç Usage durumunu, dilini, zoom aralığını, Locked bayrağını, radio-grup indeksini ve hesaplanmış EffectiveVisible'ı taşıyan bir TPdfOptionalContentInventory döndürür. Yöntem önce PDFium'a bellekteki güncel belgeyi kaydettirir, object stream'leri açar ve sonucu tarar; oturumda daha önce yapılan düzenlemeler yansır. Konfigürasyon indeksi 0 her zaman varsayılan /D sözlüğüdür ve /Configs girdileri 1'den itibaren gelir; -1 varsayılan argümanı indeks 0'ı seçer. /OCProperties'i olmayan bir belge, yöntemin exception fırlatmak yerine ErrorMessage'de gerekçesiyle False dönmesini sağlar
procedure TFormMain.ListLayers;
var
Inv: TPdfOptionalContentInventory;
G: TPdfOptionalContentGroup;
begin
// Usage varsayılanı ocuView; -1 konfigürasyon 0'ı, yani /D sözlüğünü seçer
if not Pdf.InspectOptionalContent(Inv) then
begin
Memo1.Lines.Add('No usable layers: ' + Inv.ErrorMessage);
Exit;
end;
Memo1.Lines.Add(Format('Configuration %d: %s',
[Inv.SelectedConfigurationIndex,
string(Inv.Configurations[Inv.SelectedConfigurationIndex].Name)]));
for G in Inv.Groups do
Memo1.Lines.Add(Format('obj %d %s visible=%s locked=%s radio=%d',
[G.ObjectNumber, string(G.Name),
BoolToStr(G.EffectiveVisible, True),
BoolToStr(G.Locked, True), G.RadioGroupIndex]));
end;
Memberships dizisi her OCMD'yi Policy'siyle (ocmpAnyOn, ocmpAllOn, ocmpAnyOff, ocmpAllOff), ham VisibilityExpression metniyle ve kendi EffectiveVisible'ıyla raporlar. Birkaç uç kural bilinçlidir. /P varsayılanı /AnyOn'dur ve grupsuz bir OCMD görünür sayılır. Bilinen bir OCG olmayan bir nesne numarasına referans, tüm ifadeyi düşürmek yerine görünür sayılır. /VE değerlendirmesi 32 iç içe geçme derinliğinde durur ve daha derin her şeyi gizli sayar; bu, düşmanca ya da kendine referans veren bir ifadenin incelemeyi stack overflow'a çevirmesini önler
SaveAsOptionalContentConfigured ile yeni bir katman durumu yazmak
TPdf.SaveAsOptionalContentConfigured, TPdfOptionalContentStateChange kayıtlarından oluşan bir dizi alır (grup nesne numarası artı Visible) ve seçili konfigürasyonun tam olarak o durumu ürettiği bir belge yazar. Seçili konfigürasyon, her grubu kapsayan eksiksiz /ON ve /OFF dizileriyle birlikte /BaseState /ON alır; hâlihazırda Usage sözlüğü olan her OCG ise yeni durumuna uyan bir açık ViewState (ya da Options.Usage'e uyarak PrintState / ExportState) alır. TPdfOptionalContentConfigureOptions.Default ile seçili konfigürasyonun /AS anahtarı kaldırılır; böylece bir open, print ya da export event'i katmanları geri çeviremez
procedure TFormMain.SaveWithoutDimensions(DimensionsObj, NotesObj: Integer);
var
Changes: TPdfOptionalContentStateChanges;
Options: TPdfOptionalContentConfigureOptions;
Report: TPdfOptionalContentConfigureReport;
begin
SetLength(Changes, 2);
Changes[0].GroupObjectNumber := DimensionsObj;
Changes[0].Visible := False;
Changes[1].GroupObjectNumber := NotesObj;
Changes[1].Visible := True;
// Konfigürasyon 0, ocuView, DisableAutomaticState ve EnforceRadioGroups True
Options := TPdfOptionalContentConfigureOptions.Default;
if not Pdf.SaveAsOptionalContentConfigured('C:\Out\Drawing-NoDims.pdf',
Changes, Options, Report) then
raise Exception.Create('Layer update rejected: ' + Report.ErrorMessage);
Log(Format('%d of %d groups changed, %d Usage states rewritten, /AS removed: %s',
[Report.ChangedGroupCount, Report.GroupCount,
Report.UpdatedUsageStateCount,
BoolToStr(Report.RemovedAutomaticState, True)]));
end;
Yazma yolu, PDFium'un kendi kaydetme çıktısını bayt-bayt bir önek olarak tutar ve yalnızca yeniden yazılan konfigürasyon sahibini ile Usage sözlüğü taşıyan OCG nesnelerini, ardından yeni bir xref bölümü ve trailer ekler. Tek bir bayt hedefinize ulaşmadan önce sonuç, sıkı yükleme politikası altında ayrı bir TPdf içinde yeniden açılır ve çapraz-referans tablosu doğrulanmazsa yöntem başarısız olur. Dosya overload'u bir adım daha ileri gider: hedefin yanındaki geçici bir dosyaya yazar ve hedefi yalnızca doğrulama başarılı olduktan sonra değiştirir; reddedilen bir güncelleme yarım yazılmış bir çizim geride bırakmaz. PDFium Component'taki PDF name tree ve number tree editörünün kullandığı doğrulanmış artımlı revizyon yaklaşımı da budur
Konfigüre kaydetme neyi yapmayı reddediyor?
Konfigüre kaydetme, belgenin kendisinin yasakladığı ya da güvenle temsil edemeyeceği her değişikliği reddeder ve her ret, hedefe dokunulmadan önce gerçekleşir. /OCGs içinde olmayan bir nesne numarası düpedüz başarısız olur. Konfigürasyonun /Locked dizisinde listelenen bir grubu değiştirmek başarısız olur; mevcut değerini yeniden belirtmeye ise izin verilir. EnforceRadioGroups açıkken, birden fazla görünür üyeyle kalacak her /RBGroups kümesi, diğerlerini sessizce kapatmak yerine reddedilir. Şifreli belgeler reddedilir, çünkü düz metin artımlı nesneler etkin security handler'ı taşıyamaz. İmzalı belgeler AllowSignedDocument = True geçmediğiniz sürece EPdfError fırlatır; bir sayfanın gösterdiğini değiştirmek, imza kapsamını ya da bir sertifikalandırma politikasını bozabilir
function TFormMain.SavePrintPreset(Target: TStream;
const Changes: TPdfOptionalContentStateChanges): Boolean;
var
Options: TPdfOptionalContentConfigureOptions;
Report: TPdfOptionalContentConfigureReport;
begin
Options := TPdfOptionalContentConfigureOptions.Default;
Options.Usage := ocuPrint; // /Print << /PrintState ... >> yazar
Options.ConfigurationIndex := 1; // /Configs'in ilk girdisi, /D değil
try
Result := Pdf.SaveAsOptionalContentConfigured(Target, Changes, Options,
Report); // AllowSignedDocument False kalır
if not Result then
ShowMessage(Report.ErrorMessage);
except
on E: EPdfError do
begin
ShowMessage(E.Message); // imzalı dosya: Target'a hiçbir şey yazılmadı
Result := False;
end;
end;
end;
Bunu bir toplu işe bağlamadan önce takasları bilin. Eklenen revizyon, özgün dosya baytlarınızın değil PDFium'un tam yeniden kaydının üstüne oturur; imzalı girdinin açık onay istemesinin nedeni tam olarak budur. Yeniden yazım ayrıca seçili konfigürasyonu /BaseState /ON'a normalize eder; yazarın /Unchanged ya da /OFF taban çizgisi, aynı sonucu veren görünürlükle açık dizilerle değiştirilir. /AS'yi düşürmek, yalnızca kâğıtta görünen filigran katmanı gibi yalnız-print hilelerini kaldırır; o kuralları tutmak için DisableAutomaticState'i False yapın, o event için istediğiniz durumu ezebileceklerini kabullenerek. Artı tarafta, PDF/A-2 (ISO 19005-2 clause 6.9) ile PDF/UA (ISO 14289-1 clause 7.10) konfigürasyon sözlüklerinde /AS'yi yasaklar; varsayılan çıktı, PDFium Component ile PDF/A preflight doğrulamasının aksi hâlde raporlayacağı bir sorunu daha baştan kaldırır
Katman kontrolünün bir Delphi PDF görüntüleyicideki yeri
Bir görüntüleyicide katman kontrolü, envanterin sürdüğü ve kaydedilen sonucun yeniden yüklenmesiyle tamamlanan bir checklist'tir. Checklist'i Groups'tan doldurun, Locked olan girdileri devre dışı bırakın, aynı RadioGroupIndex'i paylaşan üyeleri karşılıklı dışlayıcı sayın ve uygula'da bir TMemoryStream'e yazıp o stream'i TPdf'e geri yükleyin; görünüm yeni durumu çizsin. TPdf ile TPdfView arasındaki bağlantı Delphi'de PDFium VCL ile özellik dolu bir PDF görüntüleyici kurmak yazısında işleniyor. Lisanslama, deneme indirmeleri ve özellik setinin kalanı Delphi için PDFium Component ürün sayfasında