Artículo técnico

Estructura del Archivo PDF: Cómo Funciona Realmente el Formato

Un PDF no es un formato de documento de la misma forma en que lo es Word o RTF. Esos formatos almacenan una secuencia de contenido que un renderizador interpreta en el momento de la visualización, por lo que el resultado depende de las fuentes y del motor de diseño que estén presentes. El PDF almacena el resultado de ese proceso: instrucciones de renderizado precisas, programas de fuentes, flujos de imágenes comprimidos y un gráfico de objetos que los une en una descripción independiente de cada página. El archivo lleva suficiente información para reproducir cada página de manera idéntica en cualquier renderizador compatible, lo cual es tanto su principal objetivo de diseño como la fuente de la mayor parte de la complejidad que uno encuentra cuando intenta generar, analizar o modificar un PDF mediante programación

El modelo de objetos

Todo PDF es una colección de objetos numerados. Un objeto puede ser un booleano, un número entero, un número real, un nombre, una cadena de texto, un arreglo, un diccionario, un flujo (stream) o nulo. Casi todo lo interesante es un diccionario, que es un conjunto de pares clave-valor donde las claves son nombres y los valores son de cualquier otro tipo de objeto, incluidas las referencias a otros objetos por número y conteo de generación. Un flujo es un diccionario seguido de una secuencia de bytes, típicamente comprimida

El diccionario catálogo (catalog dictionary) es la raíz. Apunta al árbol de páginas, el cual organiza los diccionarios de páginas en una estructura de árbol equilibrado en lugar de una lista plana, por lo que navegar a la página 5,000 de un documento de 10,000 páginas no requiere recorrer cada descriptor de página anterior. Cada diccionario de página hace referencia a sus flujos de contenido (una o más secuencias de operadores de descripción de página), su diccionario de recursos (que a su vez hace referencia a descriptores de fuentes, espacios de color y objetos de imagen o XObjects) y su cuadro de medios o media box (el espacio de coordenadas en el que se encuentra la página). El origen de las coordenadas se encuentra en la esquina inferior izquierda, con la Y positiva extendiéndose hacia arriba, en unidades de 1/72 de pulgada

Al final del archivo se encuentra la tabla de referencias cruzadas, que asigna a cada número de objeto su desplazamiento de bytes dentro del archivo. Esto es lo que permite el acceso aleatorio: un visor lee primero la tabla de referencias cruzadas y luego busca directamente los objetos que necesita. El PDF 1.5 introdujo los flujos de referencias cruzadas, que comprimen la tabla en un objeto de flujo y agrupan objetos relacionados en flujos de objetos (object streams), reduciendo el tamaño del archivo de forma notable en documentos con muchos objetos pequeños

Flujos de contenido y el modelo de gráficos

El contenido visual de una página reside en uno o más flujos de contenido. Cada flujo es una secuencia de operadores PDF intercalados con sus operandos. El operador de texto BT inicia un objeto de texto, Tf selecciona una fuente y un tamaño del diccionario de recursos, Td posiciona el cursor de texto, Tj o TJ pinta una cadena de texto y ET cierra el objeto de texto. Los gráficos vectoriales siguen un patrón similar: m establece el punto de inicio de un trazado, l añade un segmento de línea, c añade una curva Bézier y f o S rellena o dibuja el contorno del trazado

El estado de los gráficos gobierna todo lo que sucede entre los operadores: la matriz de transformación actual, el grosor de la línea, el espacio de color, el color de relleno, el color del trazo y el trazado de recorte. Operadores como q y Q apilan y desapilan (push y pop) el estado de los gráficos en una pila, que es cómo el PDF implementa las transformaciones de coordenadas locales y las anulaciones de estado temporales sin afectar el contexto que los rodea. Los Form XObjects generalizan esto: un flujo de contenido independiente con su propio diccionario de recursos que se puede pintar sobre una página en posiciones y escalas arbitrarias con un solo operador Do

Incrustación de fuentes y extracción de texto

Un PDF puede hacer referencia a fuentes por su nombre y confiar en que el visor sustituya alguna, pero en la práctica, cualquier documento que intente compartir debe incrustar los datos de la fuente. Una fuente Type 1 o TrueType/OpenType incrustada en un PDF lleva un diccionario de descriptor de fuente que apunta a un flujo del archivo de la fuente. Para fuentes TrueType, ese flujo contiene el programa binario de la fuente; para Type 1, son los datos PFB. El subconjunto (subsetting), que es lo que hace cualquier generador de PDF serio, elimina los glifos no referenciados por el documento, manteniendo los tamaños de archivo manejables incluso para fuentes Unicode grandes

La extracción de texto es donde la incrustación de fuentes presenta dificultades. La representación visual de un carácter está determinada por un glifo en el programa de la fuente incrustada. El valor Unicode de ese carácter está determinado por un flujo ToUnicode CMap adjunto al diccionario de la fuente. Cuando el ToUnicode CMap falta o es incorrecto, un visor de PDF puede renderizar el texto de manera legible pero no puede extraerlo como Unicode con sentido, que es el motivo por el cual copiar y pegar desde algunos archivos PDF produce caracteres sin sentido (garbage). El PDF Etiquetado (Tagged PDF, ISO 32000 §14.8) añade una segunda capa: un árbol de estructura lógica que mapea el contenido de la página a roles semánticos del documento, como párrafos, encabezados y celdas de tablas. Los lectores de pantalla y los motores de reflujo utilizan el árbol de estructura en lugar del orden del flujo de contenido bruto, lo cual explica por qué un PDF visualmente bien diseñado todavía puede ser inaccesible si las etiquetas faltan o están mal

Actualizaciones incrementales y firmas digitales

Cuando guarda cambios en un PDF existente sin reescribirlo desde cero, los nuevos objetos se añaden después del cuerpo original del archivo, junto con una nueva sección de referencias cruzadas y un nuevo diccionario de tráiler. El tráiler actualizado apunta a los nuevos datos de referencias cruzadas, y los objetos reemplazados permanecen en el archivo pero simplemente no son referenciados por la nueva cadena de referencias cruzadas. Esto es una actualización incremental, y tiene dos consecuencias importantes

Primero, el archivo crece con cada ciclo de guardado. Un documento editado y guardado repetidamente acumula capas de objetos obsoletos. Herramientas como QPDF pueden linealizar o comprimir y reescribir un archivo para recuperar ese espacio, pero la acumulación es el comportamiento por defecto. Segundo, las firmas digitales dependen de las actualizaciones incrementales para su modelo de integridad. Una firma ISO 32000 cubre un rango de bytes del archivo, típicamente todo excepto el marcador de posición para el valor de la firma en sí. Cualquier cambio posterior a la firma que aparezca como actualizaciones incrementales adicionales será visible para un lector que valide el documento como modificaciones realizadas después de firmar, que es exactamente el registro de auditoría que uno desea tener. Sin embargo, esto también significa que ciertas modificaciones, como agregar una firma de aprobación o rellenar campos de formularios, están explícitamente permitidas por el estándar sin invalidar la firma original, siempre que los cambios se ajusten a la configuración de permisos del documento (ISO 32000-2 §12.7.6). Una modificación que quede fuera de esos permisos será marcada como no autorizada. Entender bien esta diferencia importa cuando está generando documentos que serán refrendados (countersigned) más adelante en el proceso

Niveles de conformidad y el linaje de ISO 32000

El PDF comenzó como un formato propietario de Adobe en 1993, absorbió el modelo de imágenes de PostScript y durante quince versiones acumuló características: cifrado en la 1.1, formularios interactivos en la 1.2, firmas digitales y estructura lógica en la 1.3, transparencia en la 1.4, flujos de objetos en la 1.5, cifrado AES en la 1.6. Adobe envió el PDF 1.7 a la ISO en 2007, y el resultado fue la ISO 32000-1:2008. La ISO 32000-2:2020 cubre el PDF 2.0, que hizo más estrictas varias áreas subespecificadas, revisó la derivación de clave AES-256 (revisión 6 reemplazando a la revisión 5) y agregó soporte explícito para archivos asociados y multimedia (rich media)

Los subestándares derivan de la misma base. El PDF/A (ISO 19005) intercambia características por estabilidad de archivo: sin cifrado, sin dependencias de contenido externo, todas las fuentes incrustadas, espacios de color independientes del dispositivo, metadatos XMP obligatorios. PDF/A-1 se basa en PDF 1.4, PDF/A-2 en PDF 1.7, y PDF/A-3 permite archivos incrustados de cualquier formato. PDF/X (ISO 15930) es el subconjunto de producción de impresión: intenciones de salida (output intents), cuadros de sangrado y corte, y sin transparencia en niveles de conformidad más antiguos. PDF/UA (ISO 14289) exige una estructura etiquetada, asignaciones Unicode y metadatos de idioma para la accesibilidad. Estos no son formatos que compiten entre sí; son conjuntos de restricciones adicionales por encima del PDF central, y un solo archivo puede cumplir con más de uno simultáneamente, siempre que las restricciones no entren en conflicto

Para cualquiera que escriba código que genere o procese PDF, la base de referencia práctica es ISO 32000-2, con especial atención a las secciones que cubren el modelo de referencias cruzadas (§7.5), el estado de los gráficos (§8.4), los operadores del estado del texto (§9.3), los descriptores de fuentes y ToUnicode (§9.6 y §9.10), los formularios interactivos (§12.7) y las firmas digitales (§12.8). El estándar es largo, pero la mayor parte del trabajo de PDF a nivel de programación toca repetidamente una porción estrecha del mismo. Comprender el modelo de objetos y el mecanismo de referencias cruzadas es el punto de entrada; todo lo demás es una especialización a partir de ahí