Artículo técnico

Renderización de degradados PDF en Delphi: axial y radial

Un PDF cuyo encabezado tiene un fondo degradado al estilo de Word o Excel, renderizado a una imagen, solía mostrar un rectángulo blanco en blanco donde debería estar la mezcla de colores. El renderizador de páginas de HotPDF ahora respeta el operador de PDF sh (sombreado) para degradados axiales de Tipo 2 y radiales de Tipo 3: evalúa la función de sombreado a lo largo del eje del degradado y pinta la mezcla, mientras que las versiones anteriores omitían silenciosamente el operador y dejaban la región blanca como el papel. Se incluyen los dos tipos de sombreado que cubren casi todos los degradados de documentos de oficina; los tipos de malla (mesh) no, y este artículo es honesto sobre dónde se encuentra ese límite

Un degradado PDF es una estructura vectorial, no un mapa de bits que el renderizador pueda transferir (blit). Un diccionario de sombreado (ISO 32000-1 §8.7.4.5) describe la geometría (un eje o un par de círculos en el arreglo Coords) más una función de color, y el operador sh pinta ese sombreado a través de la región de recorte actual, el mismo modelo gráfico que expone HotPDF cuando usted dibuja rutas y rellenos en el lienzo de una página. El renderizador de páginas de HotPDF recorre el flujo de contenido operador por operador, y any operador para el cual no tenga una ruta de código se omite para que el resto de la página se siga renderizando. Antes de la versión 2.335.0, sh residía en ese conjunto omitido: un degradado de encabezado o de página completa no aportaba nada a la salida, por lo que el fondo se mostraba blanco. El archivo nunca estuvo dañado. El renderizador simplemente no tenía un controlador para ese operador específico, y un cuadro blanco es exactamente el aspecto de un controlador ausente

¿Por qué un degradado de PDF se renderiza como un cuadro blanco?

Un sombreado no se puede pintar hasta que se evalúe su función, por lo que ese mecanismo tuvo que implementarse primero. Los sombreados axiales Tipo 2 y radiales Tipo 3 contienen una /Function que asocia una posición paramétrica a lo largo del degradado con un color (ISO 32000-1 §7.10), y el evaluador de funciones de HotPDF resuelve el FunctionType y lo procesa. La interpolación exponencial Tipo 2 (§7.10.3) calcula C0 + t^N * (C1 - C0) con delimitación de Domain y Range; las funciones muestreadas Tipo 0 (§7.10.2) leen una cuadrícula de muestras de 8, 16 o 32 bits y eligen la más cercana a través del mapa Encode, el caso cubierto en detalle en nuestro análisis de búsquedas de color muestreado Tipo 0; las funciones de unión Tipo 3 (§7.10.4) seleccionan una subfunción mediante el arreglo Bounds y realizan una recursión en ella. Las funciones calculadoras PostScript Tipo 4 (§7.10.5) no se evalúan: se degradan de manera controlada a una evaluación fallida en lugar de un color incorrecto, coincidiendo con la política conservadora que adopta HotPDF en toda la ruta de renderización. Este evaluador se lanzó en la versión 2.334.0, una versión antes del operador en sí, porque el pintor de sombreado es tan bueno como la función subyacente

¿Cómo convierte HotPDF un degradado continuo en píxeles?

HotPDF aproxima la mezcla continua con una ejecución finita de bandas de color sólido. El pintor de sombreado recorre el eje del degradado, lo divide en hasta 64 bandas (menos cuando el eje es corto en píxeles de dispositivo), evalúa la función en la posición paramétrica de cada banda y llena un rectángulo perpendicular al eje con un pincel sólido. El compromiso es la cantidad de bandas frente a la suavidad: más bandas siguen la mezcla de manera más cercana pero requieren más rellenos, y 64 es el límite deliberado. Dado que el conteo también escala con la longitud del eje en píxeles de dispositivo, la resolución importa. Renderizar la misma página a un DPI más alto alarga el eje, por lo que un degradado corto gana bandas y sus franjas se suavizan hasta alcanzar el límite establecido

// The shading discretizer uses up to 64 color bands along the gradient
// axis, but never more than the axis is long in device pixels. Rendering
// the same page at a higher DPI lengthens that axis, so a short gradient
// gains bands and the banding softens until the 64-band ceiling is hit.
Thumb := Pdf.RenderLoadedPageToBitmap(PageIndex, 96);   // coarser bands
Proof := Pdf.RenderLoadedPageToBitmap(PageIndex, 300);  // up to 64 bands

Renderizar una página sombreada a un mapa de bits

El punto de entrada público no cambia: RenderLoadedPageToBitmap toma un índice de página basado en cero y un valor de DPI, devuelve un mapa de bits de 24 bits propiedad del llamador y devuelve nil en caso de falla en lugar de generar una excepción, por lo que la compatibilidad con sombreado es transparente para el código que usted ya tiene. Una página que solía renderizar su encabezado degradado en blanco ahora devuelve el mismo mapa de bits con la mezcla pintada, y no se requiere ningún cambio de API para obtenerla. Lo único que vale la pena recordar es la propiedad: el llamador libera el mapa de bits devuelto. El flujo completo de renderización (interpretación de flujo de contenido, glifos incrustados y almacenamiento en caché de páginas) se cubre en la guía para renderizar páginas PDF a un mapa de bits en Delphi

var
  Pdf: THotPDF;
  Bmp: TBitmap;
begin
  Pdf := THotPDF.Create(nil);
  try
    if Pdf.LoadFromFile('quarterly-report.pdf') > 0 then
    begin
      // Page 1 (zero-based) at 150 DPI. A gradient-filled header that
      // used to come back blank now carries its color blend.
      Bmp := Pdf.RenderLoadedPageToBitmap(0, 150);
      if Assigned(Bmp) then
      try
        Bmp.SaveToFile('page1.bmp');
      finally
        Bmp.Free;
      end;
    end;
  finally
    Pdf.Free;
  end;
end;

Una comprobación barata contra regresiones proviene de la misma llamada. Renderice la página, obtenga una muestra de un píxel donde deba estar la banda del degradado y confirme que ya no sea el color blanco del papel al que el renderizador solía recurrir como valor predeterminado, una comprobación de una sola línea que detecta un retorno silencioso al comportamiento anterior de no hacer nada

Bmp := Pdf.RenderLoadedPageToBitmap(0, 150);
if Assigned(Bmp) then
try
  // True when the sh operator painted; False if the region fell back to white.
  HeaderPainted := Bmp.Canvas.Pixels[Bmp.Width div 2, 8] <> clWhite;
finally
  Bmp.Free;
end;

Lo que HotPDF no pinta: sombreados de malla y bordes de recorte

Los cuatro tipos de sombreado de malla (mesh) están fuera de alcance, y esto debe tenerse en cuenta al procesar un documento. Las mallas de triángulos de Gouraud de forma libre (Tipo 4), las mallas de Gouraud en forma de cuadrícula (Tipo 5), las mallas de parches de Coons (Tipo 6) y las mallas de parches de producto tensor (Tipo 7), definidas en ISO 32000-1 §8.7.4.5.5 a §8.7.4.5.8, no se renderizan; una página que use una de ellas se seguirá renderizando, solo que esa región se dejará como está. Vale la pena mencionar claramente dos aspectos adicionales. Los rectángulos de banda cubren la franja de sombreado en lugar de recortarse exactamente a la ruta de recorte actual, por lo que un degradado enmascarado en una forma redondeada o irregular se pinta como su franja delimitadora hasta que se incorpore el recorte de región preciso en una etapa posterior. HotPDF también asume que la salida de la función es RGB o escala de grises, por lo que un sombreado creado en CMYK o en un espacio de color inusual se aproxima en lugar de gestionarse el color. Para los documentos que la mayoría de los equipos de Delphi y C++Builder procesan habitualmente (reportes, facturas, estados de cuenta y presentaciones de diapositivas exportadas a PDF), los degradados axiales y radiales cubren prácticamente todos los casos que encontrará, mientras que las pruebas de diseño con muchas mallas deben tratarse como una vista previa en lugar de una prueba colorimétrica

El renderizador de páginas de HotPDF, la compatibilidad con el operador sh descrita aquí y el evaluador de funciones Tipo 0/2/3 debajo de él se distribuyen como parte de HotPDF Component para Delphi y C++Builder: una biblioteca nativa de VCL sin dependencias de DLL externas, que cubre la creación, edición, extracción de texto y renderización de PDF en un solo paquete