Criando e lendo PDFs com pdfpecker
O pdfpecker transforma HTML e CSS (ou Markdown) em PDF sem navegador e renderiza páginas PDF de volta para imagens para que você possa ver o que criou. Trabalhe nesta ordem: escreva HTML, converta, veja as páginas, corrija, converta novamente.
Configuração
python3 -c "import pdfpecker" 2>/dev/null || python3 -m pip install --quiet pdfpecker
O script auxiliar é scripts/pdf.py na pasta desta habilidade (no Claude Code: ${CLAUDE_SKILL_DIR}/scripts/pdf.py).
Ele encapsula o pacote para que você não precise de Python próprio para as tarefas comuns:
python3 scripts/pdf.py html invoice.html invoice.pdf # imagens e CSS resolvem ao lado do arquivo HTML
python3 scripts/pdf.py md notes.md notes.pdf --page-size Letter
python3 scripts/pdf.py preview invoice.pdf --dpi 80 # escreve invoice-page-1.png, ... e imprime os caminhos
python3 scripts/pdf.py text report.pdf --pages 1-2
python3 scripts/pdf.py markdown report.pdf report.md # qualquer PDF como Markdown, tabelas e listas preservadas
python3 scripts/pdf.py info report.pdf # contagem de páginas
python3 scripts/pdf.py merge all.pdf cover.pdf report.pdf
Execute python3 scripts/pdf.py <comando> --help para todas as opções. Em Python, as mesmas chamadas são
pdfpecker.html_to_pdf(html, base_dir=...), html_file_to_pdf(caminho, saida), markdown_to_pdf(texto),
pdf_to_images(pdf, dpi=80), pdf_to_text(pdf), pdf_to_markdown(pdf), pdf_page_count(pdf), merge_pdfs([...])
e pdf_to_pdfa(pdf, "saida.pdf") (um PDF existente para PDF/A para arquivamento).
Escrevendo o HTML
Comece a partir de um modelo quando um se encaixar: templates/invoice.html (fatura de uma página com tabela de itens) e
templates/report.html (relatório de várias páginas com capa, numeração de páginas, tabela que repete o cabeçalho e um
gráfico em SVG). Copie-o para junto da sua saída e edite-o.
Coloque o layout da página em CSS, não em opções:
@page {
size: A4; /* ou Letter, A5, "A4 landscape", 210mm 99mm */
margin: 18mm 16mm 20mm;
@bottom-center { content: "Página " counter(page) " de " counter(pages); font: 9pt sans-serif; color: #666; }
}
@page :first { @bottom-center { content: none; } }
h2 { break-after: avoid; } /* mantenha um cabeçalho com o que segue */
tr, figure, .card { break-inside: avoid; }
.new-page { break-before: page; }
thead { display: table-header-group; } /* repetido em toda página (padrão para <thead>) */
O que saber (detalhes em reference.md):
- Sem JavaScript. Scripts não são executados. Desenhe gráficos como SVG inline ou CSS (barras como
<div>s dimensionadas) e preencha os dados antes de converter. - Sem rede. Imagens, folhas de estilo e fontes carregam da pasta do arquivo HTML (
base_dir) ou URIsdata:, nunca de URLs http(s). Baixe o que precisar primeiro ou incorpore. - Fontes. Sem fontes próprias, o texto usa Helvetica (
sans-serif, Arial), Times (serif) e Courier (monospace), com fallbacks incorporados, que cobrem Latim, Grego e Cirílico. Chinês, Japonês, Coreano, Árabe, Hebraico, Hindi, Tailandês e outros scripts aparecem como?a menos que você passe uma fonte que os tenha:--font NotoSansSC-Regular.otf(ou--system-fontspara usar as fontes instaladas na máquina). Use@font-facecom umsrcrelativo para uma tipografia específica. - CSS moderno funciona: flexbox, grid, tabelas, floats, multi-coluna, posicionamento, transformações, gradientes, sombras,
cantos arredondados,
object-fit, SVG, fontes web, contadores e variáveis CSS. Layout como você faria para a visualização de impressão do Chrome; PdfPecker segue o layout do Chrome. - Unidades. Use
mm,ptoupx(96 px por polegada). Largura de conteúdo A4 com margens de 16 mm é 178 mm (cerca de 673 px).
Verificando o resultado
Sempre veja as páginas antes de entregar um PDF: execute preview e visualize os PNGs. Verifique se há texto cortado ou
saindo da página, tabela ou cabeçalho dividido de forma inadequada entre páginas, uma última linha solitária em uma nova página, páginas vazias,
? no lugar de letras (falta de fonte) e imagens que não carregaram (caminho errado). text confirma as palavras e a ordem. Corrija o HTML ou CSS, converta novamente e veja novamente.
Erros
O script sai com status 1 e imprime o motivo. Em Python, todo erro é um pdfpecker.PdfPeckerError:
PdfPeckerArgumentError para uma opção inválida, PdfReadError para um arquivo que não é um PDF legível,
PdfPasswordError, PdfLimitError (muitas páginas), PdfTimeoutError e PdfFileError para uma fonte ou arquivo
que não pode ser lido.