Uma caixa ciano pousa sobre um fundo amarelo, e o graphics state que a pinta carrega /op true e /OPM 1. Na tela, a sobreposição é ciano chapado. Na folha impressa, a mesma sobreposição sai verde, porque o RIP deixou a chapa amarela em paz e deitou o ciano por cima. Os dois resultados seguem o arquivo à risca; a renderização de tela simplesmente nunca perguntou o que um dispositivo de imagem faz com aquela flag, então uma aprovação feita na tela cobre uma cor que nunca chega ao papel
Por que uma página imprime diferente de como pré-visualiza?
Overprint é uma instrução ao dispositivo de saída sobre chapas, e uma tela RGB não tem chapas. A ISO 32000-1 §8.6.7 define o que acontece quando a entrada OP (traço) ou op (preenchimento) de um ExtGState é true: os colorantes que a pintura atual não nomeia mantêm o que já estava na sua chapa, em vez de serem zerados. Um objeto ciano pintado assim não remove nada da chapa amarela. Um visualizador que compõe em RGB não tem onde guardar o amarelo, então pinta o ciano por cima e segue o baile
Nenhuma das saídas está quebrada. A divergência está construída dentro dos dois modelos de imagem, e continua invisível até alguém segurar uma prova impressa ao lado do monitor. Isso é tarde demais para um designer que definiu texto preto para knock out por engano, ou que deixou um logo branco em overprint esperando que ele apareça
Ligando a prova com RenderOverprintPreview
O HotPDF expõe a prova como um Boolean no documento, o THotPDF.RenderOverprintPreview, que assume False. Com ele definido, a renderização bitmap rastreia as chapas process sob cada pintura em overprint e aplica as regras do §8.6.7 antes de escrever o pixel, então sobreposições mostram a combinação de tintas que a imprensa produziria. Deixar o padrão desligado é o certo para visualização comum, porque leitores de um PDF de escritório esperam que ele pareça com o que o visualizador de sempre mostra. Ligue-o no passo cuja saída vai para um operador de pré-impressão
var
Pdf: THotPDF;
Device: THPDFBitmapRenderDevice;
Proof: TBitmap;
begin
Pdf := THotPDF.Create(nil);
try
Pdf.LoadFromFile('cover-cmyk.pdf');
Pdf.RenderOverprintPreview := True; // prova as chapas, o padrão é False
Device := THPDFBitmapRenderDevice.Create;
try
if Pdf.RenderLoadedPageToDevice(0, 150, Device) then
begin
Proof := Device.TakeBitmap; // quem chama passa a ser dono de Proof daqui em diante
try
Image1.Picture.Assign(Proof);
finally
Proof.Free;
end;
end;
finally
Device.Free;
end;
finally
Pdf.Free;
end;
end;
As regras de chapa dependem do espaço de cores da pintura em overprint, e valem a pena conhecer porque cada uma explica uma surpresa diferente em uma prova:
- DeviceCMYK sob
/OPM 1: um componente de zero deixa a sua chapa intocada, um componente diferente de zero a substitui. Ciano 100 / amarelo 0 sobre um fundo amarelo mantém o amarelo e vira verde - DeviceGray: a pintura nomeia apenas a chapa preta, então ciano, magenta e amarelo por baixo sobrevivem. Um logo DeviceGray branco definido para overprint sobre um fundo CMY portanto desaparece
- Separation e DeviceN: um colorante chamado
Cyan,Magenta,YellowouBlacksubstitui direto aquela chapa process,/Nonenão pinta nada, e/Allescreve toda chapa process - Colorantes spot: qualquer outro nome é tratado como uma tinta spot; o tint transform dela dá uma cor alternativa, que é multiplicada sobre as chapas process por baixo, então o spot escurece o que cobre em vez de substituir
A prova se aplica a paths preenchidos e traçados e a texto, incluindo texto em modo de renderização stroke, onde a flag de traço OP decide em vez da op. Imagens, imagens inline e shadings sh seguem pelos seus pipelines completos de cor raster e pintam com a opacidade ordinária delas. Na prática, isso cobre o que os relatórios preflight mais marcam: regras de overprint, keylines, tipos e tintas chapadas
A transparência continua viva com a prova ligada. Um grupo de transparência com knockout definido ainda derruba, e o grupo é composto na mesma passada que as regras de overprint, então um arquivo pronto para impressão com arte transparente sobre um fundo preto em overprint prova os dois efeitos juntos. Acertar um e errar o outro só produziria uma prova errada diferente
A configuração também participa da identidade das renderizações em cache. O RenderLoadedPageToBitmapCached chaveia as suas entradas por página, DPI e uma variante construída das configurações de render que incluem o RenderOverprintPreview, e a camada de disco usa a mesma variante. Um visualizador que alterna entre preview normal e prova ganha duas entradas de cache separadas e nunca precisa de uma chamada ao InvalidateRenderedPageCache só porque o interruptor mudou
A armadilha do /OPM 0 em arquivos DeviceCMYK
Aqui está o caso que manda as pessoas procurar um bug. Um arquivo define /op true em um preenchimento DeviceCMYK ciano mas deixa o OPM no padrão 0, e a prova ainda mostra o ciano derrubando o amarelo. A prova está certa. Sob modo de overprint 0, o §8.6.7 diz que uma pintura DeviceCMYK define todos os quatro colorantes process, zeros incluídos, então o componente amarelo zero substitui a chapa amarela exatamente como um knockout faria. O modo de overprint 0 só protege chapas que a pintura não nomeia, o que para uma cor CMYK de quatro componentes significa chapas spot e nada mais
Nas chapas process que uma prova composta mostra, o modo 0 e um knockout simples dão os mesmos pixels, então o HotPDF pinta esses objetos DeviceCMYK como knockouts comuns. Para um objeto CMYK sobreimprimir outras tintas process, o ExtGState que carrega /op true também precisa de /OPM 1. Quando uma prova e a intenção do designer discordam sobre um objeto DeviceCMYK, abra aquele ExtGState e procure a entrada OPM antes de suspeitar de qualquer outra coisa
A surpresa reversa também existe. Sob /OPM 1, branco CMYK é quatro zeros, e quatro zeros sob overprint deixam toda chapa como estava. Texto branco definido para overprint some na folha, e a prova mostra ele sumindo, que é toda a razão para rodar uma
Três dispositivos por trás de RenderLoadedPageToDevice
O THotPDF.RenderLoadedPageToDevice(PageIndex, DPI, Device) é um ponto de entrada único cujo alvo é decidido pelo objeto de dispositivo que você passa. Ele dispara uma exceção para um device nil, trata um DPI abaixo de 1 como 150 e retorna o que o dispositivo reportar do seu método Execute. O THPDFRenderDevice é a base abstrata com dois membros virtuais: Kind, que retorna rdkBitmap, rdkDeviceContext ou rdkEnhancedMetafile, e Execute(Document, PageIndex, DPI)
Os três dispositivos distribuídos são donos das suas saídas de formas diferentes:
- O
THPDFBitmapRenderDevicesegura umTBitmapna sua propriedadeBitmape o libera no destrutor, a menos que oTakeBitmapjá o tenha entregado a você - O
THPDFDeviceContextRenderDevice.Create(ADC, AWidth, AHeight)desenha em umHDCque você já tem e não é dono de nada; o construtor dispara em um DC zero ou um tamanho não positivo, e nenhum fundo é pintado, então um DC de tela precisa do seu próprio preenchimento branco - O
THPDFMetafileRenderDevicesegura umTMetafileaté oTakeMetafiletransferi-lo. Texto e paths vetoriais continuam escaláveis no enhanced metafile, enquanto image XObjects chegam rasterizados
A propriedade segue as regras comuns do Delphi. Leia a propriedade Bitmap ou Metafile quando o objeto só precisa viver enquanto o dispositivo; chame o método Take quando ele tem que sobreviver a ele. Pegue o bitmap, libere o dispositivo, esqueça o bitmap, e o leak cresce com a contagem de páginas: invisível em uma amostra de cinco páginas, óbvio em um lote de quinhentas. Dê a cada objeto o seu próprio try/finally e a pergunta de quem libera o quê responde a si mesma
Despache pelo Kind no código da aplicação em vez de testar is THPDFBitmapRenderDevice. Como Execute e Kind são métodos virtuais públicos, você pode escrever a sua própria classe de dispositivo, e código que confere o kind continua funcionando quando um dos seus substitui um dispositivo distribuído
Por que uma renderização para impressora cai em um canto?
O caminho de contexto de dispositivo dimensiona a página pelo argumento DPI, não pela largura e altura que você passa. O renderizador escala unidades PDF por DPI / 72 e usa a altura apenas para ancorar a origem da página no fundo da superfície. Fixe 300 no código e mande o job para uma impressora de 600 dpi, e a página sai com metade do tamanho, empurrada para o canto inferior esquerdo da folha. A resolução da impressora é uma propriedade do driver, então pergunte ao 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
// pergunte ao driver; 300, 600 e 1200 dpi são todos comuns
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; // troca 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;
A largura e a altura vêm da caixa visível da página, o CropBox recortado ao MediaBox, na resolução da própria impressora, e quem chama as troca para páginas rotacionadas antes de criar o dispositivo. Isso acompanha o que o renderizador espera quando ancora a origem
A prova de overprint não viaja por esse caminho. Os dispositivos de contexto de dispositivo e metafile emitem chamadas GDI direto no alvo, e as regras de chapa precisam dos pixels já existentes sob cada pintura, que só a renderização bitmap tem. Para uma prova em papel, renderize o bitmap da prova e estique-o no canvas da impressora. Um pequeno dispositivo customizado mantém isso atrás do mesmo ponto de entrada:
type
// um dispositivo seu: bitmap da prova, depois esticado na impressora
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; // deixa a configuração de quem chama como estava
end;
Result := Proof <> nil;
if Result then
try
Printer.Canvas.StretchDraw(
Rect(0, 0, Printer.PageWidth, Printer.PageHeight), Proof);
finally
Proof.Free;
end;
end;
Chame-o entre o Printer.BeginDoc e o Printer.EndDoc com um DPI que dê ao bitmap pixels suficientes para a folha, cerca de 200 a 300 para uma prova em tamanho carta. O retângulo de stretch acima preenche a área imprimível; mantenha a proporção da página nele se a página e o papel diferirem de forma
Onde a prova se encaixa ao lado do preflight
A prova responde a uma pergunta: quais tintas sobrevivem onde objetos se sobrepõem. Ela é composta no mesmo bitmap RGB de 24 bits de qualquer outra renderização, então as suas cores mostram a combinação de tintas em vez de uma cor de folha medida. Condições de imprensa são uma questão de gestão de cores, e o documento as trata via ConfigureRenderICCWorkflow, que recebe um perfil de prova, um perfil de saída e uma flag de compensação de ponto preto, e ClearRenderICCWorkflow para descartá-los de novo
O lugar mais produtivo para uma renderização de prova é ao lado das checagens que você já roda. Uma passada de preflight reporta que o texto preto está em overprint; a renderização da prova mostra ao operador o que isso faz na página; ambos caem no mesmo relatório. Trabalho de embalagem tende a misturar overprint com tintas spot, e o passo a passo de renderização de cores spot Separation e DeviceN cobre o lado dos colorantes da mesma página, incluindo visões de chapa única via RenderLoadedPageSeparationPlate. Os artigos sobre renderizar uma página PDF para um bitmap e imprimir um PDF carregado via TPrinter cobrem os dois alvos de dispositivo na forma simples deles
Tudo isso roda em código Delphi e C++Builder nativo, sem DLL de renderização para distribuir ao lado do executável. A página do componente Delphi da HotPDF lista os recursos de renderização e pré-impressão e tem um build de teste para rodar esses exemplos contra os seus próprios arquivos de impressão