Teknisk artikel

PDF/E-1 ingeniørdokumenter i Delphi med PDFlibPas

PDF/E-1 er arkiveringsprofilen til ingeniørdokumenter, og PDFlibPas implementerer den som en author mode, du slår til med SetPDFEMode, plus en bounded preflight, der læser content streams operator for operator. Profilen er ikke PDF/A med en anden etiket: den har sin egen identification namespace, sit eget lifecycle-metadatakrav og én regel, der gør indholdsvalidering strengere end nogen arkiveringsprofil, du har mødt

Ingeniørmæssige deliverables er grunden til, at profilen findes. Et tegningssæt, der skal være læsbart og bevist uændret tyve år fra nu, med en revisionshistorik, der overlever, og med farver, der betyder det samme på plotteren i den anden bygning. De krav producerer en specifikation, hvis forventninger for størstedelens vedkommende ligger uden for sideindholdet, i metadata og farvestyring, hvilket netop er der, hvor en generisk PDF-writer tager fejl

Egen identification, ikke en variation over PDF/A

Det første, der skal sidde rigtigt, er, at PDF/E-1-identification ikke kan produceres ved at tilpasse PDF/A- eller PDF/X-mønsteret. Den bruger en distinkt XMP namespace, http://www.aim.org/pdfe/ns/id/, og versionsværdien skal optræde to steder: som document information entry og som den namespace-kvalificerede XMP-egenskab. At skrive kun XMP-egenskaben ud, eller kun information entry, giver en fil, der bærer intentionen og fejler ved validering

Output intent har en tilsvarende specifik form. PDF/E-1 kræver en indlejret ICC-profil med subtype-identifikatoren ISO_PDFE1, og profilen skal have et komponentantal, der matcher den device color-familie, dokumentet faktisk bruger. Sidstnævnte klausul er det sted, hvor implementationer lydløst tager fejl, for det betyder, at intent'en ikke kan vælges på forhånd og derefter ignoreres

Hvorfor kræver device color en gennemgang af hele dokumentet?

Fordi color spaces gemmer sig i resource dictionaries, som en scanning på sideniveau aldrig når. PDF/E-1 behandler DeviceRGB og DeviceCMYK som gensidigt udelukkende familier for et dokument, så at validere profilen betyder at kende hver eneste device color space, hvad som helst i filen bruger. En form XObject har sine egne resources. Det har et pattern også, og det har et image også. Et tiling pattern inde i en form XObject inde i en side ligger tre niveauer nede, og en validator, der kun tjekker de top-level page resources, vil godkende et dokument, der bruger begge familier

Gennemgangen registrerer derfor color spaces, mens den vandrer gennem pages, forms, images og patterns som én traversal, og først derefter afgør den, om dokumentet er sammenhængende, og om output intent matcher. Samme ræsonnement driver preflight-arkitekturen generelt: delvis traversal producerer false passes, og et false pass på et conformance-tjek er værre end intet tjek, for det registreres 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 holder lifecycle-metadataen synkroniseret ved hver save.
    // Spørg før gemning, om dokumentet ville bestå sin egen gate
    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;

Lifecycle-metadata er en forpligtelse pr. save

PDF/E-1 beder om mere end en dokumentidentifikator. Minimumssættet omfatter media management document identifier, en version identifier, en rendition class, creation time, modification time, metadata time og en title. Det er et ordforråd til revisionsporing, og det findes, fordi en ingeniørmæssig deliverable forventes at blive genudgivet snarere end skrevet én gang

Konsekvensen for en implementation er, at disse felter ikke kan sættes ved dokumentoprettelse. Bliver modification time skrevet, når du slår moden til, og dokumentet redigeres bagefter, er XMP-snapshot og den faktiske dokumenttilstand drevet fra hinanden, og en validator, der sammenligner dem, melder en inkonsistens, ingen havde tænkt sig. Author mode synkroniserer derfor felterne umiddelbart før hver save, så metadataen beskriver de byte, der er ved at blive skrevet, snarere end de byte, der eksisterede, da author mode blev slået til

Det er et generelt princip for conformance-metadata, og det er værd at sige separat fra PDF/E: afledt metadata hører hjemme på save-stien, ikke edit-stien. Ethvert felt beregnet ud fra dokumenttilstand skal recomputeres i det øjeblik, tilstanden fastfryses, ellers er det en cache uden invalidation

PDFlibPas PDF/E-1-diagram over hele dokumentets device color-gennemgang, der vandrer gennem page-, form XObject-, tiling pattern- og image resource dictionaries og indsamler DeviceRGB- og DeviceCMYK-familierne, før sammenhængen bedømmes, ved siden af de lifecycle-metadatafelter, author mode resynkroniserer umiddelbart før hver save, så XMP-snapshot matcher de byte, der er ved at blive skrevet
Farvesammenhæng kan først bedømmes, efter én traversal har nået hver resource dictionary, og afledt lifecycle-metadata recomputeres i det øjeblik dokumenttilstanden fastfryses, ikke i det øjeblik, moden slås til

Reglen, der gør indholdsvalidering streng

PDF/E-1 tillader ikke, at compatibility section-operatorerne absorberer ukendt indhold. I almindelig PDF indrammer BX og EX en region, hvor en consumer skal ignorere operatorer, den ikke genkender, hvilket er nødudgangen, der lader en producer skrive nyere konstruktioner ud uden at bryde ældre readers. Under PDF/E-1 er den flugt lukket, så enhver operator, preflighten ikke genkender, meldes ubetinget, uanset om den ligger inde i en compatibility section

Effekten på en validator er betydelig. Den kan ikke skippe regioner, den ikke forstår, hvilket betyder, at operand-parseren faktisk skal parse hver operator i hver content stream. Det er der, grænserne kommer ind. Traversal er cappet ved 128 niveauer af nesting, en million objekter og 64 MiB indhold, og de grænser er ikke performance-tuning. En fjendtlig eller blot ødelagt fil kan præsentere en objektgraf med cykler eller en nesting-dybde, der forvandler en rekursiv validator til en stack overflow, og grænserne er det, der forhindrer et valideringspass i at blive en denial-of-service-vektor. Den samme defensive holdning er beskrevet i sikker parsing af upålidelige PDF-filer

// Selvstændig validering af en fil, du ikke selv har produceret,
// uden at indlæse 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;

Hvad save-gaten reparerer, og hvad den nægter

Gaten deler sit arbejde i to stadier, og opdelingen er en brugbar designidé i sig selv. Først normaliserer den ting, der er trygt reparerbar: annotation print flags, no-zoom- og no-rotate-flaggene på text annotations og appearance-generation-flagget på form dictionary. Det er indstillinger med én korrekt værdi under profilen og intet informationsindhold, så at rette dem lydløst er rigtigt, og at nægte over dem ville være pædanti

Så tjekker den de begrænsninger, der ikke kan repareres uden at ændre, hvad dokumentet betyder: version, identification, encryption, output intent, device color-sammenhæng og tilstedeværelsen af dynamisk form-indhold. Et dokument, der fejler nogen af dem, nægtes, for at opfinde et output intent eller vælge en farvefamilie på forfatterens vegne ville give en fil, der består validering og misrepræsenterer indholdet

PDFlibPas PDF/E-1 save gate-diagram for Delphi, der viser den bounded preflight, som scanner hver content stream-operator under 128-niveaus nesting, én million objekter og 64 MiB-loft, lydløst reparerer annotation print-, zoom- og rotate-flags, nægter forkert version, identification, encryption, output intent, device color eller dynamisk form-indhold og melder blockers gennem GetPDFEDiagnostics
Gaten reparerer lydløst kun det, der bærer ingen information, nægter enhver begrænsning, en reparation ville forvanske, og forvandler nægtelsen til en blocker-liste gennem GetPDFEDiagnostics, før nogen byte når disken

At læse diagnostikken tilbage gennem GetPDFEDiagnostics før gemning forvandler den nægtelse til en handlingsorienteret liste frem for en fejlet operation. I en batch-pipeline: kald den på hvert dokument, log blockers pr. fil, og rout fejlene til en kø, et menneske kigger på. Det er langt mere nyttigt end en save, der kaster en exception, for blockers klumper sig normalt sammen: fyrre dokumenter, der fejler på grund af samme manglende output intent, er én fix, ikke fyrre

Valget mellem arkiveringsprofilerne

PDF/E-1 er det rigtige target, når deliverable er ingeniørdokumentation med en revisionslivscyklus, og især når device color-sammenhæng betyder noget, fordi output går til plottere og large-format-printere. PDF/A er det rigtige target, når målet er langsigtet læsbarhed af dokumenter i generel forstand, og det er profilen med den bredeste validator-understøttelse. De to er ikke udskiftelige, og et dokument kan tilfredsstille den ene og fejle den anden

PDFlibPas-beslutningsdiagram, der sammenligner PDF/E-1- og PDF/A-arkiveringsprofilerne for Delphi: PDF/E-1 til ingeniør-deliverables med revisionslivscyklus, plotterfarver og kontraktmæssig validering under egen XMP namespace med ISO_PDFE1 output intent, PDF/A til generel langsigtet læsbarhed med den bredeste validator-understøttelse
Start med, hvem der validerer filen i den fjerne ende: profilerne kræver forskellig identification, metadata og farvegarantier, og et dokument kan tilfredsstille den ene og fejle den anden

Skal du vælge, så start med, hvem der validerer filen i den fjerne ende. PDF/A-valideringsværktøj er overalt, og den tilsvarende preflight i PDFlibPas er beskrevet i PDF/A- og PDF/UA-preflight. PDF/E-validering er mere specialiseret og er typisk et kontraktmæssigt krav snarere end et default. Skal et eksisterende arkiv bringes op på en profil, det aldrig var skrevet til, er metadata-reparationsstien i konvertering til PDF/A med metadata-reparation mønsteret at følge, og samme form gælder her: identificér, reparer det trygge, nægt resten med en liste

Author mode, den boundede content-preflight og det selvstændige compliance-tjek følger alle med PDFlibPas Delphi PDF-biblioteket, så et dokument kan produceres under profilen og efterfølgende verificeres uafhængigt gennem en separat kodevej, hvilket er den eneste ordning, der er værd at stole på for et conformance-krav