Artículo técnico

Prueba de overprint CMYK y dispositivos de render en HotPDF

Una caja cian se sienta sobre un fondo amarillo, y el estado de gráficos que la pinta carga /op true y /OPM 1. En pantalla el solape es cian plano. En la hoja de imprenta el mismo solape sale verde, porque el RIP dejó la plancha amarilla en paz y puso cian encima. Ambos resultados siguen el archivo al pie de la letra; el render de pantalla simplemente nunca preguntó qué hace un dispositivo de imagen con esa bandera, así que una aprobación hecha en pantalla cubre un color que jamás llega al papel

¿Por qué una página se imprime distinto de cómo se previsualiza?

El overprint es una instrucción al dispositivo de salida sobre planchas, y una pantalla RGB no tiene planchas. ISO 32000-1 §8.6.7 define qué pasa cuando la entrada OP (trazo) o op (relleno) de un ExtGState es true: los colorantes que la pintura actual no nombra conservan lo que ya había en su plancha, en lugar de borrarse a cero. Un objeto cian pintado así no le quita nada a la plancha amarilla. Un visor que compone en RGB no tiene dónde guardar el amarillo, así que pinta cian por encima y sigue

Ninguna salida está rota. El desacuerdo está construido dentro de los dos modelos de imagen, y permanece invisible hasta que alguien sostiene una prueba impresa junto al monitor. Eso ya es tarde para un diseñador que puso texto negro en knockout por error, o que dejó un logo blanco en overprint y esperaba verlo

Comparación de overprint CMYK en HotPDF donde un visor plano hace knockout del amarillo bajo el cian mientras la vista previa de overprint prueba ambas tintas de proceso y expone texto blanco accidentalmente en overprint
Un visor plano pinta solo la tinta de arriba mientras la prueba de overprint compone ambas tintas, exponiendo trampas como texto blanco accidentalmente en overprint

Activar la prueba con RenderOverprintPreview

HotPDF expone la prueba como un Boolean en el documento, THotPDF.RenderOverprintPreview, que vale False por defecto. Con ella activa, el render a bitmap sigue las planchas de proceso debajo de cada pintura en overprint y aplica las reglas de §8.6.7 antes de escribir el píxel, así que los solapes muestran la combinación de tintas que la imprenta produciría. Dejar el valor por defecto apagado es lo correcto para vista ordinaria, porque los lectores de un PDF de oficina esperan que se vea como su visor usual lo muestra. Actívela en el paso cuya salida va a un operador de preimpresión

var
  Pdf: THotPDF;
  Device: THPDFBitmapRenderDevice;
  Proof: TBitmap;
begin
  Pdf := THotPDF.Create(nil);
  try
    Pdf.LoadFromFile('cover-cmyk.pdf');
    Pdf.RenderOverprintPreview := True;    // pruebe las planchas, el valor por defecto es False
    Device := THPDFBitmapRenderDevice.Create;
    try
      if Pdf.RenderLoadedPageToDevice(0, 150, Device) then
      begin
        Proof := Device.TakeBitmap;        // el llamador es dueño de Proof desde aquí
        try
          Image1.Picture.Assign(Proof);
        finally
          Proof.Free;
        end;
      end;
    finally
      Device.Free;
    end;
  finally
    Pdf.Free;
  end;
end;

Las reglas de plancha dependen del espacio de color de la pintura en overprint, y valen conocerlas porque cada una explica una sorpresa distinta en una prueba:

  • DeviceCMYK bajo /OPM 1: un componente de cero deja su plancha intacta, un componente distinto de cero la reemplaza. Cian 100 / amarillo 0 sobre un fondo amarillo conserva el amarillo y se pone verde
  • DeviceGray: la pintura nombra solo la plancha negra, así que el cian, el magenta y el amarillo de debajo sobreviven. Un logo DeviceGray blanco puesto en overprint sobre un fondo CMY por tanto desaparece
  • Separation y DeviceN: un colorante llamado Cyan, Magenta, Yellow o Black reemplaza esa plancha de proceso directamente, /None no pinta nada en absoluto, y /All escribe todas las planchas de proceso
  • Colorantes directas: cualquier otro nombre se trata como una tinta directa (spot); su transformación de tinte da un color alterno, que se multiplica sobre las planchas de proceso de debajo, así que la directa oscurece lo que cubre en lugar de reemplazarlo

La prueba aplica a paths rellenos y de trazo y al texto, incluido el texto en modo de render de trazo, donde la bandera de trazo OP decide en lugar de op. Las imágenes, las imágenes en línea y los sombreados sh siguen por sus pipelines de color raster completos y pintan con su opacidad ordinaria. En la práctica eso cubre lo que los reportes preflight marcan más: reglas de overprint, keylines, tipografía y tintas planas

La transparencia sigue viva con la prueba activa. Un grupo de transparencia con knockout configurado igual hace knockout, y el grupo se compone en la misma pasada que las reglas de overprint, así que un archivo listo para imprenta con arte transparente sobre un fondo negro en overprint prueba ambos efectos juntos. Acertar con uno y fallar con el otro solo produciría una prueba equivocada distinta

El ajuste también toma parte en la identidad de los renders cacheados. RenderLoadedPageToBitmapCached construye sus claves sobre página, DPI y una variante construida desde los ajustes de render que incluyen RenderOverprintPreview, y el nivel de disco usa la misma variante. Un visor que alterna entre vista normal y vista de prueba recibe dos entradas de caché separadas y nunca necesita una llamada a InvalidateRenderedPageCache solo porque el interruptor cambió

La trampa del /OPM 0 en archivos DeviceCMYK

Este es el caso que manda a la gente a buscar un bug. Un archivo pone /op true en un relleno DeviceCMYK cian pero deja OPM en su valor por defecto de 0, y aun así la prueba muestra cian haciendo knockout del amarillo. La prueba está en lo correcto. Bajo el modo de overprint 0, §8.6.7 dice que una pintura DeviceCMYK establece los cuatro colorantes de proceso, ceros incluidos, así que el componente amarillo cero reemplaza la plancha amarilla exactamente como lo haría un knockout. El modo de overprint 0 solo protege las planchas que la pintura no nombra, lo que para un color CMYK de cuatro componentes significa planchas directas y nada más

Sobre las planchas de proceso que muestra una prueba compuesta, el modo 0 y un knockout plano dan los mismos píxeles, así que HotPDF pinta esos objetos DeviceCMYK como knockouts ordinarios. Para que un objeto CMYK haga overprint sobre otras tintas de proceso, el ExtGState que carga /op true también necesita /OPM 1. Cuando una prueba y la intención del diseñador discrepan sobre un objeto DeviceCMYK, abra ese ExtGState y busque la entrada OPM antes de sospechar de cualquier otra cosa

La sorpresa inversa también existe. Bajo /OPM 1, el blanco CMYK son cuatro ceros, y cuatro ceros bajo overprint dejan cada plancha como estaba. El texto blanco puesto en overprint se esfuma en la hoja, y la prueba muestra que se esfuma, que es toda la razón para correr una

Tres dispositivos detrás de RenderLoadedPageToDevice

THotPDF.RenderLoadedPageToDevice(PageIndex, DPI, Device) es un punto de entrada único cuyo objetivo lo decide el objeto de dispositivo que usted pasa. Lanza una excepción para un dispositivo nil, trata un DPI por debajo de 1 como 150, y devuelve lo que el dispositivo reporte desde su método Execute. THPDFRenderDevice es la base abstracta con dos miembros virtuales: Kind, que devuelve rdkBitmap, rdkDeviceContext o rdkEnhancedMetafile, y Execute(Document, PageIndex, DPI)

Los tres dispositivos incluidos poseen su salida de maneras distintas:

  • THPDFBitmapRenderDevice sostiene un TBitmap en su propiedad Bitmap y lo libera en su destructor a menos que TakeBitmap se lo haya entregado antes
  • THPDFDeviceContextRenderDevice.Create(ADC, AWidth, AHeight) dibuja en un HDC que usted ya tiene y no posee nada; el constructor lanza ante un DC cero o un tamaño no positivo, y no se pinta ningún fondo, así que un DC de pantalla necesita su propio relleno blanco
  • THPDFMetafileRenderDevice sostiene un TMetafile hasta que TakeMetafile lo transfiere. El texto y los paths vectoriales siguen escalables en el metarchivo mejorado, mientras que los image XObjects llegan rasterizados
Arquitectura de render de HotPDF abriendo una llamada RenderLoadedPageToDevice en abanico hacia dispositivos de render bitmap, contexto de dispositivo de impresora y metarchivo mejorado con sus valores Kind y reglas de propiedad
Una llamada de render se abre en abanico hacia dispositivos bitmap, contexto de dispositivo y metarchivo cuyo Kind reporta el objetivo y cuyos métodos Take entregan la propiedad

La propiedad sigue las reglas planas de Delphi. Lea la propiedad Bitmap o Metafile cuando el objeto solo necesita vivir tanto como el dispositivo; llame al método Take cuando tiene que sobrevivirlo. Tome el bitmap, libere el dispositivo, olvide el bitmap, y el leak crece con el conteo de páginas: invisible en una muestra de cinco páginas, obvio en un lote de quinientas. Dele a cada objeto su propio try/finally y la pregunta de quién libera qué se responde sola

Despache sobre Kind en el código de la aplicación en lugar de probar is THPDFBitmapRenderDevice. Como Execute y Kind son métodos virtuales públicos, puede escribir su propia clase de dispositivo, y el código que verifica el tipo sigue funcionando cuando uno suyo hace de substituto de un dispositivo incluido

¿Por qué un render a impresora aterriza en una esquina?

La ruta de contexto de dispositivo dimensiona la página desde el argumento DPI, no desde el ancho y alto que usted pasa. El renderizador escala las unidades PDF por DPI / 72 y usa la altura solo para anclar el origen de página al fondo de la superficie. Fije 300 a piedra y mande el trabajo a una impresora de 600 dpi, y la página sale a la mitad de tamaño, empujada a la esquina inferior izquierda de la hoja. La resolución de impresora es una propiedad del driver, así que pregúntele al driver:

procedure PrintPage(Pdf: THotPDF; PageIndex: Integer);
var
  Device: THPDFDeviceContextRenderDevice;
  PrinterDPI, W, H, Tmp: Integer;
  L, B, R, T: Single;
begin
  if not Pdf.GetLoadedPageVisibleBox(PageIndex, L, B, R, T) then
    Exit;
  Printer.BeginDoc;
  try
    // pregúntele al driver; 300, 600 y 1200 dpi son todos comunes
    PrinterDPI := GetDeviceCaps(Printer.Handle, LOGPIXELSX);
    W := Round((R - L) * PrinterDPI / 72);
    H := Round((T - B) * PrinterDPI / 72);
    if (Pdf.GetLoadedPageRotation(PageIndex) mod 180) = 90 then
    begin
      Tmp := W; W := H; H := Tmp;            // intercambio para páginas 90 / 270
    end;
    Device := THPDFDeviceContextRenderDevice.Create(
      Printer.Canvas.Handle, W, H);
    try
      Pdf.RenderLoadedPageToDevice(PageIndex, PrinterDPI, Device);
    finally
      Device.Free;
    end;
  finally
    Printer.EndDoc;
  end;
end;

El ancho y el alto vienen de la caja visible de la página, la CropBox recortada a la MediaBox, a la resolución propia de la impresora, y el llamador los intercambia para páginas rotadas antes de crear el dispositivo. Eso coincide con lo que el renderizador espera cuando ancla el origen

La prueba de overprint no viaja por esta ruta. Los dispositivos de contexto de dispositivo y metarchivo emiten llamadas GDI directo al objetivo, y las reglas de plancha necesitan los píxeles ya debajo de cada pintura, que solo tiene el render a bitmap. Para una prueba en papel, renderice el bitmap de prueba y estírelo sobre el canvas de la impresora. Un pequeño dispositivo a medida mantiene eso detrás del mismo punto de entrada:

type
  // un dispositivo suyo: bitmap de prueba, luego estirado sobre la impresora
  TPrinterProofDevice = class(THPDFRenderDevice)
  public
    function Kind: THPDFRenderDeviceKind; override;
    function Execute(Document: THotPDF; PageIndex, DPI: Integer): boolean;
      override;
  end;

function TPrinterProofDevice.Kind: THPDFRenderDeviceKind;
begin
  Result := rdkDeviceContext;
end;

function TPrinterProofDevice.Execute(Document: THotPDF;
  PageIndex, DPI: Integer): boolean;
var
  Proof: TBitmap;
  OldProof: Boolean;
begin
  OldProof := Document.RenderOverprintPreview;
  Document.RenderOverprintPreview := True;
  try
    Proof := Document.RenderLoadedPageToBitmap(PageIndex, DPI);
  finally
    Document.RenderOverprintPreview := OldProof;  // deje el ajuste del llamador como estaba
  end;
  Result := Proof <> nil;
  if Result then
  try
    Printer.Canvas.StretchDraw(
      Rect(0, 0, Printer.PageWidth, Printer.PageHeight), Proof);
  finally
    Proof.Free;
  end;
end;

Llámelo entre Printer.BeginDoc y Printer.EndDoc con un DPI que le dé al bitmap suficientes píxeles para la hoja, alrededor de 200 a 300 para una prueba tamaño carta. El rectángulo de estiramiento de arriba llena el área imprimible; conserve la relación de aspecto de la página dentro si la página y el papel difieren de forma

Dónde encaja la prueba junto al preflight

La prueba responde una pregunta: qué tintas sobreviven donde los objetos se solapan. Se compone sobre el mismo bitmap RGB de 24 bits que cualquier otro render, así que sus colores muestran la combinación de tintas y no un color de hoja medido. Las condiciones de imprenta son una cuestión de gestión de color, y el documento las maneja a través de ConfigureRenderICCWorkflow, que toma un perfil de prueba, un perfil de salida y una bandera de compensación de punto negro, y ClearRenderICCWorkflow para soltarlos otra vez

El lugar más productivo para un render de prueba es junto a las verificaciones que usted ya corre. Una pasada preflight reporta que el texto negro está en overprint; el render de prueba le muestra al operador qué hace eso en la página; ambos aterrizan en el mismo reporte. El trabajo de packaging tiende a mezclar overprint con tintas directas, y el recorrido de renderizado de colorantes directas Separation y DeviceN cubre el lado de colorantes de la misma página, incluidas vistas de una sola plancha vía RenderLoadedPageSeparationPlate. Los artículos sobre renderizar una página PDF a un bitmap y imprimir un PDF cargado por TPrinter cubren los dos objetivos de dispositivo en su forma plana

Todo esto corre en código Delphi y C++Builder nativo sin ninguna DLL de renderizado que distribuir junto al ejecutable. La página del componente HotPDF para Delphi lista las funciones de renderizado y preimpresión y tiene una build de prueba para correr estos ejemplos contra sus propios archivos de imprenta