Bir çizim takımı ölçülerini kendi katmanında getirir ve onları gizlemenin bariz yolu, o grubun referansını varsayılan konfigürasyonun /ON dizisinden /OFF'a taşımaktır. Dosya kaydedilip yeniden açılır ve ölçü çizgileri hâlâ başlık bloğunun üzerinden basılıdır. Neden bir nesne ötededir, grup sözlüğünün içindedir: /Usage << /View << /ViewState /ON >> >> — renderer'ın konfigürasyon dizilerinden önce okuduğu açık bir durum
Bir katmanın durumu PDF'te birkaç yerde yaşayabilir ve /OCProperties düzenlemesi bunlardan yalnızca birine dokunur. Google'ın PDFium motoru optional content'i doğru render eder ama genel C API'sinde optional content gruplarını (OCG) listelemeye, bir konfigürasyon seçmeye ya da bir grubu açıp kapatmaya yarayan işlev yoktur. Katman süren Delphi kodu, nesneleri kendisi yeniden yazıp renderer'ın karar sırasını tam olarak yeniden oynamak zorundadır; yoksa katman listesi bir durum, sayfa başka bir durum gösterir
PDFium'un render ettiğini değiştirmek için /ON ve /OFF'u düzenlemek neden yetmez?
/ON ve /OFF dizileri beş adımın yalnızca ikincisidir ve sonraki iki adım onları ezebilir. ISO 32000-1 §8.11.4.3 optional content konfigürasyon sözlüğünü /BaseState, /ON, /OFF, /Locked, /RBGroups ve /AS ile tanımlar; §8.11.4.4 ise bir OCG'nin taşıyabileceği Usage sözlüğünü. Belirtimde Usage, bir grubun ne işe yaradığını anlatır ve /AS'deki otomatik-durum girdileri o anlatımı ON ya da OFF'a çevirir. PDFium daha kısa bir yol izler: bir amaç için render ederken o amaçtaki grubun kendi açık durumu kazanır. Birleştirildiğinde sıra şöyle görünür:
- Konfigürasyonun
/BaseState'inden başlayın;/ONile/Unchangedgörünür sayılır, yalnızca/OFFgizler /ONdizisini, sonra/OFFdizisini uygulayın; ikisinde de listelenen bir grup gizlenmiş kalır- İstenen amaç 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- Seçili konfigürasyonun
/ASdizisini en son işletin; eşleşen event için girdiler, listeledikleri grupların durumunu belirler
Üçüncü adım açılıştaki dosyayı açıklar: bazı exportlar, oluşturdukları her gruba /ViewState /ON yazar ve o andan sonra dizi düzenlemesinin hiçbir hali o katmanları gizleyemez. Yazdırma ve export aynı kuralı tek bir kıvırımla izler: renderer önce /PrintState'i ya da /ExportState'i okur ve özel girdi yoksa /ViewState'e döner. Tek başına bir /ViewState /ON bu yüzden katmanı kâğıtta da sabitler. Dördüncü adım daha sessizdir. /Intent /Design etiketli bir grup view-intent görünürlüğünün büsbütün dışındadır ve dizilerden bağımsız boyar; /Intent anahtarı hiç olmayan bir grup ise /View sayılır — belirtimin verdiği varsayılan budur
InspectOptionalContent ile katmanları ve render durumlarını listelemek
PDFium Component o sırayı TPdf.InspectOptionalContent içinde yeniden oynar. Metot bir TPdfOptionalContentInventory doldurur ve başarıda True döndürür; Usage parametresinin varsayılanı ocuView, ConfigurationIndex parametresinin varsayılanı -1'dir ve bu, 0 indeksini seçer. Konfigürasyon indeksi 0 varsayılan /D sözlüğüdür; /Configs girdileri 1 indeksinden itibaren dosya sırasıyla izler. Taramadan önce metot, PDFium'dan açık belgeyi belleğe kaydetmesini ister ve nesne akışlarını genişletir; böylece oturumda daha önce yapılmış düzenlemeler sonuca yansır. /OCProperties taşımayan bir dosya ya da mevcut aralığın dışında bir konfigürasyon indeksi, çağrıyı ErrorMessage'de gerekçeyle False döndürür; iki durumda da özel durum fırlatmaz
procedure TFormMain.ListLayers;
var
Inv: TPdfOptionalContentInventory;
Cfg: TPdfOptionalContentConfiguration;
G: TPdfOptionalContentGroup;
begin
// Usage varsayılanı ocuView'dır; -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;
Cfg := Inv.Configurations[Inv.SelectedConfigurationIndex];
Memo1.Lines.Add(Format('Configuration %d "%s", %d groups, /AS present: %s',
[Inv.SelectedConfigurationIndex, string(Cfg.Name), Length(Inv.Groups),
BoolToStr(Cfg.HasAutomaticState, True)]));
for G in Inv.Groups do
Memo1.Lines.Add(Format('obj %d %-24s visible=%s locked=%s radio=%d',
[G.ObjectNumber, string(G.Name),
BoolToStr(G.EffectiveVisible, True),
BoolToStr(G.Locked, True), G.RadioGroupIndex]));
end;
Her TPdfOptionalContentGroup nesne numarasını, adını, Intents'ini ve ViewState, PrintState, ExportState açık durumlarını taşır; her biri ocsUnspecified, ocsOn ya da ocsOff'tur. Bir durum ocsOn okurken grup /OFF dizisinde duruyorsa, açılış paragrafındaki tuzağı buldunuz demektir. Locked ve RadioGroupIndex seçili konfigürasyondan gelir ve hiçbir /RBGroups kümesine ait olmayan bir grup için RadioGroupIndex -1'dir
Usage sözlüğünün gerisi, dosyanın bildirdiği gibi raporlanır: Language ve LanguagePreferred, UserType ve UserNames, PageElementSubtype ve bir HasZoomRange bayrağının arkasında MinimumZoom ile MaximumZoom. EffectiveVisible bunların hiçbirine bağlı değildir; yakınlaştırmaya bağlı gösterim görüntüleyicinizin işidir. Her TPdfOptionalContentConfiguration adını, BaseState'ini, dizi içeriklerini ve RadioGroups'unu açar; üstüne /Order'u grup referanslarına düzleştirip iç içe etiket dizilerinin metin etiketlerini atlayan OrderGroupObjectNumbers'u verir
Yazdırma ve export ekrana katılmayabilir
Usage argümanı cevabı değiştirir ve amacı da budur. ocuPrint altında envanter, /ViewState'e geri dönüşlü /PrintState'i okur ve yalnızca /Event'i /Print olan /AS girdileri katılır. Yalnızca kâğıtta görünmek üzere kurulmuş bir filigran katmanı bu yüzden ocuView altında gizli, ocuPrint altında görünür raporlar. İki geçişi karşılaştırmak bu katmanları, çıktı kimseyi şaşırtmadan önce yakalar
procedure TFormMain.ReportPrintOnlyLayers;
var
OnScreen, OnPaper: TPdfOptionalContentInventory;
I: Integer;
begin
if not Pdf.InspectOptionalContent(OnScreen, ocuView) or
not Pdf.InspectOptionalContent(OnPaper, ocuPrint) then
Exit;
// İki geçiş de aynı /OCGs dizisini okur; grup sırası uyuşur
for I := 0 to High(OnScreen.Groups) do
if OnScreen.Groups[I].EffectiveVisible <> OnPaper.Groups[I].EffectiveVisible then
Memo1.Lines.Add(Format('%s: screen=%s, print=%s',
[string(OnScreen.Groups[I].Name),
BoolToStr(OnScreen.Groups[I].EffectiveVisible, True),
BoolToStr(OnPaper.Groups[I].EffectiveVisible, True)]));
end;
OCMD görünürlük ifadeleri nasıl değerlendirilir?
Bir optional content üyelik sözlüğü (OCMD, ISO 32000-1 §8.11.2.2), bir içerik parçasını bir /P politikası ya da grupları /And, /Or ve /Not ile birleştiren bir /VE görünürlük ifadesi üzerinden birkaç gruba bağlar. Belirtim, /P'ye /AnyOn varsayılanını verir, /VE mevcutsa /OCGs ve /P'ye üstünlük tanır ve grupsuz bir OCMD'nin görünürlük üzerinde etkisi olmadığını söyler
Envanterin Memberships dizisi bu kuralları, aynı geçişin grup başına sonuçlarına karşı uygular; böylece istediğiniz kullanım sona kadar taşınır. Her üyelik grup nesne numaralarını, Policy'yi (ocmpAnyOn, ocmpAllOn, ocmpAnyOff, ocmpAllOff ya da bu dördü dışındaki bir ad için ocmpUnknown), ham VisibilityExpression metnini ve kendi EffectiveVisible'ını bildirir. Grupsuz bir OCMD görünür sayılır. Bilinen bir OCG olmayan bir nesne numarasına referans da görünür sayılır; böylece tek bir başıboş referans çevresindeki her şeyi gizlemez. /VE değerlendirmesi 32 iç içe derinlikte durur ve daha derinleri gizli sayar; kendine referans veren bir ifade yığını taşıramaz. Tarama, /Type /OCMD ile dolaylı nesne olarak saklanan her OCMD'yi listeler; nesne akışları dahil
SaveAsOptionalContentConfigured ile yeni bir katman durumu yazmak
TPdf.SaveAsOptionalContentConfigured, her biri bir GroupObjectNumber ve bir Visible bayrağı tutan TPdfOptionalContentStateChange kayıtlarından oluşan bir dizi alır. Beş adımlı sıra altında seçili konfigürasyonun tam olarak o durumu ürettiği bir kopya yazar. Bahsetmediğiniz gruplar, envanterin onlar için hesapladığı görünürlüğü korur
procedure TFormMain.SaveWithoutDimensions(DimensionsObj, NotesObj: Integer;
ForPrint: Boolean);
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;
Options := TPdfOptionalContentConfigureOptions.Default;
if ForPrint then
begin
Options.Usage := ocuPrint; // /Print << /PrintState ... >> yazar
Options.ConfigurationIndex := 1; // ilk /Configs girdisi; /D olduğu gibi kalır
end;
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;
Çıktı, PDFium'un kendi kaydettiği belgeyi bayt bayt bir önek olarak tutar ve yalnızca yeniden yazılan konfigürasyon sahibini, Usage sözlükleri taşıyan OCG nesnelerini, ardından yeni bir xref bölümü ve trailer'ı ekler. Herhangi bir şey hedefinize ulaşmadan önce sonuç, sıkı yükleme politikası altındaki ayrı bir TPdf'te yeniden açılır ve o yükleme başarılı olmazsa ya da çapraz referans tablosu doğrulanmazsa metot başarısız olur. Dosya aşırı yükü, hedefin yanına geçici bir dosyaya yazar ve hedefi yalnızca doğrulamadan sonra değiştirir; reddedilen bir güncelleme önceki çizimi olduğu gibi bırakır. PDFium Component'taki PDF ad ağacı ve numara ağacı düzenleyicisinin kullandığı doğrulanmış artımlı revizyon yaklaşımının aynısıdır. Bir yazdırma ön ayarını teyit etmek için çıktıyı yeniden yükleyip InspectOptionalContent(Inv, ocuPrint, 1) çağırın; gruplar geçirdiğiniz durumları bildirmeli
Konfigüre kaydetme neyi yapmayı reddediyor?
Konfigüre kaydetme, belgenin yasakladığı ya da güvenle taşıyamayacağı her değişikliği reddeder ve her ret, hedef yazılmadan önce gerçekleşir. Kontroller sabit bir sırada çalışır. İmzalı bir belge, başka hiçbir şey olmadan EPdfError fırlatır; AllowSignedDocument = True geçirmediyseniz. Şifreli bir belge sonraki reddedilendir; çünkü düz metin artımlı nesneler etkin güvenlik işleyicisini taşıyamaz. Sonra istenen her değişiklik sınanır: /OCGs içinde olmayan bir nesne numarası büsbütün başarısız olur ve konfigürasyonun /Locked dizisinde listelenen bir gruba yapılan değişiklik başarısız olur; mevcut değerini yeniden bildirmek geçer. Son olarak EnforceRadioGroups açıktırken, birden fazla görünür üyeyle kalacak bir /RBGroups kümesi reddedilir. İmza reddi dışındaki her ret, gerekçeyi Report.ErrorMessage'e koyup False döndürür
O kapılardan ikisi belirtimin kesinlikle istediğinden daha ileri gider. §8.11.4.3, /Locked'ı görüntüleyicinin kullanıcı arayüzü üzerinden yapılacak değişikliklere karşı bir koruma olarak anlatır ve radyo düğmesi gruplarını, biri açıldığında öteki üyeleri kapatmak olarak. PDFium Component ikisini programatik değişikliklere de uygular ve radyo gruplarında üye seçip kapatmak yerine reddeder. Karşılıklı dışlayan bir kümenin iki üyesi istenince kütüphane hangisini kastettiğinizi bilemez ve bir tahmin, isteğinizle çelişirdi. Ötekileri aynı Changes dizisinde kapatın, kaydetme geçer
İmzalı belge kapısı şunun için vardır: eklenen revizyon, PDFium'un tam yeniden kaydının üstüne oturur ve bu yeni bir bayt dizisidir; mevcut bir imzanın kapsadığı bayt aralığının sağ kaldığı varsayılamaz. AllowSignedDocument = True'yu yalnızca o imzanın kaybı kabul edilebilirken geçirin
Toplu işte üç yan etki önem taşır. Yeniden yazım, seçili konfigürasyonu /BaseState /ON'a normalize eder; yazarın /Unchanged ya da /OFF tabanı, aynı görünürlüğü üreten açık dizilere dönüşür. /AS'yi düşürmek, yalnızca kâğıtta beliren filigran katmanı gibi yalnızca-yazdırma hilelerini de kaldırır; o kuralları tutmak isterseniz DisableAutomaticState'i False yapın ve kendi eventlerinizde istediğiniz durumu ezebileceklerini kabul edin. Ve /ON ile /OFF dizileri, Options.Usage için hesaplanan durumlardan yazılır; dolayısıyla konfigürasyon 0'a kaydedilen bir yazdırma ön ayarı, Usage sözlüğü olmayan her grup için ekranın gösterdiklerini de değiştirir. Yazdırma ön ayarlarını bir /Configs girdisinde tutun, /D'yi ekrana bırakın. Uyum tarafında PDF/A-2 (ISO 19005-2 clause 6.9) ve 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 yoksa bildireceği bir bulguyu baştan temizler
Katman değişikliklerini bir Delphi görüntüleyici içinde uygulamak
Görüntüleyicide katman kontrolü, envanterden kurulan bir kontrol listesi, ardından belleğe kaydetme ve yeniden yüklemedir. Kontrol listesini Groups'tan doldurun, Locked bayrağı ayarlı girdileri devre dışı bırakın, aynı RadioGroupIndex'i paylaşan üyeleri karşılıklı dışlayan sayın ve uygulamada stream aşırı yükü üzerinden bir TMemoryStream'e yazın. TPdf.LoadDocument etkin olmayan bir bileşen bekler; önce onu kapatın. Tamponlanmış yükleme baytları kopyalar; stream'i hemen serbest bırakabilirsiniz
procedure TFormMain.ApplyLayerChecklist(
const Changes: TPdfOptionalContentStateChanges);
var
Report: TPdfOptionalContentConfigureReport;
Output: TMemoryStream;
KeepPage: Integer;
begin
Output := TMemoryStream.Create;
try
try
if not Pdf.SaveAsOptionalContentConfigured(Output, Changes,
TPdfOptionalContentConfigureOptions.Default, Report) then
begin
ShowMessage('Layer update rejected: ' + Report.ErrorMessage);
Exit;
end;
except
on E: EPdfError do
begin
ShowMessage(E.Message); // imzalı dosya: Output hâlâ boş
Exit;
end;
end;
KeepPage := Pdf.PageNumber;
Pdf.Active := False;
Pdf.LoadDocument(Output); // Buffered varsayılanı True
Pdf.PageNumber := KeepPage;
finally
Output.Free;
end;
end;
Yeniden yüklemeden sonra PDFium yeni konfigürasyondan boyar; ekranla sonraki InspectOptionalContent çağrısı aynı şeyi söyler. TPdf ile TPdfView arasındaki bağlantı, Delphi'de PDFium VCL ile özellik zengini bir PDF görüntüleyici kurma makalesinde işlenir. Belgenin henüz katmanı yoksa ve eklemeniz gerekiyorsa, Delphi'de OCG ve OCMD ile PDF katmanları oluşturma makalesi SaveAsOptionalContentCreated'i anlatır
Fiyatlandırma, deneme sürümü ve bileşenin diğer belge özellikleri PDFium Component for Delphi ürün sayfasında listelenir