HotPDF schreibt native PDF-2.0-Dokumente aus Delphi und C++Builder, einschließlich der drei PDF/A-4-Archiv-Profile und barrierefreier PDF/UA-2-Ausgabe mit Namensraum-Strukturelementen. Sie auszuwählen ist Sache von zwei Eigenschaften, doch die Standards hinter diesen Eigenschaften haben sich stärker verändert, als die Versionsnummer vermuten lässt: PDF/A-4 hat die Konformitätsbuchstaben fallengelassen, die jeder mit PDF/A-2 gelernt hat, und PDF/UA-2 hat Struktur-Namensräume eingeführt, die ein Part-1-Dokument nie hatte
Dieser Artikel behandelt, was sich in der erzeugten Datei tatsächlich ändert und welche Fehler HotPDF bei EndDoc zu einer Ausnahme macht statt zu einem Dokument, das beim Kunden bei der Validierung scheitert
Wie sich die PDF/A-4-Identifikation von Part 2 und 3 unterscheidet
PDF/A-4 identifiziert sich über Part-Nummer und Revisionsjahr, ohne Konformitätsbuchstaben beim Basis-Part. Setzt man PDFACompliance auf '4', emittiert HotPDF pdfaid:part=4 mit pdfaid:rev=2020 und gar keinen pdfaid:conformance-Eintrag. Der Buchstabe ist nicht verloren gegangen — Part 4 hat keine A/B/U-Level, weil die Anforderungen, die sie früher trennten, in den Basis-Part eingefaltet wurden
Zwei Erweiterungen behalten einen Buchstaben. '4E' wählt PDF/A-4e für technische Dokumente und emittiert Konformität E, was die 3D- und RichMedia-Anmerkungs-Pfade erlaubt, die die anderen Profile verbieten. '4F' wählt PDF/A-4f und emittiert Konformität F, was eine eingebettete Datei beliebigen Formats erlaubt. Alle drei erzwingen einen PDF-2.0-Header, verlangen die üblichen PDF/A-Ausgabe-Absicht- und Metadaten-Prüfungen und verbieten Verschlüsselung — eine verschlüsselte Archivdatei ist ein Widerspruch, den der Standard nicht zulässt
var
Pdf: THotPDF;
begin
Pdf := THotPDF.Create(nil);
try
Pdf.FileName := 'invoice-archive.pdf';
Pdf.PDFACompliance := '4F'; // PDF/A-4f: associated files of any format
Pdf.BeginDoc;
Pdf.CurrentPage.SetFont('Arial', [], 11);
Pdf.CurrentPage.TextOut(50, 760, 0, 'Invoice 2026-0731');
Pdf.AddPDFAssociatedFile('invoice.xml', 'text/xml',
'Structured invoice data', 'Data', LoadInvoiceBytes);
Pdf.EndDoc;
finally
Pdf.Free;
end;
end;
AddPDFAssociatedFile bettet die Datei ein, baut ihre FileSpec mit einer /AFRelationship und registriert sie sowohl im /AF-Array des Catalog als auch im EmbeddedFiles-Namensbaum. Beide Registrierungen sind vorgeschrieben; eine Datei, die nur in einer der beiden geführt ist, ist der häufigste Einzelgrund, warum eine Hybrid-Rechnung eine flüchtige Sichtprüfung besteht und an einem echten Validator scheitert. Die Beziehungs-Zeichenfolge akzeptiert Source, Data, Alternative, Supplement oder Unspecified, und das aktive Profil muss PDF/A-3, PDF/A-4e oder PDF/A-4f sein — das Basis-Profil von Part 4 lässt keine zugehörigen Dateien zu. Der ältere Name AddPDFA3AssociatedFile funktioniert für bestehenden Code weiterhin
Was PDF/UA-2 verlangt, was PDF/UA-1 nicht verlangte
PDF/UA-2 erzwingt PDF 2.0 und emittiert pdfuaid:part=2 mit pdfuaid:rev=2024, und es führt Namensräume in den Strukturbaum ein. Ein Part-1-Dokument hatte ein flaches Vokabular an Standard-Rollen. Ein Part-2-Dokument kann eigene Rollen führen, solange jede zu einem deklarierten Namensraum gehört, was domänenspezifisches Tagging für unterstützende Technologien lesbar macht statt zu Raterei
Zwei Methoden setzen das um. RegisterStructureNamespace legt ein indirektes /Type /Namespace-Dictionary an oder verwendet es erneut und listet es in StructTreeRoot /Namespaces, wobei es das Dictionary zurückgibt, damit man es wiederverwenden kann. AddStructureElementNS legt ein Strukturelement an, dessen /NS-Eintrag auf dieses Dictionary zeigt, was einen Rollennamen außerhalb des Standard-Sets legitimiert. Wiederholte Aufrufe mit derselben URI verwenden ein Dictionary statt Duplikate aufzutürmen
var
Root: THPDFDictionaryObject;
begin
Pdf.PDFUACompliance := True;
Pdf.PDFUAPart := 2; // part 2 forces PDF 2.0
Pdf.Lang := 'en-US';
Pdf.BeginDoc;
Root := Pdf.AddStructureElement('Document', nil);
Pdf.AddStructureElementNS('WidgetGroup',
'https://example.com/ns/widgets', Root);
Pdf.EndDoc;
end;
Lang ist hier keine Zierde. Ein getaggtes Dokument ohne deklarierte natürliche Sprache lässt einen Screen-Reader bei der Aussprache raten, und PDF/UA behandelt das Fehlen als Mangel, nicht als Präferenz
Welche Struktur-Fehler fängt EndDoc ab?
Vier, und jeder entspricht einem Dokument, das sonst kaputt bei einem Validator ankäme. Die Struktur-Wurzel muss exakt ein Top-Level-Document-Element enthalten. Jedes Namensraum-Dictionary muss indirekt sein, als Namespace typisiert und eine eindeutige nicht-leere URI tragen. Jede /NS-Referenz eines Strukturelements muss zu einem Dictionary auflösen, das tatsächlich im /Namespaces-Array der Wurzel geführt ist. Und eine Rolle ohne Namensraum muss eine PDF-2.0-Standard-Rolle sein oder über die RoleMap auflösen
Diese feuern bei EndDoc, weil das der letzte Moment ist, in dem der gesamte Baum im Speicher existiert, und der erste, in dem er vollständig ist. Sie früher abzufangen hieße, gültige Zwischenzustände abzulehnen; sie später abzufangen hieße, sie gar nicht abzufangen. Die praktische Folge für den eigenen Code ist, dass ein Struktur-Fehler am Ende der Erzeugung mit einer Meldung auftaucht, die das Problem benennt, statt Wochen später als ein veraPDF-Bericht aufzutauchen, den jemand von einem Kunden weiterleitet
Die PDF-2.0-Rollen, die man kennen sollte
Die typisierte Rollen-Enumeration erhält DocumentFragment, Aside, Title, FENote, Sub, Em, Strong und Artifact. Drei davon ändern, wie man gewöhnliche Geschäftsdokumente taggt. Aside gibt Seitenleisten und Zitaten endlich ein Zuhause, das kein zweckentfremdetes Sect ist. FENote markiert Fuß- und Endnoten als das, was sie sind, sodass ein Reader sie anbieten kann statt sie mit dem Fließtext zu verschachteln. Em und Strong ersetzen die semantische Raterei, die daraus entstand, Hervorhebung als Span-Level-Formatierung zu taggen
Die String-Überladung akzeptiert zusätzlich die offene Form Hn, einschließlich H7 und darüber hinaus. PDF 1.7 machte bei H6 Schluss, was tiefe technische Dokumente zwang, ihre Gliederung abzuflachen oder Ebenen wiederzuverwenden. Wer Norm-Dokumente, Gesetzestexte oder Teile-Kataloge erzeugt, kann allein deshalb die Ausgabe auf PDF 2.0 umstellen
Was vor der Umstellung der Produktions-Ausgabe zu prüfen ist
PDF 2.0 ist eine Header-Änderung mit langer Nachwirkung. Ältere Archiv-Ingest-Werkzeuge, manche Druck-RIPs und eine erstaunliche Zahl von Line-of-Business-Betrachtern akzeptieren nur bis PDF 1.7 und scheitern am Header statt an etwas, das man falsch gemacht hat. Vor der Umstellung die verarbeitenden Systeme bestätigen, und daran denken, dass die Wahl eines PDF/A-4-Profils PDF 2.0 mit auswählt, ob man es wollte oder nicht
Eine sichere Reihenfolge ist, PDF/A-3 für Dokumente beizubehalten, die nach außen an unbekannte Leser gehen, PDF/A-4f für interne Archive zu verwenden, bei denen man den Ingest kontrolliert, und PDF/UA-2 nur dort zu übernehmen, wo die Barrierefreiheits-Policy es namentlich verlangt. Wer zuerst die Archiv-Seite angeht, für den behandeln die Leitfäden zur PDF/A-, PDF/X- und PDF/UA-Validierung und zu ZUGFeRD- und Factur-X-Hybrid-Rechnungen auf PDF/A-3 die Profil-Wahlen, die vor der Versionsnummer zählen, und die Hinweise zum automatisierten Preflight-Bericht zeigen, wie man das Urteil zum Teil des Builds macht statt zu einem manuellen Schritt
HotPDF liefert die gesamte PDF-2.0-Autoren-Oberfläche als nativen VCL-Code für Delphi und C++Builder, sodass PDF/A-4- und PDF/UA-2-Ausgabe keine externe Engine und kein Redistributable brauchen — die HotPDF-Komponenten-Seite listet die unterstützten Profile und RAD-Studio-Versionen