Um contrato digitalizado é uns poucos pontos por polegada de tinta preta em papel branco. Armazenado como um mapa de bits de um bit por pixel já é pequeno, mas mesmo assim cem páginas dessas inflam um PDF para além do que se enviaria por correio eletrónico. O filtro certo muda a aritmética. O JBIG2 é a compressão de maior rácio que a ISO 32000-1 define para imagens bilevel, e num conjunto de texto digitalizado reduz habitualmente para metade o que o CCITT Grupo 4 produz. Este é o filtro a utilizar quando a entrada é fax, digitalização ou de outra forma reduzida a duas cores, e o HotPDF pode escrevê-lo diretamente num PDF
O formato obtém o rácio com duas ideias que um codec de imagem genérico não tem. Modela como as manchas negras se encontram contra um fundo branco e nota que uma página digitalizada é composta sobretudo pelas mesmas poucas centenas de formas de glifo repetidas milhares de vezes. Compreender ambas é o que permite escolher as opções de codificação deliberadamente em vez de adivinhar
Onde o JBIG2 se situa na especificação PDF
A ISO 32000-1 lista JBIG2Decode entre os filtros de fluxo no §7.4.7, disponível a partir do PDF 1.4. Aplica-se a um único lugar: XObjects de imagem cujo /BitsPerComponent é 1 e cujo espaço de cores resolve para um único canal. Esse é todo o ponto. O JBIG2 é um codec bilevel, por isso nunca compete com DCT ou JPXDecode em fotografias. Compete com CCITTFaxDecode, os filtros de fax Grupo 3 e Grupo 4, exatamente no tipo de página a duas cores que um scanner de documentos produz
O descodificador consome a organização JBIG2 incorporada que a norma designa como perfil PDF, onde cada fluxo de imagem contém uma sequência de segmentos em vez de um bitstream puro. Um fluxo /JBIG2Globals opcional transporta segmentos partilhados por várias imagens no mesmo documento, que é o mecanismo que permite que conteúdo repetido seja armazenado uma única vez para todo o ficheiro em vez de uma vez por página. O HotPDF emite o fluxo por imagem por defeito e mantém o canal de globais livre a menos que um backend o solicite
A arquitetura de codificador centrada no backend
Um codificador JBIG2 completo é um software de grande dimensão, e as partes mais agressivas dele foram historicamente gravadas por patentes e distribuídas sob licenças que não se adequam a todos os produtos. O HotPDF resolve essa tensão separando a interface do motor. A unidade HPDFJBIG2 define as chamadas que o resto da biblioteca efetua, e inclui um codificador incorporado modesto para que o JBIG2 funcione imediatamente. Quando se precisam de rácios de nível de produção, regista-se um motor mais potente e a biblioteca delega-lhe, sem qualquer alteração no código de chamada
A mudança é uma única chamada de registo. Sem nenhum backend registado, o codificador recorre ao seu caminho incorporado. Registe um e cada codificação subsequente é executada através dele
uses
HPDFJBIG2;
// Query what is active, then optionally install a stronger engine.
if not IsJBIG2EncoderBackendAvailable then
// Production backend not present: HotPDF uses its built-in MMR path.
RegisterJBIG2EncoderBackend(MyVendorJBIG2Encode);
// Later, to return to the built-in behaviour:
// ClearJBIG2Backends;
O mesmo mecanismo existe para descodificação através de RegisterJBIG2DecoderBackend, com IsJBIG2DecoderBackendAvailable para verificá-lo. É por isso que uma biblioteca inclui um caminho incorporado pequeno mais uma articulação de backend em vez de um codificador monolítico. O caminho incorporado mantém o binário enxuto e livre de emaranhamentos de licença, enquanto a articulação permite que uma equipa que tenha licenciado um codificador completo o conecte sem tocar na camada de escrita de PDF
O que as opções de codificação efetivamente trocam
A codificação é configurada através de TJBIG2EncodeOptions, um registo com os campos Lossless, UseGlobalSegments, UseSymbolDictionary e LossyLevel. O wrapper compatível com componentes THPDFJBIG2Options publica Lossless, UseSymbolDictionary e LossyLevel para que possam ser definidos a partir do Inspetor de Objetos, e converte para o registo internamente. Três intenções orientam as definições
A reconstrução sem perdas mantém todos os píxeis. Defina Lossless como True e deixe LossyLevel em zero, e o mapa de bits descodificado é bit a bit idêntico à entrada. Esta é a única escolha segura para arte vetorial, desenhos técnicos e qualquer página onde um píxel perdido possa mudar o significado, como uma assinatura ou um carimbo. A codificação por dicionário de símbolos ativa a desduplicação com reconhecimento de texto e é a opção que separa o JBIG2 dos filtros de fax. O nível com perdas, um inteiro de 0 a 9, permite que um backend capaz troque fidelidade por tamanho ao tratar marcas quase idênticas como o mesmo símbolo. Zero significa sem perdas. O codificador incorporado honra apenas o caminho sem perdas e ignora qualquer nível com perdas diferente de zero, pelo que os níveis mais altos só têm efeito quando é registado um backend que os implementa
var
Options: TJBIG2EncodeOptions;
begin
Options := DefaultJBIG2EncodeOptions; // Lossless True, symbol dictionary on
Options.Lossless := True;
Options.LossyLevel := 0; // 0 keeps every pixel
Options.UseSymbolDictionary := True; // dedupe repeated glyphs
// Pass Options to a backend, or let THPDFJBIG2Options carry them.
end;
Dicionários de símbolos e por que as digitalizações de texto ganham
Uma página de texto digitalizado não é realmente uma imagem de palavras. É a mesma letra e impressa várias centenas de vezes, o mesmo t, a mesma vírgula, cada instância uma cópia ligeiramente ruidosa de uma forma subjacente. Um dicionário de símbolos captura essa estrutura. O codificador recolhe as marcas distintas da página num dicionário, armazena cada forma uma vez e depois regista a página como uma lista de posições que referenciam entradas do dicionário. Mil ocorrências do mesmo glifo custam um mapa de bits armazenado mais mil posicionamentos económicos
É precisamente aqui que o JBIG2 ultrapassa o CCITT Grupo 4. O Grupo 4 codifica cada linha de digitalização contra a linha acima sem qualquer noção de glifo, por isso paga o custo total de cada letra cada vez que a letra aparece. O JBIG2 paga uma vez. Quando o mesmo dicionário é promovido para o fluxo de globais ao nível do documento, a poupança acumula-se ao longo de uma digitalização de múltiplas páginas, porque as formas partilhadas de página a página são armazenadas uma única vez para todo o ficheiro. Em texto denso a diferença não é marginal. É a razão pela qual o JBIG2 existe
Região genérica e MMR para todo o resto
Nem toda a imagem bilevel é texto. Mapas, esquemas, desenhos de engenharia e páginas mistas têm arte vetorial que nenhum dicionário pode resumir. Para esses, o JBIG2 codifica uma região genérica, um retângulo de píxeis comprimido diretamente sem qualquer treino de símbolos. A norma permite que uma região genérica use MMR, a codificação READ modificada que o fax Grupo 4 já utiliza, que modela cada linha de píxeis contra a linha acima
Este é o caminho que o HotPDF inclui no seu codificador incorporado. Quando nenhum backend está registado e o pedido é sem perdas, a biblioteca comprime o mapa de bits como uma única região genérica MMR e envolve-a na estrutura de segmento JBIG2 que o perfil PDF requer. Não precisa de dicionário, de passagem de treino nem de segunda imagem para referência, pelo que é o padrão confiável para arte vetorial e conteúdo bilevel misto. Não corresponderá a um codificador de dicionário de símbolos completo em texto puro, mas é sempre correto, sempre sem perdas e sempre presente. A superfície do codificador para ele é uma chamada
var
Encoder: THPDFJBIG2Encoder;
ImageData: TJBIG2ByteArray;
Scanlines: TJBIG2ScanlineArray; // one byte array per row, MSB-first
W, H: Integer;
begin
// Scanlines, W and H describe a 1-bit page; each row is (W + 7) div 8 bytes.
Encoder := THPDFJBIG2Encoder.Create;
try
if Encoder.EncodeToByteArray(Scanlines, W, H, ImageData) then
// ImageData now holds a JBIG2 stream ready for a /JBIG2Decode XObject.
;
finally
Encoder.Free;
end;
end;
Ativá-lo ao construir um documento
Para uso quotidiano não se toca na classe de codificador diretamente. O HotPDF expõe o JBIG2 como uma escolha de compressão de imagem no documento. A enumeração THPDFImageCompressionType inclui icJBIG2 ao lado das opções Flate, JPEG e CCITT, e o documento tem uma propriedade JBIG2Options do tipo THPDFJBIG2Options que contém as definições usadas quando essa compressão é selecionada. Configure ambas antes de adicionar as imagens bilevel a comprimir desta forma
var
Pdf: THotPDF;
begin
Pdf := THotPDF.Create(nil);
try
Pdf.ImageCompressionType := icJBIG2; // route 1-bit images through JBIG2
Pdf.JBIG2Options.Lossless := True; // keep every pixel
Pdf.JBIG2Options.UseSymbolDictionary := True;
Pdf.JBIG2Options.LossyLevel := 0;
// Add pages and place your scanned 1-bit images here.
finally
Pdf.Free;
end;
end;
Uma conveniência que vale a pena referir é o add-on DBGridHotPDFExport, que renderiza um TDBGrid diretamente para um PDF. A sua saída é em grande parte linhas bilevel e texto, por isso um documento configurado para JBIG2 mantém essas exportações compactas sem qualquer tratamento adicional da sua parte. Dois tópicos relacionados neste blogue aprofundam o fluxo de trabalho envolvente. Para saber como imagens e fontes são dispostas ao criar relatórios, consulte saída de relatório com fontes e imagens em Delphi. Quando um documento comprimido tem de satisfazer um perfil de arquivo, as regras em validação PDF/A, PDF/X e PDF/UA em Delphi indicam que filtros um dado nível de conformidade aceita. O JBIG2 é fornecido como parte do Componente HotPDF para Delphi e C++Builder, a par das APIs de carregamento, edição e encriptação descritas neste blogue