Artículo técnico

Máscaras suaves y aplanado de transparencia en Delphi

PDF Library for Delphi crea desde Delphi los dos tipos de máscara suave de PDF. SetImageSoftMaskEx vincula una imagen de máscara a una imagen de destino y puede escribir la entrada /Matte que necesita el arte premultiplicado. NewSoftMaskGraphicsState construye una máscara de alfa o de luminosidad a partir de contenido capturado y devuelve un estado gráfico que aplicas al dibujo posterior. Y cuando un consumidor no puede manejar transparencia en absoluto, FlattenTransparency renderiza el resultado visual y sustituye cada página por él

Las máscaras suaves son la forma en que PDF expresa un desvanecido en degradado, una viñeta, una foto fundida sobre un fondo, y cualquier otro efecto donde la opacidad varía a través de una región. La transparencia constante es un único número en el estado gráfico; una máscara suave es toda una función de la posición, y hasta que puedas crear una, toda una categoría de diseño no se puede reproducir

Los dos tipos de máscara, y qué lee cada uno

Una máscara de alfa toma sus valores del canal alfa del contenido enmascarante. Una máscara de luminosidad los toma del brillo del contenido enmascarante, de modo que un área blanca es totalmente opaca y un área negra totalmente transparente. La luminosidad es la que eligen los diseñadores, porque pintar un degradado en escala de grises es una forma natural de describir un desvanecido

Las máscaras suaves de tipo Form se construyen a partir de contenido capturado, y varios detalles son fijos y no opcionales. El contenido capturado se convierte en un grupo de transparencia aislado en DeviceRGB, de modo que la máscara se evalúa en un espacio de color conocido. El color de fondo debe por tanto tener tres componentes, en concordancia con ese grupo. La función de transferencia acepta /Identity o un objeto de función válido, lo que te permite remodelar la curva de la máscara sin repintar el arte

Diagrama que compara las máscaras suaves de luminosidad y alfa alimentando NewSoftMaskGraphicsState, con un recordatorio de que el estado gráfico persiste hasta que se borra
Las máscaras de luminosidad leen el brillo mientras que las máscaras de alfa leen la cobertura, y NewSoftMaskGraphicsState envuelve cualquiera de las dos en un estado gráfico persistente
uses
  PDFlibrary;

var
  Lib: TPDFlib;
  MaskCapture, MaskGS, PhotoID: Integer;
begin
  Lib := TPDFlib.Create;
  try
    Lib.LoadFromFile('brochure.pdf', '');

    // La página 4 lleva un degradado en escala de grises pintado para usarse como máscara
    MaskCapture := Lib.CapturePage(4);

    MaskGS := Lib.NewSoftMaskGraphicsState(MaskCapture,
      PDF_SOFT_MASK_LUMINOSITY, '0 0 0', '/Identity');

    Lib.SelectPage(1);
    Lib.SetGraphicsState(MaskGS);
    PhotoID := Lib.AddImageFromFile('hero.jpg', 0);
    Lib.SelectImage(PhotoID);
    Lib.DrawImage(40, 700, 515, 260);        // se desvanece bajo la máscara

    // Los ajustes de ExtGState persisten: cierra el ámbito explícitamente
    Lib.SetGraphicsState(Lib.NewSoftMaskGraphicsState(0,
      PDF_SOFT_MASK_NONE, '', ''));

    Lib.SaveToFile('brochure-masked.pdf');
  finally
    Lib.Free;
  end;
end;

Ese último paso no es decoración. Los parámetros de estado gráfico persisten hasta que se cambian, y aplicar un estado gráfico ordinario después no borra una máscara suave activa. Sin un /SMask /None explícito, todo lo que se dibuje después del arte enmascarado hereda la máscara, uno de los errores más desconcertantes de diagnosticar visualmente

Máscaras de imagen y la entrada Matte

Para el enmascarado a nivel de imagen, la imagen de máscara se normaliza primero a DeviceGray, de modo que una máscara suministrada en cualquier espacio de color se comporte de forma predecible. La entrada opcional /Matte, de uno a cuatro componentes según el espacio de color de la imagen, le dice a un consumidor que los datos de la imagen están premultiplicados contra ese color, lo cual evita el halo oscuro que aparece cuando un arte premultiplicado se compone como si fuera alfa directo

Diagrama que muestra cómo la ausencia de una entrada Matte produce halos oscuros, mientras que un Matte declarado compone con limpieza, junto a las salvaguardas de PDF 1.4, PDF/A y PDF/X
Un /Matte declarado evita el halo oscuro del arte premultiplicado, mientras que los archivos PDF/A-1 y PDF/X-1 se rechazan antes de cambiar ningún objeto

Aquí importan dos salvaguardas. PDF/A-1 y PDF/X-1 prohíben la transparencia, y la llamada se rechaza antes de modificar cualquier objeto, en lugar de producir un archivo que falle la validación más tarde. Y una máscara suave exitosa requiere PDF 1.4, que la biblioteca establece automáticamente — la transparencia no existía antes de esa versión, y una cabecera 1.3 en un archivo que contiene máscaras suaves es sencillamente falsa

Los estados repetidos se reutilizan: el mismo formulario capturado, tipo de máscara, fondo y firma de función de transferencia producen el mismo objeto de estado gráfico en lugar de uno nuevo por llamada. En un documento que enmascara cien imágenes de forma idéntica, eso son noventa y nueve objetos que nunca llegan a escribirse

Por qué aplanar, y qué hace realmente el aplanado

La transparencia sigue siendo la fuente más común de «se ve bien en pantalla y mal en la imprenta». Los RIP más antiguos, algunos sistemas de presentación regulatoria y PDF/X-1a exigen todos un archivo sin ninguna transparencia activa

El aplanado aquí es deliberadamente literal: cada página del rango solicitado se renderiza a un DPI elegido contra un fondo opaco, y el contenido y los recursos de la página se sustituyen por esa única imagen. Como el renderizador produce el resultado compuesto final, esto cubre todo a la vez — grupos de transparencia, modos de fusión, máscaras suaves, patrones y formularios anidados — sin ninguna lógica de aproximación por construcción que pueda salir mal. La memoria de rasterizado pico se mantiene acotada a una página

Diagrama de pipeline de FlattenTransparency renderizando cada página solicitada a 300 DPI sobre un fondo opaco y guardando un archivo PDF 1.3 plano listo para imprenta
Cada página solicitada se renderiza una vez al DPI elegido y vuelve como una única imagen opaca guardada en un archivo PDF 1.3 veraz
// Aplana las páginas 1-8 a 300 DPI sobre blanco, y guarda como PDF 1.3
Lib.FlattenTransparency('1-8', 300, $FFFFFF, 0);
Lib.SaveToFile('press-ready.pdf');

El coste es igual de literal: la salida es una imagen, así que el texto deja de ser seleccionable o buscable y los bordes vectoriales se remuestrean al DPI elegido. Aplanar es un paso de entrega, no un paso de edición. Conserva el original transparente y aplana una copia

Páginas rotadas, unidades de usuario y las cajas de página

Una página rotada necesita un cuidado que una implementación ingenua se salta. Tras renderizar, el ancho y el alto visuales se escriben de vuelta en el MediaBox, la unidad de usuario se pliega en el DPI efectivo y el nuevo tamaño de página, y la entrada /Rotate, la unidad de usuario y las cajas de página auxiliares se eliminan

Saltarse eso produce un archivo donde la imagen aplanada es correcta pero un visor la vuelve a rotar, o la escala por una unidad de usuario que ya no aplica. Eliminar las cajas en lugar de recalcularlas es la decisión correcta, porque un TrimBox que describe la geometría previa al aplanado es peor que no tener TrimBox en absoluto

Las anotaciones y los campos de formulario se renderizan en la imagen estática por defecto y se eliminan los objetos interactivos, que es lo que quiere un entregable listo para imprenta. Si conservas los objetos interactivos en su lugar, el paso de anotaciones del renderizador se desactiva para que nada se dibuje dos veces

La comprobación de versión que examina todo

Guardar como PDF 1.3 exige que no quede transparencia en ninguna parte, y la comprobación previa al guardado examina cada objeto indirecto, no solo los alcanzables desde las páginas. Eso es más estricto de lo que parece a primera vista y es correcto: una máscara suave huérfana dejada atrás por una edición anterior sigue estando en el archivo, y un consumidor que recorra objetos en lugar de páginas la encontrará

Para que la degradación de versión sea posible, un paso de marcado y barrido se ejecuta por defecto una vez que cada página objetivo se ha sustituido con éxito, liberando los objetos inalcanzables. La consecuencia a tener en cuenta es que los identificadores de imagen, página capturada y estado gráfico obtenidos antes de ese barrido pueden dejar de ser válidos después. Vuelve a obtener los identificadores de recurso que necesites antes de seguir editando, o desactiva el barrido y acepta que la versión entonces no se podrá rebajar

Dos complementos completan el panorama. El arte vectorial que usa sombreados y degradados en lugar de máscaras se trata en gráficos vectoriales, shaders y degradados, y a menudo es la mejor ruta cuando el efecto se puede expresar como un sombreado. Y si la razón por la que estás aplanando es un requisito de color y no de transparencia, la ruta de conversión de recolorear un documento a otro espacio de color conserva el texto activo donde el aplanado no lo haría

La creación de máscaras suaves, el aplanado y el motor de renderizado que hay detrás se distribuyen en una única biblioteca para Delphi, C++Builder y Free Pascal; la lista completa de funciones está en la página de PDF Library for Delphi