Artículo técnico

Salida PDF/A, PDF/X y PDF/UA en Delphi con HotPDF

PDF/A, PDF/X y PDF/UA son tres normas distintas que resuelven tres problemas distintos: archivado a largo plazo, intercambio para imprenta y accesibilidad. No son tres casillas de un mismo formulario de conformidad, y el error más habitual es tratarlas como si lo fueran. Un archivo puede ser PDF/A impecable e inservible para una imprenta; un maestro de impresión perfecto puede resultar ilegible para un lector de pantalla. Peor aún: las tres son restricciones sobre la estructura interna del archivo, no sobre su aspecto. Un documento que se abre sin problemas en todos los visores que tiene puede seguir suspendiendo la validación a la primera, y suele hacerlo

HotPDF, la biblioteca PDF VCL nativa de losLab, trata la conformidad como algo que se declara antes de que exista la primera página. Se fija una propiedad de conformidad, se adjuntan las estructuras que exige la norma y la biblioteca rechaza al guardar las configuraciones que contradicen el perfil. Es un modelo mejor que generar un archivo y confiar en que un posprocesador se lo pueda adaptar a posteriori, porque casi nada de lo que exigen estas normas puede añadirse después

Tres normas ISO, tres promesas distintas

PDF/A (ISO 19005) trata del tiempo. Promete que un archivo se seguirá representando igual dentro de décadas, así que exige autosuficiencia completa: todas las fuentes incrustadas, todo color dotado de significado independiente del dispositivo mediante un OutputIntent, metadatos XMP completos y la prohibición de cualquier cosa cuyo comportamiento dependa del entorno. El cifrado y JavaScript quedan fuera, porque nadie puede garantizar que el descifrador o el motor de scripts existan en 2050

PDF/X (ISO 15930) trata del color sobre papel. Existe para que un diseñador pueda entregar un archivo a una imprenta sin que ninguno de los dos tenga que hablar del asunto, lo que implica condiciones de impresión caracterizadas, una clave /Trapped obligatoria, geometría de corte y sangrado definida y, en la variante X-1a, nada de transparencia viva que el RIP tenga que adivinar. PDF/UA (ISO 14289) trata de quién puede leer el resultado. La tecnología de asistencia necesita un árbol de etiquetas completo, un orden de lectura sensato, un idioma de documento declarado y alternativas textuales para todo lo que no sea texto

Como las tres tiran en direcciones distintas, elija la norma que gobierna cada canal de salida en lugar de perseguir un único archivo que las satisfaga todas. Un maestro de impresión solo en CMYK es justo lo que no hay que entregar a quien usa un lector de pantalla y nunca ve el color, y el blindaje del perfil de archivado frente al comportamiento dinámico choca con cualquier cosa interactiva. Genere por canal a partir de los mismos datos de origen y se ahorrará el conflicto entero

HotPDF genera archivos PDF/A, PDF/X y PDF/UA por canal de salida a partir de un único documento fuente en Delphi, y cada norma ISO mantiene una promesa estructural distinta
PDF/A, PDF/X y PDF/UA tiran en direcciones distintas, así que HotPDF genera un archivo por canal de salida a partir del mismo origen

PDF/A: el OutputIntent es la parte que todo el mundo olvida

Si un archivo PDF/A suspende la validación, el OutputIntent es lo primero que hay que revisar. Es la estructura que los generadores se saltan con más frecuencia, precisamente porque nada visible depende de ella. ISO 19005 exige una: un perfil ICC incrustado que fije qué significan de verdad los colores de dispositivo del documento. HotPDF convierte ese perfil en una entrada explícita y no en una ocurrencia tardía:

var
  Pdf: THotPDF;
  ICC: TFileStream;
begin
  Pdf := THotPDF.Create(nil);
  try
    Pdf.FileName := 'invoice-archival.pdf';
    Pdf.PDFACompliance := 'B';            // nivel B: fidelidad visual
    Pdf.Lang := 'en-US';
    Pdf.StandardFontEmulation := False;   // incrusta fuentes reales, sin emulación Base-14
    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;

Aquí unos pocos detalles deciden si pasa o no. StandardFontEmulation tiene que estar desactivada: las fuentes Base-14 emuladas no se incrustan, y la incrustación no es negociable bajo ISO 19005. El cifrado debe seguir desactivado, así que no combine nunca PDFACompliance con ActivateProtection; un archivo de archivado cifrado es una contradicción que el validador detecta de inmediato. El número de componentes de AddPDFAOutputIntent debe coincidir con el perfil: 3 para un perfil RGB como sRGB IEC61966-2.1 y 4 para CMYK. HotPDF vigila el uso de DeviceRGB y DeviceCMYK frente al intent declarado mientras escribe, de modo que un relleno CMYK perdido en un documento con intent RGB se convierte en un problema notificado y no silencioso

Vale la pena decir algo sobre el perfil ICC: trátelo como un artefacto de despliegue versionado, no como un archivo que alguien dejó un día en el servidor de compilación. Sus bytes se incrustan en cada documento que genera, así que un perfil truncado o corrupto envenena en silencio todo un lote y solo se entera en el momento de validar. Distribúyalo con su instalador, registre su suma de comprobación en el registro de ejecución y cárguelo con el patrón TFileStream mostrado arriba para que un archivo ausente falle de forma ruidosa durante la generación y no calladamente en la puerta del archivo histórico

PDF/X para imprenta: Trapped, CMYK y el perfil de máquina

Los maestros de impresión invierten la historia del color. La máquina quiere CMYK caracterizado, y la norma le obliga a declarar si se ha aplicado reventado incluso cuando la respuesta honesta es que no tiene ni idea. La clave /Trapped es obligatoria de todos modos:

Pdf.PDFXCompliance := 'X-1a';
Pdf.Trapped := 'Unknown';        // clave obligatoria según 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;
// dibuje con colores seguros en CMYK, sin transparencia ni cifrado
Pdf.EndDoc;

El número de componentes es ahora 4 para el perfil CMYK de máquina. X-1a prohíbe además la transparencia viva, así que audite todo el código de dibujo que superponga elementos translúcidos; lo que un visor compone en pantalla es exactamente lo que un RIP se negará a interpretar. Cuando su imprenta le envíe otra caracterización, cambie los bytes del perfil y la cadena identificadora, pero deje intacta la estructura que los rodea

PDF/UA: la estructura se genera, nunca se añade después

La accesibilidad es la norma que más equipos intentan atornillar al final, y castiga ese enfoque con más dureza que las otras dos. El árbol de etiquetas tiene que reflejar el orden en que se creó lógicamente el contenido, información que sencillamente ya no está disponible una vez escrito el archivo. Activar PDFUACompliance pone en marcha la salida etiquetada, y la API de estructura vincula cada llamada de dibujo con su papel semántico sobre la marcha:

HotPDF construye el árbol de etiquetas PDF/UA en directo conforme se ejecuta cada llamada de dibujo de Delphi, y el texto emitido fuera de BeginTaggedContent y EndTaggedContent queda invisible para los lectores de pantalla
El árbol de etiquetas se escribe mientras usted dibuja, y el texto fuera de un par etiquetado se representa bien pero queda invisible para los lectores de pantalla
Pdf.PDFUACompliance := True;     // activa por sí sola el PDF etiquetado
Pdf.Lang := 'en-US';             // fíjelo explícitamente; si queda vacío recurre a 'en'
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;

El fallo que hay que vigilar es el texto dibujado fuera de cualquier par BeginTaggedContent/EndTaggedContent. Se representa a la perfección y queda invisible para un lector de pantalla, así que ningún probador vidente lo detecta jamás; el error se publica y solo aflora cuando un usuario real de tecnología de asistencia se topa con el hueco. Cuando sus plantillas lleven nombres de papel de estructura personalizados, asígnelos al conjunto estándar con AddStructRoleMap('MyHead', 'H1') para que los lectores conformes sepan qué significan. ISO 14289 exige además un idioma declarado. HotPDF recurre a 'en' cuando Lang está vacío, pero eso es una red de seguridad, no un motivo para dejar sin fijar el idioma real del documento

Verificación: fíese del validador, no del visor

Que un visor abra su archivo no demuestra nada sobre la conformidad, así que la verificación pertenece a la ruta de publicación, con herramientas que comprueban estructura en vez de representación. Para PDF/A y PDF/UA, veraPDF es el validador abierto de referencia; informa de los fallos por cláusula ISO, lo que remite directamente a la configuración anterior. Para PDF/X, los perfiles de Preflight de Adobe Acrobat siguen siendo la comprobación práctica, porque la conformidad de imprenta tiene tanto de intención de color como de sintaxis

El generador cumple su parte. Al guardar, HotPDF concilia los indicadores de función con la versión de PDF configurada y degrada en silencio lo que esa versión no puede expresar, como AES-256 bajando a AES-128 por debajo de PDF 1.7. Las barreras de conformidad de EndDoc van más lejos y lanzan una excepción ante contradicciones duras, como pedir PDFACompliance junto con cifrado. Ninguna de las dos sustituye al validador externo. Solo evitan que configuraciones imposibles lleguen siquiera a él

Las barreras de conformidad de HotPDF en EndDoc atrapan configuraciones imposibles antes de que veraPDF valide PDF/A y PDF/UA y de que Acrobat Preflight valide PDF/X en una ruta de publicación en Delphi
HotPDF rechaza las configuraciones contradictorias en EndDoc, y son los validadores independientes los que deciden la conformidad real

Hay una costumbre que compensa una y otra vez: versione todo el montaje de conformidad como una unidad. La versión de HotPDF, la revisión de la plantilla, la suma de comprobación del perfil ICC, la compilación del validador que dio el visto bueno. La conformidad se desvía en cuanto cualquiera de esas piezas cambia bajo las demás, y las auditorías más feas son aquellas en que nadie puede reconstruir qué combinación produjo un archivo de hace cinco años. Un solo registro de configuración por lote lo zanja para siempre

Por último, ejecute el validador sobre salida real de producción, nunca sobre una muestra pulcra hecha a mano. Los fallos que muerden vienen de datos que nadie previó: un logotipo de cliente que llega en CMYK mientras el intent dice RGB, un retoque de plantilla que cuela una fuente sin incrustar, una ruta de código nueva que dibuja texto fuera del árbol de etiquetas. Guarde un archivo defectuoso conocido de cada incidente pasado como entrada de regresión y la barrera de conformidad seguirá siendo honesta con el tiempo. Para el lado de la representación de estas cadenas, consulte nuestro artículo sobre salida de informes, fuentes e imágenes con HotPDF; para conectar validadores a una compilación, hay un artículo complementario sobre automatizar las comprobaciones de preflight de PDF

Las propiedades de conformidad, los output intents y la API de etiquetado usados en estos ejemplos se distribuyen con el HotPDF Delphi Component para Delphi y C++Builder; la página del producto enlaza la referencia completa de cada llamada mostrada aquí