Qué es realmente un PDF
ISO 32000-2 §7 Evidence: Standard-backed
De un vistazo
Sección titulada «De un vistazo»Un PDF no es una descripción de página que casualmente está dentro de un archivo. Es una pequeña base de datos en forma de grafo con una impresora acoplada. Esta página describe las cuatro partes que tiene todo PDF —encabezado, cuerpo, tabla de referencias cruzadas y tráiler— y cómo las escribe NextPDF para que un lector pueda encontrar cada objeto sin tener que adivinar.
Por qué esto importa
Sección titulada «Por qué esto importa»La mayoría de los errores en los PDF no son errores de representación. Son errores de estructura: un desplazamiento de bytes que apunta un carácter más allá del objeto que debería, un tráiler que nombra la raíz equivocada, una entrada de la tabla de referencias cruzadas que no coincide con el lugar donde realmente está el objeto. Ninguno de ellos cambia el aspecto de una página hasta que un lector toma una ruta distinta por el archivo y acaba leyendo más allá del final.
Si se trata un PDF como algo opaco, esos fallos parecen aleatorios. Si se conoce el modelo de objetos, se ven exactamente como lo que son: un número que no coincide con una posición. Leer el formato marca la diferencia entre «el PDF está dañado» y «el desplazamiento del objeto 14 está obsoleto porque el escritor lo midió antes de que se finalizara la longitud del flujo».
La versión corta
Sección titulada «La versión corta»Un PDF tiene cuatro partes, en el orden en que aparecen en el archivo:
- Un encabezado: una línea que nombra la versión (
%PDF-2.0). - Un cuerpo: una secuencia de objetos indirectos numerados: diccionarios, flujos, arreglos, números, cadenas y nombres.
- Una tabla de referencias cruzadas (o, en PDF 2.0, un flujo de referencias cruzadas): un índice que va del número de objeto al desplazamiento de bytes, para que se pueda acceder a cualquier objeto sin recorrer el archivo.
- Un tráiler: un pequeño diccionario que nombra el objeto raíz del documento y apunta al lugar donde comienza la sección de referencias cruzadas.
Un lector no lee un PDF de principio a fin. Lee primero la última línea, encuentra startxref, salta a la sección de referencias cruzadas y la usa como índice del cuerpo. El formato está diseñado para leerse desde atrás hacia adelante. Ese único hecho explica gran parte de su diseño.
Cómo lo aborda NextPDF
Sección titulada «Cómo lo aborda NextPDF»NextPDF construye un PDF tal como se lee el formato: primero el objeto, luego se registra el desplazamiento y la tabla se escribe al final.
Un único registro (src/Core/ObjectRegistry.php) asigna un número a cada objeto indirecto. El registro reparte números secuenciales mediante allocate() y, después de que los bytes de un objeto se escriben en el búfer de salida, registra el desplazamiento de bytes mediante register(). Los desplazamientos nunca se adivinan de antemano. Se observan mediante BinaryBuffer::getOffset() en el momento en que se emite el encabezado del objeto. Por eso una entrada de referencias cruzadas de NextPDF no puede desviarse del objeto que describe: el desplazamiento es la posición real que tenía el búfer.
Cuando el cuerpo está completo, una estrategia de serialización específica de la versión (src/Writer/PdfSerializationStrategy.php) escribe la sección de referencias cruzadas y el tráiler:
Pdf20StreamStrategyemite un flujo comprimido de referencias cruzadas (/Type /XRef): el valor predeterminado de PDF 2.0.Pdf17TableStrategyyPdf14TableStrategyemiten una tabla tradicional de referencias cruzadas de 20 bytes más un diccionario de tráiler separado, que requieren los perfiles PDF/A que exigen una estructura de archivo más antigua.
La estrategia la elige el perfil de salida; no se infiere. Sea cual sea, los bytes finales tienen la misma forma: la sección de referencias cruzadas, luego startxref, luego el desplazamiento de bytes y luego %%EOF. Esa cola es lo primero que encuentra un lector.
- Step 1 of 4: ISO 32000-2 §7.5.5 — %%EOF and startxref at the file end
- Step 2 of 4: ISO 32000-2 §7.5.4 / §7.5.8 — the cross-reference section maps object number to offset
- Step 3 of 4: ISO 32000-2 §7.5.5 — the trailer names /Root, the document catalog
- Step 4 of 4: ISO 32000-2 §7.3.10 — each indirect object is reached at its recorded offset
Qué dice la evidencia
Sección titulada «Qué dice la evidencia»La estructura de cuatro partes no es una convención de NextPDF; es la cláusula de estructura de archivo de Spec: ISO 32000-2, §7.5 ISO 32000-2 §7.5 . La norma define un PDF como un encabezado, un cuerpo de objetos, una tabla de referencias cruzadas y un tráiler, y establece que un lector debería analizarlo desde el final del archivo. La última línea es %%EOF, y las dos líneas anteriores son la palabra clave startxref y el desplazamiento de bytes hasta la sección de referencias cruzadas.
Un objeto indirecto se define como un número de objeto y un número de generación, separados por espacios en blanco, seguidos del valor del objeto delimitado por las palabras clave obj y endobj. La combinación de número de objeto y número de generación identifica el objeto de forma única; una referencia indirecta a él se escribe como el número de objeto, el número de generación y la palabra clave R. El ObjectRegistry de NextPDF refleja esto con exactitud: un número secuencial, generación 0 para los objetos recién escritos y un desplazamiento registrado.
Desde PDF 1.5 en adelante también se permite que los objetos estén dentro de un flujo de objetos, donde se almacenan sin las palabras clave obj/endobj y deben tener generación cero. El flujo de referencias cruzadas (/Type /XRef,
Spec: ISO 32000-2, §7.5.8 ISO 32000-2 §7.5.8 ) es el mecanismo de PDF 2.0
que indexa tanto los objetos ordinarios como los comprimidos.
El CrossReferenceStream de NextPDF lo construye con un arreglo de anchos de campo /W y
compresión FlateDecode.
Ejemplo práctico
Sección titulada «Ejemplo práctico»Esta es la forma de un cuerpo mínimo de PDF y su tráiler. Los números de la sección de referencias cruzadas son desplazamientos de bytes. Deben ser exactos, por lo que NextPDF los registra desde el búfer en lugar de calcularlos.
%PDF-2.01 0 obj<< /Type /Catalog /Pages 2 0 R >>endobj2 0 obj<< /Type /Pages /Kids [3 0 R] /Count 1 >>endobj3 0 obj<< /Type /Page /Parent 2 0 R /MediaBox [0 0 612 792] >>endobjxref0 40000000000 65535 f0000000009 00000 n0000000058 00000 n0000000122 00000 ntrailer<< /Size 4 /Root 1 0 R >>startxref196%%EOFUn lector abre esto desde el final: %%EOF, luego startxref 196, luego se desplaza al byte 196, donde comienza xref, lee que el objeto 1 está en el byte 9, sigue /Root 1 0 R hasta el catálogo y recorre el árbol de páginas desde ahí. El objeto 0 es siempre la cabecera de la lista de objetos libres con generación 65535: una peculiaridad heredada del diseño más antiguo del formato, reproducida fielmente porque los lectores la esperan.
Concepto erróneo habitual
Sección titulada «Concepto erróneo habitual»La trampa es creer que un PDF se lee de arriba abajo como código fuente. No es así. El cuerpo puede tener los objetos en cualquier orden. Los números de objeto no tienen por qué ser secuenciales en el archivo, y un lector nunca depende de que lo sean. El único índice con autoridad es la sección de referencias cruzadas, y la única forma de encontrarla es el tráiler al final. Un PDF con un cuerpo perfectamente válido y un único número erróneo en startxref es ilegible. Un PDF con los objetos escritos en un orden cualquiera pero con una tabla de referencias cruzadas correcta está bien. La posición no significa nada; la posición registrada lo es todo.
Límites y fronteras
Sección titulada «Límites y fronteras»Esta página describe la estructura del archivo, no el contenido de la página. Cómo llegan las marcas a una página —flujos de contenido, operadores gráficos, presentación de texto— es un tema aparte. Tampoco cubre lo que sucede cuando un archivo se modifica después de escribirse. Eso corresponde a las actualizaciones incrementales, donde se anexa una segunda sección de referencias cruzadas y el tráiler encadena hacia atrás.
NextPDF es un escritor. El comportamiento descrito aquí es cómo serializa un documento que ha construido. No es un analizador de PDF de propósito general ni una herramienta de reparación. No promete leer, reconstruir ni rescatar un archivo arbitrario de terceros con una tabla de referencias cruzadas dañada. La garantía es acotada y deliberada. Los archivos que NextPDF escribe tienen desplazamientos que coinciden, porque se miden, no se predicen.
Mini-FAQ
Sección titulada «Mini-FAQ»¿Por qué hay números de generación si los archivos nuevos siempre usan 0? Los números de generación existen para reutilizar objetos entre actualizaciones. Un archivo recién escrito tiene todos los objetos en generación 0. Las generaciones distintas de cero aparecen solo cuando un archivo se ha actualizado de forma incremental y se recicla un número de objeto.
¿Pueden dos objetos tener el mismo número? En una única sección de referencias cruzadas, no. A lo largo de las actualizaciones incrementales, un archivo puede contener físicamente varias copias del mismo número de objeto. Prevalece la entrada de referencias cruzadas más reciente. Ese es el tema de la página siguiente.
¿Importa el orden de los objetos en el archivo para la salida? No. NextPDF escribe los objetos en un orden determinista para obtener compilaciones reproducibles, pero un lector lo resuelve todo a través de la sección de referencias cruzadas, de modo que el orden físico no tiene significado semántico.
Documentos relacionados
Sección titulada «Documentos relacionados»- Actualizaciones incrementales y por qué importan: qué sucede cuando se modifica un PDF ya escrito: secciones anexadas y un tráiler encadenado.
- Flujos y filtros: cómo se comprimen y codifican los objetos de flujo del cuerpo.
- PDF 2.0: qué cambió: cómo difiere la estructura de archivo entre 1.7 y la base 2.0 a la que se orienta NextPDF.
Glosario
Sección titulada «Glosario»- Objeto indirecto: un objeto numerado en el cuerpo, escrito como
N G obj … endobj, dondeNes el número de objeto yGel número de generación. - Referencia indirecta: un puntero a un objeto indirecto, escrito
N G R. - Tabla de referencias cruzadas (xref): el índice que va del número de objeto al desplazamiento de bytes. En PDF 2.0 esto suele ser un flujo de referencias cruzadas (
/Type /XRef) en lugar de la clásica tabla de texto de 20 bytes por entrada. - Tráiler: el diccionario al final de una sección de referencias cruzadas que nombra
/Root(el catálogo del documento) y/Size, y se encuentra mediante el desplazamientostartxref. - Flujo de objetos: un objeto de flujo que contiene a su vez otros objetos indirectos (comprimidos juntos); los miembros no tienen
obj/endobjy tienen generación cero. - Catálogo del documento: el objeto nombrado por
/Root; el punto de entrada al árbol de páginas y a todo lo demás del documento.