PDFium Component upravlja sloje neobvezne vsebine PDF (OCG) v Delphiju skozi dve metodi TPdf: InspectOptionalContent našteje vsak sloj skupaj z vidnostjo, ki jo bo PDFium dejansko izrisal, SaveAsOptionalContentConfigured pa zapiše preverjeno kopijo, v kateri so sloji, ki jih izberete, preklopljeni v ali iz. Druga metoda hkrati nevtralizira pravila Usage in /AS, ki bi sicer tiho razveljavila Vašo spremembo. Obe delujeta na dokumentu, ki je že odprt v TPdf, zato ni drugega razčlenjevalnika, ki bi ga bilo treba usklajevati s tem, kar prikazuje pregledovalnik
Zahteva ponavadi pride iz delavnice za CAD ali GIS: nabor risb se pošlje s kotami, pripombami in glavo risbe na ločenih slojih, stranka pa želi kopijo s skritimi kotami, preden gre k dobavitelju. PDFium neobvezno vsebino izriše pravilno, a njegov javni ABI nima funkcije za naštevanje OCG, izbiro konfiguracije ali preklop stanja sloja. Torej se spustite na raven objektov, uredite /OCProperties, shranite, znova naložite — in sloj je še vedno tam. Razlog je logika vidnosti PDFium in vredno je razumevanja, preden se dotaknete katerega koli bajta
Zakaj urejanje /ON in /OFF ne spremeni tega, kar PDFium izriše?
Urejanje tabel /ON in /OFF konfiguracijskega slovarja ne zadošča, ker PDFium pusti, da izrecno stanje znotraj lastnega slovarja /Usage OCG premaga ti tabeli, pravilo samodejnega stanja /AS pa lahko nato preglasi oboje. ISO 32000-1 §8.11.4 opisuje konfiguracije in slovarje uporabe kot ločena mehanizma; izrisovalnik PDFium ju zloži v eno samo odločitev, InspectOptionalContent pa jo reproducira v tem vrstnem redu:
- Začnite pri
/BaseStatekonfiguracije, kjer/ONin/Unchangedoba štejeta kot vidna in le/OFFskriva - Uporabite tabelo
/ONkonfiguracije, nato njeno tabelo/OFF, tako da skupina, navedena v obeh, konča skrita - Uporabite izrecno stanje Usage skupine za zahtevano uporabo, na primer
/Usage << /View << /ViewState /OFF >> >>, ki preglsi vse zgoraj - Skupino, katere
/Intentne vsebuje ne/Viewne/All, obravnavajte kot vidno, saj ne sodeluje pri vidnosti z namenom pogleda - Nazadnje poženite tabelo
/ASizbrane konfiguracije, katere vnosi za ujemajoči se dogodek nastavijo stanje skupin, ki jih navajajo
Tretji korak je tisti, ki ljudi zažge. Datoteka, shranjena z orodjem za postavitev, pogosto nosi /ViewState /ON na vsakem OCG, PDFium potem ignorira Vašo skrbno urejeno tabelo /OFF: shranjevanje uspe, datoteka se čisto ponovno odpre in sloj še vedno slika. Za Print in Export OcExplicitUsageState najprej prebere PrintState ali ExportState in pade nazaj na ViewState, kadar posebnega vnosa ni, zato osamljen ViewState /ON pripne sloj tudi za tiskanje. Označena vsebina, ki se sklicuje na OCMD (§8.11.2.2), se nato razreši proti tem rezultatom na skupino, prek politike /P ali, če je prisoten, izraza vidnosti /VE
Kako naštejete sloje, ki jih bo PDFium dejansko pokazal?
TPdf.InspectOptionalContent vrne TPdfOptionalContentInventory, katerega tabela Groups nosi številko objekta vsakega OCG, ime, namene, tri stanja Usage, jezik, obseg povečave, zastavico Locked, indeks radijske skupine in izračunani EffectiveVisible. Metoda najprej od PDFium zahteva shranjevanje trenutnega dokumenta v pomnilniku, razširi toke objektov in preišče rezultat, tako da se spremembe, narejene prej v seji, odražajo. Indeks konfiguracije 0 je vedno privzeti slovar /D in vnosi /Configs sledijo od indeksa 1; privzeti argument -1 izbere indeks 0. Dokument brez /OCProperties naredi, da metoda vrne False z razlogom v ErrorMessage, namesto da sproži izjemo
procedure TFormMain.ListLayers;
var
Inv: TPdfOptionalContentInventory;
G: TPdfOptionalContentGroup;
begin
// Usage je privzeto ocuView; -1 izbere konfiguracijo 0, slovar /D
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;
Tabela Memberships poroča vsak OCMD z njegovo Policy (ocmpAnyOn, ocmpAllOn, ocmpAnyOff, ocmpAllOff), surovim besedilom VisibilityExpression in njegovim lastnim EffectiveVisible. Nekaj mejnih pravil je namernih. /P ima privzeto /AnyOn in OCMD brez skupin se šteje kot viden. Sklic na številko objekta, ki ni znan OCG, se obravnava kot viden, namesto da bi spodletel celoten izraz. Ovrednotenje /VE se ustavi pri globini gnezdenja 32 in vse globljeje obravnava kot skrito, kar preprečuje, da bi sovražen ali samonanašajoč se izraz pretvoril pregled v prekoračitev sklada
Zapis novega stanja sloja s SaveAsOptionalContentConfigured
TPdf.SaveAsOptionalContentConfigured vzame tabelo zapisov TPdfOptionalContentStateChange (številka objekta skupine plus Visible) in zapiše dokument, v katerem izbrana konfiguracija proizvede točno to stanje. Izbrana konfiguracija dobi /BaseState /ON plus popolni tabeli /ON in /OFF, ki pokrijeta vsako skupino, vsak OCG, ki že ima slovar Usage, pa dobi izrecen ViewState (ali PrintState / ExportState, slediti Options.Usage), ki se ujema z njegovim novim stanjem. S TPdfOptionalContentConfigureOptions.Default je ključ /AS izbrane konfiguracije odstranjen, tako da dogodek odpiranja, tiskanja ali izvoza ne more slojev preklopiti nazaj
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;
// Konfiguracija 0, ocuView, DisableAutomaticState in 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;
Zapisovalna pot obdrži PDFiumov lasten shranjeni izhod kot predpono, bajt za bajtom, in pripne le prenovljenega lastnika konfiguracije ter objekte OCG, ki nosijo slovarje Usage, ki jim sledi nov razdelek xref in trailer. Preden en sam bajt doseže Vaš cilj, je rezultat znova odprt v ločenem TPdf pod strogo politiko nalaganja, metoda pa spodleti, če tabela navzkrižnih sklicev ni veljavna. Preobremenitev za datoteko gre še korak dlje: piše v začasno datoteko poleg cilja in cilj zamenja šele, ko se potrditev uspe, zato zavrnjena posodobitev nikoli ne pusti za sabo polzapisane risbe. To je isti pristop preverjene inkrementalne revizije, ki ga uporablja urejevalnik imenskih in številčnih dreves PDF v PDFium Component
Česa se konfigurirano shranjevanje odklanja?
Konfigurirano shranjevanje odklanja vsako spremembo, ki jo dokument sam prepoveduje ali je ne zna varno predstaviti, vsaka zavrnitev pa se zgodi, preden se cilj kadarkoli dotakne. Številka objekta, ki ni v /OCGs, spodleti brez pogajanj. Sprememba skupine, navedene v tabeli /Locked konfiguracije, spodleti, čeprav je ponovitev njene trenutne vrednosti dovoljena. Z vklopljenim EnforceRadioGroups je vsaka množica /RBGroups, ki bi končala z več kot enim vidnim članom, zavrnjena, namesto da bi druge tiho izklopila. Šifrirani dokumenti so zavrnjeni, ker inkrementalni objekti v čistem besedilu ne morejo nositi dejavnega varnostnega upravljalnika. Podpisani dokumenti sprožijo EPdfError, razen če podate AllowSignedDocument = True, saj lahko sprememba tega, kaj stran prikazuje, pokvari pokritost podpisa ali politiko overitve
function TFormMain.SavePrintPreset(Target: TStream;
const Changes: TPdfOptionalContentStateChanges): Boolean;
var
Options: TPdfOptionalContentConfigureOptions;
Report: TPdfOptionalContentConfigureReport;
begin
Options := TPdfOptionalContentConfigureOptions.Default;
Options.Usage := ocuPrint; // zapiše /Print << /PrintState ... >>
Options.ConfigurationIndex := 1; // prvi vnos /Configs, ne /D
try
Result := Pdf.SaveAsOptionalContentConfigured(Target, Changes, Options,
Report); // AllowSignedDocument ostane False
if not Result then
ShowMessage(Report.ErrorMessage);
except
on E: EPdfError do
begin
ShowMessage(E.Message); // podpisanca: v Target ni zapisano nič
Result := False;
end;
end;
end;
Poznajte kompromise, preden to povežete v paketno opravilo. Pripeta revizija leži na vrhu polnega ponovnega zapisa PDFium, ne Vaših izvirnih bajtov datoteke — točno zato potrebuje podpisan vnos izrecno privolitev. Prenova tudi normalizira izbrano konfiguracijo na /BaseState /ON, tako da je izhodišče /Unchanged ali /OFF avtorja zamenjano z izrecnima tabelama z isto posledično vidnostjo. Odstranitev /AS odstrani trike le za tiskanje, kot je sloj z vodnim žigom, ki se pokaže le na papirju; nastavite DisableAutomaticState na False, da ta pravila ohranite, in sprejmite, da lahko preglasijo Vaše zahtevano stanje za ta dogodek. Na pozitivni strani PDF/A-2 (ISO 19005-2 točka 6.9) in PDF/UA (ISO 14289-1 točka 7.10) oba prepovedujeta /AS v konfiguracijskih slovarjih, zato privzeti izhod odstrani eno težavo, ki bi jo Vaša validacija PDF/A preflight s komponento PDFium Component sicer prijavila
Kje se nadzor slojev ujema s pregledovalnikom PDF v Delphiju
V pregledovalniku je nadzor slojev kontrolni seznam, ki ga poganja inventar plus ponovno nalaganje shranjenega rezultata. Kontrolni seznam napolnite iz Groups, onemogočite vnose, ki so Locked, člane z istim RadioGroupIndex obravnavajte kot medsebojno izključujoče in ob uporabi zapišite v TMemoryStream ter ta tok naložite nazaj v TPdf, tako da pogled slika novo stanje. Ožičenje med TPdf in TPdfView pokriva gradnja bogatega pregledovalnika PDF s PDFium VCL v Delphiju. Licenciranje, preskusni prenosi in preostanek nabora funkcij so na strani izdelka PDFium Component for Delphi