Guia do PDFsharp: Crie arquivos PDF com MigraDoc e PdfSharpCore
O PDFsharp é uma biblioteca .NET de código aberto para criar e editar documentos PDF a partir de código C#. Você desenha texto, linhas e imagens em uma página, chama o método Save e pronto, tem um arquivo PDF. Sem mecanismo de navegador, sem binário nativo. O projeto existe desde 2005 e muitas das faturas, relatórios e certificados gerados por back-ends .NET ainda hoje passam por ele.
Escrevi este guia para desenvolvedores que precisam de PDFs no servidor e querem saber o que esperar. Abordaremos como o PDFsharp e o MigraDoc funcionam juntos, qual versão instalar, como criar o primeiro arquivo funcional, os problemas com fontes no Linux, a recente mudança de licença e o momento em que você deve optar por outra solução.
O que é o PDFsharp e o que ele pode fazer?
Por trás da biblioteca PDFsharp está a empira Software GmbH, uma pequena empresa alemã que mantém o projeto ativo há quase vinte anos. A maior parte do seu tempo será dedicada a uma única classe, XGraphics. Se você já trabalhou com pintura em WinForms usando System.Drawing.Graphics, você se sentirá em casa em dez minutos: fonte, pincel, eixo x e y, e pronto.
Ao abrir a caixa, você recebe:
- Crie documentos PDF do zero com texto, formas vetoriais, linhas e imagens.
- Abra arquivos PDF existentes e adicione conteúdo às suas páginas, como carimbos, marcas d'água ou números de página.
- Mescle e divida documentos importando páginas de um arquivo para outro.
- Incorpore e selecione subconjuntos de fontes para que o arquivo tenha a mesma aparência em todas as máquinas.
- Adicione marcadores, links e metadados do documento, como título, autor e palavras-chave.
- Proteja arquivos com senhas e sinalizadores de permissão.
- Assinar documentos digitalmente (a partir da versão 6.2)
A implantação é monótona, e digo isso como um elogio. Tudo é código gerenciado, então seu profissional de operações nunca precisa instalar um Chrome sem interface gráfica em um servidor ou procurar uma DLL do Ghostscript às 2 da manhã. Você referencia um pacote NuGet, envia a atualização e pronto.
Agora, aqui está o problema. Você recebe uma tela e nada mais. Um parágrafo longo atinge a margem inferior? Problema seu. Uma tabela ultrapassa a primeira página? Também é problema seu, a menos que você use o MigraDoc.
PDFsharp e MigraDoc: qual camada você precisa?
Mesmo fornecedor, mesmo cronograma de lançamentos, funções bem diferentes. O MigraDoc Foundation fica um andar acima do PDFsharp. Em vez de dizer onde uma string deve ser inserida, você fornece seções, parágrafos, tabelas, cabeçalhos, rodapés, estilos e até mesmo gráficos, e ele descobre onde tudo deve ficar. O resultado é um PDF. Ou RTF, para aquele colega que insiste em abrir tudo no Word.
Em resumo: PDFsharp significa "coloque este texto em x=40, y=120". MigraDoc significa "aqui estão trinta linhas e um cabeçalho que se repete, você organiza as páginas".
| Tarefa | Melhor ajuste | Por que |
|---|---|---|
| Certificado ou bilhete de uma página com posições fixas | PDFsharp | Controle total sobre cada coordenada |
| Relatório com várias páginas, tabelas e cabeçalhos. | MigraDoc | Paginação e estilos automáticos |
| Fatura com número variável de itens de linha | MigraDoc | As tabelas crescem e se dividem ao longo das páginas. |
| Carimbo, marca d'água ou números de página em PDF existente | PDFsharp | MigraDoc apenas cria novos documentos. |
| Mesclar ou dividir arquivos existentes | PDFsharp | A importação de páginas é um recurso do PDFsharp |
| Gráfico de negócios dentro de um relatório | MigraDoc | Suporte integrado para gráficos |
| Misto: relatório gerado automaticamente mais uma capa personalizada. | Ambos | MigraDoc pode ser renderizado em uma página PDFsharp |
Na prática, os projetos acabam usando ambos. Texto corrido inserido pelo MigraDoc, capa desenhada à mão ou carimbo em um PDF de algum fornecedor inserido na camada inferior. De qualquer forma, não dá para evitar a instalação do PDFsharp, já que o pacote MigraDoc o inclui como dependência.
Explicação das compilações do PDFsharp: compilação principal, GDI+ e WPF
Usuários iniciantes geralmente ficam presos na próxima posição da lista de pacotes do NuGet. O PDFsharp 6 vem em três versões, cada uma com sua própria versão MigraDoc.
| Pacote NuGet | Construir | Plataformas | Fontes e imagens |
|---|---|---|---|
| PDFsharp / PDFsharp-MigraDoc | Essencial | Windows, Linux, macOS | Requer um resolvedor de fontes; imagens BMP, PNG e JPEG. |
| PDFsharp-GDI / PDFsharp-MigraDoc-GDI | GDI+ | Somente para Windows | Utiliza as fontes instaladas através do System.Drawing |
| PDFsharp-WPF / PDFsharp-MigraDoc-WPF | WPF | Somente para Windows | Utiliza fontes instaladas via WPF. |
Os pacotes atuais são compatíveis com .NET 8, 9 e 10, além de .NET Standard 2.0 e .NET Framework 4.6.2. Portanto, praticamente tudo que ainda está em desenvolvimento está incluído, desde uma ferramenta WinForms já antiga até uma API ASP.NET Core totalmente nova.
Aplicativo de console, API Web, Docker, Azure Functions, qualquer coisa no Linux? Versão principal. GDI+ ou WPF só fazem sentido para um aplicativo de desktop Windows onde você deseja usar fontes do sistema ou uma pré-visualização em um controle nativo. Alguém no Stack Overflow perguntou uma vez se o aplicativo de console precisava da versão WPF. Não precisava.

Como instalar o PDFsharp a partir do NuGet no Visual Studio
Você ainda encontrará posts em fóruns da época do WinForms dizendo para baixar um arquivo ZIP, encontrar uma DLL e adicionar a referência manualmente. Ignore-os. Instale o PDFsharp pelo NuGet; o gerenciador de pacotes controla as versões, então você não precisa se preocupar com isso.
- Abra sua solução no Visual Studio e clique com o botão direito do mouse no projeto no Solution Explorer.
- Selecione Gerenciar Pacotes NuGet , acesse a guia Procurar e pesquise por "PDFsharp".
- Selecione PDFsharp (versão Core) ou PDFsharp-MigraDoc se também precisar de formatação de documentos. Verifique se a editora é a empira Software GmbH.
- Clique em Instalar e aceite a solicitação de licença.
- Compile o projeto uma vez para confirmar se o pacote foi restaurado corretamente.
Usuários de dispositivos terminais podem pular a etapa de clicar:
bash dotnet add package PDFsharp dotnet add package PDFsharp-MigraDoc
Dentro do Console do Gerenciador de Pacotes, o comando equivalente é `Install-Package PDFsharp`. E, por favor, não misture versões diferentes. Já vi uma equipe perder uma tarde inteira por causa de conflitos de tipos, porque um projeto fazia referência ao PDFsharp e o projeto vizinho incluía o PDFsharp-GDI.
Seu primeiro documento PDF com PDFsharp em C
A seguir, apresentamos o programa mais simples capaz de gerar um arquivo PDF de uma página. Ele funciona na versão Core de qualquer sistema operacional, desde que um resolvedor de fontes esteja configurado (próxima seção).
```csharp
usando PdfSharp.Drawing;
usando PdfSharp.Pdf;
// O PDFsharp 6.5+ requer a seleção de uma licença antes do primeiro uso.
PdfSharpLicense.SetAgplLicense();
var documento = novo PdfDocument();
document.Info.Title = "Olá PDFsharp";
Página PdfPage = document.AddPage();
XGraphics gfx = XGraphics.FromPdfPage(page);
var font = new XFont("Arial", 20, XFontStyleEx.Bold);
gfx.DrawString("Olá, PDFsharp!", fonte, XBrushes.Black,
novo XRect(0, 0, page.Width.Point, page.Height.Point),
XStringFormats.Center);
document.Save("hello.pdf");
```
Todos os programas do PDFsharp seguem este formato: documento, página, XGraphics, desenho, salvar. As unidades são pontos (1/72 de polegada) e a origem fica no canto superior esquerdo. Na versão 6.2.x, exclua a linha da licença. Essa API só apareceu na versão 6.5.0.
E a versão MigraDoc:
```csharp
usando MigraDoc.DocumentObjectModel;
usando MigraDoc.Rendering;
var doc = novo Documento();
Seção seção = doc.AddSection();
section.AddParagraph("Olá, MigraDoc!");
var renderizador = novo PdfDocumentRenderer { Document = doc };
renderizador.RenderDocumento();
renderer.PdfDocument.Save("hello-migradoc.pdf");
```
Sem coordenadas em lugar nenhum. Jogue 500 parágrafos e você obterá quantas páginas forem necessárias, sem nenhum código de paginação da sua parte.
Fontes na versão principal do PDFsharp: O problema do resolvedor
Pergunte por aí e a reclamação mais frequente será sobre fontes. As compilações GDI+ e WPF simplesmente leem as fontes TrueType instaladas no Windows. A compilação Core não pode assumir nada, porque um contêiner Linux enxuto geralmente não possui nenhuma fonte utilizável. Portanto, a primeira implantação do Docker tende a terminar com uma exceção informando que nenhuma fonte apropriada foi encontrada.
A solução é um resolvedor de fontes, uma classe que implementa a interface IFontResolver. Ela possui dois métodos:
- ResolveTypeface mapeia uma família e um estilo solicitados (por exemplo, "Arial", negrito) para um nome de fonte.
- GetFont retorna os bytes brutos do arquivo TTF para aquele nome de fonte.
Registre-o uma única vez na inicialização por meio do GlobalFontSettings.FontResolver, antes que o primeiro XFont seja criado.
```csharp
public class AppFontResolver : IFontResolver
{
public FontResolverInfo? ResolveTypeface(string family, bool bold, bool italic)
=> new FontResolverInfo(bold ? "Inter-Bold" : "Inter-Regular");
public byte[]? GetFont(string faceName) => File.ReadAllBytes(Path.Combine(AppContext.BaseDirectory, "Fonts", faceName + ".ttf"));
}
GlobalFontSettings.FontResolver = novo AppFontResolver();
```
Coisas que vale a pena saber antes de você mesmo se deparar com elas:
- Mantenha seus arquivos TTF em uma pasta "Fonts" no projeto e configure-os para serem copiados para o diretório de saída, ou incorpore-os como recursos para que a imagem do contêiner sempre os contenha.
- A versão 6.2.0 removeu o antigo CoreBuildFontResolver. No Windows ou WSL2, você pode restaurar um comportamento semelhante com GlobalFontSettings.UseWindowsFontsUnderWindows, mas isso não tem efeito no Linux ou macOS.
- O repositório oficial de exemplos inclui um SubstitutingFontResolver que você pode copiar como ponto de partida.
- Verifique a licença da fonte antes de incorporar uma fonte comercial em arquivos gerados. Fontes de código aberto como Inter, Roboto ou Noto dispensam essa questão.
Com o resolvedor configurado, a saída é idêntica no Windows, Linux e macOS.
Mesclar, assinar e proteger arquivos com o PDFsharp 6
Muitas equipes nunca criam um documento do zero. Elas usam a biblioteca para colar, carimbar ou bloquear arquivos já existentes. A mesclagem é feita em poucas linhas: abra cada fonte no modo de importação e copie as páginas.
csharp var output = new PdfDocument(); foreach (var path in new[] { "part1.pdf", "part2.pdf" }) { using var input = PdfReader.Open(path, PdfDocumentOpenMode.Import); foreach (PdfPage p in input.Pages) output.AddPage(p); } output.Save("merged.pdf");
A divisão é o mesmo processo inverso, um arquivo de saída por página ou intervalo. Para proteção, o documento.SecuritySettings aceita uma senha de usuário, uma senha de proprietário e sinalizadores de permissão (imprimir, copiar texto e assim por diante).
Duas funcionalidades muito solicitadas finalmente chegaram à versão 6.2:
- Assinaturas digitais baseadas em CMS. Um assinante padrão é fornecido em um assembly PDFsharp.Cryptography separado, e você pode integrar o seu próprio implementando IDigitalSigner. O suporte a servidor de carimbo de data/hora funciona no .NET moderno, mas não na versão do .NET Framework.
- Saída em PDF/A para arquivamento. A documentação oficial descreve o recurso como funcionando "com algumas limitações" e ainda em desenvolvimento, portanto, valide o resultado com um verificador de PDF/A antes de considerá-lo como um requisito para conformidade.
Essa versão também trouxe glifos de emoji coloridos e uma implementação gerenciada de MD5, o que é importante se você estiver executando o programa sob as regras FIPS ou em Blazor.
Repositório PDFsharp, Forks do PdfSharpCore e versões 1.x
Pesquise por PDFsharp no GitHub e você encontrará vários projetos com nomes quase idênticos. A culpa é do histórico.
A antiga linha 1.x (1.50, 1.51) só funcionava no .NET Framework. Quando o .NET Core foi lançado, as pessoas não quiseram esperar, então fizeram as adaptações por conta própria. O PdfSharpCore, iniciado por Stefan Steiger e posteriormente adotado por outras versões, é o mais conhecido. Ele removeu o GDI+ e conseguiu executar o código no Linux anos antes do lançamento oficial.
Então chegou o PDFsharp 6: uma reescrita completa em .NET moderno com uma versão Core oficial e multiplataforma. Os forks perderam grande parte da sua razão de ser.
| Projeto | Mantenedor | Plataformas | Status |
|---|---|---|---|
| PDFsharp 6.x (repositório empira/PDFsharp) | empira Software GmbH | .NET 8–10, .NET Standard 2.0, .NET Framework 4.6.2 | Mantido ativamente |
| PDFsharp 1.5x | empira Software GmbH | Somente para .NET Framework | O código-fonte permanece no GitHub, mas não recebe mais manutenção. |
| PdfSharpCore e suas variantes | Comunidade | .NET Core / .NET Standard 2.0 | Varia conforme a ramificação, atualizações mais lentas |
| PDFsharp-MigraDoc 6.x | empira Software GmbH | Igual ao PDFsharp 6 | Mantido ativamente |
Então, aquela discussão "PdfSharp vs PdfSharpCore" que continua aparecendo no Reddit? Novo projeto, pacotes oficiais. Mantenha um fork apenas se o código antigo já depender dele e a migração não valer a pena agora. E quando a documentação parecer insuficiente, consulte o repositório de exemplos separado do Empira. Suas pastas e arquivos são exemplos executáveis, o que é muito melhor do que ficar adivinhando.
O PDFsharp é gratuito? Alterações de licenciamento no PDFsharp 6.5
Sim, durante a maior parte de sua existência. Possuía licença MIT, o que significa uso comercial praticamente sem restrições. Todas as versões até a 6.2.4, inclusive, ainda possuem essa licença.
A versão 6.5.0 mudou isso. A biblioteca agora possui dupla licença:
- AGPL (licença gratuita). Você a habilita chamando PdfSharpLicense.SetAgplLicense() antes de usar a biblioteca. A AGPL exige que você disponibilize seu código-fonte aos usuários, incluindo aqueles que interagem com seu software por meio de uma rede, portanto, ela não é adequada para SaaS de código fechado.
- Licença comercial. Você compra uma chave de licença do fornecedor e a carrega com PdfSharpLicense.LoadLicense(...). Isso remove as obrigações da AGPL.
A partir da versão 6.5.0, seu código precisa escolher uma explicitamente. As versões de pré-visualização da 7.0 funcionam da mesma maneira.
Na prática:
- Projetos de código aberto compatíveis com a AGPL podem continuar usando a versão mais recente gratuitamente.
- Produtos de código fechado podem adquirir uma licença comercial ou permanecer na versão 6.2.x, que continua sob a licença MIT. Permanecer na versão atual significa perder correções futuras, portanto, avalie esse custo com sinceridade.
- Independentemente da sua escolha, leia o texto da licença na íntegra e peça à sua equipe jurídica para aprová-la. Este guia não constitui aconselhamento jurídico.

Onde o PDFsharp deixa a desejar e com o que combiná-lo
A biblioteca cumpre bem a sua função. O problema é que a sua função é limitada, e as mesmas lacunas surgem em todos os tópicos do fórum.
- Sem conversão de HTML para PDF. O PDFsharp não renderiza HTML nem CSS. Existe um complemento da comunidade, o HtmlRenderer.PdfSharp, mas ele suporta apenas HTML 4.01 e CSS nível 2, portanto, layouts modernos com flexbox ou grid não funcionarão. Equipes que precisam de modelos HTML geralmente optam por um renderizador de navegador sem interface gráfica.
- Sem JavaScript. Gráficos ou conteúdo criados no lado do cliente não podem ser capturados.
- Não há renderização de imagens. O PDFsharp não consegue converter uma página PDF em PNG para miniaturas ou pré-visualizações. Para isso, você precisa de um rasterizador separado.
- Extração de texto limitada. É possível percorrer o fluxo de conteúdo, mas não existe uma API de alto nível que retorne o texto limpo com suas posições. O PdfPig, uma biblioteca de código aberto independente, foi desenvolvido especificamente para leitura e extração de texto.
- Suporte parcial a formulários. O preenchimento de formulários AcroForm simples funciona; formulários complexos com scripts são outra história.
- As tabelas precisam do MigraDoc. Com o PDFsharp padrão, você calcula a altura de cada linha manualmente.
Isso não significa que seja uma má escolha. Documentos baseados em dados, como faturas, extratos, etiquetas e certificados, são exatamente o seu ponto forte, e o tamanho do arquivo é mínimo. Já cópias perfeitas de páginas da web, não.
PDFsharp para faturas e recibos de pagamento em criptomoedas
Os recibos são provavelmente o tipo de documento mais comum criado com o PDFsharp. Recibos de criptomoedas são um pouco mais complicados do que os de cartão. A boa notícia é que, assim que o gateway acessa seu webhook (um callback HTTP enviado quando o status do pagamento muda), você já tem todos os dados. Nada mais para pesquisar.
O que eu colocaria em um deles:
- Número do pedido ou da fatura e dados do comerciante
- Valor em criptomoeda e seu equivalente em moeda fiduciária no momento do pagamento.
- Moeda e rede (por exemplo, USDT na TRON versus USDT no Ethereum)
- Hash da transação, para que o cliente possa verificá-la em um explorador de blocos.
- Um endereço de carteira de recebimento abreviado e o horário de confirmação.
- Um código QR que direciona para a página da transação ou da fatura.
Use fonte monoespaçada para hashes e endereços. Os clientes forçam a vista para ler um caractere por vez, e em Arial, um zero e um O maiúsculo parecem gêmeos. Se o hash for muito largo, quebre-o em várias linhas; texto de 6 pontos não ajuda em nada. Incorpore as fontes, salve o arquivo com o pedido e assine-o caso seu contador solicite recibos.
Nada disso cobre o recebimento do pagamento em si. Para essa parte, você usaria um gateway como o Plisio . Ele aceita BTC, USDT e várias outras criptomoedas, gera a fatura e envia uma solicitação ao seu endpoint sempre que o status muda. Seu manipulador passa o payload para o MigraDoc e o comprador recebe um recibo com seu logotipo enquanto ainda está na página de agradecimento.
Conclusão
Continuo voltando ao PDFsharp por um motivo: ele é pequeno e não atrapalha. A versão Core funciona em qualquer lugar onde o .NET funcione, e o MigraDoc cuida do layout quando uma tela não é suficiente. Três coisas para definir logo de início: qual versão usar, como as fontes são carregadas e qual licença você está usando agora que a versão 6.5 passou a ser AGPL. Imprima dados, não páginas da web, e ele funcionará por anos.