Getting started
Install the package and produce your first PDF in under five minutes.
Rivoli PDF is an in-process .NET PDF library: no Ghostscript, no headless browser, nothing to install at the OS level and no external process to shell out to. Layout and PDF writing are pure managed code; raster image work goes through SkiaSharp, whose native assets NuGet restores for you (see the FAQ for the platform matrix, including Alpine/musl). You build a document tree in memory and write it to a PDF. This page gets you from an empty project to a real file on disk.
Install
Section titled “Install”Rivoli PDF ships as three packages: Rivoli.Pdf.Core (the document model and builders),
Rivoli.Pdf (the PDF writer), and the optional Rivoli.Pdf.Html (HTML to PDF conversion):
dotnet add package Rivoli.Pdf.Coredotnet add package Rivoli.PdfThe packages target .NET 8 and .NET 10 and run on Windows, Linux, and macOS.
Hello, PDF
Section titled “Hello, PDF”A complete program that produces a one-paragraph PDF:
using Rivoli.Pdf;using Rivoli.Pdf.Builders;using Rivoli.Pdf.Model;
var doc = Document.Create("Hello", "Rivoli.Pdf");doc.DefaultPageSize = PageSize.A4;doc.DefaultMargin = Margin.Standard;
var section = doc.AddSection();section.AddParagraph("Hello, PDF.");
doc.SavePdf("hello.pdf");Three things are happening here:
Document.Createbuilds the in-memory tree and sets the title and author metadata.AddSectionappends a section: a run of pages that share page setup, andAddParagraphadds a block of text to it.SavePdf(an extension method fromRivoli.Pdf) lays the tree out and writes the bytes.
Where the file lands
Section titled “Where the file lands”SavePdf("hello.pdf") writes to a path relative to the process’s current working
directory: typically your project folder when you run with dotnet run. Pass an
absolute path if you want to be sure:
doc.SavePdf(Path.Combine(Environment.CurrentDirectory, "hello.pdf"));A slightly richer document
Section titled “A slightly richer document”Real documents have headings, structured content, and a bit of styling. Here’s a short report with a heading, an intro paragraph, a bulleted list, and a table:
using Rivoli.Pdf;using Rivoli.Pdf.Builders;using Rivoli.Pdf.Model;
var doc = Document.Create("Quarterly Report", "Finance");doc.DefaultPageSize = PageSize.A4;doc.DefaultMargin = Margin.Standard;
var section = doc.AddSection();
section .H1("Quarterly Report") .AddParagraph("Prepared by the finance team. Figures are unaudited.");
section.AddUnorderedList(list => list .Item("Revenue grew 18% quarter over quarter.") .Item("Operating margin held steady at 22%.") .Item("Headcount increased by 14."));
section.AddTable(table => table .Header("Quarter", "Revenue", "Profit") .Row("Q1", "$1.2M", "$200K") .Row("Q2", "$1.5M", "$250K"));
doc.SavePdf("report.pdf");The fluent helpers (H1, AddParagraph, AddUnorderedList, AddTable), each
return the object they were called on, so you can chain them or call them in
sequence, whichever reads better. They are thin wrappers over plain C# objects;
see Working with the builder for the three
construction styles and when to reach for each.
Heading levels at a glance
Section titled “Heading levels at a glance”The heading helpers map to font sizes for you, so you rarely set sizes by hand:
| Helper | Level | Use for |
|---|---|---|
H1 | 1 | Document or chapter title |
H2 | 2 | Major section |
H3 | 3 | Subsection |
H4–H6 | 4–6 | Finer-grained nesting |
AddHeading(text) is equivalent to H1(text); AddHeading(text, level) lets you
pass the level as a number when it’s computed.
- Building blocks: the document tutorial, starting from the DOM and working up.
- The document model: how Document, Section, Block, and Inline fit together.
- How-to guides: task-focused recipes for common documents.