gn-pdf
Declarative PDF composition library for .NET, built on SkiaSharp. MIT-licensed for commercial use and resale.
Compose documents as typed node trees (Sheet, Stack, Track, Grid, …) with first-class Quill rich text, Font Awesome icons, SVG, line charts, and PDF merge with remapped internal links.
License
| Component | License | Commercial / resale |
|---|---|---|
| GnPdf (this code) | MIT | Yes |
| SkiaSharp | MIT | Yes |
| Svg.Skia | MIT | Yes |
| PDFsharp | MIT | Yes (annotations + merge) |
| GnPdf.Icons.FontAwesome.Free | MIT code + FA Free icons (CC BY 4.0) | Yes — keep attribution (NOTICE) |
Font Awesome Pro / Duotone (fad) |
Not included | Register licensed paths via IconRegistry.RegisterDuotone |
Packages
| Package ID | Purpose |
|---|---|
GeraldNeumann.GnPdf |
Core Compose API + PDF generation |
GeraldNeumann.GnPdf.Icons.FontAwesome.Free |
Curated FA Free SVG paths |
GeraldNeumann.GnPdf.Fonts.Carlito |
Optional Carlito TTF pack (Calibri alias) |
Private feed only: GitHub Packages. Not published to nuget.org.
Version lives in version.txt (SemVer + -aN alphas). Changelog: CHANGELOG.md · docs/whats-new/.
Install (consumers)
dotnet nuget add source "https://nuget.pkg.github.com/gerald-neumann/index.json" `
--name github --username USERNAME --password $env:GITHUB_TOKEN --store-password-in-clear-text
dotnet add package GeraldNeumann.GnPdf --version 0.7.0-a1
dotnet add package GeraldNeumann.GnPdf.Icons.FontAwesome.Free --version 0.7.0-a1
Pack / publish (maintainers)
.\scripts\pack-lib.ps1
$env:GITHUB_TOKEN = 'ghp_...'
.\scripts\publish-lib.ps1
See scripts/README.md.
Quick start
using GnPdf;
using GnPdf.Compose;
using GnPdf.Icons.FontAwesome.Free;
FontAwesomeFreeIcons.Register();
Pdf.Create()
.Sheet(s => s
.A4()
.Margin(Length.Cm(2))
.Body(Stack.Of(
Track.Of(
Slot.Grow(Text.Line("Hello gn-pdf").Size(18).Bold()),
Slot.Fit(Icon.Named("building").Size(18))
)
)))
.ToPdf("hello.pdf");
Font Awesome Pro / duotone (client-side)
gn-pdf never redistributes Pro glyphs. Register licensed SVG path pairs; secondary paints behind primary (default secondary opacity 0.4).
IconRegistry.RegisterDuotone("cloud-arrow-down", primaryPath, secondaryPath);
Icon.Named("cloud-arrow-down").Size(18).Color(brandBlue);
Icon.Named("cloud-arrow-down").Size(18)
.PrimaryColor(brandBlue)
.SecondaryColor(brandBlueLight)
.SecondaryOpacity(0.55f);
Grid, SVG, charts, merge + links
Grid.Of(GridColumn.Grow(), GridColumn.Grow(2), GridColumn.Fixed(80))
.Header(Text.Line("A").Bold(), Text.Line("B").Bold(), Text.Line("C").Bold())
.Cells(/* … */)
.AllowBreak();
Compose.Svg.From((w, h) => $"<svg width=\"{w}\" height=\"{h}\">…</svg>");
Chart.Line(c =>
{
c.Title("Position Burn-Down");
c.YMin(0);
c.Series("Actual", points, s => s.Color(accent));
c.Series("Projected", projected, s => s.Color(accent).Dashed());
}).Height(200);
var merged = Pdf.Merge(overviewPdf, detailPdf1, detailPdf2); // remaps named destinations
Quill WYSIWYG (HTML + Delta)
Prefer Quill Delta JSON or getSemanticHTML().
Compose.Quill.Html(html, opts =>
{
opts.FontSize = 10;
opts.LineHeight = 1.5f;
opts.MaxImageWidth = 400f;
});
Compose.Quill.Delta(deltaJson, opts =>
{
opts.FontSize = 10;
opts.LineHeight = 1.5f;
});
Layout helpers
Text.Line("Title").AlignCenter().MaxWidth(Length.Cm(22));
Stack.Of(/* … */).Pad(8).KeepIntact(); // stay on one page
Spacer.Need(80); // break if less room left
Break.Page;
Overlay.Of(
Text.Line("Row title").PadLeft(32),
Compose.Svg.From((w, h) => treeSvg).Width(28)
);
Nanga demo
.\start-demo.ps1
Output: demo-output/
| File | Document |
|---|---|
01-invoice.pdf |
Rechnung |
02-proposal.pdf |
Angebot |
03-order-confirmation.pdf |
Auftragsbestätigung |
04-timesheet.pdf |
Timesheet |
05-expense-sheet.pdf |
Reisekosten |
06-purchase-order-report.pdf |
Auftragsreport (+ burn-down chart) |
07-account-order-report.pdf |
Account order report (SVG tree + Pdf.Merge links) |
08-task-effort-matrix.pdf |
Task-effort matrix |
09-multipage-table.pdf |
Long table pagination + Break.Page |
10-quill-wysiwyg.pdf |
Quill HTML / Delta |
11-layout-chrome.pdf |
KeepIntact / NeedSpace / MaxWidth / Overlay |
Demo branding under demo/assets/ is sample-only — not in the NuGet packages.
Benchmarks
dotnet run --project demo/GnPdf.Demo -c Release -- --bench --label local --iterations 25
Results land in bench-results/ (see bench-results/SUMMARY.md). Optional --perf font,wrap,media,stream,memo isolates caches.
Status
v0.7.0-a1 — breaking Compose API (Pdf / Sheet / Stack / Track / Grid). Previous nested fluent builders are removed.
Customer handover: docs/customer-handover.md.