Produção de Livros

O preto de quatro cores que encharca o corpo do seu livro

Corpo de texto em preto de quatro cores soma 400% de tinta e pede registro perfeito. O caminho para o PDF/X-1a com Ghostscript, o que ele não escreve sozinho e como provar o arquivo.

JonathanJonathan
8 min de leitura1.531 palavras
Capa do artigo: O preto de quatro cores que encharca o corpo do seu livro (eBuz, Produção de Livros)

Pegue um miolo diagramado na tela. O texto está em preto, a gráfica pede PDF/X-1a, e você exporta. Parece resolvido.

Agora olhe como esse preto foi escrito. Muitos programas escrevem o preto da tela como uma mistura das quatro tintas da impressão. É o chamado preto de quatro cores. Em um título grande, funciona. Em corpo pequeno, exige que as quatro chapas encaixem sem desvio nenhum. Se uma escorregar, a letra ganha um contorno colorido e perde nitidez.

A regra da nossa casa é simples: texto e cinzas saem em K puro, só a tinta preta. Em um teste, trocamos o preto do corpo por quatro cores e o arquivo passou a ter 400% de cobertura de tinta. O gate reprovou, porque o teto do nosso miolo é 300%. Este artigo mostra como fechar o miolo em PDF/X-1a e provar o resultado.

O que o PDF/X-1a pede, e o que nós fazemos

O PDF/X é uma família de padrões criada para troca de arquivo entre quem cria e quem imprime. No X-1a, o arquivo precisa ser autossuficiente e previsível. Na prática, o nosso miolo fecha assim:

  • Tudo em CMYK. Nenhum RGB.
  • Perfil de cor declarado, em uma estrutura chamada OutputIntent.
  • Fontes embutidas no arquivo.
  • TrimBox e BleedBox em cada página, dizendo onde corta e até onde vai a tinta (explicado em sangria, corte e zona de segurança).
  • Chaves de identificação GTS_PDFXVersion e GTS_PDFXConformance.
  • Sem transparência e sem link. Uma anotação de link, mesmo marcada para impressão, fere o X-1a. Por isso o miolo de impressão sai sem link clicável.

O compilador Typst não grava PDF/X. Na versão que usamos, a lista de padrões que ele aceita tem PDF/A e PDF/UA. O fechamento é um passo à parte, e as ferramentas são o Ghostscript e a biblioteca pikepdf.

Passo 1: escreva o texto em K puro na origem

Não deixe a conversão decidir a cor do texto. No Typst, declare:

#let tinta = cmyk(0%, 0%, 0%, 100%)
#set text(font: "Crimson Pro", size: 10.5pt, fill: tinta)

Cinzas seguem a mesma lógica: cmyk(0%, 0%, 0%, 70%) e cmyk(0%, 0%, 0%, 45%). O Ghostscript não mexe no que já é CMYK. Ele só converte o que está em RGB, como fotos e cores de painel.

Passo 2: feche com Ghostscript e pikepdf

O Ghostscript faz a conversão de cor e escreve o OutputIntent. Ele não escreve as chaves GTS_PDFXVersion e GTS_PDFXConformance, nem as caixas de corte. O pikepdf completa. Este é o script inteiro que usamos para o teste, com um perfil provisório:

#!/usr/bin/env python3
"""Fecha um PDF de miolo em PDF/X-1a: CMYK, perfil declarado, TrimBox, BleedBox e chaves de identificação.
Uso: python3 fecha_pdfx.py entrada.pdf saida.pdf sangria_mm "Título" [perfil.icc]"""
import os, subprocess, sys
import pikepdf

entrada, saida, sangria_mm, titulo = sys.argv[1], sys.argv[2], float(sys.argv[3]), sys.argv[4]
icc = sys.argv[5] if len(sys.argv) > 5 else "/usr/share/color/icc/ghostscript/default_cmyk.icc"  # PROVISÓRIO
provisorio = len(sys.argv) <= 5
cond = "PROVISORIO, confirmar com a grafica" if provisorio else "perfil da grafica"

ps = saida + ".def.ps"
open(ps, "w").write(f"""%!
/ICCProfile ({icc}) def
[ /Title ({titulo}) /Creator (fecha_pdfx) /DOCINFO pdfmark
[/_objdef {{icc_PDFX}} /type /stream /OBJ pdfmark
[{{icc_PDFX}} <</N 4>> /PUT pdfmark
[{{icc_PDFX}} ICCProfile (r) file /PUT pdfmark
[/_objdef {{OutputIntent_PDFX}} /type /dict /OBJ pdfmark
[{{OutputIntent_PDFX}} <<
  /Type /OutputIntent /S /GTS_PDFX
  /OutputCondition ({cond}) /OutputConditionIdentifier ({cond})
  /RegistryName (http://www.color.org) /DestOutputProfile {{icc_PDFX}}
>> /PUT pdfmark
[{{Catalog}} <</OutputIntents [ {{OutputIntent_PDFX}} ]>> /PUT pdfmark
""")

tmp = saida + ".tmp.pdf"
subprocess.run(["gs", f"--permit-file-read={icc}", "-dPDFX", "-dBATCH", "-dNOPAUSE", "-dNOOUTERSAVE", "-dSAFER",
                "-sDEVICE=pdfwrite", "-dPDFSETTINGS=/prepress", "-dCompatibilityLevel=1.3",
                "-sColorConversionStrategy=CMYK", "-dProcessColorModel=/DeviceCMYK",
                "-dOverrideICC=true", f"-sOutputICCProfile={icc}", "-dAutoRotatePages=/None",
                "-dSubsetFonts=true", "-dEmbedAllFonts=true",
                "-dDownsampleColorImages=false", "-dDownsampleGrayImages=false",
                f"-sOutputFile={tmp}", ps, entrada], check=True)

S = sangria_mm * 72 / 25.4
with pikepdf.open(tmp) as pdf:
    for page in pdf.pages:
        mb = [float(v) for v in page.MediaBox]
        page.BleedBox = pikepdf.Array(mb)                                      # a sangria é o próprio papel
        page.TrimBox = pikepdf.Array([mb[0] + S, mb[1] + S, mb[2] - S, mb[3] - S])  # onde a faca corta
    pdf.docinfo["/GTS_PDFXVersion"] = pikepdf.String("PDF/X-1:2001")
    pdf.docinfo["/GTS_PDFXConformance"] = pikepdf.String("PDF/X-1a:2001")
    pdf.docinfo["/Trapped"] = pikepdf.Name("/False")
    pdf.docinfo["/Title"] = pikepdf.String(titulo)
    pdf.save(saida)
os.remove(tmp); os.remove(ps)
print("fechado:", saida, "| perfil", "PROVISORIO" if provisorio else "da grafica")

Rode assim:

python3 fecha_pdfx.py miolo-cru.pdf miolo-x.pdf 3 "Título do livro"

O quarto argumento opcional é o caminho do perfil de cor da sua gráfica. Sem ele, o script usa o perfil padrão do Ghostscript, que em Linux costuma estar em default_cmyk.icc (ache com find /usr -name default_cmyk.icc). Esse perfil é provisório, e o script escreve isso dentro do próprio arquivo. Perfil provisório não é perfil: é um lembrete de que falta perguntar à gráfica qual usar.

Passo 3: prove o arquivo

Fechar não é provar. Rodamos estas conferências no PDF resultante:

pdfinfo -box miolo-x.pdf       # versão 1.3, título, MediaBox, TrimBox, BleedBox
pdffonts miolo-x.pdf           # coluna "emb" deve ser "yes" em todas
gs -q -o - -sDEVICE=inkcov miolo-x.pdf   # cobertura por página

Na saída do inkcov, cada linha traz quatro números: ciano, magenta, amarelo e preto. Em uma página de texto em K puro, os três primeiros são zero. No nosso arquivo de teste, as linhas saíram como 0.00000 0.00000 0.00000 0.00286 CMYK OK: só preto.

E duas conferências por script:

import pikepdf
d = pikepdf.open("miolo-x.pdf")
print({k: str(v) for k, v in d.docinfo.items()
       if k.startswith("/GTS") or k == "/Trapped"})
oi = d.Root.OutputIntents[0]
print("OutputIntent:", oi.S, str(oi.OutputConditionIdentifier))
print("anotações:", sum(len(p.get("/Annots", [])) for p in d.pages))

No teste: GTS_PDFXVersion e GTS_PDFXConformance presentes, OutputIntent do tipo /GTS_PDFX com a condição "PROVISORIO", e zero anotações.

Por fim, a cobertura total de tinta. Rasterize em CMYK e some os quatro canais no ponto mais carregado:

gs -dBATCH -dNOPAUSE -dSAFER -q -sDEVICE=tiff32nc -r40 \
   -sOutputFile=p%04d.tif miolo-x.pdf

Depois leia cada TIFF com Pillow e numpy, some os canais e pegue o máximo. O teto do nosso miolo é 300%, provisório, porque o papel ainda não foi definido: papel sem revestimento costuma segurar 240 a 260%, e couché, 300 a 330%. O limite real é da gráfica. O artigo sobre o checklist de preflight do miolo junta tudo isso em uma conferência só.

A ordem das operações

A ordem importa, e já nos custou retrabalho:

  1. Texto e cinzas em K puro, escritos no arquivo de origem.
  2. Compilação em modo de impressão, com sangria e margens espelhadas.
  3. Fechamento com Ghostscript (conversão de cor e OutputIntent).
  4. Gravação de TrimBox, BleedBox e chaves de identificação com pikepdf.
  5. Conferência do PDF final, e só dele.

Se você inverter o 4 e o 3, o Ghostscript refaz as páginas e as caixas de corte somem. Se pular o 5, o fechamento vira apenas uma esperança de que deu certo. Sempre abra e meça o arquivo que vai seguir para a gráfica, e não o que está antes do fechamento.

O que NÃO está provado

Dois pontos honestos, que entram em todo arquivo que fechamos assim:

  1. A validação formal em PDF/X-1a não foi feita. Fechamos com Ghostscript e pikepdf e conferimos as propriedades acima. Não passamos o arquivo por Acrobat ou pdfToolbox. A gráfica pode rodar o preflight dela, e ele pode apontar algo que a nossa conferência não vê.
  2. O perfil de cor é provisório até a gráfica informar o dela. Nunca adote um perfil em silêncio.

O erro que custa caro

Considerar que "está em CMYK" resolve. Um arquivo pode ter o texto em quatro cores, passar no teste de espaço de cor e estourar a cobertura de tinta. Outro erro frequente é deixar um link clicável dentro do miolo de impressão: ele parece inofensivo e fere o padrão. Os dois são pegos por medição, não por inspeção visual. No teste de mutação que montamos para este cluster, seis arquivos estragados de propósito foram todos reprovados, entre eles o de preto de quatro cores e o de link.

Quando NÃO usar

Se o seu arquivo não vai para impressão, como um livro só digital, o PDF/X não é necessário. Se a sua gráfica pedir outro padrão, como PDF/X-4, o X-1a não é o que ela quer: pergunte antes de fechar. O valor padrão do nosso script, 1.3 de compatibilidade, é o de X-1a.

Alternativa sem o nosso ambiente

  • Ghostscript e pikepdf, como no artigo. O Ghostscript tem licença AGPL, e existe licença comercial da empresa que o mantém.
  • Preflight do Acrobat ou pdfToolbox, comerciais, que convertem e validam em um passo. Preços a confirmar nos sites oficiais.
  • A própria gráfica. Muitas aceitam o PDF aberto e fecham elas mesmas. Pergunte qual o perfil e o padrão dela antes de decidir.

O que o Claude faz hoje, e como fazer sem ele

Hoje o Claude roda o fechamento e o gate do miolo, e relata o resultado. Sem ele, você roda o script do artigo e as conferências do passo 3, uma por uma. O script e as conferências dependem só de Ghostscript, pikepdf, poppler, Pillow e numpy.

Onde entra na operação

O fechamento é o último passo do miolo antes de ele ir para a gráfica, depois da sangria e antes do pacote final com especificação. O desenho completo está em Como produzimos o miolo de um livro profissional sem InDesign. O formato que serve de base está em 6 x 9 e a armadilha do 16x23.

Baixe, para guardar: checklist de preflight do miolo, com comando e limite por item (PDF).

Versões usadas neste artigo: veja a matriz de versões.

Perguntas frequentes

O Typst gera PDF/X direto?

Na versão que usamos, não. A lista de padrões que o compilador aceita tem PDF/A e PDF/UA, e não tem PDF/X. Por isso o fechamento é feito depois, com Ghostscript para a cor e o OutputIntent, e pikepdf para as caixas de corte e as chaves de identificação.

O que é preto de quatro cores e por que evitar no corpo do texto?

É um preto formado pela mistura das quatro tintas da impressão. Em corpo pequeno, ele exige encaixe perfeito entre as chapas, e uma pequena folga deixa a letra com contorno colorido. Também soma 400% de tinta. Para texto de corpo, usamos só a tinta preta (K puro).

Posso colocar link clicável no miolo que vai para a gráfica?

Não, se o arquivo for PDF/X-1a. Uma anotação de link, mesmo marcada para impressão, fere o padrão. O miolo de impressão sai sem link, e a versão digital pode ter.

Meu PDF fechado está validado como PDF/X-1a?

Não necessariamente. Fechamos com Ghostscript e pikepdf e conferimos as propriedades, mas a validação formal exige uma ferramenta própria, como o preflight do Acrobat ou o pdfToolbox. A gráfica também pode rodar o preflight dela.