Artículo técnico

Incrustar imágenes AVIF, HEIF y JPEG XL en PDF desde Delphi

PDF Library for Delphi acepta imágenes AVIF, HEIF y JPEG XL como entrada mediante AddModernImageFromFile y sus variantes de flujo y cadena, preservando el alfa, el perfil ICC incrustado y los canales de 16 bits en su camino hacia el objeto de imagen del PDF. La detección de formato ocurre sobre una lectura acotada de número mágico, y la decodificación pasa por un backend reemplazable, así que no se invoca nada externo para un archivo que en realidad no es ninguno de esos formatos

Estos formatos llegaron a los flujos de trabajo de documentos a través de los teléfonos. iOS ha producido HEIC de forma predeterminada durante años, los dispositivos Android producen AVIF, y un técnico de campo que fotografía una pieza dañada envía una imagen que un generador de informes PDF construido en 2015 no puede abrir en absoluto. La ruta de respaldo genérica, decodificar a través de un mapa de bits de plataforma, produce de forma confiable color de 8 bits y pierde el alfa y el perfil de color en el camino

¿Qué conserva la ruta de imagen moderna que una conversión a mapa de bits pierde?

Tres cosas, y cada una tiene un flujo de trabajo que depende de ella. El alfa sobrevive, lo cual importa para logotipos y recortes de producto compuestos sobre el contenido de la página. El perfil ICC sobrevive, lo cual importa para cualquier cosa que vaya a imprimirse o a igualarse en color. Y los canales de 16 bits sobreviven, lo cual importa para imágenes médicas y científicas donde la cuantización de 8 bits destruye precisamente las gradaciones para las que se capturó la imagen

Pasar una imagen por un mapa de bits de plataforma pierde las tres cosas en un solo paso, y lo hace en silencio: el PDF resultante se ve aproximadamente correcto, y nadie lo nota hasta que una imprenta pregunta por qué el rojo corporativo está mal. El valor de opción 8 en las llamadas de imagen moderna es el indicador que mantiene juntos el alfa, el ICC y los canales de 16 bits, y es el predeterminado para esas llamadas

Agregar una a una página

La llamada devuelve un identificador de imagen, que luego se selecciona y se dibuja, o se dibuja y se libera en un solo paso:

uses
  PDFlibrary, PDFlibModernImage;

var
  Lib: TPDFlib;
  ImageID: Integer;
begin
  Lib := TPDFlib.Create;
  try
    Lib.NewDocument;
    Lib.SetPageSize('A4');
    Lib.NewPage;

    // Options = 8 mantiene el alfa, el ICC y los canales 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;

La detección precede a la decodificación y es deliberadamente estrecha. La biblioteca lee un encabezado acotado, reconoce las marcas del formato de archivo de medios base ISO que identifican AVIF y HEIF, y reconoce tanto las firmas sin procesar como las de contenedor de JPEG XL, y luego restaura la posición del flujo de quien llama. Una entrada desconocida o disfrazada nunca llega al códec externo, lo que evita que un ejecutable renombrado se entregue a un decodificador como si fuera una imagen

¿Dónde ocurre realmente la decodificación?

Los formatos de imagen modernos son códecs grandes y complejos, y poner uno dentro de una biblioteca PDF sería una decisión de diseño extraña. El backend predeterminado carga dinámicamente un módulo MagickWand desplegable dentro del proceso y lo busca en un orden documentado: un archivo o directorio explícito que configures, variables de entorno, el directorio del ejecutable y la ruta de búsqueda del sistema

Las aplicaciones que ya distribuyen un decodificador, o que no deben cargar ningún módulo externo en absoluto, registran su propia retrollamada en su lugar. El contrato es pequeño: leer el flujo de entrada, escribir un PNG en el flujo de salida, respetar la orientación solicitada:

function MyDecoder(InStream, OutPNG: TStream;
  ImageFormat: TPDFlibModernImageFormat;
  ApplyOrientation: Boolean): Boolean;
begin
  // Decodifica InStream con tu propio códec y escribe los bytes PNG en OutPNG
  Result := DecodeWithBundledCodec(InStream, OutPNG,
    ImageFormat, ApplyOrientation);
end;

begin
  RegisterModernImageDecoderBackend(MyDecoder);
  // ... agregar imágenes ...
  ClearModernImageDecoderBackend;    // volver al backend predeterminado
end;

El despliegue obtiene una comodidad y una contención deliberada. Si el directorio del códec contiene un subdirectorio modules\coders, la biblioteca completa las variables de entorno del códec que necesita ese diseño, pero solo cuando la aplicación anfitriona todavía no las configuró. Una aplicación con su propia estrategia de despliegue de tiempo de ejecución la conserva

¿Por qué PNG en el medio?

Puentear a través de un PNG en memoria en lugar de un búfer de píxeles sin procesar parece un paso adicional y en realidad es el paso correcto más económico. PNG expresa todo lo que tiene que sobrevivir, alfa, tipo de color, profundidad de bits y un perfil ICC incrustado, y la biblioteca ya tiene una ruta madura y bien probada de PNG hacia un objeto de imagen PDF con los filtros y el espacio de color correctos. Reutilizarla significa que los formatos modernos heredan años de trabajo de corrección en lugar de obtener una implementación paralela

El puente está enteramente en memoria, así que no se crean archivos temporales y no se necesita limpieza ante un fallo. Un detalle necesitó manejo explícito: algunas conversiones descartan el perfil ICC al cambiar de formato. El backend, por lo tanto, captura el perfil de origen antes del cambio de formato, lo comprime con Flate, construye un fragmento iCCP válido con un CRC recalculado, y elimina cualquier fragmento sRGB que entraría en conflicto con él. En pruebas, un AVIF decodificado conservó RGBA de 16 bits con alfa de 16 bits, y el perfil extraído del PDF resultante coincidió byte por byte con el perfil de origen en 60.960 bytes

Notas prácticas antes de activarlo en producción

Verifica la disponibilidad al inicio y no en la primera fotografía. ModernImageCodecAvailable reporta si se puede usar un backend, y SetModernImageCodecLibrary apunta a un archivo o directorio explícito cuando tu despliegue coloca el códec en un lugar no estándar:

Lib.SetModernImageCodecLibrary('C:\MyApp\codecs');
if Lib.ModernImageCodecAvailable = 0 then
  Log('modern image input unavailable - HEIC and AVIF will be refused');

Vigila el tamaño de archivo del resultado. Una imagen RGBA de 16 bits con un perfil incrustado es un objeto de imagen PDF grande, y un informe con cuarenta de ellas será voluminoso. Cuando el documento está destinado a visualización en pantalla en lugar de impresión, submuestrear antes de incrustar es el trade-off correcto, y las palancas generales de tamaño se cubren en optimización del tamaño de archivo PDF

Por último, decide la política de color de forma deliberada. Conservar el perfil de origen es correcto para trabajo de archivo e impresión; convertir a un espacio a nivel de documento es correcto cuando un conjunto mixto de fotografías debe verse consistente, y la ruta de conversión se describe en recolorear un documento a otro espacio de color. Si necesitas confirmar qué realmente terminó en el archivo, la ruta de inspección en extracción de texto, imagen y fuente reporta los objetos de imagen que lleva un documento

La entrada de imágenes modernas, la gestión de color y la optimización de imágenes forman parte de la misma biblioteca para Delphi, C++Builder y Free Pascal; la lista completa de funciones está en la página de PDF Library for Delphi