neuron-explorer
Qwen3.5‑4B 전용 조향형 뉴런 탐색기, 모든 MLP 뉴런을 밀어 결과를 보관·탐색
PdfPecker는 브라우저 없이 HTML·Markdown를 PDF로 변환하는 빠르고 무료인 C# 라이브러리입니다
PdfPecker is a fast, free (MIT) C# library that converts HTML and Markdown to PDF in .NET 8, 9 and 10. No browser, no native binaries, no third-party packages.
개발 도구C# · HTMLGitHub @Moonwalker1307온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
Fast, dependency-free HTML and Markdown to PDF for .NET
저장소 README에서 가져옴
README 전체를 불러오는 중입니다.
README 전문 보기 ↗Fast HTML and Markdown to PDF conversion, PDF to PNG, JPEG, WebP and TIFF rendering, and PDF to HTML, for .NET, with no dependencies.
PdfPecker has its own HTML parser, Markdown parser, CSS engine, layout engine and PDF writer, and its own PDF renderer. It does not start a browser, ship native binaries or pull in third-party packages; the NuGet package depends only on the .NET base class library.
using PdfPecker;
byte[] pdf = HtmlToPdf.Convert("<h1>Hello</h1><p>World</p>");
File.WriteAllBytes("hello.pdf", pdf);
Documentation: pdfpecker.net/docs · HTML to PDF in C#: a step-by-step guide
dotnet add package PdfPecker
The package targets net8.0, net9.0 and net10.0, so it works on .NET 8 and later, on Windows, Linux and macOS.
// HTML string to PDF bytes, or file to file (relative images and stylesheets resolve against the HTML file's folder)
byte[] pdf = HtmlToPdf.Convert(html);
HtmlToPdf.ConvertFile("invoice.html", "invoice.pdf");
// ASP.NET Core
app.MapGet("/invoice", () => Results.File(HtmlToPdf.Convert(html), "application/pdf", "invoice.pdf"));
// Page size, margins, footer and fonts
var options = new PdfOptions
{
PageSize = PageSize.Letter,
Margins = PageMargins.FromMillimeters(20, 15, 20, 15),
FooterText = "Page {page} of {pages}",
};
options.Fonts.AddFile("fonts/OpenSans-Regular.ttf");
byte[] letter = HtmlToPdf.Convert(html, options);
// Markdown to PDF or HTML, merging, PDF pages to PNG, and a whole PDF to one black and white fax TIFF
byte[] guide = MarkdownToPdf.Convert(File.ReadAllText("README.md"));
string guideHtml = MarkdownToHtml.Convert(File.ReadAllText("README.md"));
byte[] merged = PdfMerger.Merge(invoicePdf, termsPdf);
byte[][] pngs = PdfToImage.Convert(pdf, new ImageOptions { Dpi = 150 });
byte[] tiff = PdfToImage.ConvertToTiff(pdf, new ImageOptions { Dpi = 200, TiffColorMode = TiffColorMode.BlackAndWhite });
// Make any existing PDF smaller: losslessly, or with images downsampled to 150 dpi and recompressed as JPEG
byte[] smaller = PdfCompactor.Compact(File.ReadAllBytes("scan.pdf"));
byte[] smallest = PdfCompactor.Compact(pdf, new PdfCompactOptions { MaxImageDpi = 150, ImageQuality = 75 });
// Strip JavaScript, launch and submit actions and other active content from a PDF someone sent you
byte[] safe = PdfSanitizer.RemoveActiveContent(File.ReadAllBytes("received.pdf"));
// Fast Web View: the first page shows while the rest of a large PDF is still downloading
byte[] web = HtmlToPdf.Convert(html, new PdfOptions { Linearize = true });
byte[] mergedForWeb = PdfLinearizer.Linearize(PdfMerger.Merge(invoicePdf, termsPdf));
// Title, author, PDF version, page sizes, encryption and PDF/A claim of any PDF
var properties = PdfDocumentProperties.Read(File.ReadAllBytes("received.pdf"));
Console.WriteLine($"{properties.Title} by {properties.Author}: PDF {properties.Version}, {properties.PageCount} pages, {properties.PdfAConformance}");
// Any PDF as one self-contained HTML page: page images with selectable, searchable text and working links
string html = PdfToHtml.Convert(File.ReadAllBytes("statement.pdf"));
// Or its text as headings, paragraphs, lists and real <table> elements in reading order, for search and language models
string structured = PdfToHtml.Convert(File.ReadAllBytes("statement.pdf"), new PdfHtmlOptions { Mode = PdfHtmlMode.Structured });
// The same structure with the PDF's fonts, colours, backgrounds, borders and pictures
string styled = PdfToHtml.Convert(File.ReadAllBytes("statement.pdf"),
new PdfHtmlOptions { Mode = PdfHtmlMode.Structured, IncludeStyles = true, IncludeImages = true });
// Open a PDF once and render its pages one at a time, or in parallel
var renderer = PdfRenderer.Open(pdf);
renderer.RenderPage(0, new ImageOptions { Dpi = 150 }).Save("page1.png");
The conversion methods are static and thread-safe, so you can convert many documents in parallel. The few instance types are FontCollection and PdfRenderer, which can be shared by parallel work, and StreamingPdfMerger, which is not thread-safe: it builds one output and is used from one thread at a time.
PdfPecker.Fluent builds the same PDFs from C# code instead of HTML,
in the style of QuestPDF, so most QuestPDF documents port by changing the using lines. It is a separate package from
this repository, released with every PdfPecker release under the same version, and its only dependency is PdfPecker.
dotnet add package PdfPecker.Fluent
using PdfPecker.Fluent;
Document.Create(container => container.Page(page =>
{
page.Size(PageSizes.A4);
page.Margin(2, Unit.Centimetre);
page.Header().Text("Invoice 2026-104").FontSize(20).Bold();
page.Content().Table(table =>
{
table.ColumnsDefinition(columns => { columns.RelativeColumn(3); columns.RelativeColumn(); });
table.Cell().Text("Consulting");
table.Cell().AlignRight().Text("1,200.00");
});
page.Footer().AlignCenter().Text(x => { x.CurrentPageNumber(); x.Span(" / "); x.TotalPages(); });
}))
.GeneratePdf("invoice.pdf");
It writes compact HTML and CSS and renders it with PdfPecker, so every PdfOptions feature (PDF/A, PDF/UA,
signatures, e-invoices) works with it. What it covers and how it differs from QuestPDF is in its
README.
shape-outside, multi-column layout,
positioning (also the legacy clip: rect(), and absolute boxes inside a positioned inline element, such as
tooltips and badges), transforms, gradients (also in oklch and other colour spaces, and as
list markers), fixed background images (placed on each page's paper, as Chrome prints them), filters, masks,
media and container queries, logical properties, writing-mode (with floats, sized boxes and vertical-lr line
order), text-wrap, hanging indents (text-indent with hanging and each-line), emphasis
marks (text-emphasis), line-clamp with your own block-ellipsis, underlines from the font or below the descenders
(text-underline-position), drop caps, ::first-line styles with a background, ::marker styles (a larger marker font or a tall marker image makes its
line taller, content: none hides the marker, counter(list-item) numbers it and its own direction orders its
text, as in Chrome), images and gradients in ::before and ::after content, inline SVG (with
percentage coordinates and sizes, as in Bootstrap's placeholder images, and HTML in <foreignObject>) and PNG, JPEG, GIF, WebP, BMP and TIFF images (also chosen by srcset, <picture> and
image-set(),
shown by <embed> and <object>, and photos turned upright by their EXIF orientation), and CSS-only charts such as
Charts.css (column, bar, area, line and pie charts), laid out as Chrome lays them out. Older CSS works too: the
-webkit- property names Chrome still takes (-webkit-transform, -webkit-flex, ...), the legacy
display: -webkit-box and its -webkit-box- properties, and the -webkit-gradient() and prefixed gradient
syntaxes. As in browsers, a length without a unit (width: 200) counts as pixels only in a page without a doctype;
with <!DOCTYPE html> it is ignored. Without a doctype, lines also follow Chrome's quirks-mode line heights: a line of
small <font> text, or an image alone in a table cell, is only as tall as its content. The old body attributes
topmargin, leftmargin, marginheight and marginwidth set the page margins as they do in Chrome.
MorePdfPecker is built for HTML templates you control: it runs no JavaScript, and conversion never fetches anything from
the network (remote images and stylesheets load only through a ResourceResolver you supply; those in data: URLs need
none). Only signing goes online, and only when you ask: a timestamp from the server you name in TimestampUrl, OCSP and CRL data for long-term
validation when you turn on FetchRevocationData (from public addresses only, unless your UrlFilter allows others), and online revocation checks when verification uses
X509RevocationMode.Online. See the limitations for what it does not do yet.
The same three documents converted to A4 PDF by PdfPecker and six .NET alternatives, on one 4-core cloud VM (Intel Xeon @ 2.1 GHz, 260 MB L3, 16 GB, Linux, .NET 10.0.13). Times are medians after a 3-second warm-up, averaged over two runs; "first PDF" includes starting the browser where there is one. Parallel runs one conversion per core at once on the 5-page document. Peak memory is the proportional set size (PSS) of the whole process tree, so a browser's helper processes are included once and shared pages are not double-counted; .NET processes run with a 16 MB GC gen0 budget, as .NET would otherwise size it from the CPU cache.
PdfPecker is 50 to 200 times faster than the Chromium-based converters on the small documents and uses an eighth or less of their memory. How to read the table and how it was measured is in Performance; the benchmark itself, to run on your own machine, is in PdfPecker.Benchmarks.
| Converter | Engine | To deploy | First PDF | Invoice, 1 page | Feature tour, 5 pages | Report, 30 pages | Parallel | Peak memory |
|---|---|---|---|---|---|---|---|---|
| PdfPecker | own, managed | 5.1 MB DLL | 0.40 s | 0.92 ms | 2.9 ms | 33 ms | 1,132 docs/s | 92 MB |
| HtmlRenderer.PdfSharp 1.6.1 | own, managed (CSS 2) | 5.0 MB of DLLs | 0.54 s | 4.9 ms | 16 ms | 360 ms | 114 docs/s | 255 MB |
| iText pdfHTML 6.3.4 | own, managed | 11 MB of DLLs | 1.18 s | 24 ms | 132 ms | 2.2 s | 15 docs/s | 707 MB |
| wkhtmltopdf 0.12.6 | Qt WebKit, native | about 90 MB with Qt | 0.33 s | 282 ms | 309 ms | 600 ms | 12 docs/s | 165 MB |
| PuppeteerSharp 25.13 | Chromium 141 | about 600 MB browser | 1.15 s | 106 ms | 142 ms | 496 ms | 15 docs/s | 813 MB |
| Microsoft.Playwright 1.63 | Chromium 141 | browser + 135 MB driver | 0.98 s | 131 ms | 167 ms | 517 ms | 12 docs/s | 1,027 MB |
| Syncfusion HTML to PDF 35.1.40 | Chrome (Blink), bundled | about 545 MB with Chrome | 2.46 s | 183 ms | 236 ms | 968 ms | 3 docs/s | 2,239 MB |
dotnet build
dotnet test
dotnet run --project samples/PdfPecker.Sample -c Release # converts samples/PdfPecker.Sample/html/*.html and *.md into ./output
dotnet run --project samples/PdfPecker.Fluent.Sample -c Release # writes the PdfPecker.Fluent examples into ./output
dotnet run --project bench/PdfPecker.Benchmarks -c Release
dotnet run --project bench/PdfPecker.Benchmarks -c Release -- --requirements # memory and CPU per conversion
bench/compare-versions.sh v1.21.0 # this checkout against a release, in turns on this machine
dotnet pack src/PdfPecker -c Release -o ./nupkg # also checks the public API against the last release
dotnet pack src/PdfPecker.Fluent -c Release -o ./nupkg # the fluent package, with the same version
Requirements and details are in BUILD.md and TESTING.md; how to fuzz the parsers is in fuzz/README.md.
To contribute, see CONTRIBUTING.md. Report security problems privately as described in SECURITY.md.
MIT. The third-party fonts, font data and code built into the library are listed, with their licenses, in THIRD-PARTY-NOTICES.md.
@page sizes, borders, padding and background images (which cover the whole sheet) and margin boxes, running headers and footers (also a first page of its own, and bands
of their own for named pages), footnotes, tables of contents with page numbers, the page count anywhere in the content (counter(pages), as in Prince), the first and last page of a section and page numbers counted within it (-pdfpecker-target-pages(), and {section-page:id} in running headers and footers), break control (also table row groups
and group header rows kept together, as reports keep a group on one page, and forced breaks between table rows and between flex lines), table rows that break inside at a page's end as in Chrome, unless a cell would have nothing before the break, table
headers and footers repeated on every page (also around a row split across pages), and
bookmarks from the headings that bookmark-level, bookmark-label and bookmark-state can extend, rename or close.
More-pdfpecker-scale-to-fit: shrink fits text of any length into a fixed space, for
labels, badges and certificates. MoreBarcode.QrCode("https://example.com"). MorePdfCompactor makes any PDF smaller without changing how it looks, and
PdfOptions.Linearize or PdfLinearizer writes a linearized PDF whose first page shows before the rest arrives.
MorePdfSanitizer takes JavaScript, actions that launch programs, open other files or
submit form data, XFA and media annotations out of PDFs from others, and HasActiveContent tells whether a PDF has
any. Pages, text, links and form fields stay.ImageToPdf puts scans and photos on pages of their own size or fitted to a page size, with
photos turned upright by their EXIF orientation.
MorePdfOptions.StripImageMetadata removes EXIF (GPS location included), XMP, IPTC and comments
from embedded JPEGs while keeping their pixels and colours.HtmlToImage goes from HTML to images in one call. MorePdfToHtml turns any PDF into one script-free HTML file that looks like the PDF, with text you can
select, search and copy. PdfHtmlMode.Structured writes the text instead as flowing headings, paragraphs, lists and
real <table> elements in reading order, with nothing placed at a fixed position, for search indexes and language
models. A tagged PDF (PDF/UA, or any PDF with a structure tree) is read from its tags, which say exactly what each
heading, list item and table cell is. Other PDFs are read from their layout: tables come from the rules and borders
the PDF draws and from text that lines up in columns, with header rows, spanned cells and wrapped cells. Reading the
layout can turn unusual layouts, floats and charts into plain paragraphs, and scanned pages have no text to give.
IncludeStyles keeps how the page looks in that structure: fonts, sizes, colours, backgrounds, rounded boxes, table
borders, column widths and alignment, as CSS classes. IncludeImages adds the page's pictures as <img> elements.
MoreCreationDate or SOURCE_DATE_EPOCH gives byte-identical PDFs, for build pipelines
and output caches. MorePdfPeckerException, and the *File methods never leave a
half-written output. More