PDF Library for Delphi puede fusionar imágenes dentro de un PDF que se ven iguales pero no son idénticas byte a byte, mediante DeduplicateSimilarImages. La deduplicación exacta solo fusiona imágenes cuyos diccionarios y cargas codificadas coinciden; esta compara cómo se ven realmente las imágenes, usando un hash perceptual más dos umbrales de error de píxel, y redirige cada referencia hacia un único objeto canónico
Los archivos donde esto vale la pena son los que crecieron por accidente. Un lote escaneado donde cada página lleva el mismo logotipo recodificado por un escáner distinto. Un informe armado a partir de fuentes que cada una embebió el mismo gráfico con una calidad JPEG ligeramente distinta. Un catálogo cuyas miniaturas se regeneraron con dos herramientas. En cada caso el archivo contiene muchas copias de una sola imagen, y la deduplicación exacta no puede tocar ninguna de ellas
Qué tiene que significar "suficientemente similar"
Tres umbrales deben cumplirse todos antes de que se fusionen dos imágenes, y cada uno captura un tipo distinto de diferencia. La distancia de hash perceptual acota la diferencia estructural: se calcula un hash de diferencia de 64 bits a partir de una muestra de 64 por 64 de la imagen decodificada, y la distancia de Hamming permitida va de 0 a 7. El error medio por canal acota la desviación global, que es lo que produce la recodificación. El error máximo de un solo canal acota la diferencia localizada, que es lo que produce una edición pequeña
Exigir los tres a la vez es lo que hace defendible la fusión. Una imagen que difiere por una marca de agua en una esquina tiene un error medio bajo y un error máximo alto, así que la barrera de error máximo la rechaza. Una imagen que ha sido recomprimida tiene un error pequeño en todas partes, así que pasa. Esa es exactamente la distinción que necesita trazar un optimizador de tamaño
uses
PDFlibrary;
var
Lib: TPDFlib;
Stats: TPDFlibImageSimilarityDedupStats;
Merged: Integer;
begin
Lib := TPDFlib.Create;
try
Lib.LoadFromFile('scanned-batch.pdf', '');
// Distancia de hash 2, error medio 2, error de un solo canal 4.
// Las opciones pueden pedir una ejecución de prueba para no modificar nada
Merged := Lib.DeduplicateSimilarImages(2, 2, 4, 0, Stats);
if Merged < 0 then
raise Exception.Create('deduplication failed');
Log(Format('%d scanned, %d merged, %d refs repointed, %d bytes duplicated',
[Stats.ImagesScanned, Stats.ImagesDeduplicated,
Stats.ReferencesRepointed, Stats.DuplicatePayloadBytes]));
Log(Format('worst accepted: hash %d, mean %.2f, channel %d',
[Stats.MaxAcceptedHashDistance, Stats.MaxAcceptedMeanError,
Stats.MaxAcceptedChannelError]));
Lib.SaveToFile('scanned-batch-optimised.pdf');
finally
Lib.Free;
end;
end;
La identidad semántica va antes que la similitud visual
Antes de comparar ningún píxel, las imágenes candidatas deben coincidir semánticamente. La biblioteca construye una firma estable a partir del diccionario de imagen completo, excluyendo /Length, /Filter y /DecodeParms, de modo que las dimensiones, el espacio de color, la profundidad de bits, las máscaras, el arreglo /Decode, la interpolación, la pertenencia a contenido opcional y los metadatos tienen que coincidir todos
Este orden evita toda una clase de fusiones erróneas. Dos imágenes pueden verse idénticas en una muestra de 64 por 64 y comportarse de forma distinta en la página: una con /Interpolate en true y otra sin él se suavizarán de forma distinta al escalarse, y una que pertenezca a un grupo de contenido opcional desaparecerá cuando esa capa se oculte. Fusionar a través de esos límites produce un documento más pequeño y equivocado
Solo se escanean los Image XObjects indirectos. Las imágenes en línea son una construcción distinta con una economía distinta, y las imágenes que no se pueden decodificar se omiten de forma conservadora y se cuentan, en lugar de fusionarse por fe — sin evidencia de píxeles, no hay fusión
Cómo la búsqueda se mantiene barata
Comparar cada imagen contra todas las demás es cuadrático, algo inaceptable en un documento que contiene miles de imágenes. Por eso el hash se divide en ocho bandas de 8 bits, cada una con un índice ordenado
El principio del palomar hace el resto: si dos hashes difieren en como máximo 7 bits, deben coincidir exactamente en al menos una de las ocho bandas. Por eso buscar candidatos banda por banda encuentra cada coincidencia permitida sin un escaneo exhaustivo por pares, y el límite publicado de 7 existe precisamente porque la garantía solo se sostiene hasta esa distancia
Los candidatos y las coincidencias de banda se ordenan de forma determinista por número de objeto y generación, y el número de objeto más bajo se vuelve canónico. Eso hace reproducible la salida: ejecutar el optimizador dos veces sobre la misma entrada produce las mismas elecciones canónicas, algo que importa cuando el resultado se compara o se firma
Ejecuciones de prueba e informes honestos
Como esta es una optimización con pérdida en el sentido de que las imágenes fusionadas no eran idénticas, el flujo de trabajo sensato es mirar antes de saltar. La opción de ejecución de prueba reporta qué se fusionaría y cuánta carga se recuperaría sin modificar el grafo de objetos, de modo que un trabajo por lotes pueda registrar el efecto y una persona pueda aprobar los umbrales una vez, en lugar de por cada archivo
Dos notas de honestidad en el informe merecen mención. La cifra recuperable estima solo la carga codificada de los flujos duplicados; no cuenta la sobrecarga de diccionarios, objetos indirectos y referencias cruzadas, así que la reducción real de tamaño de archivo es ligeramente mayor que la reportada, no menor. Y el informe expone el error máximo aceptado y la carga de trabajo de comparación, para que usted pueda ver qué tan cerca de sus umbrales estuvieron las fusiones
La cuadrícula de muestreo fija de 64 por 64 es una aproximación intencional, y tiene una consecuencia que vale la pena decir con claridad: una diferencia más pequeña que una celda de muestra puede pasar inadvertida incluso con un umbral de cero. Una sola palabra cambiada en una página escaneada podría no sobrevivir ese muestreo. Cuando se requiere una prueba a nivel de bytes, use en su lugar la ruta de deduplicación exacta — esa fusiona solo recursos genuinamente idénticos y no hace ningún juicio visual
Dónde encaja esto en un pipeline de reducción de tamaño
Ordene las pasadas por riesgo. Ejecute primero la deduplicación exacta de recursos, ya que no tiene pérdida y es gratuita. Luego el subsetting de fuentes, que también carece de pérdida y suele ser la ganancia individual más grande en documentos con mucho texto, como se cubre en optimización del tamaño de archivo PDF y subsetting de fuentes. Luego la recompresión o el submuestreo de imágenes, si el medio de destino lo permite. La deduplicación perceptual pertenece después de esas, porque es el único paso cuyo resultado depende de un juicio
Elija los umbrales por clase de documento, no de forma global. Para lotes escaneados donde cada página lleva el mismo membrete, una distancia de hash de 2 a 3 con un error medio cercano a 2 fusiona el membrete de forma confiable. Para documentos donde las imágenes llevan datos — gráficos, mapas, imágenes médicas — use umbrales de cero o casi cero, o sáltese la pasada por completo, porque dos gráficos que difieren en un punto graficado son dos gráficos distintos sin importar cuán parecidos se vean a 64 por 64
Después de optimizar, verifique. Renderice una muestra de páginas antes y después y compárelas, y compruebe que la cantidad de páginas y de imágenes cambió como esperaba. La ruta de inspección de qué contiene realmente un documento se describe en auditar el tamaño de archivo PDF por categoría, que también es la forma más rápida de averiguar si las imágenes son su problema en primer lugar
La deduplicación perceptual, la deduplicación exacta de recursos y la auditoría de tamaño operan sobre el mismo grafo de objetos para Delphi, C++Builder y Free Pascal; la lista completa de funciones está en la página de PDF Library for Delphi