HotPDF écrit des documents PDF 2.0 natifs depuis Delphi et C++Builder, y compris les trois profils d'archivage PDF/A-4 et la sortie accessible PDF/UA-2 avec éléments de structure à espace de noms. Les sélectionner est l'affaire de deux propriétés, mais les normes derrière ces propriétés ont plus changé que le numéro de version ne le suggère : PDF/A-4 a abandonné les lettres de conformité que chacun avait apprises avec PDF/A-2, et PDF/UA-2 a introduit des espaces de noms de structure qu'un document de partie 1 n'avait jamais eus
Cet article couvre ce qui change effectivement dans le fichier généré, et quelles erreurs HotPDF transforme en exception à EndDoc plutôt qu'en document qui échoue à la validation chez le client
Comment l'identification PDF/A-4 diffère des parties 2 et 3
PDF/A-4 s'identifie par numéro de partie et année de révision, sans lettre de conformité pour la partie de base. Réglez PDFACompliance à '4' et HotPDF émet pdfaid:part=4 avec pdfaid:rev=2020 et aucune entrée pdfaid:conformance du tout. La lettre n'a pas été perdue — la partie 4 n'a pas de niveaux A/B/U, car les exigences qui les séparaient autrefois ont été fondues dans la partie de base
Deux extensions gardent une lettre. '4E' sélectionne PDF/A-4e pour les documents d'ingénierie et émet la conformité E, qui autorise les chemins d'annotation 3D et RichMedia que les autres profils interdisent. '4F' sélectionne PDF/A-4f et émet la conformité F, qui autorise un fichier incorporé de n'importe quel format. Les trois forcent un en-tête PDF 2.0, exigent les contrôles habituels d'intention de sortie et de métadonnées PDF/A, et interdisent le chiffrement — un fichier d'archivage chiffré est une contradiction que la norme n'entend pas
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 incorpore le fichier, construit son FileSpec avec un /AFRelationship, et l'enregistre à la fois dans le tableau /AF du Catalog et dans l'arbre de noms EmbeddedFiles. Les deux enregistrements sont exigés ; un fichier listé dans un seul d'entre eux est la raison la plus courante pour laquelle une facture hybride passe un contrôle oculaire rapide et échoue à un vrai validateur. La chaîne de relation accepte Source, Data, Alternative, Supplement ou Unspecified, et le profil actif doit être PDF/A-3, PDF/A-4e ou PDF/A-4f — le profil de partie 4 de base n'admet pas de fichiers associés. L ancien nom AddPDFA3AssociatedFile fonctionne encore pour le code existant
Ce que PDF/UA-2 exige que PDF/UA-1 n'exigeait pas
PDF/UA-2 force PDF 2.0 et émet pdfuaid:part=2 avec pdfuaid:rev=2024, et introduit les espaces de noms dans l'arborescence de structure. Un document de partie 1 avait un vocabulaire plat unique de rôles standard. Un document de partie 2 peut porter des rôles personnalisés tant que chacun appartient à un espace de noms déclaré, ce qui rend le balisage spécifique à un domaine lisible par les technologies d'assistance au lieu d'être devinette
Deux méthodes implémentent cela. RegisterStructureNamespace crée ou réutilise un dictionnaire indirect /Type /Namespace et le liste dans StructTreeRoot /Namespaces, renvoyant le dictionnaire pour que vous puissiez le réutiliser. AddStructureElementNS crée un élément de structure dont l'entrée /NS pointe vers ce dictionnaire, ce qui autorise un nom de rôle hors de l'ensemble standard. Les appels répétés avec la même URI réutilisent un seul dictionnaire plutôt que d'empiler des doublons
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 n'est pas de la décoration ici. Un document balisé sans langue naturelle déclarée laisse un lecteur d'écran deviner la prononciation, et PDF/UA traite l'omission comme un défaut plutôt qu'une préférence
Quelles erreurs de structure EndDoc attrape-t-il ?
Quatre, et chacune correspond à un document qui atteindrait autrement un validateur cassé. La racine de structure doit contenir exactement un élément Document de plus haut niveau. Chaque dictionnaire d'espace de noms doit être indirect, typé Namespace, et porter une URI unique non vide. Chaque référence /NS d'élément de structure doit résoudre vers un dictionnaire effectivement listé dans le tableau /Namespaces racine. Et un rôle non espacé de noms doit être un rôle standard PDF 2.0 ou résoudre via la RoleMap
Cela se déclenche à EndDoc parce que c'est le dernier moment où l'arbre entier existe en mémoire et le premier où il est complet. Les attraper plus tôt signifierait rejeter des états intermédiaires valides ; les attraper plus tard signifierait ne pas les attraper du tout. La conséquence pratique pour votre code est qu'un bogue de structure affleure à la fin de la génération avec un message nommant le problème, au lieu d'affleurer des semaines plus tard comme un rapport veraPDF que quelqu un fait suivre depuis un client
Les rôles PDF 2.0 à connaître
L enum de rôles typé gagne DocumentFragment, Aside, Title, FENote, Sub, Em, Strong et Artifact. Trois d'entre eux changent la façon dont vous balisez des documents commerciaux ordinaires. Aside donne enfin aux barres latérales et aux citations tirées un foyer qui ne soit pas un Sect mal utilisé. FENote marque les notes de bas de page et notes de fin pour ce qu'elles sont, donc un lecteur peut les proposer plutôt que de les intercaler avec le texte courant. Em et Strong remplacent la devinette sémantique qui venait du balisage de l'emphase comme une mise en forme de niveau span
La surcharge de chaîne accepte en outre la forme ouverte Hn, y compris H7 et au-delà. PDF 1.7 s'arrêtait à H6, ce qui forçait les documents techniques profonds à aplanir leur plan ou à réutiliser des niveaux. Si vous générez des normes, des codes juridiques ou des catalogues de pièces, cela seul peut être la raison de déplacer la sortie vers PDF 2.0
Que vérifier avant de basculer la sortie de production
PDF 2.0 est un changement d'en-tête avec une longue traîne. Les outils d'ingestion d'archives plus anciens, certains RIP d'impression et un nombre surprenant de visionneuses métier n'acceptent que jusqu'à PDF 1.7, et ils échouent sur l'en-tête plutôt que sur quoi que ce soit que vous ayez fait de mal. Avant de basculer, confirmez les systèmes consommateurs, et souvenez-vous que sélectionner un profil PDF/A-4 sélectionne PDF 2.0 que vous l'ayez demandé ou non
Une séquence sûre est de garder PDF/A-3 pour les documents qui vont vers l'extérieur à des lecteurs inconnus, d'utiliser PDF/A-4f pour les archives internes où vous contrôlez l'ingestion, et d'adopter PDF/UA-2 seulement là où la politique d'accessibilité le nomme. Si vous travaillez d'abord le côté archivage, les guides de validation PDF/A, PDF/X et PDF/UA et de factures hybrides ZUGFeRD et Factur-X sur PDF/A-3 couvrent les choix de profil qui comptent avant le numéro de version, et les notes sur le rapport de préflight automatisé montrent comment faire du verdict une partie de votre construction plutôt qu'une étape manuelle
HotPDF livre toute la surface de création PDF 2.0 comme du code VCL natif pour Delphi et C++Builder, donc la sortie PDF/A-4 et PDF/UA-2 n'a besoin d'aucun moteur externe ni redistribuable — la page composant HotPDF liste les profils et versions RAD Studio pris en charge