Document Generation
Create PDF documents from scratch using the fluent layout API. Configure pages, margins, headers, footers, metadata, and generation settings.
Document.Create
Every document starts with Document.Create, which accepts a handler delegate to define the document's content. Call .Page() inside the handler to add one or more page definitions.
using FolioPDF;
using FolioPDF.Fluent;
using FolioPDF.Helpers;
Document.Create(doc =>
{
doc.Page(page =>
{
page.Size(PageSizes.A4);
page.Margin(50);
page.Content().Text("Hello from FolioPDF!");
});
}).GeneratePdf("output.pdf");
The returned Document object supports chaining with .WithMetadata() and .WithSettings() before any .GeneratePdf() call.
Page Setup
Size
Set the page size with a predefined constant or custom dimensions. All measurements default to PDF points (1/72 inch) unless a Unit is specified.
// Predefined sizes
page.Size(PageSizes.A4); // 595.28 x 841.89 pt
page.Size(PageSizes.Letter); // 612 x 792 pt
page.Size(PageSizes.Legal); // 612 x 1008 pt
// Custom size in points
page.Size(400, 600);
// Custom size with unit conversion
page.Size(8.5f, 11f, Unit.Inch);
page.Size(210, 297, Unit.Millimetre);
// Landscape: swap width and height
page.Size(PageSizes.A4.Landscape());
// Continuous page: fixed width, height grows with content
page.ContinuousSize(595.28f);
| Method | Description |
|---|---|
Size(PageSize) | Fixed width and height from a PageSize constant |
Size(float, float, Unit) | Fixed width and height with optional unit |
ContinuousSize(float, Unit) | Fixed width, variable height (receipt-style) |
MinSize(PageSize) | Minimum page dimensions |
MaxSize(PageSize) | Maximum page dimensions |
Margins
Margins define the space between the page edge and the content area. Margins are applied uniformly or per-side.
// Uniform margin on all sides
page.Margin(50);
page.Margin(2, Unit.Centimetre);
// Horizontal and vertical
page.MarginHorizontal(40);
page.MarginVertical(60);
// Individual sides
page.MarginTop(80);
page.MarginBottom(40);
page.MarginLeft(60);
page.MarginRight(60);
Page Color
Set the page background color. The default is white.
page.PageColor(Color.FromHex("#F5F5F5"));
Page Slots
Each page has five layout slots. The Content slot drives pagination — when content overflows, a new page is generated. Header and Footer repeat on every page. Background and Foreground are drawn behind and in front of all other slots.
| Slot | Description | Repeats on every page? |
|---|---|---|
page.Background() | Drawn behind header + content + footer | Yes |
page.Header() | Top section, above content | Yes |
page.Content() | Primary content — drives pagination | N/A (flows across pages) |
page.Footer() | Bottom section, below content | Yes |
page.Foreground() | Drawn in front of header + content + footer | Yes |
doc.Page(page =>
{
page.Size(PageSizes.A4);
page.Margin(50);
page.Background()
.Background(Color.FromHex("#FAFAFA"));
page.Header()
.Text("Quarterly Report").FontSize(10).FontColor(Color.Grey);
page.Content().Column(col =>
{
col.Spacing(10);
col.Item().Text("Section 1").FontSize(18).Bold();
col.Item().Text("Content goes here...");
});
page.Footer().AlignCenter().Text(t =>
{
t.Span("Page ");
t.CurrentPageNumber();
t.Span(" of ");
t.TotalPages();
});
page.Foreground()
.AlignCenter().AlignMiddle()
.Text("DRAFT").FontSize(72).FontColor(Color.FromRGBA(200, 200, 200, 80));
});
Headers and Footers with Page Numbers
Use the rich text API inside a header or footer to insert dynamic page numbers. The TextDescriptor provides several page-number methods.
page.Footer().Row(row =>
{
row.RelativeItem().Text("Confidential").FontSize(8).FontColor(Color.Grey);
row.RelativeItem().AlignRight().Text(t =>
{
t.Span("Page ").FontSize(8);
t.CurrentPageNumber().FontSize(8);
t.Span(" / ").FontSize(8);
t.TotalPages().FontSize(8);
});
});
| Method | Output |
|---|---|
CurrentPageNumber() | Current page number (e.g. "3") |
TotalPages() | Total document pages (e.g. "12") |
BeginPageNumberOfSection("name") | First page of a named section |
EndPageNumberOfSection("name") | Last page of a named section |
PageNumberWithinSection("name") | Relative page within a section (e.g. "2" of 5) |
TotalPagesWithinSection("name") | Total pages in a named section |
Multi-Page Documents
Call doc.Page() multiple times to define different page templates. Each call creates a separate page set with its own size, margins, and slots. Content inside a single .Content() slot automatically paginates when it overflows.
Document.Create(doc =>
{
// Cover page (no header/footer)
doc.Page(page =>
{
page.Size(PageSizes.A4);
page.Margin(80);
page.Content()
.AlignCenter().AlignMiddle()
.Text("Annual Report 2026").FontSize(36).Bold();
});
// Content pages (with header/footer)
doc.Page(page =>
{
page.Size(PageSizes.A4);
page.Margin(50);
page.Header().Text("Annual Report 2026").FontSize(10);
page.Content().Column(col =>
{
col.Spacing(10);
for (int i = 0; i < 200; i++)
col.Item().Text($"Paragraph {i + 1}: Lorem ipsum dolor sit amet...");
});
page.Footer().AlignCenter().Text(t =>
{
t.CurrentPageNumber();
t.Span(" / ");
t.TotalPages();
});
});
}).GeneratePdf("annual-report.pdf");
ContentDirection (RTL)
FolioPDF supports right-to-left (RTL) layouts for Arabic, Hebrew, and other RTL scripts. Set the direction at the page level or on individual containers.
// Page-level RTL
page.ContentFromRightToLeft();
// Container-level RTL
col.Item().ContentFromRightToLeft().Text("مرحبا بالعالم");
// Reset to LTR inside an RTL context
col.Item().ContentFromLeftToRight().Text("English text here");
When RTL is active, Row items flow from right to left, Column items keep their top-to-bottom order, and text spans resolve direction automatically from the script of their content unless overridden.
DocumentMetadata
Metadata is embedded in the PDF's /Info dictionary and displayed by viewers like Adobe Acrobat under Document Properties.
Document.Create(doc =>
{
doc.Page(page =>
{
page.Size(PageSizes.A4);
page.Content().Text("Metadata Example");
});
})
.WithMetadata(new DocumentMetadata
{
Title = "Quarterly Report Q1 2026",
Author = "Finance Department",
Subject = "Financial performance summary",
Keywords = "finance, quarterly, 2026, Q1",
Creator = "TrueSpar Reporting",
Producer = "FolioPDF",
Language = "en-US"
})
.GeneratePdf("report.pdf");
| Property | Type | Description |
|---|---|---|
Title | string? | Document title shown in viewer title bar |
Author | string? | Document author |
Subject | string? | Brief description of content |
Keywords | string? | Comma-separated keywords for search |
Creator | string? | Application that created the document |
Producer | string? | Library that produced the PDF (default: "FolioPDF") |
Language | string? | BCP 47 language tag (e.g. "en-US", "de-DE") |
CreationDate | DateTimeOffset | Document creation timestamp (default: now) |
ModifiedDate | DateTimeOffset | Last modification timestamp (default: now) |
DocumentSettings
Generation settings control output quality, compliance level, image handling, and accessibility tagging.
Document.Create(doc => { /* ... */ })
.WithSettings(new DocumentSettings
{
CompressDocument = true,
ImageCompressionQuality = ImageCompressionQuality.High,
ImageRasterDpi = 288,
PdfAConformance = PdfAConformance.PdfA_2B,
PdfUaConformance = PdfUaConformance.PdfUA_1,
AutoTagDocument = true,
ContentDirection = ContentDirection.LeftToRight
})
.GeneratePdf("compliant-output.pdf");
| Property | Default | Description |
|---|---|---|
CompressDocument | true | Whether to compress PDF streams |
ImageCompressionQuality | High | JPEG quality for opaque images: Best, High, Medium, Low, VeryLow |
ImageRasterDpi | 288 | DPI for rasterizing images (4x base 72 DPI) |
PdfAConformance | None | PDF/A level: None, PdfA_2A, PdfA_2B, PdfA_2U, PdfA_3A, PdfA_3B, PdfA_3U |
PdfUaConformance | None | PDF/UA level: None, PdfUA_1 |
AutoTagDocument | true | Auto-generate accessibility structure tags (P, Figure, Table) |
EnableForms | false | Enable AcroForm widget injection for interactive forms |
ContentDirection | LeftToRight | Default text/layout direction for the document |
Output Formats
Document.Create returns an IDocument that can be output as PDF, SVG, or raster images.
var document = Document.Create(doc => { /* ... */ });
// PDF output
document.GeneratePdf("output.pdf"); // to file
document.GeneratePdf(stream); // to stream
byte[] bytes = document.GeneratePdf(); // to byte array
// Open in default viewer (development only)
document.GeneratePdfAndShow();
// SVG output (one string per page)
IReadOnlyList<string> svgs = document.GenerateSvg();
document.GenerateSvg(index => $"page_{index}.svg");
// Raster images
var images = document.GenerateImages(new ImageGenerationSettings
{
ImageFormat = ImageFormat.Png,
RasterDpi = 300,
Quality = 90
});
document.GenerateImages(index => $"page_{index}.png");
Merging Documents
Combine multiple IDocument instances into a single PDF using Document.Merge.
var cover = Document.Create(doc =>
{
doc.Page(page =>
{
page.Size(PageSizes.A4);
page.Content().AlignCenter().AlignMiddle()
.Text("Cover Page").FontSize(36).Bold();
});
});
var body = Document.Create(doc =>
{
doc.Page(page =>
{
page.Size(PageSizes.A4);
page.Margin(50);
page.Content().Text("Main content...");
});
});
Document.Merge(cover, body)
.WithMetadata(new DocumentMetadata { Title = "Combined Document" })
.GeneratePdf("merged.pdf");
Tip: Document.Merge creates a new MergedDocument that implements IDocument and supports its own .WithMetadata() and .WithSettings() chains. Page numbering across merged documents is continuous — the footer's TotalPages() reflects the combined count.
Default Text Style
Set a page-level default text style that applies to all text elements on that page unless overridden.
page.DefaultTextStyle(TextStyle.Default
.WithFontFamily("Inter")
.WithFontSize(11)
.WithColor(Color.FromHex("#333333")));
// Or via a handler
page.DefaultTextStyle(style => style
.WithFontFamily("Inter")
.WithFontSize(11));
Note: Each slot (Header, Content, Footer) inherits the page default text style. Span-level overrides (e.g. .Bold(), .FontSize(14)) take precedence over the default.