PDF/E-1 ist das Archivprofil für Engineering-Dokumente, und PDFlibPas setzt es als Author Mode um, den Sie mit SetPDFEMode einschalten, plus einen begrenzten Preflight, der Content Streams Operator für Operator liest. Das Profil ist kein PDF/A mit anderem Etikett: Es hat seinen eigenen Identifikations-Namensraum, seine eigene Lifecycle-Metadaten-Anforderung und eine Regel, die die Inhaltsvalidierung strenger macht als bei jedem Archivprofil, das Sie bisher getroffen haben
Engineering-Lieferobjekte sind der Grund, warum es dieses Profil gibt. Ein Zeichnungssatz, der in zwanzig Jahren noch lesbar und nachweislich unverändert sein muss, mit einer Revision History, die überlebt, und mit Farben, die auf dem Plotter im anderen Gebäude dasselbe bedeuten. Diese Anforderungen erzeugen eine Spezifikation, deren Forderungen größtenteils außerhalb des Seiteninhalts liegen, in Metadaten und Farbmanagement — genau dort, wo ein generischer PDF-Writer sie vermasselt
Eigene Identifikation, keine Variante von PDF/A
Das Wichtigste zuerst: Die PDF/E-1-Identifikation lässt sich nicht durch Anpassen des PDF/A- oder PDF/X-Musters erzeugen. Sie benutzt einen eigenen XMP-Namensraum, http://www.aim.org/pdfe/ns/id/, und der Versionswert muss an zwei Stellen auftauchen: als Document Information Entry und als namespace-qualifizierte XMP-Eigenschaft. Nur die XMP-Eigenschaft oder nur der Informationseintrag ergibt eine Datei, die die Absicht trägt und an der Validierung scheitert
Der Output Intent hat eine ebenso spezifische Form. PDF/E-1 verlangt ein eingebettetes ICC-Profil mit dem Subtyp-Identifikator ISO_PDFE1, und das Profil muss eine Komponentenzahl haben, die zur Gerätefarbfamilie passt, die das Dokument tatsächlich benutzt. Diese letzte Klausel ist der Punkt, an dem Implementierungen still scheitern, denn sie bedeutet: Der Intent lässt sich nicht vorab wählen und dann ignorieren
Warum braucht Gerätefarbe einen Sweep über das ganze Dokument?
Weil Farbräume sich in Ressourcenwörterbüchern verstecken, die ein Scan auf Seitenebene nie erreicht. PDF/E-1 behandelt DeviceRGB und DeviceCMYK als gegenseitig ausschließende Familien für ein Dokument, also bedeutet die Profilvalidierung, jeden Geräteraum zu kennen, den irgendetwas in der Datei benutzt. Ein Form XObject hat eigene Ressourcen. Ein Pattern ebenso, und ein Bild auch. Ein Tiling-Pattern in einem Form XObject in einer Seite liegt drei Ebenen tief, und ein Validator, der nur die Ressourcen der obersten Seitenebene prüft, segnet ein Dokument ab, das beide Familien nutzt
Der Sweep registriert Farbräume daher beim Durchlaufen von Seiten, Forms, Bildern und Patterns als eine einzige Traversierung und entscheidet erst danach, ob das Dokument konsistent ist und ob der Output Intent passt. Dasselbe Denken treibt generell die Preflight-Architektur: Partielle Traversierung erzeugt falsche Pässe, und ein falscher Pass bei einer Konformitätsprüfung ist schlimmer als keine Prüfung, weil er als Nachweis protokolliert wird
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');
// Der Author Mode hält die Lifecycle-Metadaten bei jedem Speichern auf Stand.
// Vor dem Speichern fragen, ob das Dokument seine eigene Schranke passieren würde
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-Metadaten sind eine Pflicht bei jedem Speichern
PDF/E-1 verlangt mehr als einen Dokumentenidentifikator. Der Mindestsatz umfasst den Media-Management-Dokumentenidentifikator, einen Versionsidentifikator, eine Rendition Class, Erstellungszeit, Änderungszeit, Metadatenzeit und einen Titel. Das ist ein Vokabular zur Revisionsverfolgung, und es existiert, weil von einem Engineering-Lieferobjekt erwartet wird, dass es neu aufgelegt wird, statt einmal geschrieben zu werden
Die Konsequenz für eine Implementierung: Diese Felder lassen sich nicht bei der Dokumenterstellung setzen. Wird die Änderungszeit beim Einschalten des Modus geschrieben und das Dokument danach bearbeitet, driftet der XMP-Snapshot vom tatsächlichen Dokumentzustand auseinander, und ein Validator, der beide vergleicht, meldet eine Inkonsistenz, die niemand beabsichtigt hat. Der Author Mode synchronisiert die Felder deshalb unmittelbar vor jedem Speichern, sodass die Metadaten die Bytes beschreiben, die gleich geschrieben werden, nicht die, die beim Einschalten des Modus existierten
Das ist ein allgemeines Prinzip für Konformitätsmetadaten, das sich lohnt, losgelöst von PDF/E festzuhalten: Abgeleitete Metadaten gehören auf den Speicherpfad, nicht auf den Bearbeitungspfad. Jedes aus dem Dokumentzustand berechnete Feld muss in dem Moment neu berechnet werden, in dem der Zustand eingefroren wird, sonst ist es ein Cache ohne Invalidierung
Die Regel, die die Inhaltsvalidierung streng macht
PDF/E-1 erlaubt es nicht, dass die Compatibility-Section-Operatoren unbekannten Inhalt schlucken. In gewöhnlichem PDF klammern BX und EX einen Bereich, in dem ein Consumer Operatoren ignorieren muss, die er nicht erkennt — die Notluke, durch die ein Producer neuere Konstrukte ausgeben kann, ohne ältere Reader zu brechen. Unter PDF/E-1 ist diese Luke geschlossen, also wird jeder Operator, den der Preflight nicht erkennt, bedingungslos gemeldet, ob er nun in einer Compatibility Section sitzt oder nicht
Die Wirkung auf einen Validator ist erheblich. Er kann keine Bereiche überspringen, die er nicht versteht, das heißt, der Operandenparser muss wirklich jeden Operator in jedem Content Stream parsen. Genau hier kommen die Grenzen ins Spiel. Die Traversierung ist bei 128 Verschachtelungsebenen, einer Million Objekten und 64 MiB Inhalt gedeckelt, und diese Limits sind kein Performance-Tuning. Eine feindliche oder bloß kaputte Datei kann einen Objektgraphen mit Zyklen oder eine Verschachtelungstiefe präsentieren, die einen rekursiven Validator in einen Stack Overflow verwandelt, und die Limits verhindern, dass ein Validierungslauf zum Denial-of-Service-Vektor wird. Dieselbe defensive Haltung beschreibt sicheres Parsen nicht vertrauenswürdiger PDFs
// Eigenständige Validierung einer Datei, die Sie nicht erzeugt haben,
// ohne sie in eine Dokumentinstanz zu laden
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;
Was die Save-Schranke repariert und was sie verweigert
Die Schranke teilt ihre Arbeit in zwei Stufen, und diese Teilung ist für sich genommen eine brauchbare Designidee. Zuerst normalisiert sie das, was sich gefahrlos reparieren lässt: die Print-Flags von Annotationen, die No-Zoom- und No-Rotate-Flags an Textannotationen und das Appearance-Generation-Flag im Form-Wörterbuch. Das sind Einstellungen mit genau einem korrekten Wert unter dem Profil und ohne Informationsgehalt, sie lautlos zu korrigieren ist also richtig, und daran zu scheitern wäre Pedanterie
Dann prüft sie die Constraints, die sich nicht reparieren lassen, ohne zu ändern, was das Dokument bedeutet: Version, Identifikation, Verschlüsselung, Output Intent, Gerätefarbkohärenz und das Vorhandensein dynamischen Formularinhalts. Ein Dokument, das an einer dieser Bedingungen scheitert, wird verweigert, denn einen Output Intent zu erfinden oder eine Farbfamilie anstelle des Autors zu wählen, ergäbe eine Datei, die die Validierung passiert und den Inhalt falsch darstellt
Die Diagnose vor dem Speichern über GetPDFEDiagnostics zurückzulesen, macht aus dieser Verweigerung eine umsetzbare Liste statt einer fehlgeschlagenen Operation. Rufen Sie sie in einer Batch-Pipeline bei jedem Dokument auf, protokollieren Sie die Blocker pro Datei und leiten Sie die Fehlfälle in eine Queue, die ein Mensch ansieht. Das ist weit nützlicher als ein Speichern, das eine Exception wirft, denn Blocker treten meist gehäuft auf: Vierzig Dokumente, die am selben fehlenden Output Intent scheitern, sind eine Korrektur, nicht vierzig
Wahl zwischen den Archivprofilen
PDF/E-1 ist das richtige Ziel, wenn das Lieferobjekt Engineering-Dokumentation mit einem Revisionszyklus ist, und insbesondere, wenn Gerätefarbkohärenz zählt, weil die Ausgabe auf Plotter und Großformatdrucker geht. PDF/A ist das richtige Ziel, wenn es um langfristige Lesbarkeit von Dokumenten allgemein geht, und es ist das Profil mit der breitesten Validator-Unterstützung. Beide sind nicht austauschbar, und ein Dokument kann das eine erfüllen und am anderen scheitern
Wenn Sie wählen, beginnen Sie damit, wer die Datei am anderen Ende validiert. PDF/A-Validierungswerkzeuge gibt es überall, und der zugehörige Preflight in PDFlibPas ist in PDF/A- und PDF/UA-Preflight beschrieben. PDF/E-Validierung ist spezieller und meist eine vertragliche Forderung statt ein Default. Muss ein bestehendes Archiv auf ein Profil gebracht werden, für das es nie geschrieben wurde, ist der Metadaten-Reparaturpfad in Konvertierung zu PDF/A mit Metadaten-Reparatur das Muster, dem man folgt — und dieselbe Form gilt hier: identifizieren, reparieren, was sicher ist, den Rest mit einer Liste verweigern
Author Mode, der begrenzte Inhalts-Preflight und die eigenständige Compliance-Prüfung liegen alle mit der PDFlibPas Delphi PDF library vor, sodass ein Dokument unter dem Profil erzeugt und danach über einen separaten Codepfad unabhängig verifiziert werden kann — die einzige Konstellation, der man bei einer Konformitätsaussage trauen sollte