Technischer Artikel

PDF/A, PDF/X und PDF/UA in Delphi: HotPDF-Leitfaden

PDF/A, PDF/X und PDF/UA sind drei verschiedene Standards, die drei verschiedene Probleme lösen: Langzeitarchivierung, Druckdatenaustausch und Barrierefreiheit. Sie sind keine drei Kontrollkästchen auf einem Konformitätsformular, und der häufigste Fehler besteht darin, sie so zu behandeln. Eine Datei kann makelloses PDF/A und für eine Druckerei nutzlos sein; ein perfektes Druck-Master kann für einen Screenreader unlesbar sein. Schlimmer noch: Alle drei sind Einschränkungen der internen Dateistruktur, nicht des Aussehens. Ein Dokument, das sich in jedem Viewer, den Sie besitzen, sauber öffnet, kann die Validierung beim ersten Versuch trotzdem nicht bestehen, und tut das meist auch

HotPDF, die native VCL-PDF-Bibliothek von losLab, behandelt Konformität als etwas, das Sie deklarieren, bevor die erste Seite existiert. Sie setzen eine Compliance-Eigenschaft, hängen die vom Standard geforderten Strukturen an, und die Bibliothek verweigert beim Speichern Konfigurationen, die dem Profil widersprechen. Das ist ein besseres Modell, als eine Datei zu erzeugen und zu hoffen, dass ein Nachbearbeitungsschritt sie nachrüsten kann, denn das meiste, was diese Standards verlangen, lässt sich nachträglich nicht mehr hinzufügen

Drei ISO-Standards, drei verschiedene Versprechen

Bei PDF/A (ISO 19005) geht es um Zeit. Es verspricht, dass eine Datei auch in Jahrzehnten noch identisch dargestellt wird, und verlangt daher vollständige Selbstständigkeit: jede Schrift eingebettet, jeder Farbe über einen OutputIntent eine geräteunabhängige Bedeutung gegeben, vollständige XMP-Metadaten und ein Verbot von allem, dessen Verhalten von der Umgebung abhängt. Verschlüsselung und JavaScript sind ausgeschlossen, weil niemand garantieren kann, dass der Entschlüsseler oder die Skript-Engine im Jahr 2050 noch existiert

Bei PDF/X (ISO 15930) geht es um Farbe auf Papier. Es existiert, damit ein Designer eine Datei an eine Druckerei übergeben kann, ohne dass beide sie besprechen müssen, was charakterisierte Druckbedingungen, einen verpflichtenden /Trapped-Schlüssel, definierte Beschnitt- und Anschnittgeometrie und, in der Variante X-1a, keine Live-Transparenz bedeutet, über die der RIP raten müsste. Bei PDF/UA (ISO 14289) geht es darum, wer das Ergebnis lesen kann. Assistive Technologie braucht einen vollständigen Tag-Baum, eine sinnvolle Lesereihenfolge, eine deklarierte Dokumentsprache und Textalternativen für alles, was kein Text ist

Weil die drei in verschiedene Richtungen ziehen, wählen Sie den maßgeblichen Standard pro Ausgabekanal, statt einer Datei nachzujagen, die alle erfüllt. Ein reines CMYK-Druck-Master ist genau das Falsche für einen Screenreader-Nutzer, der nie Farbe sieht, und die Sperre des Archivprofils gegen dynamisches Verhalten kollidiert mit allem Interaktiven. Erzeugen Sie pro Kanal aus denselben Quelldaten, und Sie umgehen den ganzen Konflikt

HotPDF erzeugt in Delphi PDF/A-, PDF/X- und PDF/UA-Dateien pro Ausgabekanal aus einem Quelldokument, wobei jeder ISO-Standard ein anderes strukturelles Versprechen einhält
PDF/A, PDF/X und PDF/UA ziehen in verschiedene Richtungen, daher erzeugt HotPDF eine Datei pro Ausgabekanal aus derselben Quelle

PDF/A: Der OutputIntent ist der Teil, den alle vergessen

Wenn eine PDF/A-Datei die Validierung nicht besteht, ist der OutputIntent das Erste, was zu prüfen ist. Es ist die Struktur, die Generatoren am häufigsten auslassen, gerade weil nichts Sichtbares davon abhängt. ISO 19005 verlangt einen: ein eingebettetes ICC-Profil, das festlegt, was die Gerätefarben des Dokuments tatsächlich bedeuten. HotPDF macht dieses Profil zu einer expliziten Eingabe statt zu einem Nachgedanken:

var
  Pdf: THotPDF;
  ICC: TFileStream;
begin
  Pdf := THotPDF.Create(nil);
  try
    Pdf.FileName := 'invoice-archival.pdf';
    Pdf.PDFACompliance := 'B';            // Stufe B: visuelle Treue
    Pdf.Lang := 'en-US';
    Pdf.StandardFontEmulation := False;   // echte Schriften einbetten, keine Base-14-Emulation
    ICC := TFileStream.Create('sRGB.icc', fmOpenRead);
    try
      Pdf.AddPDFAOutputIntent('sRGB IEC61966-2.1', '', ICC, 3, 'DeviceRGB');
    finally
      ICC.Free;
    end;
    Pdf.BeginDoc;
    Pdf.CurrentPage.SetFont('Arial', [], 11);
    Pdf.CurrentPage.TextOut(50, 760, 0, 'Archival invoice body');
    Pdf.EndDoc;
  finally
    Pdf.Free;
  end;
end;

Einige Details entscheiden hier über Bestehen oder Scheitern. StandardFontEmulation muss aus sein: Emulierte Base-14-Schriften werden nicht eingebettet, und Einbettung ist unter ISO 19005 nicht verhandelbar. Verschlüsselung muss deaktiviert bleiben, also kombinieren Sie PDFACompliance niemals mit ActivateProtection; eine verschlüsselte Archivdatei ist ein Widerspruch, den der Validator sofort erkennt. Die Komponentenanzahl in AddPDFAOutputIntent muss zum Profil passen, also 3 für ein RGB-Profil wie sRGB IEC61966-2.1 und 4 für CMYK. HotPDF verfolgt beim Schreiben die Verwendung von DeviceRGB und DeviceCMYK gegen den deklarierten Intent, sodass eine verirrte CMYK-Füllung in einem Dokument mit RGB-Intent zu einem gemeldeten Problem wird statt zu einem stillen

Eines lohnt sich zum ICC-Profil zu sagen: Behandeln Sie es als versioniertes Deployment-Artefakt, nicht als Datei, die jemand einmal auf dem Build-Server abgelegt hat. Seine Bytes werden in jedes Dokument eingebettet, das Sie erzeugen, sodass ein abgeschnittenes oder beschädigtes Profil still einen ganzen Stapel vergiftet, und Sie erfahren es erst bei der Validierung. Liefern Sie es mit Ihrem Installer aus, protokollieren Sie seine Prüfsumme im Lauflog und laden Sie es über das oben gezeigte TFileStream-Muster, damit eine fehlende Datei während der Erzeugung laut scheitert statt still am Archiv-Gate

PDF/X für den Druck: Trapped, CMYK und das Druckprofil

Druck-Master kehren die Farbgeschichte um. Die Druckmaschine will charakterisiertes CMYK, und der Standard zwingt Sie anzugeben, ob Trapping angewendet wurde, selbst wenn die ehrliche Antwort lautet, dass Sie keine Ahnung haben. Der /Trapped-Schlüssel ist in jedem Fall verpflichtend:

Pdf.PDFXCompliance := 'X-1a';
Pdf.Trapped := 'Unknown';        // verpflichtender Schlüssel unter ISO 15930
ICC := TFileStream.Create('FOGRA39.icc', fmOpenRead);
try
  Pdf.AddPDFXOutputIntent('FOGRA39 (ISO 12647-2:2004)', '', ICC, 4, 'DeviceCMYK');
finally
  ICC.Free;
end;
Pdf.BeginDoc;
// mit CMYK-sicheren Farben zeichnen, keine Transparenz, keine Verschlüsselung
Pdf.EndDoc;

Die Komponentenanzahl ist jetzt 4 für das CMYK-Druckprofil. X-1a verbietet außerdem Live-Transparenz, prüfen Sie also jeden Zeichencode, der halbtransparente Elemente übereinanderlegt; was ein Viewer auf dem Bildschirm zusammensetzt, ist genau das, was ein RIP zu interpretieren verweigert. Wenn Ihre Druckerei eine andere Charakterisierung schickt, tauschen Sie die Profilbytes und die Bezeichner-Zeichenkette aus und lassen die umgebende Struktur unangetastet

PDF/UA: Struktur wird erzeugt, nie nachgerüstet

Barrierefreiheit ist der Standard, den Teams am häufigsten am Ende anzuschrauben versuchen, und er bestraft diesen Ansatz härter als die anderen beiden. Der Tag-Baum muss die Reihenfolge widerspiegeln, in der der Inhalt logisch erstellt wurde, und diese Information haben Sie schlicht nicht mehr, sobald die Datei geschrieben ist. Das Setzen von PDFUACompliance schaltet die getaggte Ausgabe ein, und die Struktur-API bindet jeden Zeichenaufruf im laufenden Betrieb an seine semantische Rolle:

HotPDF baut den PDF/UA-Tag-Baum live auf, während jeder Delphi-Zeichenaufruf ausgeführt wird, und Text, der außerhalb von BeginTaggedContent und EndTaggedContent ausgegeben wird, bleibt für Screenreader unsichtbar
Der Tag-Baum wird beim Zeichnen geschrieben, und Text außerhalb eines getaggten Paars wird korrekt dargestellt, bleibt aber für Screenreader unsichtbar
Pdf.PDFUACompliance := True;     // aktiviert automatisch getaggtes PDF
Pdf.Lang := 'en-US';             // explizit setzen; leer fällt auf 'en' zurück
Pdf.BeginDoc;

Root := Pdf.AddStructureElement(sstDocument, nil);
H1 := Pdf.EmitTaggedHeading(1, Root, 50, 700, 'Quarterly Report');
Para := Pdf.BeginTaggedContent('P', Root);
Pdf.CurrentPage.TextOut(50, 650, 0, 'Revenue grew in all regions.');
Pdf.EndTaggedContent;

Pdf.EndDoc;

Der Fehler, auf den Sie achten müssen, ist Text, der außerhalb eines BeginTaggedContent/EndTaggedContent-Paars gezeichnet wird. Er wird perfekt dargestellt und bleibt für einen Screenreader unsichtbar, sodass kein sehender Tester ihn je bemerkt; der Fehler wird ausgeliefert und tritt erst zutage, wenn ein tatsächlicher Nutzer assistiver Technologie auf die Lücke stößt. Wenn Ihre Vorlagen eigene Strukturrollennamen tragen, bilden Sie sie mit AddStructRoleMap('MyHead', 'H1') auf den Standardsatz ab, damit konforme Reader wissen, was sie bedeuten. ISO 14289 verlangt außerdem eine deklarierte Sprache. HotPDF fällt auf 'en' zurück, wenn Lang leer ist, aber das ist ein Sicherheitsnetz, kein Grund, die tatsächliche Dokumentsprache ungesetzt zu lassen

Verifikation: dem Validator vertrauen, nicht dem Viewer

Ein Viewer, der Ihre Datei öffnet, beweist nichts über Konformität, daher gehört die Verifikation in den Release-Pfad mit Werkzeugen, die Struktur statt Darstellung prüfen. Für PDF/A und PDF/UA ist veraPDF der offene Validator in Referenzqualität; er meldet Fehler nach ISO-Klausel, was sich direkt auf die obige Konfiguration zurückführen lässt. Für PDF/X sind die Preflight-Profile von Adobe Acrobat nach wie vor die praktische Prüfung, denn Druckkonformität ist ebenso eine Frage der Farbabsicht wie der Syntax

Der Generator leistet seinen eigenen Beitrag dazu. Beim Speichern gleicht HotPDF die Funktions-Flags mit der konfigurierten PDF-Version ab und stuft still herab, was die Version nicht ausdrücken kann, etwa AES-256, das unter PDF 1.7 auf AES-128 fällt. Die Compliance-Gates in EndDoc gehen weiter und lösen bei harten Widersprüchen direkt eine Exception aus, etwa wenn PDFACompliance zusammen mit Verschlüsselung angefordert wird. Keines davon ersetzt den externen Validator. Sie verhindern nur, dass unmögliche Konfigurationen ihn überhaupt erreichen

HotPDF-Compliance-Gates in EndDoc fangen unmögliche Konfigurationen ab, bevor veraPDF PDF/A und PDF/UA und Acrobat Preflight PDF/X in einem Delphi-Release-Pfad validieren
HotPDF verweigert widersprüchliche Konfigurationen bei EndDoc, und unabhängige Validatoren entscheiden über die tatsächliche Konformität

Eine Gewohnheit zahlt sich immer wieder aus: Versionieren Sie das gesamte Compliance-Setup als Einheit. Das HotPDF-Release, die Vorlagenrevision, die Prüfsumme des ICC-Profils, den Validator-Build, der die Freigabe erteilt hat. Konformität driftet in dem Moment, in dem sich eines davon unter den anderen ändert, und die hässlichsten Audits sind diejenigen, bei denen niemand rekonstruieren kann, welche Kombination eine fünf Jahre alte Archivdatei erzeugt hat. Ein einziger Konfigurationsdatensatz pro Stapel klärt das ein für alle Mal

Zuletzt: Lassen Sie den Validator auf echter Produktionsausgabe laufen, nie auf einem sauberen handgebauten Beispiel. Die Fehler, die wehtun, stammen aus Daten, die niemand vorhergesehen hat: ein Kundenlogo, das als CMYK ankommt, während der Intent RGB sagt, eine Vorlagenänderung, die eine nicht eingebettete Schrift einschleust, ein neuer Codepfad, der Text außerhalb des Tag-Baums zeichnet. Bewahren Sie von jedem vergangenen Vorfall eine bekannt fehlerhafte Datei als Regressionseingabe auf, und das Compliance-Gate bleibt über die Zeit ehrlich. Zur Darstellungsseite dieser Pipelines siehe unseren Artikel über Berichtsausgabe, Schriften und Bilder mit HotPDF; zum Einbinden von Validatoren in einen Build gibt es einen Begleitartikel zur Automatisierung von PDF-Preflight-Prüfungen

Die in diesen Beispielen verwendeten Compliance-Eigenschaften, Output-Intents und die Tagging-API werden mit der HotPDF Delphi Component für Delphi und C++Builder ausgeliefert; die Produktseite verlinkt die vollständige Referenz für jeden hier gezeigten Aufruf