PDF/A et accessibilité

Ce qui rend PDF/A délicat, c’est que la conformité est totalement invisible. Le même document LaTeX produit un PDF d’aspect identique qui passe en A-2b et échoue en A-1b — et lorsqu’on lance réellement la vérification, le validateur donne la raison en une ligne : un dictionnaire ExtGState porte une clé ca valant 0.5 au lieu de 1.0. PDF/A ne parle pas de beaux PDF ; c’est une exigence ISO sur la structure interne du fichier. Cette page présente ce que la norme réclame vraiment, les deux voies depuis LaTeX (pdfx et \DocumentMetadata) et l’étape le plus souvent omise : comment savoir si le fichier produit est réellement conforme.

Ce que PDF/A exige réellement

PDF/A (ISO 19005) est une norme d’archivage et, au fond, elle réclame une seule chose : le fichier doit être entièrement autonome. Celui qui l’ouvrira dans dix ans n’aura ni vos polices, ni vos réglages de gestion des couleurs, ni aucun de vos autres fichiers — et il doit pourtant s’afficher correctement. Toutes les exigences concrètes en découlent. Polices entièrement incorporées (ne jamais compter sur ce qui est installé chez le lecteur). Pas de chiffrement (une clé perdue, un document perdu). Métadonnées XMP (titre et auteur conservés dans le PDF sous forme de XML standard). Une intention de sortie incorporée, c’est-à-dire un profil ICC (pour que « ce rouge » emporte avec lui la définition de son espace colorimétrique). La même logique explique la méfiance envers tout ce qui pointe hors du fichier, comme la destination d’envoi d’un formulaire.

Produire du PDF/A avec pdfx — le profil ICC est fourni

Une ligne, \usepackage[a-2b]{pdfx}, plus un fichier \jobname.xmpdata contenant le titre et l’auteur : c’est tout. Il n’y a pas de profil ICC à aller chercher. On a longtemps conseillé de télécharger le profil sRGB sur le site d’Adobe, mais dans TeX Live 2024 le paquet colorprofiles en fournit un, et le journal consigne l’incorporation sous la forme <<sRGB.icc>>. Dans ce même journal, ** pdfx: Metadata file document.xmpdata read successfully. confirme la lecture des métadonnées ; si le fichier manque, on lit ** pdfx: No file document.xmpdata . Metadata will be incomplete! — sachant que, comme on le verra, ignorer cet avertissement donne quand même un fichier qui passe la validation. Outre a-1b, a-2b et a-3b, le paquet propose les niveaux d’accessibilité a-1a, a-2a, a-3a et les niveaux Unicode a-2u, a-3u. Les variantes PDF/X orientées impression (x-1a et consorts) viennent du même paquet.

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, A-2b et A-4 : la transparence passe-t-elle ?

Le chiffre désigne la version de PDF sous-jacente, la lettre finale le degré d’exigence. A-1 repose sur PDF 1.4, A-2 sur PDF 1.7, A-3 est A-2 avec pièces jointes autorisées, A-4 repose sur PDF 2.0. Le b final signifie basic : l’apparence doit être reproductible, rien de plus. a signifie accessible et ajoute le balisage, c’est-à-dire la structure logique. u exige que le texte se projette sur Unicode. En pratique, la différence qui fait mal concerne la transparence. Prenez un document avec deux rectangles TikZ en opacity=0.5, compilez-le avec [a-1b]{pdfx} et passez-le à veraPDF : il échoue à la clause 6.4 d’ISO 19005-1:2005, motif « An ExtGState dictionary contains the ca key (fill alpha) with value 0.5 other than 1.0 ». Changez uniquement l’option en [a-2b] et il passe. Un fait vieux de vingt ans — PDF 1.4 ignore la transparence — décide encore aujourd’hui de ce qu’un dépôt acceptera.

NiveauPDF de basePoint clé
A-1bPDF 1.4Le plus étroit. Pas de transparence : toute image utilisant opacity échoue. Les flux d’objets sont également interdits
A-2bPDF 1.7La transparence passe. Le choix par défaut depuis LaTeX. JPEG 2000 est également autorisé
A-3bPDF 1.7A-2b plus pièces jointes quelconques. Exigé quand les données brutes doivent voyager dans le document
A-4PDF 2.0Le plus récent. L’en-tête doit être %PDF-2.0, d’où la nécessité de pdfversion=2.0. Absent de pdfx ; passer par \DocumentMetadata

La voie \DocumentMetadata — accorder pdfversion ou échouer

L’autre voie est \DocumentMetadata{pdfstandard=A-2b}, placé avant \documentclass. Elle ne charge aucun paquet et accepte tout, de A-1B à A-4 — mais écrite telle quelle, seul A-2b passe réellement. pdfTeX écrit du PDF 1.5 par défaut ; pour A-1b, c’est rejeté parce que la table de références croisées est un flux (The document uses xref streams, clause 6.1.4), et pour A-4 parce que « File header %PDF-1.5 ... does not match the pattern %PDF-2.n » (clause 6.1.2). Le remède tient dans les mêmes accolades : ajoutez pdfversion=1.4 et A-1b passe ; ajoutez pdfversion=2.0 et A-4 passe. À l’inverse, ajoutez pdfversion=2.0 à A-2b et il échoue avec « %PDF-2.0 ... does not match the pattern %PDF-1.n » — car A-2 est défini sur PDF 1.7, pas au-delà. Chaque norme a une bonne réponse différente, et c’est précisément là qu’on se trompe.

Ce que vous avez écritLaissé par défaut (PDF 1.5)Avec pdfversion ajouté
pdfstandard=A-1bÉchoue — clause 6.1.4, « uses xref streams »Avec pdfversion=1.4, réussit
pdfstandard=A-2bRéussit — la seule combinaison qui n’a besoin de rienAjouter pdfversion=2.0 la fait échouer (clause 6.1.2)
pdfstandard=A-4Échoue — clause 6.1.2, « header %PDF-1.5 »Avec pdfversion=2.0, réussit

Pourquoi, alors, pdfx en a-1b réussit-il tout en écrivant un en-tête PDF 1.5 ? La réponse est dans le source du paquet. La ligne 515 de pdfx.sty porte le commentaire « PDF/A-1b doesn't allow object compression », et les lignes suivantes posent \pdfobjcompresslevel=0. Plutôt que de discuter du chiffre en en-tête, il cesse simplement d’utiliser la fonction que la norme interdit. C’est là toute la différence de nature entre les deux voies. pdfx est un paquet qui plie la sortie jusqu’à ce qu’elle entre dans la norme ; \DocumentMetadata est un mécanisme du noyau qui déclare la norme revendiquée — à vous de faire en sorte que le contenu soit à la hauteur de la déclaration. L’autre différence tient aux métadonnées : pdfx lit .xmpdata automatiquement, tandis que \DocumentMetadata ne remplit ni titre ni auteur. Ces valeurs se posent à la main avec \hypersetup{pdftitle=...} et compagnie (voir la page signets et métadonnées).

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.

Vérifier ce qu’on a produit : veraPDF, et ce qu’une réussite ne garantit pas

Rien du côté de LaTeX ne permet de savoir si le fichier est conforme. Le journal indique seulement qu’une sortie PDF/A a été demandée ; que le résultat satisfasse vraiment la norme est une autre affaire. Ce verdict revient à un validateur PDF/A, et le standard de fait est veraPDF, le vérificateur de référence libre. Il ne fait pas partie de TeX Live et s’installe séparément. Son usage est simple : verapdf file.pdf lit l’identifiant XMP contenu dans le PDF, en déduit le niveau à contrôler et répond en une ligne, PASS ... 2b ou FAIL ... 1b. L’option -f 1b force un niveau. En cas d’échec, ce qu’il faut lire, c’est le numéro de clause : 6.4 (transparence), 6.1.2 (version d’en-tête), 6.3.3 (apparence des annotations) désignent directement ce qu’il faut corriger.

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 fait ici évitera bien des regrets : réussir la validation ne signifie pas que les métadonnées sont acceptables. Oubliez le fichier .xmpdata, laissez l’avertissement ** pdfx: No file ... Metadata will be incomplete! sans suite, puis passez le résultat à veraPDF : il répond PASS ... 1b. Sans titre ni auteur dans le fichier. Le niveau b exige que les métadonnées XMP soient structurellement présentes et correctes, non qu’elles soient renseignées. Or ce sont précisément ces champs vides qui gênent bibliothécaires et responsables de dépôt : considérez donc la réussite du validateur et l’achèvement du dépôt comme deux choses distinctes. Il est également prudent de garder l’habitude de vérifier l’incorporation des polices avec pdffonts (la page sur la production de PDF en traite).

Les formulaires interactifs et PDF/A ne font pas bon ménage

Un seul champ de saisie créé avec l’environnement Form de hyperref suffit à faire échouer la validation PDF/A. Placez un unique \TextField dans un document, compilez-le avec [a-2b]{pdfx}, passez-le à veraPDF : il échoue à la clause 6.3.3, « An annotation does not contain an appearance dictionary ». hyperref laisse au lecteur le soin de dessiner le champ — c’est le sens de NeedAppearances — alors que PDF/A exige que les apparences soient figées dans le fichier. Ajoutez un bouton d’envoi et les manquements se multiplient, avec la clause 6.4.1, « A Widget annotation dictionary shall not contain the A or AA keys » : attacher une action à un contrôle de formulaire est en soi interdit. À la réflexion, rien de plus logique : une norme d’archivage ne peut bénir un widget dont la fonction est de communiquer avec l’extérieur. Si un destinataire réclame à la fois PDF/A et un formulaire remplissable, les exigences se contredisent : posez la question avant de construire.

PDF balisé et PDF/UA : l’accessibilité reste un chantier

Le balisage exigé par les niveaux a de PDF/A consiste à incorporer la structure logique — titres, paragraphes, listes, ordre de lecture, textes alternatifs — dans le PDF, afin qu’un lecteur d’écran puisse le parcourir. La norme d’accessibilité autonome est PDF/UA (ISO 14289), dont la deuxième partie s’appelle PDF/UA-2. Côté LaTeX, l’implémentation est le paquet tagpdf du LaTeX Project (Ulrike Fischer) ; la version livrée avec TeX Live 2024 est la 0.98x, datée du 2024-02-29 — un numéro de version commençant par zéro dit tout. Les commandes de bas niveau qui posent les balises à la main, comme \tagstructbegin, viennent de ce paquet. De fait, écrire \DocumentMetadata{tagging=on} sur le noyau de TeX Live 2024 (LaTeX2e 2023-11-01) produit ! LaTeX Error: The key 'document/metadata/tagging' is unknown and is being ignored. Dans cette version, l’interrupteur est testphase=phase-III, et alors pdfinfo rapporte bien Tagged: yes. Comme son nom l’indique, c’est un dispositif en phase de test : l’écriture changera. Consultez la documentation courante avant de vous y fier.

Et une remarque honnête s’impose : satisfaire les deux à la fois n’est pas encore aisé. En partant d’un document qui passe avec pdfstandard=A-2b seul et en ajoutant testphase=phase-III, veraPDF a renvoyé un échec à la clause 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) ». Il ne s’agit pas d’un défaut de la structure de balisage, mais d’un écart dans les largeurs de glyphes de la police incorporée. Si l’on vous demande un PDF/A balisé, passez-le à veraPDF avant l’envoi — supposer que cela marchera, c’est se retrouver bloqué la veille de l’échéance.

À faire avant de déposer

  • Demandez d’abord le niveau. Si l’on vous dit seulement « PDF/A », vérifiez s’il s’agit d’A-1b ou d’A-2b. Dès qu’il y a de la transparence dans les figures, cette différence décide de l’acceptation.
  • Dans le doute, pdfx en a-2b. \usepackage[a-2b]{pdfx} plus titre et auteur dans \jobname.xmpdata. C’est la seule combinaison qui passe sans rien ajouter.
  • Si A-4 est requis, utilisez \DocumentMetadata{pdfstandard=A-4,pdfversion=2.0}. pdfx s’arrête à A-3 et ne produit pas A-4.
  • N’oubliez pas le .xmpdata. La validation réussit sans lui : allez donc chercher vous-même l’avertissement Metadata will be incomplete! dans le journal.
  • Lancez verapdf document.pdf une fois avant chaque envoi. Il ne fait pas partie de TeX Live et s’installe séparément. En cas d’échec, lisez le numéro de clause (6.4, 6.1.2, 6.3.3).
  • Renoncez aux formulaires. Un document comportant des champs remplissables ne sera pas conforme à PDF/A.