Modern CSS
Flexbox, grid, var(), calc(), transforms, gradients, rounded corners, shadows, opacity and @page.
Open source · MIT · .NET 10
PdfPecker turns HTML and Markdown into PDFs, and PDFs into images, from plain .NET. No browser to start, no native binaries to ship, no third-party packages. Just one small DLL.
dotnet add package PdfPecker
Every method is static and thread-safe, so you can convert many documents at once. Write the HTML the way you already do, with modern CSS, and get a PDF back as bytes, a stream or a file.
using PdfPecker;
byte[] pdf = HtmlToPdf.Convert("<h1>Hello</h1><p>World</p>");
File.WriteAllBytes("hello.pdf", pdf);
// Or straight from ASP.NET Core
app.MapGet("/invoice", () =>
Results.File(HtmlToPdf.Convert(html), "application/pdf", "invoice.pdf"));
Built for invoices, payslips, reports, tickets and statements: the templates you control.
Flexbox, grid, var(), calc(), transforms, gradients, rounded corners, shadows, opacity and @page.
CommonMark 0.31 plus GitHub tables, task lists and strikethrough. Out comes a styled PDF or HTML page.
TrueType, OpenType, WOFF and WOFF2, subset and embedded, with kerning, ligatures and full Unicode.
Running headers and footers with page numbers, repeated table headers, orphans, widows and break control.
PNG, JPEG, GIF and WebP, and SVG drawn as crisp vectors, inline or from files.
Archival PDF/A-2b and 3b, AES-256 encryption, permissions and watermarks.
PAdES signatures with your certificate, visible signature boxes and trusted timestamps.
Factur-X and ZUGFeRD: your invoice XML embedded in a valid PDF/A-3, following the EN 16931 standard of EU Directive 2014/55/EU on e-invoicing.
Combine any PDFs, streamed one at a time, with links, bookmarks and form fields kept.
Its own renderer turns any PDF page into a PNG, with no Ghostscript or native code.
Clickable links, jumps inside the document, and bookmarks from your headings.
No JavaScript, no network, no file access unless allowed, page limits and cancellation for untrusted input.
Documents a second with one conversion per core on a 4-core cloud VM, on a 5-page document.
| Converter | Engine | To deploy | Invoice, 1 page | Report, 30 pages | Peak memoryMemory |
|---|---|---|---|---|---|
| PdfPecker | own, managed | 3.1 MB DLL | 0.86 ms | 39 ms | 83 MB |
| HtmlRenderer. | own, managed (CSS 2) | 2.4 MB of DLLs | 5.0 ms | 473 ms | 255 MB |
| wkhtmltopdf | Qt WebKit, native | about 90 MB | 289 ms | 693 ms | 164 MB |
| Puppeteer | Chromium | about 600 MB | 128 ms | 539 ms | 849 MB |
| Playwright | Chromium | browser + 135 MB | 142 ms | 522 ms | 986 MB |
Medians after warm-up, Linux, .NET 10. Chromium runs JavaScript and is the reference for CSS; PdfPecker does not run scripts. How it was measured
// Markdown to PDF, styled like a GitHub README
byte[] pdf = MarkdownToPdf.Convert(File.ReadAllText("README.md"));
// Markdown to HTML: a body fragment, or a complete page with the stylesheet
string fragment = MarkdownToHtml.Convert("# Hello\n\n*World*");
string page = MarkdownToHtml.ConvertDocument(markdown);
var options = new PdfOptions
{
PageSize = PageSize.Letter.Landscape,
Margins = PageMargins.FromMillimeters(20, 15, 20, 15),
BaseDirectory = "/var/app/templates", // where relative images and stylesheets come from
FooterText = "Page {page} of {pages}",
Title = "Invoice 42", Author = "Accounts",
MaxPages = 1000,
};
byte[] pdf = HtmlToPdf.Convert(html, options);
var options = new PdfOptions();
options.Fonts.AddFile("fonts/OpenSans-Regular.ttf")
.AddFile("fonts/OpenSans-Bold.ttf"); // only the glyphs you use are embedded
byte[] pdf = HtmlToPdf.Convert(
"<p style=\"font-family: 'Open Sans'\">Łódź, Ελλάδα, Москва</p>", options);
var archived = new PdfOptions { Conformance = PdfConformance.PdfA2b };
var secret = new PdfOptions
{
Watermark = new PdfWatermark { Text = "CONFIDENTIAL", Opacity = 0.25f },
Security = new PdfSecurity { UserPassword = "1234", Permissions = PdfPermissions.Print },
};
var eInvoice = new PdfOptions { EInvoice = new PdfEInvoice(File.ReadAllBytes("invoice.xml")) };
byte[] merged = PdfMerger.Merge(invoicePdf, termsPdf, attachmentPdf);
// Streams in and out: one input in memory at a time
await PdfMerger.MergeAsync(uploads.Select(f => f.OpenReadStream()), response.Body);
// Every page as PNG bytes, rendered in parallel
byte[][] pages = PdfToImage.Convert(pdfBytes, new ImageOptions { Dpi = 150 });
// report.pdf -> out/report-1.png, out/report-2.png, ...
PdfToImage.ConvertFile("report.pdf", "out");
Converted on our server in milliseconds and sent straight back. Nothing is stored.
Paste HTML or drop a file, then set any PdfOptions setting: page, header and footer, watermark, password, PDF/A and more.
Open the converter →Write Markdown and get a clean PDF, or a complete HTML page with its stylesheet.
Open the converter →Render each page to a PNG at the resolution you need, for previews, thumbnails or chat.
Make images →PdfPecker is a document engine, not a web browser. That is what makes it fast and small.