Una caja cian se sienta sobre un fondo amarillo, y el estado de gráficos que la pinta lleva /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 del amarillo en paz y puso el cian encima. Los dos resultados siguen el archivo al pie de la letra; el render de pantalla simplemente nunca preguntó qué hace un dispositivo de imagen con ese flag, así que una aprobación hecha en pantalla cubre un color que nunca llega al papel
¿Por qué una página imprime distinto de como se previsualiza?
La sobreimpresión es una instrucción al dispositivo de salida sobre las planchas, y una pantalla RGB no tiene planchas. ISO 32000-1 §8.6.7 define qué pasa cuando la entrada OP (trazo) u op (relleno) de un ExtGState es verdadera: los colorantes que la pintura actual no nombra conservan lo que ya hubiera en su plancha, en lugar de borrarse a cero. Un objeto cian pintado así no quita nada de la plancha del amarillo. Un visor que compone en RGB no tiene dónde guardar el amarillo, así que pinta el cian por encima
Ninguna de las dos salidas está rota. La discrepancia está construida dentro de los dos modelos de imagen, y se queda invisible hasta que alguien sostiene una prueba impresa junto al monitor. Eso es tarde en el trabajo para un diseñador que puso texto negro en sobreimpresión por error, o que dejó un logo blanco en sobreimpresión esperando que se viera
Activar la prueba con RenderOverprintPreview
HotPDF expone la prueba como un Boolean del documento, THotPDF.RenderOverprintPreview, que vale False por defecto. Con él activado, el render a bitmap rastrea las planchas de proceso bajo cada pintura en sobreimpresión 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 produciría la imprenta. Dejar el valor por defecto apagado es lo correcto para visualización ordinaria, porque los lectores de un PDF de oficina esperan que se vea como lo muestra su visor habitual. Actívalo en el paso cuya salida va al 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; // prueba las planchas, por defecto False
Device := THPDFBitmapRenderDevice.Create;
try
if Pdf.RenderLoadedPageToDevice(0, 150, Device) then
begin
Proof := Device.TakeBitmap; // el caller 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 planchas dependen del espacio de color de la pintura en sobreimpresión, y valen la pena conocerlas porque cada una explica una sorpresa distinta en una prueba:
- DeviceCMYK bajo
/OPM 1: un componente a cero deja su plancha intacta, uno distinto de cero la reemplaza. Cian 100 / amarillo 0 sobre un fondo amarillo conserva el amarillo y se vuelve verde - DeviceGray: la pintura nombra solo la plancha del negro, así que el cian, el magenta y el amarillo de debajo sobreviven. Un logo blanco DeviceGray puesto en sobreimpresión sobre un fondo CMY desaparece por tanto
- Separation y DeviceN: un colorante llamado
Cyan,Magenta,YellowoBlackreemplaza esa plancha de proceso directamente,/Noneno pinta nada, y/Allescribe todas las planchas de proceso - Colorantes planos: cualquier otro nombre se trata como una tinta plana; su transformación de tint da un color alternativo, que se multiplica sobre las planchas de proceso de debajo, así que la tinta oscurece lo que cubre en lugar de reemplazarlo
La prueba aplica a paths de relleno y de trazo y al texto, incluido el texto en modo de render de trazo, donde decide el flag de trazo OP en lugar de op. Las imágenes, las imágenes en línea y los sombreados sh siguen por sus pipelines de color ráster completos y pintan con su opacidad ordinaria. En la práctica eso cubre lo que los informes de preflight marcan más: reglas de sobreimpresión, keylines, tipografía y tintas planas
La transparencia sigue viva con la prueba activada. Un grupo de transparencia con knockout puesto sigue haciendo knockout, y el grupo se compone en la misma pasada que las reglas de sobreimpresión, así que un archivo listo para imprenta con arte transparente sobre un fondo negro en sobreimpresión prueba ambos efectos juntos. Acertar con uno y fallar con el otro solo produciría una prueba equivocada distinta
El ajuste también participa en la identidad de los renders cacheados. RenderLoadedPageToBitmapCached construye sus claves con página, DPI y una variante construida de los ajustes de render que incluye RenderOverprintPreview, y el nivel de disco usa la misma variante. Un visor que alterna entre vista normal y vista de prueba obtiene dos entradas de caché separadas y nunca necesita una llamada a InvalidateRenderedPageCache solo porque el conmutador 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 sobre un relleno cian DeviceCMYK pero deja OPM en su valor por defecto 0, y entonces la prueba sigue mostrando el cian eliminando el amarillo. La prueba está en lo cierto. Bajo el modo de sobreimpresión 0, §8.6.7 dice que una pintura DeviceCMYK fija los cuatro colorantes de proceso, ceros incluidos, así que el componente amarillo a cero reemplaza la plancha del amarillo exactamente como lo haría un knockout. El modo de sobreimpresión 0 solo protege las planchas que la pintura no nombra, lo que para un color CMYK de cuatro componentes significa las planchas planas y nada más
En las planchas de proceso que muestra una prueba compuesta, el modo 0 y un knockout simple dan los mismos píxeles, así que HotPDF pinta esos objetos DeviceCMYK como knockouts ordinarios. Para que un objeto CMYK haga sobreimpresión sobre otras tintas de proceso, el ExtGState que lleva /op true también necesita /OPM 1. Cuando una prueba y la intención del diseñador discrepan sobre un objeto DeviceCMYK, abre ese ExtGState y busca la entrada OPM antes de sospechar de cualquier otra cosa
La sorpresa contraria también existe. Bajo /OPM 1, el blanco CMYK son cuatro ceros, y cuatro ceros bajo sobreimpresión dejan cada plancha como estaba. Una tipografía blanca puesta en sobreimpresión se esfuma en la hoja, y la prueba muestra cómo se esfuma, que es toda la razón para ejecutar una
Tres dispositivos detrás de RenderLoadedPageToDevice
THotPDF.RenderLoadedPageToDevice(PageIndex, DPI, Device) es un único punto de entrada cuyo objetivo decide el objeto de dispositivo que le pases. Lanza una excepción ante un dispositivo nil, trata un DPI menor que 1 como 150, y devuelve lo que el dispositivo informe 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 son dueños de su salida a su manera:
THPDFBitmapRenderDeviceguarda unTBitmapen su propiedadBitmapy lo libera en su destructor salvo queTakeBitmapte lo haya entregado antesTHPDFDeviceContextRenderDevice.Create(ADC, AWidth, AHeight)dibuja en unHDCque ya tienes y no es dueño de 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 relleno blanco propioTHPDFMetafileRenderDeviceguarda unTMetafilehasta queTakeMetafilelo transfiere. El texto y los paths vectoriales siguen siendo escalables en el enhanced metafile, mientras que los XObjects de imagen llegan rasterizados
La propiedad sigue las reglas normales de Delphi. Lee la propiedad Bitmap o Metafile cuando el objeto solo necesita vivir tanto como el dispositivo; llama al método Take cuando tiene que sobrevivirle. Toma el bitmap, libera el dispositivo, olvida el bitmap, y la fuga crece con el número de páginas: invisible en una muestra de cinco páginas, evidente en un lote de quinientas. Dale a cada objeto su propio try/finally y la pregunta de quién libera qué se responde sola
Despacha por 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, puedes escribir tu propia clase de dispositivo, y el código que comprueba el tipo sigue funcionando cuando uno tuyo haga de dispositivo incluido
¿Por qué un render a impresora aterriza en una esquina?
La vía de contexto de dispositivo dimensiona la página desde el argumento DPI, no desde la anchura y altura que le pasas. El renderer escala las unidades PDF por DPI / 72 y usa la altura solo para anclar el origen de la página en el fondo de la superficie. Fija 300 a pelo y manda el trabajo a una impresora de 600 dpi, y la página sale a 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 pídesela 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
// pregunta al driver; 300, 600 y 1200 dpi son todos habituales
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; // intercambia 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;
La anchura y la altura salen de la caja visible de la página, la CropBox recortada por la MediaBox, a la resolución propia de la impresora, y quien llama las intercambia para páginas rotadas antes de crear el dispositivo. Eso coincide con lo que el renderer espera cuando ancla el origen
La prueba de sobreimpresión no baja por este camino. Los dispositivos de contexto de dispositivo y de metafile emiten llamadas GDI directamente al objetivo, y las reglas de planchas necesitan los píxeles ya existentes bajo cada pintura, que solo tiene el render a bitmap. Para una prueba en papel, renderiza el bitmap de la prueba y estíralo sobre el canvas de la impresora. Un pequeño dispositivo propio mantiene eso detrás del mismo punto de entrada:
type
// un dispositivo tuyo: 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; // deja el ajuste del caller 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ámalo entre Printer.BeginDoc y Printer.EndDoc con un DPI que dé al bitmap suficientes píxeles para la hoja, unos 200 a 300 para una prueba tamaño carta. El rectángulo de estirado de arriba llena el área imprimible; conserva dentro la relación de aspecto de la página 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 del color, y el documento las maneja con ConfigureRenderICCWorkflow, que toma un perfil de prueba, un perfil de salida y un flag de compensación de punto negro, y ClearRenderICCWorkflow para soltarlos
El sitio más productivo para un render de prueba es junto a las comprobaciones que ya ejecutas. Una pasada de preflight informa de que el texto negro está en sobreimpresión; el render de prueba le muestra al operador qué hace eso en la página; los dos aterrizan en el mismo informe. El trabajo de packaging tiende a mezclar sobreimpresión con tintas planas, y el recorrido de el render de colores planos Separation y DeviceN cubre el lado de colorantes de la misma página, incluidas las vistas de una sola plancha con RenderLoadedPageSeparationPlate. Los artículos sobre renderizar una página PDF a un bitmap y imprimir un PDF cargado con TPrinter cubren los dos objetivos de dispositivo en su forma llana
Todo esto corre en código nativo de Delphi y C++Builder sin ninguna DLL de render 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 ejecutar estos ejemplos contra tus propios archivos de imprenta