15 puntos por GN⁺ 2025-08-04 | 5 comentarios | Compartir por WhatsApp
  • El parseo de PDF debería funcionar con base en un orden y una estructura claros, pero en la práctica los archivos con frecuencia no siguen esta especificación
  • Se producen diversos errores e inconsistencias al encontrar punteros cross-reference (xref) y offsets
  • En la práctica, muchos problemas surgen por datos innecesarios antes del encabezado PDF, o por ubicaciones incorrectas de punteros y offsets
  • También hay muchos casos en los que la propia tabla xref del PDF no es clara o está mal formateada
  • Por eso, los principales visores implementan lógica adicional para soportar incluso archivos PDF no estándar

Enfoque ideal para el parseo de PDF

  • En teoría, el parseo de PDF avanza en pasos definidos
    • Buscar el comentario del encabezado de versión al inicio del archivo
    • Buscar el puntero cross-reference (xref)
    • Recolectar todos los offsets de objetos
    • Encontrar el diccionario trailer para acceder a toda la estructura del catálogo

Introducción a los objetos PDF

  • Un objeto PDF es la unidad que envuelve y almacena varios elementos del PDF, como números, cadenas y diccionarios
  • Cada objeto existe entre los marcadores "obj/endobj"
  • Los objetos se conectan entre sí mediante referencias indirectas (indirect reference, por ejemplo: "16 0 R")
  • La forma de dividir los objetos dentro del archivo es libre, pero algunos tipos de objeto deben ser necesariamente referencias indirectas

Cómo encontrar offsets de cross-reference

  • En la estructura del PDF existe una tabla cross-reference (xref), que funciona como índice de las posiciones de los objetos
  • Al final del archivo, la sintaxis "startxref" indica una posición específica en bytes como puntero
  • Este puntero señala la ubicación de xref, pero hay diferencias entre la especificación y los archivos reales. Por ejemplo, el marcador "%EOF" debería estar en la última línea, pero en los PDF reales puede aparecer en cualquier lugar dentro de los últimos 1,024 bytes
  • En archivos reales se encuentran muchas variaciones: errores de formato del puntero (startref, etc.), falta de saltos de línea y más

Cómo encontrar offsets de objetos

  • La tabla xref sigue la secuencia "xref", número inicial de objeto y cantidad de objetos, y en cada línea se registran el offset / número de generación / estado (n o f) de cada objeto
  • Puede haber varias tablas xref, o pueden estar conectadas entre sí mediante la entrada /Prev

Búsqueda de la ubicación del diccionario trailer

  • Encima del marcador startxref se encuentra el diccionario trailer, que incluye los metadatos esenciales para encontrar el objeto raíz
  • A partir del objeto raíz se puede empezar a interpretar toda la estructura

Entorno real: problemas inesperados

  • Hay muchos archivos que no cumplen la especificación de PDF, por lo que es difícil procesarlos con un parser común

  • Casos en los que suele fallar la búsqueda del puntero cross-reference

    • El puntero no está al final del archivo ni dentro de los últimos 1,024 bytes
    • Errores tipográficos (startref, etc.)
    • Formatos excepcionales
  • En una investigación de 3,977 muestras reales de PDF, aproximadamente el 0.5% tenía errores en la declaración xref

El contenido PDF comienza en un offset distinto de 0

  • Si hay datos basura (junk) antes del encabezado, todos los offsets de bytes se desplazan y la posición de startxref deja de coincidir
  • Hay que recalcular los offsets con base en la posición del encabezado y verificar ambas ubicaciones
  • Esto representa cerca del 50% de todos los errores

El puntero xref apunta al medio de la tabla xref

  • El offset indicado puede incluso llevar al medio del contenido de la tabla xref
  • Se encontró en unos 5 casos de 3,977 muestras

El puntero está cerca de xref

  • A menudo el puntero no es exacto, pero solo está desfasado por espacios o saltos de línea justo antes o después de xref

El puntero es correcto, pero los offsets xref son incorrectos

  • Los offsets registrados en la tabla xref pueden estar mal por sí mismos
  • Puede que solo algunos objetos sean correctos y el resto tenga errores de offset

El primer puntero es normal, pero el offset anterior (/Prev) es extraño

  • Hay muchos casos donde el puntero /Prev generado al modificar un PDF guarda un valor incorrecto (por ejemplo, 0)

El formato de la tabla xref es anormal

  • Aparecen distintos casos, como "xref" pegado a números sin salto de línea, más entradas de las que se declararon, o datos basura en medio de la tabla
  • Muchos de estos casos han sido reportados como issues en PdfPig y otros

Conclusión

  • Según la especificación, el parseo de PDF debería seguir un orden estructurado, pero muchos archivos reales no son así, por lo que surgen diversos problemas durante el parseo
  • Los visores PDF de uso real incluyen por defecto funciones para ampliar el soporte a PDF no conformes con la especificación
  • Este resumen solo cubrió una pequeña parte del parseo correspondiente a la especificación PDF (22 páginas de un total de 1300)

5 comentarios

 
mhj5730 2025-08-06

En esta ocasión, el resumen solo trató una parte del análisis de la especificación de PDF (22 páginas de un total de 1300) <-... vaya, 1300 páginas es una locura...

 
kaydash 2025-08-05

Vaya..

 
spp00 2025-08-05

Si quieres analizar PDFs, seamos sinceros: el PDF es un formato fácil de leer para humanos que preserva al máximo el diseño creado por personas, y se lleva pésimo con las máquinas.

 
reagea0 2025-08-05

Te entiendo. La verdad, ni siquiera sé si es fácil de leer... es demasiado pesado e incómodo.

 
GN⁺ 2025-08-04
Opiniones de Hacker News
  • La respuesta es clara

    1. Los PDF admiten adjuntar metadatos en cualquier formato que quieras
    2. Todo software que genere PDF debería adjuntar la misma información de una forma fácil de leer para las máquinas
    3. Entonces, quien quiera parsear un PDF solo tendría que mirar los metadatos
      En la práctica, mi nombre es Geoff, pero la mitad de los parsers de currículums reconocen mi nombre por separado como "Geo" y "ff"
      Esto pasa por la forma en que el texto se guarda dentro del PDF, y es un problema que sigue ocurriendo en muchas apps de origen distintas
    • Parsear un PDF y parsear el contenido de un PDF son cosas completamente distintas
      Parsear el archivo PDF ya es una molestia, pero como el propio PDF se basa en "poner algo en una posición determinada", no se parece a texto bien definido dentro de un cuadro delimitador, así que para extraer palabras hay que adivinar qué caracteres van juntos
      Si quieres ayudar a un parser de currículums, vale la pena fijarse en el árbol de accesibilidad (Accessibility tree)
      No todos los renderizadores de PDF exportan PDF accesibles, pero un PDF accesible al menos puede ayudar a leer correctamente cosas como un nombre
      El problema con "ff" probablemente es que el analizador del currículum no sabe manejar caracteres no ASCII, por ejemplo la ligadura ff
      Puedes configurar el renderizador de PDF para que no genere ligaduras, pero entonces el texto puede verse feo

    • Siento que se le está pidiendo demasiado a la palabra "debería"
      Si el uso del PDF en la práctica es bastante hostil, no creo que la gente piense de esa manera
      Empezando por el hecho de que se envían currículums en PDF precisamente para que los intermediarios no puedan corregirlos, y también hay otros motivos de "edición", como tapar información dibujando un recuadro sobre una imagen, o hacer tablas en PDF en vez de CSV para dificultar el análisis

    • En algunos casos este método sí funciona bien, y algunas apps ya lo usan
      Aun así, sigue quedando el problema de que las dos representaciones (cuerpo/metadatos) no coincidan realmente

    • También queda la duda de qué hacer con escaneos de escritura a mano u otros documentos escaneados, si el escáner y una computadora doméstica común no tienen soporte OCR perfecto

    • Probablemente el problema con ff sea que se renderiza como una ligadura

  • Soy fundador de Tensorlake
    Hicimos una API de parseo de documentos para desarrolladores
    Esta es la razón por la que un enfoque de Computer Vision sí funciona bien en la práctica para parsear PDFs
    Depender solo de los metadatos dentro del archivo no escala con la diversidad de orígenes de PDF
    Por eso convertimos el PDF en imágenes, aplicamos primero un modelo de reconocimiento de layout, luego modelos especializados para texto y tablas, y después reunimos las piezas, de modo que obtenemos resultados utilizables incluso en áreas donde la precisión es indispensable

    • A primera vista este enfoque parece ridículo, pero en realidad me parece la solución más realista
      El PDF es, en esencia, un formato diseñado para representar layouts pensados para que los lean personas, no para que los lean computadoras; es un formato enfocado en mostrar bien las cosas
      Por eso tiene sentido un enfoque que imite la forma en que leen los humanos
      Aun así, da pena que en más de 30 años el PDF no haya logrado volverse más legible para máquinas
      Me pregunto qué incentivo faltó para que eso no fuera posible
      Si alguien tiene alguna idea al respecto, me gustaría escucharla

    • Tiene algo de irónico
      Imprimir un PDF, escanearlo y luego mandarlo por correo suena como algo ridículo, pero al parsear PDFs en realidad estamos haciendo casi lo mismo
      Es frustrante que se necesite un enfoque así
      Nadie parsea HTML de esa forma

    • Soy cofundador de Nutrient.io y llevo más de 10 años trabajando con PDF
      Los visores de PDF, igual que los navegadores web, tienen que aceptar una variedad enorme de PDFs
      Como el PDF es tan antiguo, quienes generan archivos hacen modificaciones arbitrarias siempre que se vea bien en el visor que usan
      Por eso en nuestra empresa hicimos un SDK de procesamiento documental con IA (una REST API que recibe PDF y devuelve datos estructurados en JSON)
      No solo usamos métodos visuales; con experiencia en preprocesamiento y posprocesamiento estructural, ofrecemos mejores resultados tanto en rendimiento como en costo frente a un enfoque puramente visual
      Si no quieres preocuparte por procesar PDFs directamente y prefieres concentrarte en tu trabajo principal, podría servirte
      https://www.nutrient.io/sdk/ai-document-processing

    • Ya que hay alguien experto en la estructura interna de PDF, tengo una pregunta
      Me intriga por qué mupdf-gl es muchísimo más rápido que cualquier otro programa (al menos en Linux de escritorio por defecto)
      La velocidad con la que busca en PDFs grandes es claramente superior, y siempre me he preguntado por qué otros visores no pueden ser así de rápidos
      Si tienes alguna idea al respecto, me gustaría oírla

    • Al final, terminaste subcontratando el trabajo de parseo al software que usas para renderizar el PDF como imagen

  • Desde hace mucho pienso que deberíamos alejarnos de la comunicación documental centrada en el layout
    Es decir, ese layout profesionalmente adornado en realidad se parece más a una costumbre antigua, y creo que tiene muy poca relación con entender el contenido real
    Por ejemplo, los documentos que se presentan ante distintos organismos reguladores suelen ser larguísimos, y cumplir las reglas de layout implica pasar mucho tiempo trabajando en Microsoft Word
    Luego se envían en formato DOCX o PDF para garantizar ese layout, pero esos formatos son muy poco adecuados para que un programa extraiga o procese automáticamente el contenido
    Un LLM también puede leer esos archivos, pero el costo computacional es mucho mayor que con archivos simples y amigables para máquinas, como texto, markdown, XML o JSON

    Como alternativa, he pensado en la posibilidad de estandarizar formatos simples de tipo "machine-first" y "content-first" basados en JSON, XML, HTML, etc.
    Solo tendrían una estructura mínima e información para incrustar imágenes, y cuando lo lea una persona una app visor lo reconstruiría de forma agradable
    El procesamiento por máquina sería mucho más fácil
    Aunque ya existen formatos parecidos como HTML/navegadores y EPUB, creo que ya es hora de reemplazar el enfoque clásico
    Espero que la revolución de los LLM nos lleve en esa dirección, y que en el futuro el parseo caro de PDFs quede solo como un pipeline heredado

    • Estoy de acuerdo con el problema del PDF, pero pregunto si DOCX realmente es tan malo
      Todavía no he hecho un parser de DOCX, pero como DOCX está basado en XML y, salvo que definas explícitamente el layout, no todo queda fijado en coordenadas absolutas, sospecho que si JPEG vale 0 puntos, PDF 15 puntos y markdown 100 puntos, DOCX debe estar más o menos en 80 en dificultad
  • Me pareció un gran resumen, y hubo un punto adicional que me resultó interesante
    Cadena de incremental-save: el primer offset de startxref está bien, pero cuando Acrobat hace varias modificaciones y va agregando repetidamente enlaces /Prev, muchas veces estos apuntan unos bytes antes del siguiente xref
    La mayoría de los visores (incluidos PDF.js, MuPDF e incluso Adobe Reader) simplemente buscan a lo bruto el token obj por todo el archivo y reconstruyen una tabla nueva, mientras que un parser fiel a la especificación explota
    Si quieres trabajar en campo con documentos modificados repetidas veces por distintas aplicaciones, este tipo de ruta de recuperación (salvage path) es indispensable

    • Es correcto, era un caso de falla que veía seguido en el conjunto de muestras
      Muchas veces la referencia previa, o alguna dentro de la cadena, apunta a offsets fuera del archivo, offset 0 o valores incorrectos
      Lo que me llevó a escribir ese texto fue una refactorización de la lógica de parseo inicial en mi proyecto PdfPig
      Al principio porté el código de Java PDFBox, pero quería volverlo más rápido y más simple
      La nueva lógica, si se pierde aunque sea una tabla/stream xref, escanea todo el archivo y en la ruta de recuperación solo confía en esos offsets
      Pero sin duda se volvió más lenta que antes, y me cuesta saber si el cambio realmente estuvo bien
      Estoy explorando todo tipo de casos raros (edge cases) con un conjunto de prueba de 10 mil archivos
      https://github.com/UglyToad/PdfPig/pull/1102
  • Parece que sería fácil si hubiera supuestos válidos y un parser apropiado de objetos PDF, pero creo que la realidad está muy lejos de eso
    Esta situación es como un infierno de PDF
    El PDF no es una especificación, es un acuerdo social, una "vibra"
    Cuanto más forcejeas, más te hundes, y siento que ahora todos vivimos en un pantano alejado de la mirada de Dios
    Este comentario me dio risa

    • Bromeo con que este texto parece escrito por James Mickens
  • Respecto a la pregunta "¿quieres parsear un PDF?", puedo asegurar que no, en absoluto
    El motivo está bien explicado en el post original

    • Ojalá mi banco ofreciera los documentos en un formato más fácil de leer, pero hasta entonces no hay de otra

    • Ya cometí ese error antes y no pienso volver a hacerlo

  • Como alguien que ha escrito un parser de PDF, siento que PDF es un formato realmente raro
    Creo que esa rareza viene de su diseño de origen, una mezcla de binario y texto
    También sospecho que el problema de offsets xref un poco inexactos viene de bugs al manejar conversiones de saltos de línea LF/CR
    Algo que no se mencionó en el texto es que los PDF modernos (v1.5+) muchas veces ya no traen una tabla xref de texto normal, sino un "xref stream"
    En v1.6 y posteriores, incluso los propios objetos pueden ir dentro de un object stream

    • A mí también me sorprendió que no se pasara de las tablas xref simples para hablar de streams y compresión
      Todo parece ir bien, hasta que el objeto que quieres está dentro de un stream, y ese stream a su vez usa una variante de compresión PNG, o el offset está dentro de un xref stream comprimido con flate, y entonces todo se complica
      Encima, hay varias versiones del documento mezcladas, así que también es complejo determinar desde dónde hasta dónde llega la versión más reciente
      Los documentos de PDF 1.7 son fáciles de conseguir, pero hasta hace apenas 2 años la especificación de PDF 2.0 estaba detrás de un muro de pago
  • El PDF es un formato que no se diseñó pensando en streaming
    Por el trailer dictionary ubicado al final, es difícil parsearlo hasta que no se cargue el archivo completo
    Aun así, existen los "streaming PDFs", donde si la información necesaria está al principio se puede renderizar de inmediato la primera página, aunque quizá no el resto
    Hace tiempo que estoy algo alejado del mundo PDF, así que hay que tomarlo en cuenta

    • Aunque haya un footer, si el sitio web soporta Range Request y usa bien el header Content-Length, un PDF sí puede hacerse streaming
      Un lector en streaming puede hacer una solicitud HEAD, pedir los últimos cientos de bytes del archivo para obtener el puntero y la tabla, y luego seguir descargando el resto
      No sirve para PDFs generados en tiempo real, pero para un servidor web relativamente antiguo bastan 1 o 2 tiempos de ida y vuelta extra
      Por desgracia, son pocos los casos donde se presta atención a un parser por archivo basado en Range, pero técnicamente no es imposible

    • Correcto, existe el formato Linearized PDF, diseñado para mostrar rápido la primera página sin descargar el archivo completo
      En el resumen omití ese método porque implicaba mucha explicación adicional

  • Uno de los primeros proyectos que intenté al aprender Python fue un parser de PDF
    Quería extraer automáticamente mapas para una campaña de DnD, pero el resultado fue un fracaso jajaja

  • He escrito un lector de TIFF
    TIFF también tiene fama de ser fácil de escribir pero difícil de leer
    Siento que PDF entra exactamente en esa misma categoría