PDF/A y PDF/UA responden dos preguntas que no tienen nada que ver entre sí, y tratarlos como una sola casilla de accesibilidad y archivado es la forma en que archivos defectuosos llegan a un archivo con una etiqueta de conformidad. PDF/A pregunta si un archivo se seguirá representando fielmente dentro de veinte años. PDF/UA pregunta si la tecnología de asistencia puede leerlo hoy. Un documento puede aprobar uno con claridad y reprobar el otro, así que el único veredicto honesto surge de ejecutar ambos, y de hacerlo antes de escribir el archivo, no después de que un sistema posterior confíe en el identificador de conformidad incorporado en sus metadatos. Ese identificador es una autodeclaración. Nada en el formato exige que sea verdadero, y una aplicación que escribe "PDF/A-1b" en el XMP sin validar contra el estándar produce un archivo que parece conforme para todo consumidor que solo lee la etiqueta. losLab PDF Library (PDF Library for Delphi) cubre esa brecha para Delphi y C++Builder al incorporar ambos validadores en la biblioteca, por lo que la comprobación se ejecuta en proceso sin requerir un servicio externo
Dos estándares que hacen fallar archivos por razones opuestas
ISO 19005 (PDF/A) es un contrato de reproducción. Un archivo conforme debe representarse de manera idéntica décadas después en software que nunca conoció el sistema que lo produjo, por lo que las reglas atacan las dependencias externas: todas las fuentes incrustadas, el color anclado a un OutputIntent ICC incrustado o expresado en un espacio independiente del dispositivo, sin cifrado en PDF/A-1, sin JavaScript y con metadatos XMP que coincidan con el diccionario de información del documento. ISO 14289 (PDF/UA), en cambio, es un contrato de semántica. La tecnología de asistencia debe recorrer el documento y obtener significado, que reside en una capa completamente distinta: un árbol de estructura completo, texto alternativo en las figuras, un título de documento configurado para mostrarse, niveles de encabezado sin saltos y relaciones de encabezados de tabla que se conservan cuando la página ya no está en pantalla
Como los dos estándares regulan capas diferentes, los archivos que causan problemas son los que quedan entre ambos. Un documento perfecto para archivo puede ser silencioso para un lector de pantalla. Uno etiquetado de forma impecable puede hacer referencia a una fuente de escritorio que no existirá dentro de diez años. La publicación del sector público es el lugar habitual donde ambos requisitos se aplican a la vez, y una canalización allí no puede reducirlos a una sola puerta. Los hallazgos van a personas diferentes. Las fuentes no incrustadas son un defecto en el código que genera el PDF, mientras que el texto alternativo faltante corresponde a quien mantiene las plantillas de contenido, y un informe que mezcla ambos solo se reenvía dos veces
La parte de PDF/A que se elige es tan importante como lograrla. PDF/A-1 está congelado en PDF 1.4 y rechaza la transparencia y JPEG2000, dos elementos que la salida moderna de informes utiliza sin pensarlo. PDF/A-2 (ISO 19005-2, basado en ISO 32000-1) acepta ambos y es la opción predeterminada sensata para un archivo nuevo. PDF/A-3 va más allá y permite archivos incrustados de cualquier tipo, en lo que se apoyan los formatos de facturación electrónica regulada. Un equipo que aún se estandariza en PDF/A-1b en 2026 normalmente carga con un requisito redactado hace quince años, y renegociar la parte objetivo suele costar menos que eliminar la transparencia de cada gráfica que emite el sistema
Hallazgos estructurados al momento de la ingesta
El punto de entrada de la API plana es CheckFileCompliance, con el selector de prueba 1 para PDF/A y 2 para PDF/UA. Devuelve un identificador de lista de cadenas cuyos elementos son hallazgos individuales, uno por línea, exactamente la forma que una puerta automatizada necesita recorrer:
function GateArchiveUpload(Pdf: TPDFlib; const FileName: string): Boolean;
var
ListId, I: Integer;
begin
ListId := Pdf.CheckFileCompliance(FileName, '', 1, 0); // 1 = PDF/A
if ListId = 0 then
begin
// 0 significa "sin hallazgos" O "archivo ilegible" -- distingue antes de seguir
Result := Pdf.LastErrorCode = 0;
Exit;
end;
for I := 0 to Pdf.GetStringListCount(ListId) - 1 do
LogFinding(FileName, Pdf.GetStringListItem(ListId, I));
Pdf.ReleaseStringList(ListId);
Result := False;
end;
Dos detalles determinan si esto se ejecuta sin supervisión. El primero es un valor de retorno que significa dos cosas opuestas. CheckFileCompliance devuelve 0 cuando el archivo es totalmente conforme y también cuando no se pudo abrir en absoluto, porque internamente una lista de resultados vacía se reduce a 0 en ambos casos. Una puerta que interpreta 0 como aprobación dejará pasar cargas dañadas directamente al archivo, así que distinga con LastErrorCode antes de confiar en el cero, como hace la puerta anterior. El segundo se refiere a dónde está el archivo en su ciclo de vida. El verificador se ejecuta sobre el lector de transmisión de la biblioteca en lugar del modelo de documento completo, abre el archivo directamente con uso compartido de lectura y nunca llama a LoadFromFile, por lo que puede procesar entradas de varios gigabytes sin construir un árbol de objetos. Esa misma apertura de transmisión falla mientras otro proceso aún mantiene el archivo para escritura, y una carga en curso está precisamente en ese estado. Aplique la puerta después de que termine la transferencia
El diseño de transmisión vuelve a dar resultado bajo carga. Cada comprobación abre su entrada en modo de solo lectura y la comparte para lectura, por lo que una auditoría de corpus puede escalarse entre hilos o procesos de trabajo con una instancia de TPDFlib por trabajador y sin contención entre ellos. El recurso que requiere disciplina es el propio identificador. Cada resultado distinto de cero de CheckFileCompliance permanece asignado hasta que se llama a ReleaseStringList, y una puerta de larga ejecución que olvida liberarlos no falla, solo pierde memoria lentamente hasta que alguien investiga el motivo
Informes para personas, diferencias para puertas de compilación
Una lista de hallazgos tiene la forma correcta para una puerta y la forma equivocada para un correo al equipo de plantillas. CreatePreflightReport representa el mismo análisis como prosa legible, CreatePreflightReportEx agrega un selector de formato de informe y SavePreflightReport lo escribe en disco para que el informe pueda viajar dentro del paquete de documentos entregado. Muchos contratos de archivado hacen que ese informe sea un entregable por derecho propio, no solo un artefacto interno
El integrante de esta familia que se gana discretamente su lugar es ComparePreflightReports. La conformidad es una superficie de regresión como cualquier otra pieza de comportamiento. Un ajuste de plantilla, una nueva fuente corporativa con licencia o una actualización de biblioteca pueden introducir un hallazgo que no estaba en la última versión, y ninguno se anuncia por sí solo. Conserve informes de referencia de un conjunto de documentos representativos bajo control de versiones, regenérelos después de cada cambio y ejecute ComparePreflightReports para calcular la diferencia. Una diferencia vacía es un artefacto de versión que vale la pena conservar. Un hallazgo inesperado hace fallar la compilación, un lugar mucho más barato para descubrirlo que la auditoría
Generar salida que aprueba en la primera ejecución
El preflight demuestra su valor en archivos que llegan desde otros lugares. Para documentos que produce el propio código, encontrar infracciones después de generarlos y corregirlos posteriormente es el camino lento. PDF Library for Delphi incluye un modo del lado de la generación para cada estándar, y se pueden activar ambos para el mismo documento:
var
Pdf: TPDFlib;
Diag: WideString;
begin
Pdf := TPDFlib.Create;
try
Pdf.NewDocument;
Pdf.SetPDFAMode(1);
Pdf.LoadOutputIntentProfile('sRGB-IEC61966-2.1.icc', 'RGB');
Pdf.SetPDFUAMode('en-US');
Pdf.SetInformation(1, 'Quarterly Statement'); // /Title: obligatorio para PDF/UA
// ... dibujar aquí el contenido etiquetado ...
Diag := Pdf.GetPDFUADiagnostics;
if Diag <> '' then
Writeln('fix before shipping: ', Diag);
Pdf.SaveToFile('statement.pdf');
// el preflight que importa corre sobre el archivo guardado:
Writeln(Pdf.CreatePreflightReport('statement.pdf', '', 1, 0));
finally
Pdf.Free;
end;
end;
La trampa se oculta al guardar. Varias de las correcciones de conformidad ocurren mientras el documento se serializa, en lugar de cuando se activa el modo: forzar el indicador de impresión en las anotaciones, escribir el AFRelationship predeterminado para archivos incrustados de PDF/A-3 y normalizar el orden de tabulación y las descripciones de campos de formulario para PDF/UA. El documento que reside en memoria no es idéntico en bytes al que termina en disco, así que el único veredicto de preflight que significa algo es el calculado a partir del archivo guardado. Valide statement.pdf mismo. No infiera la conformidad a partir del objeto que sigue en memoria, porque los bytes que juzgaría no son los bytes que entregó
Los escenarios de facturas que llevan XML legible por máquina junto al documento visual siguen el patrón ZUGFeRD y Factur-X, que se basa en PDF/A-3. Deben establecer explícitamente la relación del adjunto con SetPDFA3DefaultAFRelationship, ya que ISO 19005-3 exige que todo archivo incrustado declare su función respecto del documento. Si se deja sin configurar, el XML incrustado es solo un blob sin propósito declarado, algo que el validador detecta
Árbitros independientes: veraPDF y Acrobat
Un productor no debe ser el único juez de su propia salida. Los verificadores de PDF Library for Delphi brindan veredictos rápidos y estructurados en proceso, que es lo deseable en la ruta crítica, pero la puerta de liberación de un lote de archivo debe aun así pasar la salida por un validador que nadie en su equipo haya escrito. veraPDF es la implementación de referencia mantenida por la comunidad para PDF/A y la herramienta que más archivos mencionan en sus criterios de aceptación, por lo que es la que conviene igualar. Los perfiles de preflight de Acrobat sirven como un desempate útil cuando veraPDF y la comprobación en proceso no coinciden. Registre el nombre del validador y su versión junto a cada informe almacenado. Afirmar que un archivo aprobó veraPDF dice muy poco sin el número de compilación que aprobó, ya que la herramienta endurece sus reglas entre versiones
Los validadores discrepan en los límites de los estándares y, cuando lo hacen, la respuesta no es escoger la herramienta que más guste. Reduzca el archivo a un ejemplo mínimo que siga provocando la discrepancia y léalo frente al texto del estándar. Una hora de ello normalmente revela una de dos cosas: un error real de la herramienta que vale la pena reportar aguas arriba o una cláusula que el equipo ha estado interpretando mal y que debería dejar por escrito en las notas de conformidad para que la siguiente persona no vuelva a debatirla
La entrada cifrada tiene un atajo. Ambos verificadores aceptan un argumento de contraseña, pero un archivo PDF/A-1 con un diccionario de cifrado ya es no conforme, porque ISO 19005-1 prohíbe el cifrado por completo, de modo que una entrega cifrada puede rechazarse antes de ejecutar un análisis más profundo. Determinar qué concede realmente un diccionario de cifrado es otra tarea, cubierta en auditoría de cifrado y permisos de PDF
Los hallazgos de PDF/UA casi siempre se remontan a cómo se creó el árbol de estructura desde el principio, y las técnicas de etiquetado que lo sustentan se explican en creación de árboles de estructura PDF etiquetados en Delphi. Los archivos que también exigen firmas digitales deben combinar esta puerta con el flujo de trabajo de firma y validación PAdES. La referencia completa de la API de preflight se encuentra en la página de producto de losLab PDF Library for Delphi