A PDF Library for Delphi cria os dois tipos de máscara suave de PDF a partir do Delphi. SetImageSoftMaskEx associa uma imagem de máscara a uma imagem de destino e pode escrever a entrada /Matte que a arte pré-multiplicada precisa. NewSoftMaskGraphicsState constrói uma máscara alfa ou de luminosidade a partir de conteúdo capturado e devolve um estado gráfico que se aplica ao desenho subsequente. E quando um consumidor não consegue lidar com transparência de todo, FlattenTransparency renderiza o resultado visual e substitui cada página por ele
As máscaras suaves são a forma como o PDF exprime um desvanecimento em gradiente, uma vinheta, uma fotografia fundida num fundo, e todos os outros efeitos em que a opacidade varia ao longo de uma região. A transparência constante é um único número no estado gráfico; uma máscara suave é toda uma função da posição, e até se conseguir criar uma, toda uma categoria de design não pode ser reproduzida
Os dois tipos de máscara, e o que cada um lê
Uma máscara alfa tira os seus valores do canal alfa do conteúdo de mascaramento. Uma máscara de luminosidade tira-os do brilho do conteúdo de mascaramento, pelo que uma área branca é totalmente opaca e uma área preta totalmente transparente. A luminosidade é a que os designers procuram, porque pintar um gradiente em escala de cinzentos é uma forma natural de descrever um desvanecimento
As máscaras suaves de formulário são construídas a partir de conteúdo capturado, e vários detalhes são fixos, em vez de opcionais. O conteúdo capturado torna-se um grupo de transparência isolado em DeviceRGB, pelo que a máscara é avaliada num espaço de cor conhecido. A cor de fundo tem, por isso, de ter três componentes, correspondendo a esse grupo. A função de transferência aceita /Identity ou um objeto de função válido, permitindo remodelar a curva da máscara sem voltar a pintar a arte
uses
PDFlibrary;
var
Lib: TPDFlib;
MaskCapture, MaskGS, PhotoID: Integer;
begin
Lib := TPDFlib.Create;
try
Lib.LoadFromFile('brochure.pdf', '');
// A página 4 contém um gradiente em escala de cinzentos pintado para ser usado 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); // desvanece sob a máscara
// As definições de ExtGState persistem: termine o âmbito explicitamente
Lib.SetGraphicsState(Lib.NewSoftMaskGraphicsState(0,
PDF_SOFT_MASK_NONE, '', ''));
Lib.SaveToFile('brochure-masked.pdf');
finally
Lib.Free;
end;
end;
Esse último passo não é decoração. Os parâmetros de estado gráfico persistem até serem alterados, e aplicar depois um estado gráfico comum não limpa uma máscara suave ativa. Sem um /SMask /None explícito, tudo o que for desenhado depois da arte mascarada herda a máscara, o que é um dos bugs mais desconcertantes de diagnosticar visualmente
Máscaras de imagem e a entrada Matte
Para mascaramento ao nível da imagem, a imagem de máscara é primeiro normalizada para DeviceGray, pelo que uma máscara fornecida em qualquer espaço de cor se comporta de forma previsível. A entrada opcional /Matte, com um a quatro componentes consoante o espaço de cor da imagem, diz a um consumidor que os dados da imagem estão pré-multiplicados contra essa cor, o que evita o halo escuro que aparece quando arte pré-multiplicada é composta como se fosse alfa direto
Duas barreiras importam aqui. O PDF/A-1 e o PDF/X-1 proíbem a transparência, e a chamada recusa antes de modificar qualquer objeto, em vez de produzir um ficheiro que falha na validação mais tarde. E uma máscara suave bem-sucedida exige PDF 1.4, que a biblioteca define automaticamente — a transparência não existia antes dessa versão, e um cabeçalho 1.3 num ficheiro com máscaras suaves é simplesmente falso
Os estados repetidos são reutilizados: o mesmo formulário capturado, tipo de máscara, fundo e assinatura de função de transferência produzem o mesmo objeto de estado gráfico, em vez de um novo por chamada. Num documento que mascara cem imagens de forma idêntica, isso são noventa e nove objetos que nunca chegam a ser escritos
Porquê achatar, e o que o achatamento realmente faz
"Parece correto no ecrã e errado na imprensa" continua a ter a transparência como causa mais comum. RIPs mais antigos, alguns sistemas de submissão regulatória e o PDF/X-1a exigem todos um ficheiro sem qualquer transparência ativa
O achatamento aqui é deliberadamente literal: cada página no intervalo pedido é renderizada a um DPI escolhido sobre um fundo opaco, e o conteúdo e os recursos da página são substituídos por essa única imagem. Como o renderizador produz o resultado composto final, isto cobre tudo de uma vez — grupos de transparência, modos de mistura, máscaras suaves, padrões e formulários aninhados — sem lógica de aproximação por construção a poder falhar. O pico de memória de rasterização mantém-se limitado a uma página
// Achatar as páginas 1-8 a 300 DPI sobre branco, e depois gravar como PDF 1.3
Lib.FlattenTransparency('1-8', 300, $FFFFFF, 0);
Lib.SaveToFile('press-ready.pdf');
A contrapartida é igualmente literal: a saída é uma imagem, pelo que o texto deixa de ser selecionável ou pesquisável, e os contornos vetoriais são reamostrados ao DPI escolhido. O achatamento é um passo de entrega, não um passo de edição. Mantenha o original transparente e achate uma cópia
Páginas rodadas, unidades de utilizador e as caixas de página
Uma página rodada precisa de cuidados que uma implementação ingénua ignora. Depois de renderizar, a largura e a altura visuais são escritas de volta na MediaBox, a unidade de utilizador é incorporada no DPI efetivo e no novo tamanho de página, e a entrada /Rotate, a unidade de utilizador e as caixas de página auxiliares são removidas
Ignorar isso produz um ficheiro em que a imagem achatada está correta, mas um visualizador volta a rodá-la, ou escala-a por uma unidade de utilizador que já não se aplica. Remover as caixas, em vez de as recalcular, é a decisão certa, porque uma TrimBox que descreve a geometria anterior ao achatamento é pior do que nenhuma TrimBox
As anotações e os campos de formulário são renderizados na imagem estática por predefinição, e os objetos interativos removidos, que é o que um entregável pronto para impressão quer. Se, em vez disso, mantiver os objetos interativos, a passagem de anotações do renderizador é desligada, para que nada seja desenhado duas vezes
A verificação de versão que analisa tudo
Gravar como PDF 1.3 exige que não reste transparência nenhuma em lado nenhum, e a verificação prévia à gravação examina todos os objetos indiretos, não apenas os alcançáveis a partir das páginas. Isso é mais estrito do que parece à primeira vista, e está correto: uma máscara suave órfã, deixada para trás por uma edição anterior, continua no ficheiro, e um consumidor que percorra objetos, em vez de páginas, vai encontrá-la
Para tornar a redução de versão exequível, uma passagem de marcar e varrer corre por predefinição assim que cada página de destino tiver sido substituída com sucesso, libertando os objetos inalcançáveis. A consequência a prever é que os identificadores de imagem, de página capturada e de estado gráfico obtidos antes dessa varredura podem deixar de ser válidos depois. Volte a obter os identificadores de recurso de que precisa antes de continuar a editar, ou desative a varredura e aceite que a versão não pode então ser reduzida
Dois complementos completam o quadro. A arte vetorial que usa sombreados e gradientes em vez de máscaras está descrita em gráficos vetoriais, shaders e gradientes, e é frequentemente o percurso melhor quando o efeito pode ser expresso como um sombreado. E se a razão para achatar for um requisito de cor, e não de transparência, o percurso de conversão em recolorir um documento para outro espaço de cor preserva o texto ativo onde o achatamento não o faria
A criação de máscaras suaves, o achatamento e o motor de renderização por trás deles fazem parte da mesma biblioteca para Delphi, C++Builder e Free Pascal; a lista completa de funcionalidades está disponível na página da PDF Library for Delphi