15 points par GN⁺ 2025-08-04 | 5 commentaires | Partager sur WhatsApp
  • Le parsing de PDF devrait fonctionner sur la base d’un ordre et d’une structure clairement définis, mais les fichiers réels ne respectent souvent pas cette spécification
  • Diverses erreurs et incohérences apparaissent lors de la recherche des pointeurs de cross-reference (xref) et des offsets
  • En pratique, de nombreux problèmes viennent de données inutiles avant l’en-tête PDF, ou d’un mauvais positionnement des pointeurs et des offsets
  • Il existe aussi de nombreux cas où la table xref du PDF elle-même est ambiguë ou mal formatée
  • C’est pourquoi les principaux lecteurs implémentent en plus une logique prenant en charge même les fichiers PDF non standard

Approche idéale du parsing de PDF

  • En théorie, le parsing de PDF suit des étapes fixes
    • Rechercher le commentaire d’en-tête de version au début du fichier
    • Rechercher le pointeur de cross-reference (xref)
    • Collecter tous les offsets d’objets
    • Trouver le dictionnaire trailer pour accéder à la structure globale du catalogue

Présentation des objets PDF

  • Les objets PDF sont des unités qui encapsulent et stockent différents éléments PDF comme des nombres, des chaînes ou des dictionnaires
  • Chaque objet se trouve entre les marqueurs "obj/endobj"
  • Les objets sont reliés entre eux par des références indirectes (indirect reference, par exemple : "16 0 R")
  • La manière de répartir les objets dans le fichier est libre, mais certains types d’objets doivent obligatoirement être en référence indirecte

Recherche des offsets de cross-reference

  • Dans sa structure, un PDF contient une table de cross-reference (xref) qui sert d’index des positions des objets
  • À la fin du fichier, la syntaxe "startxref" indique une position en octets précise comme pointeur
  • Ce pointeur désigne l’emplacement de la xref, mais il existe des écarts entre la spécification et les fichiers réels. Par exemple, le marqueur "%EOF" est censé être la dernière ligne, alors qu’en pratique il peut se trouver n’importe où dans les 1 024 derniers octets
  • Dans les fichiers réels, on observe diverses variantes : erreurs de format du pointeur (startref, etc.), absence de saut de ligne, etc.

Recherche des offsets d’objets

  • La table xref enchaîne "xref", le numéro de début des objets et le nombre d’objets, puis enregistre sur chaque ligne l’offset / le numéro de génération / l’état (n ou f) de chaque objet
  • Il peut exister plusieurs tables xref, ou elles peuvent être reliées entre elles via l’entrée /Prev

Recherche de l’emplacement du dictionnaire trailer

  • Un dictionnaire trailer se trouve au-dessus du marqueur startxref et contient les métadonnées indispensables pour trouver l’objet racine
  • À partir de l’objet racine, on peut commencer à interpréter toute la structure

En conditions réelles : des problèmes inattendus

  • De nombreux fichiers ne respectent pas la spécification PDF, ce qui les rend difficiles à traiter avec un parseur générique

  • Cas fréquents d’échec lors de la recherche du pointeur de cross-reference

    • Le pointeur n’est pas à la fin du fichier ni dans les 1 024 derniers octets
    • Faute de frappe (startref, etc.)
    • Format exceptionnel
  • Sur une étude de 3 977 échantillons PDF réels, environ 0,5 % présentaient une erreur dans la déclaration xref

Le contenu PDF ne commence pas à un offset nul

  • S’il y a des données parasites (junk) avant l’en-tête, tous les offsets en octets sont décalés et la position de startxref devient incorrecte
  • Il faut recalculer les offsets à partir de la position de l’en-tête et vérifier les deux emplacements
  • Cela représente environ 50 % des erreurs

Le pointeur xref vise le milieu de la table xref

  • L’offset indiqué peut parfois pointer en plein milieu du contenu de la table xref
  • Cas observé dans environ 5 fichiers sur 3 977 échantillons

Le pointeur se trouve près de la xref

  • Souvent, le pointeur n’est pas exact, mais l’écart correspond seulement à des espaces ou retours à la ligne juste avant ou après la xref

Le pointeur est correct, mais les offsets xref sont faux

  • Les offsets enregistrés dans la table xref peuvent eux-mêmes être erronés
  • Certains objets peuvent être corrects tandis que d’autres ont des erreurs d’offset

Le premier pointeur est correct, mais l’offset précédent (/Prev) est anormal

  • De nombreux cas montrent que le pointeur /Prev, généré lors de la modification d’un PDF, contient une valeur incorrecte (par exemple : 0)

Le format de la table xref est anormal

  • Les cas sont variés : "xref" collé aux nombres sans saut de ligne, plus d’entrées que d’objets déclarés, ou données parasites au milieu de la table
  • De nombreux signalements de ce type ont été remontés sous forme d’issues dans PdfPig et ailleurs

Conclusion

  • Selon la spécification, le parsing de PDF devrait suivre un ordre structuré, mais de nombreux fichiers réels ne s’y conforment pas, ce qui entraîne divers problèmes de parsing
  • Les lecteurs PDF utilisés en pratique incluent par défaut des fonctions élargissant la prise en charge des PDF non conformes
  • Ce résumé ne traite que d’une partie du parsing correspondant à 22 pages sur les 1 300 pages de la spécification PDF

5 commentaires

 
mhj5730 2025-08-06

Ce résumé ne traite que de l’analyse d’une petite partie de la spécification PDF (22 pages sur un total de 1300) <- ... 1300 pages, c’est absolument énorme...

 
kaydash 2025-08-05

Waouh..

 
spp00 2025-08-05

Les PDF, pour être franc, sont avant tout un format facile à lire pour les humains, conçu pour préserver au maximum la mise en page créée par l’homme, et ils sont franchement parmi les pires quand il s’agit de fonctionner avec les machines.

 
reagea0 2025-08-05

Je compatis. Honnêtement, je ne suis même pas sûr que ce soit agréable à lire... C'est trop lourd et peu pratique.

 
GN⁺ 2025-08-04
Avis Hacker News
  • La réponse est claire

    1. Le PDF permet d’attacher des métadonnées dans n’importe quel format souhaité
    2. Tous les logiciels de création de PDF devraient attacher les mêmes informations d’une manière facile à lire pour une machine
    3. Ainsi, ceux qui veulent parser des PDF n’auraient qu’à regarder les métadonnées
      En pratique, je m’appelle Geoff, et la moitié des parseurs de CV reconnaissent mon nom séparément comme "Geo" et "ff"
      C’est dû à la manière dont le texte est intégré dans le PDF, et c’est un problème récurrent avec de nombreuses applications sources
    • Parser un PDF et parser le contenu d’un PDF sont deux choses complètement différentes
      Parser le fichier PDF est déjà pénible, mais comme le PDF repose essentiellement sur le principe de « placer quelque chose à une position donnée », et non sur du texte bien défini dans des boîtes englobantes, extraire les mots oblige à deviner quelles lettres vont ensemble
      Si vous voulez aider les parseurs de CV, ça vaut le coup de regarder du côté de l’arbre d’accessibilité (Accessibility tree)
      Tous les moteurs de rendu PDF n’exportent pas des PDF accessibles, mais les PDF accessibles peuvent au moins aider à lire correctement des choses comme les noms
      Le problème du "ff" vient probablement du fait que l’analyseur de CV ne gère pas les caractères non ASCII, par exemple la ligature ff
      On peut configurer le moteur de rendu PDF pour qu’il ne génère pas de ligatures, mais le texte risque alors d’être moins esthétique

    • On dirait qu’on attend beaucoup du mot « should »
      Si l’usage du PDF est en réalité assez hostile, les gens n’ont sans doute pas ce niveau d’exigence
      Le simple fait d’envoyer un CV en PDF vise déjà à empêcher les intermédiaires de le modifier, et il y a aussi d’autres usages de « l’édition », comme masquer du contenu en dessinant des boîtes sur une image, ou produire des tableaux en PDF plutôt qu’en CSV pour compliquer l’analyse

    • En pratique, cette méthode fonctionne parfois bien, et certaines applications l’utilisent déjà
      Mais il reste le problème du décalage possible entre les deux représentations, le contenu principal et les métadonnées

    • Je me demande comment on gère les scans manuscrits ou d’autres documents numérisés, à moins que les scanners et les ordinateurs familiaux ne disposent d’un support OCR parfait

    • Le problème vient probablement du fait que ff est rendu sous forme de ligature

  • Je suis le fondateur de Tensorlake
    Nous avons créé une API de parsing de documents pour les développeurs
    C’est la raison pour laquelle l’approche Computer Vision fonctionne bien en production pour le parsing de PDF
    S’appuyer uniquement sur les métadonnées internes du fichier ne passe pas à l’échelle avec la diversité des sources de PDF
    Nous convertissons donc d’abord le PDF en images, appliquons ensuite un modèle de reconnaissance de mise en page, puis des modèles spécialisés pour le texte et les tableaux, avant de recomposer le tout, ce qui donne des résultats exploitables même dans des domaines où la précision est essentielle

    • À première vue, cette approche peut sembler ridicule, mais c’est en réalité probablement la solution la plus pragmatique
      Le PDF a été conçu fondamentalement pour représenter une mise en page destinée à être lue par des humains, pas pour être lu par des machines, et il met l’accent sur un affichage soigné
      Il semble donc logique d’adopter une méthode qui imite la façon dont les humains lisent
      Cela dit, c’est dommage que le PDF n’ait pas gagné en lisibilité machine après plus de 30 ans
      Je me demande quels incitatifs ont manqué pour rendre cela possible
      Si quelqu’un a des idées sur le sujet, je serais curieux de les entendre

    • Il y a quelque chose d’un peu absurde là-dedans
      Imprimer un PDF, le scanner, puis l’envoyer par e-mail passe pour une absurdité, mais pour parser un PDF, on fait en pratique presque la même chose
      C’est frustrant qu’une telle approche soit nécessaire
      Personne ne parse le HTML comme ça

    • Je suis cofondateur de Nutrient.io et je travaille sur le PDF depuis plus de 10 ans
      Comme les navigateurs web, les visionneuses PDF doivent accepter une énorme variété de PDF
      Le format est si ancien que les générateurs de fichiers bricolent souvent les PDF tant qu’ils s’affichent correctement dans la visionneuse qu’ils utilisent eux-mêmes
      C’est pour cela que notre entreprise a créé un SDK de traitement documentaire IA, avec une REST API qui prend un PDF en entrée et renvoie des données structurées en JSON
      Grâce non seulement aux méthodes visuelles mais aussi à notre expérience en prétraitement et post-traitement structurels, nous obtenons de meilleurs résultats en performance et en coût qu’une approche purement vision
      Si vous ne voulez pas vous préoccuper directement du traitement PDF et préférez vous concentrer sur votre vrai métier, cela peut vous aider
      https://www.nutrient.io/sdk/ai-document-processing

    • Puisqu’il y a ici un expert de la structure interne des PDF, j’ai une question
      Pourquoi mupdf-gl est-il tellement plus rapide que tous les autres programmes sur un Linux desktop standard ?
      La vitesse de recherche dans les gros PDF est nettement supérieure, et je me suis toujours demandé pourquoi les autres visionneuses ne pouvaient pas être aussi rapides
      Si quelqu’un a un éclairage là-dessus, je suis preneur

    • Au final, on a simplement sous-traité le parsing au logiciel utilisé pour rendre le PDF en image

  • Depuis longtemps, je pense qu’il faudrait sortir de cette communication documentaire centrée sur la mise en page
    Autrement dit, la mise en page sophistiquée est en fait plus proche d’une vieille habitude qu’autre chose, et elle a très peu à voir avec la compréhension réelle du contenu
    Par exemple, les dossiers soumis aux autorités réglementaires sont souvent des documents extrêmement volumineux, et respecter les règles de mise en page impose de passer beaucoup de temps dans Microsoft Word
    Pour garantir cette mise en page, on soumet ensuite au format DOCX ou PDF, alors que ces formats sont très mal adaptés à l’extraction ou à la transformation automatique du contenu par des programmes
    Les LLM peuvent lire ces fichiers eux aussi, mais à un coût de calcul bien plus élevé que pour des formats simples et machine-friendly comme le texte, le markdown, le XML ou le JSON

    Comme alternative, j’envisage la possibilité de standardiser des formats simples « machine-first » et « content-first », fondés par exemple sur JSON, XML ou HTML
    Ils ne contiendraient qu’un minimum de structure et d’informations d’intégration d’images, et une application de lecture se chargerait de les reconstituer joliment pour l’humain
    Le traitement machine en serait grandement facilité
    Même si des formats comparables existent déjà, comme HTML/browser ou EPUB, je pense qu’il est temps de remplacer l’approche classique
    J’espère que la révolution LLM nous poussera dans cette direction, et que le parsing PDF coûteux restera bientôt un pipeline hérité

    • Je suis d’accord sur les problèmes du PDF, mais est-ce que le DOCX est vraiment à ce point mauvais ?
      Je n’ai encore jamais écrit de parseur DOCX, mais puisque DOCX est basé sur XML et que, sauf si on impose explicitement une mise en page, tout n’y est pas exprimé en coordonnées absolues, j’imagine que si un JPEG vaut 0, un PDF 15 et le markdown 100, alors DOCX doit être autour de 80 en termes de facilité
  • Je trouvais que c’était un excellent récapitulatif, et il y a un autre point que j’ai trouvé intéressant
    Chaîne de sauvegarde incrémentale : le premier offset startxref est correct, mais il arrive souvent que les liens /Prev ajoutés à répétition par Acrobat à chaque modification pointent quelques octets trop tôt par rapport au xref suivant
    La plupart des visionneuses, y compris PDF.js, MuPDF et même Adobe Reader, reconstruisent alors une nouvelle table en recherchant brutalement les tokens obj dans tout le fichier, tandis qu’un parseur strictement conforme à la spécification explose
    Si l’on veut traiter, sur le terrain, des documents modifiés successivement par plusieurs applications, ce chemin de récupération est indispensable

    • C’est une remarque juste, c’est un cas d’échec que je voyais souvent dans mon ensemble d’exemples
      Il arrive fréquemment qu’une référence précédente, ou un élément de la chaîne, pointe vers un offset hors du fichier, un offset nul ou une valeur incorrecte
      Cet article a été motivé par la refonte de la logique de parsing initiale de mon projet PdfPig
      Au départ, j’avais porté le code de Java PDFBox, mais je voulais quelque chose de plus rapide et de plus simple
      La nouvelle logique scanne tout le fichier si elle manque une seule table ou un seul flux xref, et dans la voie de récupération, elle ne fait confiance qu’à cet offset
      Mais c’est clairement plus lent qu’avant, et j’ai du mal à savoir si ce changement est réellement acceptable
      J’explore toutes sortes de cas particuliers avec un jeu de test de 10 000 fichiers
      https://github.com/UglyToad/PdfPig/pull/1102
  • On pourrait croire qu’avec de bonnes hypothèses de fonctionnement et un parseur d’objets PDF correct, ce serait simple, mais en réalité ça ne l’est absolument pas
    C’est l’enfer du PDF
    Le PDF n’est pas une spécification, c’est un consensus social, une sorte d’« ambiance »
    Plus on se débat, plus on s’enfonce, et on a l’impression qu’on vit tous désormais dans un marécage hors de la vue de Dieu
    Cette formulation m’a fait rire

    • On dirait une blague disant que ce texte a été écrit par James Mickens
  • À la question « voulez-vous parser un PDF ? », je peux répondre catégoriquement : absolument pas
    Les raisons sont très bien expliquées dans le post original

    • J’aimerais que ma banque fournisse ses documents dans un format plus lisible, mais en attendant, je n’ai pas vraiment le choix

    • J’ai déjà fait cette erreur, et je compte bien ne jamais recommencer

  • Pour avoir déjà écrit un parseur PDF, je trouve vraiment que c’est un format étrange
    Cette étrangeté vient probablement de sa conception originelle, qui mélange binaire et texte
    Je suppose que le problème des offsets xref légèrement inexacts vient aussi de bugs dans la gestion des conversions de fins de ligne LF/CR
    Un point que l’article ne mentionne pas est que les PDF récents (v1.5+) utilisent souvent un « xref stream » au lieu d’une table xref en texte brut
    À partir de la v1.6, les objets eux-mêmes peuvent aussi être placés dans un object stream

    • Moi aussi, j’ai été surpris qu’on ne dépasse pas le niveau des tables xref simples pour parler aussi des flux et de la compression
      Tout semble anodin, jusqu’au moment où l’objet recherché se trouve dans un flux, que ce flux utilise une variante de compression PNG, ou que les offsets soient stockés dans un xref stream compressé en flate
      En plus, plusieurs versions d’un même document peuvent se retrouver mélangées, ce qui complique encore le fait de déterminer ce qui est réellement la version la plus récente
      Il est facile de se procurer les documents PDF 1.7, mais jusqu’il y a à peine deux ans, les spécifications PDF 2.0 étaient encore derrière un paywall
  • Le PDF n’est pas un format pensé pour le streaming
    Le trailer dictionary, situé à la fin, rend le parsing difficile tant que le fichier complet n’a pas été chargé
    Cela dit, il existe aussi des « PDF streamables », conçus de manière à pouvoir rendre immédiatement la première page si les informations nécessaires se trouvent au début, même si ce n’est pas forcément le cas du reste
    Je suis un peu éloigné du sujet PDF ces derniers temps, donc à prendre avec précaution

    • Même avec un footer, un PDF peut être diffusé en streaming si le site web prend en charge les Range Request et utilise correctement l’en-tête Content-Length
      Un lecteur en streaming peut envoyer une requête HEAD, récupérer les quelques centaines d’octets de fin du fichier pour obtenir le pointeur et la table, puis télécharger le reste ensuite
      Ce n’est pas adapté à un PDF généré en temps réel, mais pour un serveur web un peu ancien, un ou deux aller-retours supplémentaires suffisent largement
      Malheureusement, les cas où l’on prend réellement soin des parseurs fondés sur des requêtes Range par fichier restent rares, mais techniquement, ce n’est pas impossible

    • Oui, il existe un format appelé Linearized PDF, conçu pour afficher rapidement la première page sans devoir télécharger l’intégralité du fichier
      Je précise que je l’ai omis du résumé parce que cela demandait trop d’explications annexes

  • L’un de mes premiers projets quand j’apprenais Python a été un parseur PDF
    Je voulais extraire automatiquement des cartes pour une campagne de DnD, mais ça a échoué au final, haha

  • J’ai déjà écrit un lecteur TIFF
    Le TIFF a aussi la réputation d’être facile à écrire mais difficile à lire
    J’ai l’impression que le PDF appartient exactement à la même catégorie