HotPDF escribe documentos PDF 2.0 nativos desde Delphi y C++Builder, incluidos los tres perfiles archivables PDF/A-4 y la salida accesible PDF/UA-2 con elementos de estructura en espacios de nombres. Seleccionarlos es cuestión de dos propiedades, pero las normas que hay detrás cambiaron más de lo que sugiere el número de versión: PDF/A-4 eliminó las letras de conformidad que todos aprendieron con PDF/A-2, y PDF/UA-2 introdujo espacios de nombres de estructura que un documento de parte 1 nunca tuvo
Este artículo cubre qué cambia de verdad en el archivo generado, y qué errores convierte HotPDF en una excepción en EndDoc en lugar de en un documento que falla la validación en casa del cliente
Cómo difiere la identificación de PDF/A-4 respecto a las partes 2 y 3
PDF/A-4 se identifica por número de parte y año de revisión, sin letra de conformidad para la parte base. Pon PDFACompliance a '4' y HotPDF emite pdfaid:part=4 con pdfaid:rev=2020 y ninguna entrada pdfaid:conformance en absoluto. La letra no se ha perdido —la parte 4 no tiene niveles A/B/U, porque los requisitos que solían separarlos se integraron en la parte base—
Dos extensiones conservan letra. '4E' selecciona PDF/A-4e para documentos de ingeniería y emite conformidad E, que permite los caminos de anotaciones 3D y RichMedia que los demás perfiles prohíben. '4F' selecciona PDF/A-4f y emite conformidad F, que permite un archivo incrustado de cualquier formato. Los tres fuerzan una cabecera PDF 2.0, exigen las comprobaciones habituales de output intent y metadatos de PDF/A y prohíben el cifrado —un archivo archivable cifrado es una contradicción que la norma no contempla—
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 incrusta el archivo, construye su FileSpec con un /AFRelationship, y lo registra tanto en el array /AF del catálogo como en el árbol de nombres EmbeddedFiles. Ambos registros son obligatorios; un archivo listado solo en uno es el motivo más habitual por el que una factura híbrida pasa una inspección ocular rápida y falla en un validador real. La cadena de relación admite Source, Data, Alternative, Supplement o Unspecified, y el perfil activo debe ser PDF/A-3, PDF/A-4e o PDF/A-4f —el perfil base de parte 4 no admite archivos asociados—. El nombre anterior AddPDFA3AssociatedFile sigue funcionando para código existente
Qué pide PDF/UA-2 que no pedía PDF/UA-1
PDF/UA-2 fuerza PDF 2.0 y emite pdfuaid:part=2 con pdfuaid:rev=2024, e introduce espacios de nombres en el árbol de estructura. Un documento de parte 1 tenía un vocabulario plano y único de roles estándar. Un documento de parte 2 puede portar roles personalizados siempre que cada uno pertenezca a un espacio de nombres declarado, lo que hace que el marcado específico de dominio sea legible para la tecnología de asistencia en lugar de una conjetura
Dos métodos implementan esto. RegisterStructureNamespace crea o reutiliza un diccionario indirecto /Type /Namespace y lo lista en StructTreeRoot /Namespaces, devolviendo el diccionario para que puedas reutilizarlo. AddStructureElementNS crea un elemento de estructura cuya entrada /NS apunta a ese diccionario, lo que es lo que autoriza un nombre de rol fuera del conjunto estándar. Las llamadas repetidas con el mismo URI reutilizan un único diccionario en lugar de acumular duplicados
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 aquí no es decoración. Un documento etiquetado sin lengua natural declarada deja a un lector de pantalla conjeturando la pronunciación, y PDF/UA trata la omisión como un defecto, no como una preferencia
¿Qué errores de estructura atrapa EndDoc?
Cuatro, y cada uno se corresponde con un documento que de otro modo llegaría roto a un validador. La raíz de estructura debe contener exactamente un elemento Document de nivel superior. Cada diccionario de espacio de nombres debe ser indirecto, estar tipado como Namespace y portar un URI único y no vacío. Toda referencia /NS de un elemento de estructura debe resolver a un diccionario listado de verdad en el array /Namespaces de la raíz. Y un rol sin espacio de nombres debe ser un rol estándar de PDF 2.0 o resolver a través del RoleMap
Estos se disparan en EndDoc porque ese es el último instante en que el árbol entero existe en memoria y el primero en que está completo. Atraparlos antes significaría rechazar estados intermedios válidos; atraparlos después significaría no atraparlos en absoluto. La consecuencia práctica para tu código es que un fallo de estructura aflora al final de la generación con un mensaje que nombra el problema, en lugar de aflorar semanas después como un informe de veraPDF que alguien reenvía desde un cliente
Los roles de PDF 2.0 que vale la pena conocer
La enumeración de roles tipados gana DocumentFragment, Aside, Title, FENote, Sub, Em, Strong y Artifact. Tres de ellos cambian cómo marcas los documentos de negocio ordinarios. Aside por fin da a las barras laterales y las citas destacadas un sitio que no sea un Sect mal usado. FENote marca las notas al pie y las notas finales como lo que son, de modo que un lector puede ofrecerlas en lugar de intercalarlas con el cuerpo. Em y Strong sustituyen a la conjetura semántica que venía de marcar el énfasis como formato de nivel span
La sobrecarga de cadena adicionalmente acepta la forma abierta Hn, incluidos H7 y más allá. PDF 1.7 se detenía en H6, lo que forzaba a los documentos técnicos profundos a aplanar su esquema o a reutilizar niveles. Si generas documentos de normas, códigos legales o catálogos de piezas, esto solo puede ser el motivo para pasar la salida a PDF 2.0
Qué comprobar antes de cambiar la salida de producción
PDF 2.0 es un cambio de cabecera con una larga estela. Las herramientas de ingesta de archivo antiguas, algunos RIP de impresión y un número sorprendente de visores de línea de negocio solo aceptan hasta PDF 1.7, y fallan en la cabecera en lugar de en nada que hayas hecho mal. Antes de cambiar, confirma los sistemas consumidores, y recuerda que seleccionar un perfil PDF/A-4 selecciona PDF 2.0 lo pidas o no
Una secuencia segura es conservar PDF/A-3 para los documentos que van hacia lectores desconocidos, usar PDF/A-4f para archivos internos donde tú controlas la ingesta, y adoptar PDF/UA-2 únicamente donde la política de accesibilidad lo nombre. Si estás trabajando primero el lado archivable, las guías de la validación PDF/A, PDF/X y PDF/UA y de las facturas híbridas ZUGFeRD y Factur-X sobre PDF/A-3 cubren las decisiones de perfil que importan antes que el número de versión, y las notas sobre el informe automatizado de preflight muestran cómo convertir el veredicto en parte de tu build en lugar de un paso manual
HotPDF entrega toda la superficie de autoría de PDF 2.0 como código VCL nativo para Delphi y C++Builder, de modo que la salida PDF/A-4 y PDF/UA-2 no necesita ningún motor externo ni redistribuible; la página del componente HotPDF lista los perfiles admitidos y las versiones de RAD Studio