PDF/A y accesibilidad

Lo incómodo de PDF/A es que la conformidad es completamente invisible. El mismo documento LaTeX produce un PDF de aspecto idéntico que aprueba como A-2b y suspende como A-1b, y al ejecutar la comprobación el validador nombra el motivo en una línea: un diccionario ExtGState lleva una clave ca con valor 0.5 en vez de 1.0. PDF/A no trata de PDF bonitos; es un requisito ISO sobre la estructura interna del archivo. Esta página cubre qué exige realmente la norma, las dos vías desde LaTeX (pdfx y \DocumentMetadata) y el paso que casi siempre se omite: cómo averiguar si el archivo producido cumple de verdad.

Qué exige realmente PDF/A

PDF/A (ISO 19005) es una norma de archivado y, en el fondo, pide una sola cosa: el archivo debe ser completamente autocontenido. Quien lo abra dentro de diez años no tendrá tus fuentes, ni tus ajustes de gestión de color, ni ninguno de tus otros archivos, y aun así debe leerse bien. De ahí se deduce cada requisito concreto. Fuentes totalmente incrustadas (nunca confiar en lo que el lector tenga instalado). Sin cifrado (una clave perdida es un documento perdido). Metadatos XMP (título y autor guardados dentro del PDF como XML estándar). Una intención de salida incrustada, es decir, un perfil ICC (para que «este rojo» lleve consigo la definición de su espacio de color). La misma lógica explica el recelo hacia todo lo que apunta fuera del archivo, como el destino de envío de un formulario.

Generar PDF/A con pdfx: el perfil ICC ya viene incluido

Una línea, \usepackage[a-2b]{pdfx}, más un archivo \jobname.xmpdata con el título y el autor: eso basta. No hay que salir a buscar un perfil ICC. Durante años se recomendaba descargar el perfil sRGB del sitio de Adobe, pero en TeX Live 2024 el paquete colorprofiles incluye uno, y el registro anota la incrustación como <<sRGB.icc>>. En ese mismo registro, ** pdfx: Metadata file document.xmpdata read successfully. confirma que se leyeron los metadatos; si falta el archivo aparece ** pdfx: No file document.xmpdata . Metadata will be incomplete!, aunque, como se verá, ignorar ese aviso deja igualmente un archivo que supera la validación. Además de a-1b, a-2b y a-3b, el paquete ofrece los niveles de accesibilidad a-1a, a-2a, a-3a y los niveles Unicode a-2u, a-3u. Las variantes PDF/X orientadas a impresión (x-1a y afines) salen del mismo paquete.

latex
% document.tex
\documentclass{article}
\usepackage[a-2b]{pdfx}   % reads document.xmpdata, embeds sRGB.icc
\begin{document}
Hello PDF/A.
\end{document}

% document.xmpdata -- a separate file, same base name
\Title{A Test Document}
\Author{Test Author}
\Keywords{LaTeX\sep PDF/A}

A-1b frente a A-2b y A-4: si la transparencia sobrevive

El número indica la versión de PDF subyacente; la letra final, el nivel de exigencia. A-1 se apoya en PDF 1.4, A-2 en PDF 1.7, A-3 es A-2 con adjuntos permitidos y A-4 se apoya en PDF 2.0. La b final es basic: basta con que el aspecto sea reproducible. a es accessible y añade el etiquetado, es decir, la estructura lógica. u exige que el texto se pueda proyectar sobre Unicode. En la práctica, la diferencia que duele es la transparencia. Toma un documento con dos rectángulos TikZ a opacity=0.5, compílalo con [a-1b]{pdfx} y pásalo por veraPDF: falla en la cláusula 6.4 de ISO 19005-1:2005, con el motivo «An ExtGState dictionary contains the ca key (fill alpha) with value 0.5 other than 1.0». Cambia solo la opción a [a-2b] y aprueba. Un hecho de hace veinte años —PDF 1.4 no tiene transparencia— sigue decidiendo hoy qué acepta un repositorio.

NivelPDF basePunto clave
A-1bPDF 1.4El más estrecho. Sin transparencia: cualquier figura con opacity falla. Los flujos de objetos también están prohibidos
A-2bPDF 1.7La transparencia pasa. La opción por defecto desde LaTeX. También se admite JPEG 2000
A-3bPDF 1.7A-2b más adjuntos de cualquier tipo. Se pide cuando los datos originales deben viajar dentro del documento
A-4PDF 2.0El más nuevo. La cabecera debe ser %PDF-2.0, por lo que hace falta pdfversion=2.0. No está en pdfx; usa \DocumentMetadata

La vía \DocumentMetadata: ajusta pdfversion o suspenderás

La otra vía es \DocumentMetadata{pdfstandard=A-2b}, colocado antes de \documentclass. No carga ningún paquete y acepta desde A-1B hasta A-4, pero escrito tal cual, solo A-2b pasa de verdad. pdfTeX escribe PDF 1.5 por defecto; para A-1b eso se rechaza porque la tabla de referencias cruzadas es un flujo (The document uses xref streams, cláusula 6.1.4), y para A-4 porque «File header %PDF-1.5 ... does not match the pattern %PDF-2.n» (cláusula 6.1.2). El remedio está en las mismas llaves: añade pdfversion=1.4 y A-1b pasa; añade pdfversion=2.0 y A-4 pasa. En cambio, añade pdfversion=2.0 a A-2b y ahora falla con «%PDF-2.0 ... does not match the pattern %PDF-1.n», porque A-2 está definido sobre PDF 1.7 y no más allá. Cada norma tiene una respuesta correcta distinta, y ahí es justo donde se falla.

Lo que escribisteCon el valor por defecto (PDF 1.5)Añadiendo pdfversion
pdfstandard=A-1bFalla — cláusula 6.1.4, «uses xref streams»Con pdfversion=1.4 aprueba
pdfstandard=A-2bAprueba — la única combinación que no necesita nada másAñadir pdfversion=2.0 la hace fallar (cláusula 6.1.2)
pdfstandard=A-4Falla — cláusula 6.1.2, «header %PDF-1.5»Con pdfversion=2.0 aprueba

¿Por qué entonces pdfx en a-1b aprueba aun escribiendo una cabecera PDF 1.5? La respuesta está en el fuente del paquete. La línea 515 de pdfx.sty lleva el comentario «PDF/A-1b doesn't allow object compression», y justo después se fija \pdfobjcompresslevel=0. En lugar de discutir sobre el número de la cabecera, sencillamente deja de usar la función que la norma prohíbe. Ahí está la diferencia de carácter entre ambas vías. pdfx es un paquete que dobla la salida hasta que encaja en la norma; \DocumentMetadata es un mecanismo del núcleo que declara qué norma se reclama, y queda en tus manos que el contenido esté a la altura de la declaración. La otra diferencia son los metadatos: pdfx lee .xmpdata automáticamente, mientras que \DocumentMetadata no rellena ni título ni autor por su cuenta. Eso lo pones tú con \hypersetup{pdftitle=...} y similares (véase la página de marcadores y metadatos).

latex
% before \documentclass -- the version must match the standard
\DocumentMetadata{
  pdfstandard = A-4,
  pdfversion  = 2.0,   % A-4 needs a %PDF-2.0 header
  lang        = en
}
\documentclass{article}

% for A-1b it is pdfversion = 1.4 instead;
% for A-2b, leave pdfversion out entirely.

Verificar lo producido: veraPDF y lo que aprobar no significa

Desde el lado de LaTeX no hay forma de saber si el archivo cumple. El registro solo dice que se pidió salida PDF/A; si el resultado satisface realmente la norma es otra cuestión. Ese veredicto lo emite un validador PDF/A, y el estándar de facto es veraPDF, el verificador de referencia de código abierto. No forma parte de TeX Live y hay que instalarlo aparte. Su uso es simple: verapdf file.pdf lee el identificador XMP dentro del PDF, deduce contra qué nivel comprobar y responde en una línea, PASS ... 2b o FAIL ... 1b. Con -f 1b se fuerza un nivel. Cuando falla, lo que hay que leer es el número de cláusula: 6.4 (transparencia), 6.1.2 (versión de cabecera), 6.3.3 (apariencia de anotaciones) señalan directamente qué corregir.

shell
# auto-detect the level from the file itself
verapdf document.pdf
# -> PASS /path/document.pdf 2b

# force a level (useful to see what a stricter one would say)
verapdf -f 1b --format text document.pdf
# -> FAIL /path/document.pdf 1b

# the XML report names the clause and the exact reason
verapdf -f 1b document.pdf > report.xml

Un dato aquí evita disgustos posteriores: aprobar la validación no significa que los metadatos sean aceptables. Olvida el archivo .xmpdata, deja sin atender el aviso ** pdfx: No file ... Metadata will be incomplete! y pasa el resultado por veraPDF: responde PASS ... 1b. Sin título ni autor en el archivo. El nivel de conformidad b exige que los metadatos XMP estén estructuralmente presentes y correctos, no que estén rellenos. Y esos campos vacíos son justo lo que incomoda a bibliotecarios y gestores de repositorio, así que trata la aprobación del validador y la entrega terminada como dos cosas distintas. También conviene mantener la costumbre de comprobar la incrustación de fuentes con pdffonts (la página sobre generar PDF lo detalla).

Los formularios interactivos y PDF/A no se llevan bien

Basta un solo campo de entrada creado con el entorno Form de hyperref para suspender la validación PDF/A. Pon un único \TextField en un documento, compílalo con [a-2b]{pdfx} y pásalo por veraPDF: falla en la cláusula 6.3.3, «An annotation does not contain an appearance dictionary». hyperref deja que el visor dibuje el campo —eso significa NeedAppearances—, mientras que PDF/A exige que las apariencias queden grabadas en el archivo. Añade un botón de envío y los incumplimientos se multiplican, ahora con la cláusula 6.4.1, «A Widget annotation dictionary shall not contain the A or AA keys»: adjuntar una acción a un control de formulario está prohibido en sí mismo. Bien mirado, es lo esperable: una norma de archivado no puede bendecir un control cuya función es comunicarse con el exterior. Si un destinatario pide a la vez PDF/A y un formulario rellenable, los requisitos se contradicen, así que pregunta antes de construirlo.

PDF etiquetado y PDF/UA: la accesibilidad sigue en movimiento

El etiquetado que exigen los niveles a de PDF/A consiste en incrustar la estructura lógica —encabezados, párrafos, listas, orden de lectura, texto alternativo— dentro del PDF, para que un lector de pantalla pueda recorrerlo. La norma de accesibilidad independiente es PDF/UA (ISO 14289), cuya segunda parte se llama PDF/UA-2. Del lado de LaTeX la implementación es el paquete tagpdf del LaTeX Project (Ulrike Fischer); la copia incluida en TeX Live 2024 es la versión 0.98x, del 2024-02-29: un número de versión que empieza por cero lo dice todo. Los comandos de bajo nivel que colocan etiquetas a mano, como \tagstructbegin, provienen de ese paquete. En efecto, escribir \DocumentMetadata{tagging=on} sobre el núcleo de TeX Live 2024 (LaTeX2e 2023-11-01) produce ! LaTeX Error: The key 'document/metadata/tagging' is unknown and is being ignored. En esta versión el interruptor es testphase=phase-III, y entonces pdfinfo sí informa Tagged: yes. Como indica el nombre, es una función en fase de pruebas, así que la escritura cambiará. Consulta la documentación vigente antes de confiar en ella.

Y conviene anotar algo con honestidad: satisfacer ambas cosas a la vez todavía no es fácil. Partiendo de un documento que aprueba solo con pdfstandard=A-2b y añadiendo testphase=phase-III, veraPDF devolvió un fallo en la cláusula 6.2.11.5: «Glyph width 333 in the embedded font program is not consistent with the Widths entry of the font dictionary (value 334.2)». No es un defecto de la estructura de etiquetas, sino un desajuste en las anchuras de glifo de la fuente incrustada. Si te piden un PDF/A etiquetado, pásalo por veraPDF antes de enviarlo: dar por hecho que funcionará es la forma de quedarse atascado la víspera de la entrega.

Qué hacer antes de entregar

  • Pregunta primero por el nivel. Si solo te dicen «PDF/A», averigua si es A-1b o A-2b. En cuanto haya transparencia en las figuras, esa diferencia decide la aceptación.
  • En la duda, pdfx con a-2b. \usepackage[a-2b]{pdfx} más título y autor en \jobname.xmpdata. Es la única combinación que pasa sin añadir nada.
  • Si se exige A-4, usa \DocumentMetadata{pdfstandard=A-4,pdfversion=2.0}. pdfx llega hasta A-3 y no puede producir A-4.
  • No olvides el .xmpdata. La validación aprueba sin él, así que busca tú mismo en el registro el aviso Metadata will be incomplete!.
  • Ejecuta verapdf document.pdf una vez antes de cada envío. No viene con TeX Live, así que instálalo aparte. Si falla, lee el número de cláusula (6.4, 6.1.2, 6.3.3).
  • Renuncia a los formularios. Un documento con campos rellenables no cumplirá PDF/A.