Un contrato escaneado equivale a unos pocos cientos de puntos por pulgada de tinta negra sobre papel blanco. Almacenado como un mapa de bits de un bit por píxel ya es pequeño, sin embargo, cien de esas páginas aún inflan un PDF más allá de lo que enviaría por correo electrónico. El filtro adecuado cambia la aritmética. JBIG2 es la compresión de mayor proporción que ISO 32000-1 define para imágenes bitonales, y en una pila de texto escaneado, rutinariamente reduce a la mitad lo que produce CCITT Group 4. Este es el filtro que debe buscar cuando la entrada se envía por fax, se escanea o se reduce de otro modo a dos colores, y HotPDF puede escribirlo directamente en un PDF
El formato logra esta proporción con dos ideas que un códec de imágenes genérico no tiene. Modela cómo se ubican las secuencias de negro sobre un fondo blanco, y observa que una página escaneada es en su mayoría las mismas cientos de formas de glifos repetidas miles de veces. Comprender ambos aspectos es lo que le permite elegir las opciones de codificación de manera deliberada en lugar de adivinar
Dónde se ubica JBIG2 en la especificación PDF
La norma ISO 32000-1 enumera JBIG2Decode entre los filtros de flujo en la sección 7.4.7, disponible desde PDF 1.4 en adelante. Se aplica solo a un lugar: image XObjects cuyo /BitsPerComponent es 1 y cuyo espacio de color se resuelve en un solo canal. Ese es todo el punto. JBIG2 es un códec bitonal, por lo que nunca compite con DCT o JPXDecode en fotografías. Compite con CCITTFaxDecode, los filtros de fax Group 3 y Group 4, exactamente en el tipo de página de dos tonos que produce un escáner de documentos
El decodificador consume la organización JBIG2 incorporada que el estándar llama el perfil PDF, donde cada flujo de imagen contiene una secuencia de segmentos en lugar de un flujo de bits simple. Un flujo opcional /JBIG2Globals transporta segmentos compartidos en varias imágenes en el mismo documento, que es el mecanismo que permite que el contenido repetido se almacene una vez para un archivo completo en lugar de una vez por página. HotPDF emite el flujo por imagen de forma predeterminada y mantiene libre el canal de globales a menos que un backend lo solicite
La arquitectura de codificación basada primero en el backend
Un codificador JBIG2 completo es una gran pieza de software, y las partes más agresivas históricamente han estado limitadas por patentes y se han distribuido bajo licencias que no se adaptan a todos los productos. HotPDF resuelve esa tensión separando la interfaz del motor. La unidad HPDFJBIG2 define las llamadas que realiza el resto de la biblioteca e incluye un modesto codificador integrado para que JBIG2 funcione de inmediato. Cuando necesite proporciones de nivel de producción, registra un motor más sólido y la biblioteca se lo delega, sin realizar ningún cambio en su código de llamada
El cambio requiere una sola llamada de registro. Sin ningún backend registrado, el codificador recurre a su ruta integrada. Registre uno y cada codificación posterior se ejecutará a través de él
uses
HPDFJBIG2;
// Consultar lo que está activo, luego opcionalmente instalar un motor más sólido.
if not IsJBIG2EncoderBackendAvailable then
// Backend de producción no presente: HotPDF usa su ruta MMR integrada.
RegisterJBIG2EncoderBackend(MyVendorJBIG2Encode);
// Más tarde, para volver al comportamiento integrado:
// ClearJBIG2Backends;
El mismo enlace existe para la decodificación a través de RegisterJBIG2DecoderBackend, con IsJBIG2DecoderBackendAvailable para comprobarlo. Esta es la razón por la que una biblioteca se envía con una pequeña ruta integrada más un punto de conexión de backend (backend seam) en lugar de un codificador monolítico. La ruta integrada mantiene el binario ligero y libre de enredos de licencias, mientras que el punto de conexión permite que un equipo que ha obtenido la licencia de un codificador completo lo conecte sin tocar la capa de escritura de PDF en absoluto
Lo que realmente intercambian las opciones de codificación
La codificación se configura a través de TJBIG2EncodeOptions, un registro con los campos Lossless, UseGlobalSegments, UseSymbolDictionary y LossyLevel. El envoltorio amigable para el componente, THPDFJBIG2Options, publica Lossless, UseSymbolDictionary y LossyLevel para que se puedan configurar desde el Inspector de Objetos (Object Inspector), y los convierte al registro internamente. Tres intenciones impulsan la configuración
La reconstrucción sin pérdidas (lossless) conserva todos los píxeles. Establezca Lossless en True y deje LossyLevel en cero, y el mapa de bits decodificado será idéntico bit por bit a la entrada. Esta es la única opción segura para el arte lineal (line art), dibujos técnicos y cualquier página en la que un píxel omitido podría cambiar el significado, como una firma o un sello. La codificación con diccionario de símbolos activa la deduplicación consciente del texto y es la opción que separa JBIG2 de los filtros de fax. El nivel con pérdida (lossy level), un número entero de 0 a 9, permite que un backend capaz cambie fidelidad por tamaño al tratar marcas casi idénticas como el mismo símbolo. Cero significa sin pérdidas. El codificador integrado respeta solo la ruta sin pérdidas e ignora cualquier nivel con pérdida distinto de cero, por lo que los niveles más altos surten efecto solo una vez que se registra un backend que los implemente
var
Options: TJBIG2EncodeOptions;
begin
Options := DefaultJBIG2EncodeOptions; // Lossless True, diccionario de símbolos activado
Options.Lossless := True;
Options.LossyLevel := 0; // 0 conserva todos los píxeles
Options.UseSymbolDictionary := True; // deduplicar glifos repetidos
// Pasar Options a un backend, o dejar que THPDFJBIG2Options las transporte.
end;
Los diccionarios de símbolos y por qué triunfan los escaneos de texto
Una página de texto escaneado no es realmente una imagen de palabras. Es la misma letra e impresa varios cientos de veces, la misma t, la misma coma, cada instancia siendo una copia ligeramente ruidosa de una forma subyacente. Un diccionario de símbolos captura esa estructura. El codificador recopila las marcas distintas de la página en un diccionario, almacena cada forma una vez y luego registra la página como una lista de posiciones que hacen referencia a entradas del diccionario. Mil apariciones del mismo glifo cuestan un mapa de bits almacenado más mil ubicaciones económicas
Aquí es precisamente donde JBIG2 supera a CCITT Group 4. Group 4 codifica cada línea de escaneo frente a la línea de arriba sin noción de un glifo, por lo que paga el costo total de cada letra cada vez que aparece. JBIG2 paga una vez. Cuando el mismo diccionario asciende al flujo de globales a nivel de documento, el ahorro se acumula en un escaneo de varias páginas, porque las formas que comparten página tras página se almacenan una sola vez para todo el archivo. En texto denso, la diferencia no es marginal. Es la razón por la que existe JBIG2
Región genérica y MMR para todo lo demás
No todas las imágenes bitonales son texto. Los mapas, diagramas, planos de ingeniería y páginas mixtas tienen arte lineal que ningún diccionario puede resumir. Para ellos, JBIG2 codifica una región genérica (generic region), un rectángulo de píxeles comprimidos directamente sin ningún entrenamiento de símbolos. El estándar permite que una región genérica use MMR, la codificación READ modificada y modificada (modified modified READ) que ya utiliza el fax Group 4, que modela cada fila de píxeles en relación con la fila superior
Esta es la ruta que HotPDF incluye en su codificador integrado. Cuando no hay ningún backend registrado y la solicitud no tiene pérdidas, la biblioteca comprime el mapa de bits como una única región genérica MMR y lo envuelve en la estructura de segmentos JBIG2 que requiere el perfil PDF. No necesita ningún diccionario, ningún pase de entrenamiento ni una segunda imagen a la que hacer referencia, por lo que es la opción predeterminada confiable para arte lineal y contenido bitonal mixto. No igualará a un codificador completo con diccionario de símbolos en texto puro, pero siempre es correcto, siempre es sin pérdidas y siempre está presente. La superficie del codificador para ello requiere una sola llamada
var
Encoder: THPDFJBIG2Encoder;
ImageData: TJBIG2ByteArray;
Scanlines: TJBIG2ScanlineArray; // un arreglo de bytes por fila, MSB primero
W, H: Integer;
begin
// Scanlines, W y H describen una página de 1 bit; cada fila es (W + 7) div 8 bytes.
Encoder := THPDFJBIG2Encoder.Create;
try
if Encoder.EncodeToByteArray(Scanlines, W, H, ImageData) then
// ImageData ahora contiene un flujo JBIG2 listo para un XObject /JBIG2Decode.
;
finally
Encoder.Free;
end;
end;
Cómo activarlo al compilar un documento
Para el uso diario, no se toca la clase del codificador directamente. HotPDF expone JBIG2 como una opción de compresión de imágenes en el documento. La enumeración THPDFImageCompressionType incluye icJBIG2 junto a las opciones Flate, JPEG y CCITT, y el documento lleva una propiedad JBIG2Options de tipo THPDFJBIG2Options que contiene la configuración utilizada cuando se selecciona esa compresión. Configure ambos antes de agregar las imágenes bitonales que desea comprimir de esta manera
var
Pdf: THotPDF;
begin
Pdf := THotPDF.Create(nil);
try
Pdf.ImageCompressionType := icJBIG2; // enrutar imágenes de 1 bit a través de JBIG2
Pdf.JBIG2Options.Lossless := True; // conservar todos los píxeles
Pdf.JBIG2Options.UseSymbolDictionary := True;
Pdf.JBIG2Options.LossyLevel := 0;
// Agregue páginas y coloque sus imágenes de 1 bit escaneadas aquí.
finally
Pdf.Free;
end;
end;
Una comodidad que vale la pena mencionar es el complemento DBGridHotPDFExport, que renderiza un TDBGrid directamente a un PDF. Su salida está conformada en gran parte por líneas bitonales y texto, por lo que un documento configurado para JBIG2 mantiene esas exportaciones compactas sin ningún manejo adicional por su parte. Dos temas relacionados en este blog profundizan en el flujo de trabajo que lo rodea. Para saber cómo se establecen las imágenes y fuentes al crear informes, consulte la salida de informes con fuentes e imágenes en Delphi. Cuando un documento comprimido debe satisfacer un perfil de archivo, las reglas en la validación de PDF/A, PDF/X y PDF/UA en Delphi indican qué filtros acepta un nivel de conformidad dado. JBIG2 se incluye como parte del Componente HotPDF para Delphi y C++Builder, junto a las API de carga, edición y cifrado que se tratan en otras partes de este sitio