Skip to content

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.

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):

Terminal window
dotnet add package Rivoli.Pdf.Core
dotnet add package Rivoli.Pdf

The packages target .NET 8 and .NET 10 and run on Windows, Linux, and macOS.

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:

  1. Document.Create builds the in-memory tree and sets the title and author metadata.
  2. AddSection appends a section: a run of pages that share page setup, and AddParagraph adds a block of text to it.
  3. SavePdf (an extension method from Rivoli.Pdf) lays the tree out and writes the bytes.

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"));

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.

The heading helpers map to font sizes for you, so you rarely set sizes by hand:

HelperLevelUse for
H11Document or chapter title
H22Major section
H33Subsection
H4H64–6Finer-grained nesting

AddHeading(text) is equivalent to H1(text); AddHeading(text, level) lets you pass the level as a number when it’s computed.