Gerando PDFs a partir de programas C: o que funciona e o que dói

Se você está aqui tentando gerar documentos PDF diretamente de código C, provavelmente já perdeu algumas horas navegando entre bibliotecas mal documentadas e APIs que mudam a cada versão. Vou tentar poupar esse sofrimento. A situação não é bonita, mas é viável se você souber onde pisar. A abordagem mais direta é escrever o PDF byte a byte. Um arquivo PDF é, no fundo, uma estrutura textual com comandos específicos. Você pode abrir um arquivo com fopen, escrever o cabeçalho %PDF-1.4, montar o objeto de categorias, as páginas, os fluxos de conteúdo e fechar. Funciona para coisas simples — textos estáticos, formas geométricas básicas, imagens JPEG embutidas. O problema é que qualquer coisa que exija fontes TrueType, cores CMYK, JavaScript ou formatação complexa te obriga a implementar meia dúzia de subprotocolos do especificação ISO 32000, e essa especificação tem 700 páginas.

Por isso a maioria das pessoas recorre a bibliotecas. As principais opções no ecossistema C/C++ são o PDFlib, o Cairo com back-end PDF, o fpdi (via wrapper PHP ou C), e o libharu. Cada uma tem um custo diferente.

O problema prático com linguagem c em pdf

Eu precisei usar a combinação de fpdi com libharu para um sistema que deveria ler um template PDF existente, preencher campos dinâmicos com dados vindos de um banco SQLite, e salvar o resultado. O fpdi lida bem com a parte de ler e manipular o PDF template. O libharu cuida da geração. A dor real veio quando comecei a inserir strings acentuadas — ç, ã, é — nos campos de texto. O libharu por padrão usa codificação Latin-1 para strings de texto simples. Isso significa que caracteres fora do range ISO-8859-1 são silenciosamente corrompidos ou substituídos por pontos de interrogação. O PDF continua gerando, o visualizador não mostra erro nenhum, e você passa trinta minutos sem entender por que o nome "São Paulo" aparece como "So Paulo". A solução que funcionou foi converter as strings para Unicode (UTF-16BE com BOM) antes de passar para a função de inserção de texto do libharu. Não é óbvio porque a documentação não menciona isso. Código básico:

hpdf_doc_set_unicode(doc); Isso força o libharu a tratar as strings como Unicode. Depois disso, basta passar os ponteiros de string normais. Sem essa linha, todo texto com acentuação vai falhar em produção.

Outro detalhe que custa caro se você não sabe antes: o libharu não suporta imagens PNG com canal alpha (transparência). Se você tentar inserir uma imagem PNG transparente, a biblioteca converte tudo para preto e branco ou gera um artefato feio. A correção é converter as imagens para JPEG antes de passá-las ao gerador, ou usar o Cairo como alternativa se precisar de transparência.

Alternativas que valem a pena considerar

Se o seu projeto não exige C puro e pode usar C++, o PDFlib com a API C++ é muito mais maduro. Tem suporte nativo a Unicode, renderização de fontes TrueType, e um motor de layout que lida com quebras de página automaticamente. O problema é a licença: versões comerciais custam entre 1.500 e 3.000 euros por desenvolvedor. Não é algo que você coloca em um projeto open-source sem pensar muito. Uma alternativa gratuita e bastante competente é o Cairo com surface PDF. O Cairo é uma biblioteca 2D vetorial que existe desde 2001, tem bindings para C puro, e o backend PDF gera arquivos conformes com o padrão. Você desenha texto, linhas, curvas Bézier, imagens, e o Cairo cuida da formatação. A desvantagem é que não há suporte a formulários PDF, campos interativos, ou JavaScript embutido. Se o seu documento é puramente estático — relatórios, diagramas, certificados — o Cairo resolve bem.

Para projetos que já usam Python ou Node.js, vale a pena avaliar se a sobrecarga de chamar uma biblioteca de outra linguagem compensa. Um processo externo que gera o PDF via weasyprint (Python) ou puppeteer (Node) pode ser mais rápido de implementar do que lidar com as limitações do C. O custo é uma dependência a mais na arquitetura e um overhead de comunicação entre processos.

O que ninguém te avisa sobre geração de PDF em C

Performance de memória: bibliotecas como libharu carregam arquivos inteiros na memória. Se você está gerando PDFs de centenas de páginas com imagens de alta resolução, o consumo pode subir para 200-500 MB por documento. Em servidores com milhares de requisições simultâneas, isso vira um problema rapidamente. A solução prática é limitar o tamanho das imagens antes de embutir — redimensionar para no máximo 1200px de largura reduz o tamanho do PDF em cerca de 60% sem perda perceptível na qualidade de impressão. Fonts embutidas: se você precisa de uma fonte específica, o libharu e o Cairo exigem que você forneça o arquivo da fonte completo (TTF ou OTF). Fontes menores costumam ter entre 50 KB e 200 KB. Embedar múltiplas fontes em cada PDF gera arquivos grandes. Uma otimização que funciona: identifique os glifos realmente usados no documento e gere uma subset font. Isso é trabalhoso de implementar do zero, mas bibliotecas como fonttools (Python) fazem o subset e exportam um TTF menor que pode ser usado pelo gerador C.

Testes de validação: PDFs gerados programaticamente frequentemente têm erros sutis que só aparecem em leitores específicos. O Adobe Acrobat lê quase tudo. O visualizador do navegador (Chrome, Firefox) é mais rigoroso. O leitor do LibreOffice é ainda mais. Sempre valide seus PDFs gerados pelo menos nesses três ambientes antes de considerar o processo pronto para produção.

Um exemplo mínimo funcionando

Para quem quer começar do zero com libharu, a configuração básica com CMake é simples: find_package(PkgConfig REQUIRED)

pkg_check_modules(LIBHARU REQUIRED libharu) target_link_libraries(meu_prog ${LIBHARU_LIBRARIES})

target_include_directories(meu_prog PRIVATE ${LIBHARU_INCLUDE_DIRS}) Isso pressupõe que o libharu esteja instalado no sistema (pacote libharu-dev no Debian/Ubuntu, ou harfbuzz-devel no Fedora). Em ambientes Windows, o processo de instalação é mais trabalhoso — recomendo usar o MSYS2 ou compilar a partir do source com CMake mesmo, que leva uns dez minutos.

O código de geração mais básico fica assim: HPDF_Doc doc = HPDF_New(NULL, NULL);

HPDF_Page page = HPDF_AddPage(doc); HPDF_Font font = HPDF_GetFont(doc, "Helvetica", NULL);

HPDF_Page_SetFontAndSize(page, font, 12); HPDF_Page_ShowText(page, "Texto gerado em C");

HPDF_SaveToFile(doc, "saida.pdf"); HPDF_Free(doc);

Isso gera um PDF de uma página com texto simples em Helvetica. Para adicionar imagens, use HPDF_LoadPngImageFromFile ou HPDF_LoadJpegImageFromFile. Para múltiplas páginas, repita o HPDF_AddPage dentro de um loop. O libharu não faz quebra automática de páginas — se o texto ultrapassar a área útil, ele simplesmente é cortado. Você precisa calcular a posição Y manualmente e adicionar novas páginas quando necessário. Para quem está começando, o caminho mais rápido é: instalar o libharu, rodar o exemplo acima, entender onde cada parâmetro afeta a saída, e só então tentar incorporar fontes personalizadas e imagens. Pular direto para o complexo gera PDFs quebrados e muita frustração.