Article technique

Structure du fichier PDF : comment fonctionne réellement le format

Le PDF n'est pas un format de document comme Word ou RTF. Ces formats stockent une séquence de contenu que le moteur de rendu interprète lors de l'affichage, de sorte que le résultat dépend des polices et des moteurs de mise en page présents. En revanche, le PDF stocke le résultat de ce processus : des instructions de rendu précises, des programmes de polices, des flux d'images compressés et un graphe d'objets qui les lie pour former une description autonome de chaque page. Le fichier transporte suffisamment d'informations pour reproduire chaque page à l'identique sur n'importe quel moteur de rendu conforme, ce qui est à la fois son principal objectif de conception et la source de la plupart des complexités que vous rencontrez lorsque vous tentez de générer, d'analyser ou de modifier un PDF par programmation

Modèle d'objet

Chaque PDF est une collection d'objets numérotés. Un objet peut être un booléen, un entier, un réel, un nom, une chaîne, un tableau, un dictionnaire, un flux ou null. Presque tout élément intéressant est un dictionnaire, qui est un ensemble de paires clé-valeur où les clés sont des noms et les valeurs sont d'autres types d'objets, y compris des références à d'autres objets via leur numéro et leur numéro de génération. Un flux est un dictionnaire suivi d'une séquence d'octets, généralement compressée

Le dictionnaire du catalogue (catalog) est la racine. Il pointe vers l'arbre des pages, qui organise les dictionnaires de pages sous forme d'arbre équilibré plutôt que de liste plate. Ainsi, naviguer vers la page 5 000 d'un document de 10 000 pages ne nécessite pas de parcourir tous les descripteurs de pages précédents. Chaque dictionnaire de page fait référence à son flux de contenu (une séquence d'un ou plusieurs opérateurs de description de page), à son dictionnaire de ressources (qui à son tour référence les descripteurs de polices, les espaces colorimétriques et les images XObject) et à sa boîte de média (l'espace de coordonnées où se trouve la page). L'origine des coordonnées se situe dans le coin inférieur gauche, avec l'axe Y positif pointant vers le haut, en unités de 1/72 de pouce

À la fin du fichier se trouve la table de référence croisée, qui mappe chaque numéro d'objet à son décalage d'octets dans le fichier. C'est ce qui permet l'accès aléatoire : le lecteur commence par lire la table de référence croisée, puis accède directement à l'objet dont il a besoin. Le PDF 1.5 a introduit les flux de référence croisée, qui compressent la table sous forme d'un objet flux et regroupent les objets associés dans des flux d'objets, réduisant ainsi considérablement la taille du fichier pour les documents contenant de nombreux petits objets

Flux de contenu et modèle graphique

Le contenu visuel de la page réside dans un ou plusieurs flux de contenu. Chaque flux est une séquence d'opérateurs PDF entremêlés avec leurs opérandes. Les opérateurs de texte BT démarrent un objet texte, Tf sélectionne la police et la taille depuis le dictionnaire de ressources, Td positionne le curseur de texte, Tj ou TJ dessine la chaîne, et ET ferme l'objet texte. Les graphiques vectoriels suivent un modèle similaire : m définit le point de départ du tracé, l ajoute un segment de ligne, c ajoute une courbe de Bézier, et f ou S remplit ou trace le contour du tracé

L'état graphique contrôle tout ce qui se passe entre les opérateurs : la matrice de transformation actuelle, l'épaisseur de ligne, l'espace colorimétrique, la couleur de remplissage, la couleur de contour et le tracé de détourage. Des opérateurs comme q et Q poussent ou dépoussent l'état graphique de la pile, ce qui est la manière dont le PDF réalise des transformations de coordonnées locales et des surcharges d'état temporaires sans affecter le contexte environnant. Les XObjects de formulaires (Form XObject) généralisent cela : il s'agit d'un flux de contenu autonome avec son propre dictionnaire de ressources, qui peut être dessiné n'importe où sur la page à n'importe quelle échelle avec un seul opérateur Do

Incorporation de polices et extraction de texte

Un PDF peut faire référence à une police par son nom et s'en remettre au lecteur pour la remplacer, mais en pratique, tout document que vous prévoyez de partager doit intégrer les données de police. Une police Type 1 ou TrueType/OpenType intégrée dans un PDF s'accompagne d'un dictionnaire de descripteur de police pointant vers le flux du fichier de police. Pour les polices TrueType, ce flux contient le programme binaire de la police ; pour les polices Type 1, ce sont les données PFB. La création de sous-ensembles (subsetting) est une opération effectuée par tout générateur de PDF sérieux ; elle élimine les glyphes non référencés dans le document, ce qui permet de maintenir une taille de fichier raisonnable même pour les grandes polices Unicode

L'extraction de texte est l'endroit où se manifestent les effets secondaires de l'intégration des polices. La représentation visuelle d'un caractère est déterminée par les glyphes définis dans le programme de police intégré. La valeur Unicode de ce caractère est déterminée par le flux ToUnicode CMap attaché au dictionnaire de la police. Lorsque ToUnicode CMap est manquant ou incorrect, le lecteur PDF peut restituer le texte clairement mais ne peut pas l'extraire sous forme de caractères Unicode cohérents, ce qui explique pourquoi copier-coller depuis certains PDF génère des caractères illisibles. Les PDF balisés (ISO 32000 §14.8) ajoutent une seconde couche : un arbre de structure logique qui mappe le contenu de la page à des rôles sémantiques de document (tels que paragraphes, titres et cellules de tableau). Les lecteurs d'écran et les moteurs de redistribution utilisent l'arbre de structure plutôt que l'ordre du flux de contenu d'origine, ce qui explique pourquoi un PDF visuellement bien mis en page peut rester inaccessible si les balises sont manquantes ou incorrectes

Mises à jour incrémentielles et signatures numériques

Lorsque vous enregistrez des modifications dans un PDF existant au lieu de le réécrire à partir de zéro, les nouveaux objets sont ajoutés à la suite du corps du fichier d'origine, accompagnés d'une nouvelle section de références croisées et d'un nouveau dictionnaire de trailer. Le trailer mis à jour pointe vers les nouvelles données de références croisées, les objets remplacés restant dans le fichier mais cessant d'être référencés par la nouvelle chaîne de références croisées. C'est ce qu'on appelle la mise à jour incrémentielle, qui entraîne deux conséquences importantes

Premièrement, le fichier grandit à chaque cycle d'enregistrement. Les documents modifiés et enregistrés de manière répétée accumulent des couches d'objets obsolètes. Des outils comme QPDF peuvent linéariser ou compresser les fichiers pour récupérer cet espace, mais le comportement par défaut est l'accumulation. Deuxièmement, le modèle d'intégrité de la signature numérique repose sur les mises à jour incrémentielles. La signature ISO 32000 couvre une plage d'octets du fichier, généralement tout sauf l'emplacement de la valeur de la signature elle-même. Toute modification post-signature apparaissant sous forme de mise à jour incrémentielle supplémentaire peut être identifiée par le lecteur de validation comme des modifications apportées après la signature, ce qui correspond précisément à la piste d'audit souhaitée. Cependant, cela signifie également que la spécification autorise explicitement certaines modifications (telles que l'ajout d'une signature d'approbation ou le remplissage de champs de formulaire) sans invalider la signature d'origine, à condition que ces modifications respectent les autorisations du document (ISO 32000-2 §12.7.6). Les modifications dépassant ces autorisations sont marquées comme non autorisées. Comprendre cette distinction est important lorsque vous générez des documents qui seront cosignés en aval

Dès lors que la séparation entre caractères, codes et glyphes est claire, tout cela n'a plus de mystère. Intégrez les polices que vous utilisez pour dessiner, créez des sous-ensembles pour les polices volumineuses, utilisez une police Unicode et appelez RegisterUnicodeTTF dès que le texte sort de l'alphabet latin, et conservez une table de correspondance ToUnicode correcte si quelqu'un doit extraire du texte. Faites cela correctement, et les carrés cesseront d'apparaître. Pour les mécanismes périphériques, l'Analyse d'un PDF minimal montre la place du dictionnaire de police dans l'arbre des objets, et le guide de la structure des documents couvre le partage des ressources entre les pages

Le format PDF est né en 1993 en tant que format propriétaire d'Adobe, adoptant le modèle d'imagerie de PostScript et accumulant de nombreuses fonctionnalités au fil de ses 15 versions : chiffrement dans la version 1.1, formulaires interactifs dans la version 1.2, signatures numériques et structure logique dans la version 1.3, transparence dans la version 1.4, flux d'objets dans la version 1.5, chiffrement AES dans la version 1.6. Adobe a soumis le PDF 1.7 à l'ISO en 2007, donnant naissance à la norme ISO 32000-1:2008. La norme ISO 32000-2:2020 couvre le PDF 2.0, qui resserre plusieurs domaines non spécifiés, modifie la dérivation de clé AES-256 (la version 6 remplaçant la version 5) et ajoute explicitement la prise en charge des fichiers associés et des médias enrichis

Chaque sous-norme dérive de la même base. PDF/A (ISO 19005) sacrifie certaines fonctionnalités pour la stabilité de l'archivage : pas de chiffrement, pas de dépendance vis-à-vis de contenus externes, toutes les polices doivent être intégrées, espaces colorimétriques indépendants des périphériques, présence obligatoire des métadonnées XMP. PDF/A-1 est basé sur PDF 1.4, PDF/A-2 sur PDF 1.7, PDF/A-3 permet d'intégrer des fichiers de tout format. PDF/X (ISO 15930) est un sous-ensemble destiné à l'imprimerie : spécifie les intentions de rendu, les boîtes de fond perdu et de rognage, la transparence étant interdite dans les anciens niveaux de conformité. PDF/UA (ISO 14289) impose une structure balisée, des mappages Unicode ainsi que des métadonnées linguistiques pour l'accessibilité. Ce ne sont pas des formats concurrents ; il s'agit d'un ensemble de contraintes supplémentaires sur le PDF de base, et un même fichier peut être conforme à plusieurs normes simultanément si les contraintes ne se contredisent pas

Pour toute personne écrivant du code pour générer ou traiter des PDF, la référence pratique est l'ISO 32000-2, avec une attention particulière aux sections traitant du modèle de référence croisée (§7.5), de l'état graphique (§8.4), des opérateurs d'état de texte (§9.3), des descripteurs de polices et ToUnicode (§9.6 et §9.10), des formulaires interactifs (§12.7) et des signatures numériques (§12.8). Cette norme est longue, mais la plupart des travaux de programmation PDF ne concernent à plusieurs reprises qu'une fraction très étroite de celle-ci. Comprendre le modèle d'objet et le mécanisme de référence croisée est le point d'entrée ; tout le reste est une extension spécialisée basée sur cela