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_PDFXVersioneGTS_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:
- Texto e cinzas em K puro, escritos no arquivo de origem.
- Compilação em modo de impressão, com sangria e margens espelhadas.
- Fechamento com Ghostscript (conversão de cor e OutputIntent).
- Gravação de TrimBox, BleedBox e chaves de identificação com pikepdf.
- 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:
- 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ê.
- 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.



