Quand on construit un formulaire PDF en LaTeX — champs de texte remplissables, cases à cocher — on marche toujours sur la même mine. Écrivez \TextField{Name}, compilez, et il en sort un PDF sans erreur, sans avertissement et sans le moindre champ de saisie. L’étiquette « Name » est composée dans le texte, pdfinfo répond Form: none, et l’examen du fichier ne révèle aucune annotation de widget. Hors d’un environnement Form, les commandes de champ de hyperref ne produisent silencieusement rien. Cette page part de \begin{Form} et suit, mesures à l’appui, ce que chaque champ écrit réellement dans le PDF, où un bouton d’envoi expédie ses données par défaut, et à partir de quel moment il vaut mieux renoncer et faire un formulaire web.
Sans environnement Form, aucun champ n’est créé
Tout champ interactif se place dans \begin{Form} … \end{Form}. Ce n’est pas une convention d’écriture : cela change la sortie. Compilez un document où \TextField et \CheckBox sont hors de l’environnement et pdflatex se termine avec le code 0, sans le moindre avertissement — pourtant le PDF obtenu ne contient aucune annotation /Widget et pdfinfo indique toujours Form: none. Déplacez les mêmes commandes à l’intérieur et pdfinfo répond Form: AcroForm. Un formulaire PDF repose sur un unique dictionnaire AcroForm qui rassemble tous les champs, et c’est l’environnement Form qui crée ce dictionnaire. Notez aussi que \usepackage{hyperref} seul suffit : aucune option de pilote comme [pdftex] n’est nécessaire ; le journal montre hpdftex.def chargé automatiquement.
L’environnement Form accepte, à en compter dans le source de hyperref, exactement quatre clés : action (destination des données), method, encoding et NeedAppearances. Tout ce qui touche à l’apparence et au comportement d’un champ se règle dans le [...] de ce champ ; il suffit donc de voir les options de l’environnement comme les réglages d’envoi.
\documentclass{article}
\usepackage{hyperref} % no driver option needed
\begin{document}
\begin{Form}[action={https://example.org/collect},method=post]
\TextField[name=fullname,width=6cm]{Name}\par
\CheckBox[name=agree]{I agree}\par
\ChoiceMenu[combo,name=affil]{Affiliation}{University,Company,Other}\par
\Submit{Send}\quad\Reset{Clear}
\end{Form}
\end{document}Les commandes de champ et ce que chacune écrit dans le PDF
Il y a cinq commandes de champ et, côté PDF, elles se réduisent à trois types : le texte est /Tx, le choix est /Ch, et tout ce qui a forme de bouton — case à cocher, bouton poussoir, envoi, réinitialisation — est /Btn. Compilez l’exemple ci-dessus, extrayez les objets, et c’est exactement ce que l’on trouve : deux /Tx, un /Ch et quatre /Btn. Ce regroupement des boutons est prescrit par la spécification PDF ; la différence entre une case à cocher et un bouton poussoir tient non au type mais à des bits du champ de drapeaux (/Ff). Cette structure — le caractère est fixé par les drapeaux — servira à la section suivante.
| Commande | Type de champ PDF | Ce qu’elle crée |
|---|---|---|
\TextField | /Tx | Un champ de texte ; multiline, password et maxlen en changent la nature |
\CheckBox | /Btn | Une case à cocher ; valeur par défaut /Off, checked la coche d’emblée |
\ChoiceMenu | /Ch ou /Btn | combo est une liste déroulante éditable, popdown une zone de liste, radio un groupe radio (qui devient /Btn) |
\PushButton | /Btn | Un bouton poussoir ; onclick= avec du JavaScript donne une action /S /JavaScript |
\Submit / \Reset | /Btn | /S /SubmitForm et /S /ResetForm. Les noms de champ sont toujours Submit et Reset ; l’argument n’est que le libellé visible |
Sans name=, l’étiquette devient le nom du champ — et le piège des groupes radio
Sans name=, le texte de l’étiquette devient le nom du champ. Dans un PDF issu de \TextField{Your name}, le nom du champ est /T (Your name) — espaces compris. C’est un nom peu commode pour ce qui reçoit les données, et une étiquette en français donne un nom de champ en français. L’usage professionnel est donc de toujours fournir un identifiant ASCII via name=. Deuxième conséquence : écrivez deux fois le même name= et PDF traite les champs de même nom comme un seul et même champ. Deux \TextField avec name=dup produisent deux objets portant tous deux /T (dup), et saisir dans l’un remplit l’autre de la même valeur. C’est commode quand on veut délibérément répéter une valeur à deux endroits, mais une collision accidentelle donne une anomalie dont la cause est difficile à voir.
Les boutons radio cachent un problème plus profond. Compilez \ChoiceMenu[radio,name=r1]{Pick}{a,b,c} et vous obtenez trois objets /Btn tous nommés r1 — mais seul le premier figure dans le tableau /Fields du dictionnaire AcroForm. Les deux autres flottent, référencés par aucun champ. Passez le fichier à qpdf et il le dit deux fois : WARNING: this widget annotation is not reachable from /AcroForm in the document catalog. La spécification PDF veut qu’un groupe radio soit exprimé par un champ parent rassemblant ses enfants via /Kids ; hyperref les dispose à plat. Beaucoup de lecteurs l’affichent quand même, d’où le fait que le problème passe inaperçu — mais c’est une structure qui peut casser sous un processeur PDF strict ou un extracteur automatique. Quand les choix sont fixes, combo ou popdown est l’outil le plus franc.
Les options utiles : celles qui deviennent des drapeaux et les autres
Chaque champ accepte une longue liste d’options dans [...] — hyperref définit près de trente clés. Les plus employées sont name=, width=/height=, default= (valeur initiale), bordercolor/backgroundcolor, charsize, align (0 = gauche, 1 = centre, 2 = droite), maxlen= (nombre maximal de caractères) et menulength= (nombre de lignes affichées d’une liste). Parmi elles, seules multiline, readonly et password sont des interrupteurs sans valeur, en correspondance directe avec des drapeaux PDF : à partir de la ligne 5283, hyperref.sty définit ReadOnly comme bit 1, Multiline comme bit 13 et Password comme bit 14 ; en compilant un formulaire et en relisant /Ff, on obtient exactement 1, 4096 et 8192. maxlen=5, en revanche, n’est pas un drapeau : il s’écrit comme une entrée distincte /MaxLen 5. Savoir distinguer les deux indique où regarder lorsqu’une option ne fait pas ce qu’on attendait.
\begin{Form}
\TextField[name=notes,multiline,width=8cm,height=3cm]{Notes}\par
\TextField[name=locked,readonly,width=4cm,default={fixed}]{Locked}\par
\TextField[name=short,maxlen=5,width=3cm]{Max 5}\par
\TextField[name=email,width=5cm,align=0,
bordercolor={0 0 0},backgroundcolor={1 1 0.9}]{Email}
\end{Form}\Submit envoie du FDF par défaut — method=post seul ne suffit pas
C’est le point le plus important de cette page. Écrivez \begin{Form}[action={https://example.org/collect},method=post], appuyez sur le bouton d’envoi, et ce qui parvient au serveur n’est pas un POST de formulaire HTML mais du FDF, le format de données propre à Acrobat. La cause tient à la ligne 5371 de hyperref.sty : \def\Fld@export{fdf} fixe le format d’export par défaut à FDF. Compilez et extrayez l’action d’envoi : vous trouvez /S /SubmitForm sans aucune entrée /Flags — tous les drapeaux à zéro, c’est-à-dire FDF. Et method=post ? Lisez \HyField@FlagsSubmit à partir de la ligne 5378 : le drapeau GetMethod que pose method n’est utilisé que dans les branches HTML et PDF, et totalement ignoré dans la branche FDF. method=post seul n’a donc strictement aucun effet.
Pour qu’un serveur web ordinaire reçoive les données, ajoutez encoding=html à l’environnement Form. C’est une clé dédiée qui exécute \def\Fld@export{html} vers la ligne 5665 de hyperref.sty ; avec elle, l’action d’envoi gagne /Flags 4 — le bit 3, ExportFormat, est posé, donc encodage HTML. À noter : écrire autre chose que html dans encoding ne donne qu’un avertissement Form 'encoding' key with unknown value avant d’être discrètement ignoré. Les autres formats d’export disponibles sont xfdf (une variante XML de FDF) et pdf (qui envoie le PDF rempli en entier).
% FDF (the default) -- your endpoint receives an Acrobat-specific blob
\begin{Form}[action={https://example.org/collect},method=post]
% an ordinary HTML form post -- note encoding=html
\begin{Form}[action={https://example.org/collect},encoding=html,method=post]Ce que les lecteurs réels en font, et quand renoncer
Les formulaires de hyperref n’écrivent pas du tout l’apparence d’un champ dans le fichier. Ils posent /NeedAppearances true dans le dictionnaire AcroForm, ce qui revient à demander au lecteur de dessiner lui-même les contrôles. Acrobat Reader honore cette demande, mais la prise en charge varie : dans l’afficheur PDF intégré d’un navigateur ou dans un lecteur léger, le cadre peut manquer, ou rester inutilisable. Quant au JavaScript de \PushButton[onclick=...], les lecteurs qui l’exécutent sont minoritaires. La même propriété se répercute ailleurs : tout ce qui repose sur /NeedAppearances ne peut être conforme à PDF/A. Un seul champ de saisie suffit pour que veraPDF fasse échouer le fichier à la clause 6.3.3, « An annotation does not contain an appearance dictionary » (la page PDF/A détaille ce point).
Tout cela mis bout à bout, les raisons de choisir un formulaire PDF deviennent assez étroites. Pour la validation ou les scripts, il existe insdljs et eforms d’AcroTeX, mais aucun échafaudage ne garantira que cela fonctionnera dans le lecteur du destinataire. S’il s’agit simplement de collecter des réponses en ligne, la conclusion honnête est qu’un formulaire web est plus fiable et plus rapide à construire. Là où un formulaire PDF a vraiment sa place, c’est un imprimé destiné à être distribué sur papier, que le destinataire remplit par hasard à l’ordinateur avant de l’imprimer ou de l’enregistrer en PDF — autrement dit, un cas où la fonction d’envoi ne sert jamais. Pour cet usage, des cases où l’on peut taper sont réellement utiles, et combinées à des champs figés par readonly elles font un gabarit stable.