Artigo Técnico

Converter um PDF em um Único Espaço de Cores em Delphi

RecolorDocument move um PDF inteiro para um único espaço de cores, e RecolorPage faz o mesmo para uma única página. Ambos recebem 1 para tons de cinza, 2 para RGB e 3 para CMYK, e devolvem quantas cores foram convertidas. Geometria, texto e imagens ficam exatamente onde estavam; apenas a cor muda

Essa é a operação que você quer antes de enviar trabalho para uma impressora que espera um único espaço, ou quando um documento em cor precisa se tornar um documento em tons de cinza sem ser regenerado. A alternativa — reconstruir o documento a partir de seus dados de origem no espaço de destino — só está disponível quando você ainda tem os dados de origem, o que para qualquer coisa recebida de fora não é o caso

O que é convertido, e em que ordem

Primeiro os operadores de cor: os preenchimentos e traços que uma página define enquanto desenha. Uma cor já no espaço de destino é deixada intacta, então uma página cujas cores não precisam mudar mantém seus bytes originais em vez de ser reescrita com valores idênticos. Essa propriedade importa mais do que parece em um documento grande, porque objetos não tocados permanecem não tocados no arquivo

Vêm em seguida as imagens, e elas são a parte que costumava faltar. Um documento tornado cinza apenas com seus operadores convertidos ainda mostrava figuras coloridas em páginas cinza, o que é pior do que qualquer um dos extremos. Uma imagem é convertida quando ela carrega oito bits por componente, um espaço de cores de dispositivo, e ou nenhuma compressão ou apenas Flate simples

Imagens indexadas são convertidas por meio de sua tabela de cores: a paleta é convertida e cada amostra mantém o índice que já tinha. Isso cobre as imagens em paleta em que uma captura de tela ou um gráfico costumam ser salvos, e as converte independentemente de como suas amostras estão empacotadas ou comprimidas, porque as amostras nunca mudam

var
  Lib: TPDFlib;
  Converted: Integer;
begin
  Lib := TPDFlib.Create;
  try
    Lib.LoadFromFile('brochure.pdf', '');
    Converted := Lib.RecolorDocument(1);       // 1 grey, 2 RGB, 3 CMYK
    Log(Format('%d colours converted', [Converted]));
    Lib.SaveToFile('brochure-grey.pdf');
  finally
    Lib.Free;
  end;
end;

Por que um JPEG é deixado intacto?

Porque converter suas cores significaria recodificá-lo, e recodificar é uma operação diferente com consequências diferentes. Uma imagem JPEG ou de fax mantém seus próprios bytes: decodificar, converter e recomprimir mudaria os próprios dados da imagem, introduziria uma segunda geração de artefatos com perda, e mudaria o tamanho do arquivo de maneiras que o chamador não pediu

Máscaras suaves e máscaras de estêncil são deixadas intactas por um motivo diferente. Ambas são lidas como cobertura e não como cor, e converter uma delas faria a página mostrar a máscara como uma figura — uma máscara de transparência renderizada como arte cinza sobre o conteúdo que ela deveria estar moldando. Deixá-las não é uma limitação para contornar; é o resultado correto

Cores definidas por um espaço ICCBased, Separation, Indexed ou Pattern também são deixadas como estão no nível do operador. Convertê-las sem ler seus perfis mudaria a aparência da página em vez de preservá-la, e uma passagem de recolorização cuja promessa inteira é preservação não pode começar a adivinhar perfis

Gradientes são convertidos junto com as paradas por trás deles

Um gradiente é um espaço de cores mais uma função que produz cores nele, e converter um sem o outro produz nonsense — um gradiente convertido cujas paradas foram deixadas para trás é lido como um canal confundido com um nível de cinza, o que em uma página parece uma faixa da cor errada por completo. O espaço de cores do gradiente e as paradas por trás dele se movem juntos

Gradientes são encontrados onde quer que estejam: como um objeto próprio, escritos dentro do padrão que os pinta, ou situados nos recursos de shading de uma página. Essa cobertura importa porque ferramentas de design os distribuem de maneiras diferentes, e um conversor que só tratasse de um posicionamento deixaria um documento meio convertido sem nenhum padrão óbvio nas falhas

Dois tipos são deliberadamente deixados como estão. Um gradiente construído a partir de uma função sampled ou PostScript mantém sua própria definição, e o mesmo vale para os tipos mesh, que carregam suas cores em um stream em vez de em uma função. Reescrever qualquer um deles é uma operação diferente de converter uma cor, e fazê-lo silenciosamente dentro de uma passagem de recolorização seria uma surpresa

// Convert a single page - useful when only the cover needs to change
Lib.SelectPage(1);
Lib.RecolorPage(3);          // this page to CMYK
Lib.SaveToFile('cover-cmyk.pdf');

Onde a recolorização se encaixa antes de uma submissão para impressão

Use como etapa de normalização, não como gestão de cores. A recolorização converte valores entre espaços de dispositivo; ela não aplica um perfil ICC, respeita um rendering intent ou simula uma condição de impressão. Para um trabalho que precisa atingir uma prova contratual, o fluxo orientado por perfil é a resposta, e a recolorização é no máximo o passo que coloca tudo primeiro em um único espaço

Onde ela ganha seu lugar é no problema comum de produção: uma submissão que precisa ser em tons de cinza e chega com um logotipo em RGB, um documento interno que não deve ser impresso em cor, um lote de arquivos que precisa estar em um único espaço antes que uma etapa de preflight os aceite. Combine com uma verificação — as notas sobre preflight de PDF/A e PDF/UA e sobre a workbench de conformidade e assinatura cobrem a execução do veredito como parte do mesmo trabalho

Se o documento também precisar ter seu arte vetorial examinado em vez de convertido, o guia sobre gráficos vetoriais, shaders e gradientes cobre como esses objetos são construídos em primeiro lugar, o que é contexto útil para entender o que uma passagem de recolorização consegue e não consegue alcançar

O PDFlibPas é uma biblioteca PDF nativa em Pascal para Delphi, C++Builder e Lazarus sem nenhum runtime externo, de modo que uma etapa de normalização de cor roda dentro do seu próprio serviço em vez de chamar um conversor externo — veja a página do produto PDFlibPas para a API completa de processamento de documentos