1. Building blocks
The DOM, sections, and paragraphs: the primitives every document is built from.
Every Rivoli PDF document is a tree. You assemble it in memory, then hand it to the writer to produce a PDF. The tree has four levels, and almost everything you do in this tutorial is adding nodes at one of them:
Document└── Section (a run of pages with shared page setup) └── Block (paragraphs, headings, tables, lists, images, page breaks) └── Inline (runs of text, links, inline images, inside paragraphs)If you want the full reference for these types, read The document model. This chapter is the hands-on version: we’ll build a small document from the root down.
Creating a document
Section titled “Creating a document”Document (namespace Rivoli.Pdf) is the root. Create one empty, or with
metadata:
using Rivoli.Pdf;using Rivoli.Pdf.Model;
var doc = new Document(); // emptyvar titled = Document.Create("My Report"); // title onlyvar full = Document.Create("My Report", "Jane Doe"); // title + authorThe document also carries the defaults that its sections inherit: page size and margins:
var doc = Document.Create("My Report", "Jane Doe");doc.DefaultPageSize = PageSize.A4; // also Letter, Legal, A3doc.DefaultMargin = Margin.Standard; // 1 inch on all sidesPageSize.A4.Rotate() gives you landscape. A section that doesn’t set its own
page size or margin falls back to these document defaults, so set them once at
the top and forget about them.
Adding sections
Section titled “Adding sections”A Section is a run of pages that share page setup: page size, margins, columns,
header/footer, and background. Most documents need only one. You reach for a
second section when part of the document needs different page setup: a
landscape appendix after a portrait body, say.
var section = doc.AddSection(); // creates one, appends it, returns it
var appendix = doc.AddSection();appendix.PageSize = PageSize.Letter.Rotate(); // landscape, this section onlyAddSection() both creates and appends. If you’ve built a Section separately,
doc.Add(section) appends the one you already have.
Adding paragraphs
Section titled “Adding paragraphs”A Paragraph is the workhorse block: a run of inline content that flows and
wraps. The fluent helper is AddParagraph:
using Rivoli.Pdf.Builders;
section.AddParagraph("This is a paragraph. It wraps to fit the page width.");AddParagraph returns the Section, so calls chain:
section .AddParagraph("First paragraph.") .AddParagraph("Second paragraph.") .AddParagraph("Third paragraph.");For richer paragraphs (mixed formatting, links, inline images), build the
Paragraph yourself and Add it. Paragraphs compose inline content fluently:
section.Add(new Paragraph() .Add("Visit our ") .AddLink("https://example.com", "website") .Add(" for the full report."));AddLink(target, text) accepts an external URL or a #anchor that points at
another node in the same document.
Headings
Section titled “Headings”Headings are just paragraphs with larger, bolder styling. Rivoli PDF gives you
H1 through H6, plus the size-by-number form AddHeading:
section .H1("Annual Report") .H2("Executive Summary") .AddParagraph("...") .H2("Financial Results") .H3("Revenue");The level controls the font size for you:
| Helper | Level | Font size (pt) |
|---|---|---|
H1 | 1 | 24 |
H2 | 2 | 20 |
H3 | 3 | 16 |
H4 | 4 | 14 |
H5 | 5 | 12 |
H6 | 6 | 10 |
AddHeading(text) is the same as H1(text); AddHeading(text, level) takes the
level as a number, which is handy when it’s computed in a loop. Levels outside
1–6 throw, so clamp computed values before passing them.
You override the built-in heading styling per heading the same way you style any paragraph. See Styling and typography.
Vertical space
Section titled “Vertical space”To open up space between blocks, add a spacer with AddSpace:
section .AddParagraph("Above the gap.") .AddSpace() // 12 points by default .AddParagraph("Below the gap.") .AddSpace(36) // a larger, explicit gap .AddParagraph("Further down.");AddSpace inserts an empty paragraph whose trailing space equals the height you
ask for. For finer control over the space around a single block, set paragraph
spacing in its style instead.
Saving
Section titled “Saving”When the tree is complete, write it with SavePdf from Rivoli.Pdf:
using Rivoli.Pdf;
doc.SavePdf("document.pdf"); // PDF 1.4 by defaultdoc.SavePdf("document.pdf", PdfVersion.Version17);await doc.SavePdfAsync("document.pdf");Putting the whole chapter together:
using Rivoli.Pdf;using Rivoli.Pdf.Builders;using Rivoli.Pdf.Model;
var doc = Document.Create("Annual Report", "Jane Doe");doc.DefaultPageSize = PageSize.A4;doc.DefaultMargin = Margin.Standard;
var section = doc.AddSection();section .H1("Annual Report") .AddParagraph("Prepared for the board of directors.") .AddSpace() .H2("Overview") .AddParagraph("Revenue and headcount both grew this year.");
doc.SavePdf("annual-report.pdf");Fluent or POCO: your choice
Section titled “Fluent or POCO: your choice”Everything above used the fluent helpers, but every type is a plain C# object. The same document can be built by setting properties and manipulating collections directly:
var para = new Paragraph("Built without helpers");section.Blocks.Add(para);section.Blocks[0].StartOnNewPage = true;Both styles produce the same tree and mix freely. Use whichever reads better
for the code in front of you. Working with the builder
covers the trade-offs, plus the higher-level DocumentBuilder entry point.
- Styling and typography: fonts, colors, alignment, spacing, and the styling cascade.