PDF/E-1 är arkivprofilen för tekniska dokument, och PDFlibPas implementerar den som ett author mode du slår på med SetPDFEMode plus en avgränsad preflight som läser innehållsströmmar operator för operator. Profilen är inte PDF/A med en annan etikett: den har sin egen identifieringsnamnrymd, sitt eget livscykelmetadatamoment, och en regel som gör innehållsvalidering strängare än någon arkivprofil du träffat
Tekniska leveranser är anledningen till att profilen finns. Ett ritningsset som ska vara läsbart och bevisligen oförändrat om tjugo år, med en revisionshistorik som överlever, och med färg som betyder samma sak på plottern i den andra byggnaden. De kraven ger en specifikation vars tuffa delar mest ligger utanför sidinnehållet, i metadata och färghantering, vilket är precis där en generisk PDF-skrivare får det fel
Egen identifikation, inte en variant av PDF/A
Det första att få rätt är att PDF/E-1-identifikation inte kan produceras genom att anpassa PDF/A- eller PDF/X-mönstret. Den använder en egen XMP-namnrymd, http://www.aim.org/pdfe/ns/id/, och versionsvärdet måste dyka upp på två ställen: som en dokumentinformationspost och som den namnrymdskvalificerade XMP-egenskapen. Att avge bara XMP-egenskapen, eller bara informationsposten, ger en fil som bär avsikten och fallerar i valideringen
Output intent:en har en lika specifik form. PDF/E-1 kräver en inbäddad ICC-profil med subtypsidentifikatorn ISO_PDFE1, och profilen måste ha ett komponentantal som matchar den enhetsfärgfamilj dokumentet faktiskt använder. Den sista klausulen är där implementationer tyst går fel, för det betyder att intent:en inte kan väljas i förväg och sedan glömmas
Varför kräver enhetsfärg ett svep över hela dokumentet?
Därför att färgrummen gömmer sig i resursordlistor som en skanning på sidonivå aldrig når. PDF/E-1 behandlar DeviceRGB och DeviceCMYK som ömsesidigt uteslutande familjer för ett dokument, så att validera profilen innebär att känna till varenda enhetsfärgrum något i filen använder. Ett form XObject har egna resurser. Det har ett pattern också, och likaså en bild. Ett tiling pattern inuti ett form XObject inuti en sida ligger tre nivåer djupt, och en validator som bara kontrollerar sidans toppnivåresurser släpper igenom ett dokument som använder båda familjerna
Svepet registrerar därför färgrum medan det går igenom sidor, formulär, bilder och patterns som en enda traversering, och först därefter avgörs huruvida dokumentet är sammanhängande och om output intent:en matchar. Samma resonemang driver preflight-arkitekturen i allmänhet: partiell traversering ger falska godkännanden, och ett falskt godkännande på en konformanskontroll är värre än ingen kontroll, eftersom det registreras som bevis
var
Lib: TPDFlib;
Diag: WideString;
begin
Lib := TPDFlib.Create(nil);
try
Lib.LoadFromFile('assembly-drawings.pdf');
if Lib.SetPDFEMode(1) = 0 then
raise Exception.Create('PDF/E author mode was refused');
// Author mode håller livscykelmetadata i steg vid varje sparande.
// Fråga innan du sparar om dokumentet skulle klara sin egen grind
if not Lib.PDFEReadyForSave then
begin
Diag := Lib.GetPDFEDiagnostics;
Writeln('PDF/E blockers: ', Diag);
Exit;
end;
Lib.SaveToFile('assembly-drawings-pdfe.pdf');
finally
Lib.Free;
end;
end;
Livscykelmetadata är ett per-sparande åtagande
PDF/E-1 efterfrågar mer än en dokumentidentifierare. Minimisetten inkluderar media management-dokumentidentifieraren, en versionsidentifierare, en rendition class, skapandetid, ändringstid, metadatatid och en titel. Det är en revisionspårningsvokabulär, och den finns för att en teknisk leverans förväntas återutges snarare än skrivas en gång
Konsekvensen för en implementation är att dessa fält inte kan sättas vid dokumentskapandet. Om ändringstiden skrivs när du slår på läget och dokumentet redigeras efteråt har XMP-snapshoten och det faktiska dokumenttillståndet drivit isär, och en validator som jämför dem rapporterar en inkonsistens ingen avsåg. Author mode synkroniserar därför fälten omedelbart före varje sparande, så att metadatan beskriver bytena som håller på att skrivas snarare än de byten som fanns när läget slogs på
Det är en allmän princip för konformansmetadata och värd att sägas skilt från PDF/E: härledd metadata hör hemma på sparvägen, inte på redigeringsvägen. Varje fält beräknat ur dokumenttillståndet måste räknas om i ögonblicket tillståndet fryses, annars är det en cache utan invalidation
Regeln som gör innehållsvalideringen sträng
PDF/E-1 tillåter inte att kompatibilitetssektionsoperatorerna sväljer okänt innehåll. I ordinär PDF inramar BX och EX en region där en konsument måste ignorera operatorer den inte känner igen, vilket är den räddningslucka som låter en producent avge nyare konstruktioner utan att bryta äldre läsare. Under PDF/E-1 är den utvägen stängd, så vilken operator som helst som preflighten inte känner igen rapporteras ovillkorligen, oavsett om den ligger inuti en kompatibilitetssektion
Effekten på en validator är betydande. Den kan inte hoppa över regioner den inte förstår, vilket betyder att operandparsaren faktiskt måste parsa varje operator i varje innehållsström. Där kommer gränserna in. Traverseringen takas vid 128 nivåer av nästling, en miljon objekt och 64 MiB innehåll, och de gränserna är inte prestandajustering. En fientlig eller bara trasig fil kan presentera en objektgraf med cykler eller ett nästlingsdjup som förvandlar en rekursiv validator till ett stack overflow, och gränserna är det som håller ett valideringspass från att bli en denial-of-service-vektor. Samma defensiva hållning beskrivs i att parsa otillförlitliga PDF:er säkert
// Fristående validering av en fil du inte producerat, utan att
// läsa in den i en dokumentinstans
var
Issues: TStringList;
Stream: TFileStream;
I: Integer;
begin
Issues := TStringList.Create;
Stream := TFileStream.Create('incoming.pdf', fmOpenRead or fmShareDenyWrite);
try
if CheckCompliancePDFE(Stream, '', 0, Issues) = 0 then
for I := 0 to Issues.Count - 1 do
Writeln('PDF/E: ', Issues[I]);
finally
Stream.Free;
Issues.Free;
end;
end;
Vad spargrinden reparerar och vad den avslår
Grinden delar sitt arbete i två steg, och uppdelningen är en användbar designidé i sig. Först normaliserar den det som säkert kan repareras: annoteringarnas utskriftsflaggor, no-zoom- och no-rotate-flaggorna på textannoteringar, och appearance-genereringsflaggan på formulärordlistan. Det är inställningar med exakt ett korrekt värde under profilen och utan informationsinnehåll, så att fixa dem tyst är rätt och att vägra över dem vore pedanteri
Sedan kontrollerar den de villkor som inte kan repareras utan att ändra vad dokumentet betyder: version, identifikation, kryptering, output intent, enhetsfärgsammanhang och förekomsten av dynamiskt formulärinnehåll. Ett dokument som fallerar på något av dessa avslås, eftersom att hitta på en output intent eller välja en färgfamilj på författarens vägnar skulle ge en fil som klarar valideringen och ändå felaktigt representerar innehållet
Att läsa tillbaka diagnostiken via GetPDFEDiagnostics innan sparande förvandlar avslaget till en handlingsbar lista i stället för en misslyckad operation. I en batchpipeline, anropa den på varje dokument, logga blockerarna per fil och dirigera falleraren till en kö en människa tittar på. Det är betydligt mer användbart än ett sparande som raise:ar, eftersom blockerarna brukar klustra: fyrtio dokument som fallerar på samma saknade output intent är en fix, inte fyrtio
Att välja mellan arkivprofilerna
PDF/E-1 är rätt mål när leveransen är teknisk dokumentation med en revisionslivscykel, och särskilt när enhetsfärgsammanhang spelar roll eftersom utmatningen går till plotters och storformatskrivare. PDF/A är rätt mål när målet är långtids-läsbarhet för dokument i allmänhet, och det är profilen med det bredaste validatorstödet. De två är inte utbytbara, och ett dokument kan klara den ena och fallera på den andra
Om du står inför valet, börja från vem som validerar filen i andra änden. PDF/A-valideringsverktyg finns överallt, och motsvarande preflight i PDFlibPas beskrivs i PDF/A- och PDF/UA-preflight. PDF/E-validering är mer specialiserad och är vanligen ett kontraktuellt krav snarare än ett förval. När ett befintligt arkiv måste lyftas till en profil den aldrig skrevs för är metadataturepareringsvägen i konvertering till PDF/A med metadatareparation mönstret att följa, och samma form gäller här: identifiera, reparera det som är säkert, avslå resten med en lista
Author mode, den avgränsade innehållspreflighten och den fristående compliance-kontrollen medföljer alla PDFlibPas Delphi PDF library, så ett dokument kan produceras under profilen och oberoende verifieras efteråt via en separat kodväg, vilket är den enda uppläggning värd att lita på för ett konformanspåstående