Ir al contenido
getnextpdf.com

La economía del tamaño de archivo de un PDF

Spec: ISO 32000-2, §7.5.7

Dos PDF pueden verse píxel a píxel idénticos en pantalla y diferir diez veces en disco. La diferencia casi nunca es el contenido que se ve; es cómo se ensambló el archivo por debajo. Esta página es un recorrido por la economía del tamaño: adónde van realmente los bytes de un PDF y las cuatro palancas en las que un autor gasta su presupuesto de bytes.

Es la compañera de por qué los archivos son grandes de Flujos y filtros, que cubre cómo decodifica un filtro. Esta se queda en el presupuesto.

El tamaño de archivo rara vez es una métrica de vanidad. Es ancho de banda en cada descarga, almacenamiento en cada archivado y latencia en cada vista previa. Una factura de 12 MB que debería haber sido de 400 KB no es un problema cosmético cuando se generan un millón al mes: es una factura treinta veces mayor.

La parte frustrante es que la hinchazón suele ser invisible. El documento se renderiza correctamente, abre bien, imprime bien. Nada le dice que el mismo artefacto podría haber sido una fracción del tamaño, porque los bytes desperdiciados son estructurales, no visuales. Para encontrarlos hay que mirar el presupuesto, no la página.

Piense en un PDF como un presupuesto que se gasta en cuatro partidas.

  • Sobrecarga por objeto. Cada objeto indirecto lleva un envoltorio N G obj / endobj, y lo rastrea una entrada de referencias cruzadas. Un documento con muchas páginas tiene miles de objetos diminutos, y los envoltorios suman. Los flujos de objetos eliminan ese envoltorio para todo un grupo de objetos; cada objeto empaquetado sigue conservando su propia entrada de referencias cruzadas, pero como una entrada compacta de tipo 2.
  • Bytes de imagen. Para cualquier documento con fotografías o escaneados, las imágenes dominan, y la mayor palanca individual es la elección del filtro: un códec sin pérdida frente a un códec de imagen con pérdida es la diferencia entre megabytes y kilobytes.
  • Bytes de fuente. Una fuente incrustada completa son cientos de kilobytes de glifos que nunca usa. La creación de subconjuntos conserva solo los glifos que el documento dibuja realmente.
  • El índice. La tabla de referencias cruzadas que permite a un lector encontrar cada objeto puede ser ella misma un flujo comprimido en lugar de texto plano.

Acierte con las cuatro y el archivo es pequeño. Falle una y dominará todo lo demás que hizo bien.

El escritor de NextPDF es un serializador de transmisión de una sola pasada: añade los bytes de cada objeto a medida que se producen y registra una entrada de referencias cruzadas en uso clásica para cada uno. Ese valor predeterminado es rápido, predecible y produce un archivo estable byte a byte, pero no es la maquetación más pequeña posible, y NextPDF es honesto al respecto.

Un PDF es un grafo de objetos indirectos. La mayoría son diccionarios pequeños: nodos de página, diccionarios de anotación, elementos del árbol de estructura, entradas de esquema. Cada uno paga un impuesto fijo: las palabras clave obj / endobj, los números de objeto y de generación, y una entrada de referencias cruzadas que lo localiza. En un documento con miles de objetos pequeños, ese impuesto es una porción significativa del archivo.

Un flujo de objetos recoge muchos de esos pequeños objetos sin flujo en un único flujo y los comprime juntos (Spec: ISO 32000-2, §7.5.7). El envoltorio obj / endobj se elimina para todo el grupo; los valores de dentro se almacenan de forma contigua sin palabras clave por objeto, y luego se comprimen con deflate como un único bloque, lo que además comprime mejor, porque el compresor que deduplica ahora ve todos esos diccionarios similares a la vez. La entrada de referencias cruzadas no desaparece —cada objeto empaquetado sigue necesitando una— pero se encoge a una entrada binaria compacta de tipo 2 en el flujo de referencias cruzadas (más sobre esto en la Palanca 2).

En NextPDF esto lo entrega ObjectStreamPacker, un posprocesador autocontenido que toma un PDF de flujo de referencias cruzadas terminado y reescribe los objetos elegibles en un único /Type /ObjStm. Las reglas que sigue vienen directamente del estándar: un objeto elegible es un objeto de generación cero y sin flujo, tras excluir los objetos especiales que deben permanecer directamente direccionables. §7.5.7 prohíbe almacenar un objeto de flujo dentro de un flujo de objetos, así que los objetos de flujo —contenido, fuentes, imágenes— conservan sus propias entradas; y ObjectStreamPacker además declina el propio objeto de flujo de referencias cruzadas del documento (se reescribe) y el diccionario /Encrypt, ambos de los cuales deben permanecer directamente direccionables. Todo lo demás que sea de generación cero y sin flujo se empaqueta.

Object stream packing (ObjStm) — edition availability
EditionAvailability
CoreFull support in the open-source core via ObjectStreamPacker. It is opt-in: the single-pass writer’s default emits classic in-use entries, so output stays byte-identical unless you enable packing. The packer is deterministic, with its own reproducible golden baseline.
ProNot in this edition
EnterpriseNot in this edition

La activación opcional es una postura deliberada, no una limitación que se esconde. La salida predeterminada es estable byte a byte y coincide con las líneas base de referencia existentes; activar el empaquetado opta por una maquetación distinta, más pequeña e igualmente determinista. Usted elige el intercambio, y el motor nunca lo hace a sus espaldas.

Palanca 2: el índice también puede ser un flujo

Sección titulada «Palanca 2: el índice también puede ser un flujo»

Una vez que los objetos viven dentro de un flujo de objetos, el índice que apunta a ellos cambia de forma. Un lector encuentra un objeto empaquetado a través de una entrada de referencias cruzadas comprimida: una entrada de tipo 2 que nombra el flujo de objetos y el índice dentro de él (Spec: ISO 32000-2, §7.5.8.3). Como todo el flujo de referencias cruzadas es en sí mismo un flujo /Type /XRef, el índice de miles de objetos se empaqueta en binario y se comprime con deflate en lugar de escribirse como filas de texto plano. El mapa se encoge junto al territorio.

ObjectStreamPacker reconstruye exactamente esto: emite el único flujo de objetos y luego un flujo de referencias cruzadas reescrito que lleva una entrada compacta de tipo 1 para cada objeto retenido y una entrada de tipo 2 para cada uno empaquetado, preservando cada número de objeto para que las referencias existentes sigan siendo válidas.

Para cualquier documento con imágenes reales, esta palanca empequeñece a las demás. Los bytes son la misma imagen; el códec es el presupuesto. Los nombres de filtro viven en el conjunto de filtros estándar (Spec: ISO 32000-2, §7.4), y la elección entre ellos es una decisión de tamaño:

  • FlateDecode es sin pérdida. Perfecto para arte lineal, capturas de pantalla y cualquier cosa con color plano, y ruinoso para una fotografía, donde sin pérdida significa cada byte del original.
  • DCTDecode es JPEG: con pérdida, y para fotografías es la decisión correcta por un amplio margen, a menudo una reducción de diez veces a cambio de una caída de calidad que nadie nota.
  • JPXDecode es JPEG 2000: compresión wavelet con una curva de calidad/tamaño distinta, pero con soporte desigual y no permitido por algunos perfiles de archivado.

Aquí es exactamente donde importa cómo decodifica un filtro, y ese es el trabajo del artículo Flujos y filtros. El punto económico es más estrecho: una fotografía almacenada sin pérdida es la causa individual más común de un PDF innecesariamente enorme, y ningún empaquetado de flujos de objetos rescatará un archivo cuyo verdadero peso es un escaneado sin pasar por JPEG.

Palanca 4: creación de subconjuntos de fuentes

Sección titulada «Palanca 4: creación de subconjuntos de fuentes»

Una fuente incrustada es un programa. Una completa puede ser de varios cientos de kilobytes, porque lleva cada glifo que el diseñador de la tipografía dibujó jamás: miles de caracteres de escrituras que nunca usará en este documento. La creación de subconjuntos incrusta solo los glifos que el documento dibuja realmente, convirtiendo ese programa en una pequeña fracción de sí mismo. Una carta de una página no necesita la totalidad de una fuente con capacidad CJK; necesita las pocas docenas de glifos que compone. La mecánica de cómo se seleccionan y se reindexan los glifos es un tema propio; consulte Fuentes: la parte difícil.

  1. Image bytesFor media-heavy files, the largest line item. The filter choice — lossless Flate vs a lossy image codec like DCT (or JPX in a lossy mode) — is the dominant size lever.
  2. Font bytesA full embedded font is mostly glyphs you never draw. Subsetting keeps only the used glyphs, often shrinking the program by an order of magnitude.
  3. Per-object overheadThousands of small dictionaries each pay an obj/endobj envelope plus a cross-reference entry. Object streams (ObjStm) drop the envelope for the whole group; each object keeps a compact type-2 cross-reference entry.
  4. The indexA compressed cross-reference stream with type-2 entries binary-packs and deflates the map of every object, replacing plaintext index rows.
Where the bytes go: the four levers an author spends a PDF's size budget on, in the order they typically dominate a real file.

No hay aquí ninguna API fabricada que mostrar, porque las decisiones de tamaño más importantes se toman antes de que los bytes lleguen al escritor, y la única palanca estructural que NextPDF expone es una sola activación opcional. Conceptualmente, el presupuesto se lee así:

  • Alimente las fotografías como JPEG para que caigan bajo DCTDecode, no recodificadas sin pérdida. La mayor ganancia es una decisión sobre los datos de origen, no una bandera del escritor.
  • Deje que el escritor cree subconjuntos de las fuentes incrustadas para que solo se envíen los glifos dibujados.
  • Para un documento con muchos objetos pequeños, opte por el empaquetado en flujos de objetos, que encamina el archivo terminado a través de ObjectStreamPacker para agrupar los pequeños objetos sin flujo y reescribir el flujo de referencias cruzadas.

La ruta predeterminada —entradas en uso clásicas, sin ObjStm— es la línea base correcta: determinista, estable byte a byte y fácil de verificar. El empaquetado es la mejora meditada cuando lo que infla el archivo es el recuento de objetos, no el peso de las imágenes.

La trampa es recurrir a un botón de «comprimir el PDF» y esperar que lo arregle todo. La compresión no es una sola palanca; son cuatro, y no se sustituyen entre sí. El empaquetado en flujos de objetos no puede encoger una fotografía: ese es el trabajo del filtro de imagen. Un JPEG perfecto no puede compensar una fuente que olvidó someter a subconjunto. Y nada de ello ayuda si la verdadera hinchazón es un escaneado de 10 MB almacenado sin pérdida porque nadie eligió DCTDecode para él.

El segundo concepto erróneo es que más pequeño es siempre estrictamente mejor. No lo es. Los flujos de objetos son incompatibles con la linealización: la maquetación de vista web rápida que fija la colocación absoluta de los objetos para que la primera página se transmita pronto. Y algunos perfiles de archivado restringen qué filtros de imagen están siquiera permitidos. El tamaño es un eje. Se intercambia con la transmisión, la conformidad de archivado y la reproducibilidad, y el punto correcto en la curva depende de para qué sirve el documento.

Las cuatro palancas son la economía estructural del tamaño de archivo. No son una garantía universal de «hacerlo más pequeño», y NextPDF no pretende ser un reoptimizador para PDF entrantes arbitrarios.

ObjectStreamPacker es una optimización de mejor esfuerzo que nunca arriesga la corrección. Declina —devolviendo la entrada sin cambios— cuando el archivo no es un PDF de flujo de referencias cruzadas, cuando está cifrado, cuando lleva una firma digital (volver a disponer los objetos desplazaría los rangos de bytes que protege una firma), cuando ya contiene flujos de objetos, o cuando no hay ningún objeto elegible que empaquetar. Emite exactamente un flujo de objetos para todo el documento; no se divide en una colección /Extends, lo cual queda fuera de alcance y es conforme para los tamaños de documento que NextPDF produce.

Las palancas de imagen y de fuente son en gran medida decisiones sobre la entrada. El escritor de NextPDF no transcodifica implícitamente un mapa de bits sin pérdida a un flujo de imagen con pérdida —recodificar una fotografía a DCTDecode o JPXDecode es una decisión explícita de codificación de imagen aguas arriba, no algo que el serializador haga a sus espaldas— ni recupera glifos de una fuente que el llamador pidió incrustar completa. Las mayores ganancias de tamaño se hacen aguas arriba del serializador de bytes; el trabajo del motor es no desperdiciar el presupuesto que usted le trae.

  • Flujos y filtros: la compañera de cómo decodifica un filtro; esta página la complementa deliberadamente, no la duplica.
  • Qué es realmente un PDF: el modelo de objeto indirecto cuya sobrecarga por objeto reduce la palanca de los flujos de objetos.
  • La anatomía de un archivo PDF: la estructura de referencias cruzadas que se convierte en un flujo comprimido.
  • Fuentes: la parte difícil: cómo la creación de subconjuntos selecciona y reindexa los glifos que un documento dibuja.
  • Flujo de objetos (ObjStm): un único flujo que contiene muchos objetos indirectos pequeños sin flujo, comprimidos juntos, de modo que el envoltorio obj / endobj se elimina para el grupo. Cada objeto empaquetado sigue conservando su propia entrada de referencias cruzadas, como una entrada compacta de tipo 2. Activación opcional en NextPDF.
  • Objeto indirecto: un objeto numerado en el grafo de un PDF, envuelto en un envoltorio obj / endobj y rastreado por el índice de referencias cruzadas. El envoltorio es la sobrecarga por objeto.
  • Flujo de referencias cruzadas: el flujo /Type /XRef que indexa cada objeto, empaquetado en binario y comprimido con deflate en lugar de escrito como filas de texto plano.
  • Entrada comprimida (de tipo 2): una entrada de referencias cruzadas que apunta a un objeto que vive dentro de un flujo de objetos, nombrando el flujo y el índice dentro de él.
  • Creación de subconjuntos de fuentes: incrustar solo los glifos que un documento dibuja realmente, en lugar de la tipografía completa, encogiendo el programa de la fuente incrustada.
  • Filtro sin pérdida frente a con pérdida: un códec sin pérdida (FlateDecode) reproduce cada byte; un códec de imagen con pérdida (DCTDecode, o JPXDecode en un modo con pérdida) descarta detalle imperceptible a cambio de un resultado mucho más pequeño. (JPEG 2000 / JPX también puede configurarse sin pérdida.) La elección es la palanca dominante en un archivo cargado de medios.