A PDF Library for Delphi aceita imagens AVIF, HEIF e JPEG XL como entrada através de AddModernImageFromFile e das suas variantes de fluxo e de string, preservando o alfa, o perfil ICC incorporado e os canais de 16 bits no caminho para dentro do objeto de imagem PDF. A deteção de formato acontece sobre uma leitura limitada de número mágico, e a descodificação corre através de um backend substituível, pelo que nada externo é invocado para um ficheiro que não seja realmente um desses formatos
Estes formatos chegaram aos fluxos de trabalho de documentos através dos telemóveis. O iOS produz HEIC por defeito há anos, os dispositivos Android produzem AVIF, e um técnico de campo que fotografa uma peça danificada envia uma imagem que um gerador de relatórios PDF construído em 2015 simplesmente não consegue abrir. O caminho de recurso genérico, descodificar através de um bitmap da plataforma, produz de forma consistente cor de 8 bits e perde o alfa e o perfil de cor pelo caminho
O que é que o caminho de imagem moderna preserva que uma conversão para bitmap perde?
Três coisas, e cada uma tem um fluxo de trabalho que depende dela. O alfa sobrevive, o que importa para logótipos e recortes de produto compostos sobre o conteúdo da página. O perfil ICC sobrevive, o que importa para tudo o que vá ser impresso ou correspondido em cor. E os canais de 16 bits sobrevivem, o que importa para imagens médicas e científicas onde a quantização a 8 bits destrói exatamente as gradações para as quais a imagem foi captada
Passar uma imagem por um bitmap da plataforma perde as três coisas num único passo, e fá-lo silenciosamente: o PDF resultante parece aproximadamente correto, e ninguém repara até uma gráfica perguntar por que razão o vermelho corporativo está errado. O valor de opção 8 nas chamadas de imagem moderna é o sinalizador que mantém o alfa, o ICC e os canais de 16 bits em conjunto, e é a predefinição para essas chamadas
Acrescentar uma imagem a uma página
A chamada devolve um identificador de imagem, que é depois selecionado e desenhado, ou desenhado e libertado num único passo:
uses
PDFlibrary, PDFlibModernImage;
var
Lib: TPDFlib;
ImageID: Integer;
begin
Lib := TPDFlib.Create;
try
Lib.NewDocument;
Lib.SetPageSize('A4');
Lib.NewPage;
// Options = 8 mantém o alfa, o ICC e os canais de 16 bits
ImageID := Lib.AddModernImageFromFile('site-photo.heic', 8);
if ImageID > 0 then
Lib.DrawImageAndRelease(ImageID, 40, 40, 515, 340)
else
Lib.DrawText(40, 40, 'image could not be decoded');
Lib.SaveToFile('inspection-report.pdf');
finally
Lib.Free;
end;
end;
A deteção antecede a descodificação e é deliberadamente restrita. A biblioteca lê um cabeçalho limitado, reconhece as marcas de formato de ficheiro multimédia base ISO que identificam o AVIF e o HEIF, e reconhece tanto as assinaturas em bruto como as de contentor do JPEG XL, e depois restaura a posição de fluxo do chamador. Uma entrada desconhecida ou disfarçada nunca chega ao codec externo, o que impede que um executável renomeado seja entregue a um descodificador como se fosse uma fotografia
Onde é que a descodificação realmente acontece?
Os formatos de imagem modernos são codecs grandes e complexos, e colocar um deles dentro de uma biblioteca PDF seria uma escolha de design estranha. O backend predefinido carrega dinamicamente um módulo MagickWand implantável no mesmo processo e procura-o por uma ordem documentada: um ficheiro ou diretório explícito definido pelo utilizador, variáveis de ambiente, o diretório do executável, e o caminho de pesquisa do sistema
As aplicações que já incluem um descodificador, ou que não podem de todo carregar um módulo externo, registam em alternativa o seu próprio callback. O contrato é pequeno: ler o fluxo de entrada, escrever um PNG no fluxo de saída, respeitar a orientação pedida:
function MyDecoder(InStream, OutPNG: TStream;
ImageFormat: TPDFlibModernImageFormat;
ApplyOrientation: Boolean): Boolean;
begin
// Descodifique InStream com o seu próprio codec e escreva bytes PNG em OutPNG
Result := DecodeWithBundledCodec(InStream, OutPNG,
ImageFormat, ApplyOrientation);
end;
begin
RegisterModernImageDecoderBackend(MyDecoder);
// ... acrescentar imagens ...
ClearModernImageDecoderBackend; // voltar ao backend predefinido
end;
A implantação recebe uma conveniência e uma contenção deliberada. Se o diretório do codec contiver um subdiretório modules\coders, a biblioteca preenche as variáveis de ambiente de codec que esse esquema exige, mas apenas quando a aplicação anfitriã ainda não as definiu. Uma aplicação com a sua própria estratégia de implantação de runtime mantém-na
Por que razão PNG no meio?
Fazer a ponte através de um PNG em memória em vez de um buffer de pixels em bruto parece um passo extra e é, na verdade, o passo correto mais económico. O PNG exprime tudo o que tem de sobreviver, alfa, tipo de cor, profundidade de bits e um perfil ICC incorporado, e a biblioteca já tem um caminho maduro e bem testado de PNG para um objeto de imagem PDF com os filtros e o espaço de cor corretos. Reutilizá-lo significa que os formatos modernos herdam anos de trabalho de correção em vez de receberem uma implementação paralela
A ponte fica inteiramente em memória, pelo que não são criados ficheiros temporários e não é preciso nenhuma limpeza numa falha. Uma particularidade exigiu tratamento explícito: algumas conversões descartam o perfil ICC ao mudar de formato. O backend captura, por isso, o perfil de origem antes da mudança de formato, comprime-o com Flate, constrói um bloco iCCP válido com um CRC recalculado, e remove qualquer bloco sRGB que entrasse em conflito com ele. Em testes, um AVIF descodificado manteve RGBA de 16 bits com alfa de 16 bits, e o perfil extraído do PDF resultante correspondeu ao perfil de origem byte a byte, com 60 960 bytes
Notas práticas antes de ativar isto em produção
Verifique a disponibilidade no arranque, não na primeira fotografia. ModernImageCodecAvailable reporta se um backend pode ser usado, e SetModernImageCodecLibrary aponta para um ficheiro ou diretório explícito quando a implantação coloca o codec algures fora do padrão:
Lib.SetModernImageCodecLibrary('C:\MyApp\codecs');
if Lib.ModernImageCodecAvailable = 0 then
Log('modern image input unavailable - HEIC and AVIF will be refused');
Fique atento ao tamanho do ficheiro do resultado. Uma imagem RGBA de 16 bits com um perfil incorporado é um objeto de imagem PDF grande, e um relatório com quarenta destas será grande. Quando o documento se destina a visualização em ecrã e não a impressão, reduzir a resolução antes de incorporar é a opção certa, e as alavancas gerais de tamanho estão descritas em otimização do tamanho de ficheiro PDF
Por fim, decida a política de cor deliberadamente. Manter o perfil de origem é correto para trabalho de arquivo e de impressão; converter para um espaço à escala do documento é correto quando um conjunto misto de fotografias tem de parecer consistente, e o percurso de conversão está descrito em recolorir um documento para outro espaço de cor. Se precisar de confirmar o que realmente ficou no ficheiro, o percurso de inspeção em extração de texto, imagem e fonte reporta os objetos de imagem que um documento transporta
A entrada de imagem moderna, a gestão de cor e a otimização de imagem fazem parte da mesma biblioteca para Delphi, C++Builder e Free Pascal; a lista completa de funcionalidades está na página da PDF Library for Delphi