Teknisk artikel

PDF/E-1-tekniska dokument i Delphi med PDFlibPas

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

PDFlibPas PDF/E-1-diagram över enhetsfärgsvepet över hela dokumentet som går igenom resursordlistor för sida, form XObject, tiling pattern och bild och samlar DeviceRGB- och DeviceCMYK-familjer innan sammanhang bedöms, jämte livscykelmetadatafälten som author mode synkroniserar om omedelbart före varje sparande så att XMP-snapshoten matchar bytena som håller på att skrivas
Färgsammanhang kan bara bedömas efter att en traversering nått varje resursordlista, och härledd livscykelmetadata räknas om i ögonblicket dokumenttillståndet fryses, inte när läget slogs på

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

PDFlibPas PDF/E-1-spargrindsdiagram för Delphi som visar den avgränsade preflighten som skannar varje innehållsströmsoperator under 128-nivåers nästling, en-miljon-objekt- och 64 MiB-tak, tyst reparerar annoteringsutskrift samt zoom- och rotate-flaggor, avslår fel version, identifikation, kryptering, output intent, enhetsfärg eller dynamiskt formulärinnehåll och rapporterar blockerare via GetPDFEDiagnostics
Grinden reparerar tyst endast det som inte bär information, avslår varje villkor en reparation skulle förvränga och förvandlar avslag till en blockerarlista via GetPDFEDiagnostics innan några byte når disk

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

PDFlibPas-beslutsdiagram som jämför PDF/E-1- och PDF/A-arkivprofiler för Delphi: PDF/E-1 för tekniska leveranser med revisionslivscykel, plotterfärg och kontraktuell validering under sin egen XMP-namnrymd med ISO_PDFE1-output intent, PDF/A för allmän långtids-läsbarhet med det bredaste validatorstödet
Börja från vem som validerar filen i andra änden: profilerna kräver olika identifikation, metadata och färggarantier, och ett dokument kan klara den ena medan det fallerar 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