Swevo.FluentPdf 1.2.0

Prefix Reserved
dotnet add package Swevo.FluentPdf --version 1.2.0
                    
NuGet\Install-Package Swevo.FluentPdf -Version 1.2.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Swevo.FluentPdf" Version="1.2.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Swevo.FluentPdf" Version="1.2.0" />
                    
Directory.Packages.props
<PackageReference Include="Swevo.FluentPdf" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Swevo.FluentPdf --version 1.2.0
                    
#r "nuget: Swevo.FluentPdf, 1.2.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Swevo.FluentPdf@1.2.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Swevo.FluentPdf&version=1.2.0
                    
Install as a Cake Addin
#tool nuget:?package=Swevo.FluentPdf&version=1.2.0
                    
Install as a Cake Tool

FluentPdf

NuGet NuGet Downloads CI License: MIT

Free, MIT-licensed fluent PDF generation for .NET. No revenue threshold, no commercial license — ever.

Why FluentPdf?

QuestPDF's Community License (v3.0, effective July 2026) is free only for individuals, academia, charities, and businesses under $1M annual revenue — public companies and government agencies don't qualify at any revenue. If your product grows, or you're a public-sector team, you need a paid QuestPDF license. FluentPdf uses the same declarative, fluent building-block style but is MIT-licensed for everyone, regardless of revenue or company type.

Document.Create(container =>
{
    container.Page(page =>
    {
        page.Size(PageSizes.A4);
        page.Margin(40);

        page.Header().Text("Invoice #1042").FontSize(20).Bold();

        page.Content().Column(column =>
        {
            column.Item().Text("Bill to: Acme Corp");
            column.Item().Padding(0, 10, 0, 0).Table(table =>
            {
                table.ColumnsDefinition(columns =>
                {
                    columns.RelativeColumn(3);
                    columns.RelativeColumn(1);
                });
                table.HeaderCell().Text("Item").Bold();
                table.HeaderCell().Text("Price").Bold();

                foreach (var line in invoiceLines)
                {
                    table.Cell().Text(line.Name);
                    table.Cell().Text(line.Price.ToString("C"));
                }
            });
        });

        page.Footer().AlignCenter().Text(x => $"Page {x}");
    });
}).GeneratePdf("invoice.pdf");

Install

dotnet add package Swevo.FluentPdf

FluentPdf is built on PdfSharp (MIT-licensed) for low-level PDF drawing, with its own layout/pagination engine on top.

Linux font setup

PdfSharp has no bundled fonts and Linux containers often ship without any TrueType fonts at all. FluentPdf automatically scans common OS font directories (/usr/share/fonts, /usr/local/share/fonts, the Windows Fonts folder, macOS's /System/Library/Fonts) and picks the first match from DejaVu Sans, Liberation Sans, Noto Sans, Arial, Segoe UI, or Helvetica. On a bare Linux image (e.g. a minimal Docker base or a fresh GitHub Actions runner), install one:

apt-get install -y fonts-dejavu-core

Or register your own font explicitly, bypassing OS discovery entirely:

FluentPdfFonts.RegisterFont(
    "Roboto",
    regular: File.ReadAllBytes("fonts/Roboto-Regular.ttf"),
    bold: File.ReadAllBytes("fonts/Roboto-Bold.ttf"));

Core concepts

  • Document.Create(...) — top-level entry point; add one or more Page templates.
  • page.Header() / page.Content() / page.Footer() — Header and Footer are fixed-height and rendered fully on every page; Content is automatically paginated across as many pages as needed.
  • Column / Row — vertical/horizontal layout containers; Row items use relative (weighted) widths.
  • Table — relative-width columns with an optional repeating header row; splits at row boundaries across pages.
  • Text — automatic word-wrapping; splits mid-paragraph across pages if needed. Text(x => $"Page {x}") (inside Header/Footer only) renders the current page number.
  • Decorators.Padding(...), .Background(color), .Border(thickness, color), .AlignCenter() / .AlignRight() wrap whatever comes next in the chain.

Editing existing PDFs

FluentPdf.Editing.PdfEditor opens and manipulates PDFs that already exist on disk or in memory — merge, split, reorder, delete, and rotate pages — complementing Document, which only generates new PDFs from scratch.

using FluentPdf.Editing;

// Merge two files into one.
using var merged = PdfEditor.Merge("report-part1.pdf", "report-part2.pdf");
merged.Save("report-full.pdf");

// Edit a document in place.
using var editor = PdfEditor.Open("input.pdf");
editor.RotatePage(0, 90).RemovePage(2);
editor.Save("output.pdf");

// Reorder and split.
editor.Reorder(new[] { 2, 0, 1 });
var perPageDocuments = editor.Split();
var chunks = editor.SplitEvery(5);
  • PdfEditor.Open(path | bytes | stream) — opens an existing PDF for in-place editing.
  • RemovePage(index) / RotatePage(index, degrees) — modify pages in place; degrees must be a multiple of 90.
  • Reorder(newOrder) — rearranges all pages according to a full permutation of indices.
  • Split() / SplitEvery(pagesPerChunk) — produce one PdfEditor per page, or per contiguous chunk.
  • PdfEditor.Merge(...) — combines multiple files or open PdfEditor instances into one new document, in order.
  • AddAnnotation(index, annotation) — draws a HighlightAnnotation, FreehandStrokeAnnotation, TextCommentAnnotation, or ImageStampAnnotation onto the page at index. Annotations are burned into the page content the next time the document is materialized.
editor.AddAnnotation(0, new HighlightAnnotation(x: 50, y: 100, width: 200, height: 18));
editor.AddAnnotation(0, new TextCommentAnnotation(x: 50, y: 140, "Looks good to me"));
editor.AddAnnotation(0, new ImageStampAnnotation(signatureBytes, x: 300, y: 700, width: 120, height: 40));

Note: ImageStampAnnotation flattens the supplied image onto an opaque white background before stamping it (PdfSharp does not reliably alpha-blend semi-transparent PNGs). This uses System.Drawing.Common, which requires Windows at runtime.

  • Protect(userPassword, ownerPassword?) / RemoveProtection() — password-protects the output; PdfEditor.Open(path | bytes | stream, password) overloads open protected PDFs.
  • Compress(level) — recompresses embedded JPEG images to shrink output size. PdfCompressionLevel is Low / Medium (default) / High. Uses System.Drawing.Common (Windows-only at runtime).
  • Watermark(text, colorHex?, opacity?, fontSize?) — stamps diagonal, semi-transparent text across every page (e.g. "CONFIDENTIAL" or "DRAFT"). Pass null to remove a previously set watermark.
  • Bookmark(pageIndex, title) / ClearBookmarks() / Bookmarks — adds table-of-contents/outline entries that are written into the output PDF's outline tree, so the entries appear as bookmarks in any PDF viewer.
editor.Protect(userPassword: "letMeIn", ownerPassword: "adminOnly");
editor.Compress(PdfCompressionLevel.Medium);
editor.Watermark("CONFIDENTIAL");
editor.Bookmark(0, "Introduction");
editor.Save("protected-compressed.pdf");

using var reopened = PdfEditor.Open("protected-compressed.pdf", "letMeIn");
  • ToArray() / Save(path) — serialize the current state.

Pagination model

Every layout node knows how to measure itself and render as much of itself as fits in the remaining space, handing back a "continuation" for whatever didn't fit. Text and Table split mid-content (mid-line, mid-row); Row, Border, and Align move as a whole block to the next page if they don't fit (documented below as current limitations).

Known limitations (v1.0)

  • Row, Border, and Align are non-splittable — they move wholesale to the next page rather than splitting internally. Column and Table are the primary paginated containers.
  • No image support yet.
  • No cell-level borders/backgrounds inside Table (wrap individual cells with .Border() / .Background() as a workaround).

Contributions and issues for any of the above are welcome.

Design goals

  • MIT licensed, forever. No commercial tier, no revenue threshold.
  • Small, understandable engine. A handful of composable IElement nodes rather than a large proprietary layout DSL.
  • Works out of the box on Linux CI, given a system font is installed.
Package Downloads Description
Swevo.FluentExcel Downloads A free, MIT-licensed fluent Excel generation library for

💼 Need .NET consulting?

I'm the author of FluentPdf and a suite of compile-time source generators (AutoWire, AutoMap.Generator) and 28+ Polly v8 resilience packages. I'm available for consulting on Polly v8 resilience, Azure cloud architecture, and clean .NET design.

→ solidqualitysolutions.com · LinkedIn

Also by the same author

🌐 Full suite overview: swevo.github.io

Package Description
AutoBus Free, MIT-licensed message bus — alternative to MassTransit's commercial license.
AutoArchitecture Free, MIT-licensed compile-time architecture rule enforcement — alternative to NDepend.
EFCore.Outbox Transactional outbox pattern for EF Core.
Swevo.AutoAssert Free, MIT-licensed fluent assertions — alternative to FluentAssertions' commercial license.
EFCore.BulkOperations Free, MIT-licensed bulk insert/update/delete for EF Core.
AutoWire Compile-time DI auto-registration.
AutoDispatch.Generator Compile-time CQRS dispatcher — free alternative to MediatR's commercial license.
PollyAnalyzers Free Roslyn analyzers for async/resilience anti-patterns — blocking calls, async void, fire-and-forget tasks, swallowed exceptions.
PollyAction Free retry/backoff GitHub Action — wrap any CI step with exponential-backoff retries.

License

MIT © Justin Bannister

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.2.0 78 7/21/2026
1.0.1 103 7/7/2026
1.0.0 98 7/7/2026

1.2.0: Add PdfEditor.Watermark for diagonal repeated text stamping across every page, and PdfEditor.Bookmark/ClearBookmarks/Bookmarks for adding table-of-contents/outline entries that are written into the output PDF's outline tree. 1.1.0: Add PdfEditor.Protect/RemoveProtection for password protection (with password-aware Open overloads), and PdfEditor.Compress for JPEG image recompression (PdfCompressionLevel: Low/Medium/High). PdfEditor.Split/SplitEvery for splitting a document into separate files were already present and are now documented as part of the monetizable feature set. 1.0.2: Fix ImageStampAnnotation rendering as invisible for semi-transparent PNGs (now flattened onto an opaque background before stamping; requires Windows via System.Drawing.Common). 1.0.1: Add missing package icon. 1.0.0: Initial release. Fluent document builder with Text/Column/Row/Table components, automatic pagination (including mid-table and mid-text page breaks), padding/border/background decorators, and page numbering.