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);
MethodDescription
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.

SlotDescriptionRepeats on every page?
page.Background()Drawn behind header + content + footerYes
page.Header()Top section, above contentYes
page.Content()Primary content — drives paginationN/A (flows across pages)
page.Footer()Bottom section, below contentYes
page.Foreground()Drawn in front of header + content + footerYes
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);
    });
});
MethodOutput
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");
PropertyTypeDescription
Titlestring?Document title shown in viewer title bar
Authorstring?Document author
Subjectstring?Brief description of content
Keywordsstring?Comma-separated keywords for search
Creatorstring?Application that created the document
Producerstring?Library that produced the PDF (default: "FolioPDF")
Languagestring?BCP 47 language tag (e.g. "en-US", "de-DE")
CreationDateDateTimeOffsetDocument creation timestamp (default: now)
ModifiedDateDateTimeOffsetLast 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");
PropertyDefaultDescription
CompressDocumenttrueWhether to compress PDF streams
ImageCompressionQualityHighJPEG quality for opaque images: Best, High, Medium, Low, VeryLow
ImageRasterDpi288DPI for rasterizing images (4x base 72 DPI)
PdfAConformanceNonePDF/A level: None, PdfA_2A, PdfA_2B, PdfA_2U, PdfA_3A, PdfA_3B, PdfA_3U
PdfUaConformanceNonePDF/UA level: None, PdfUA_1
AutoTagDocumenttrueAuto-generate accessibility structure tags (P, Figure, Table)
EnableFormsfalseEnable AcroForm widget injection for interactive forms
ContentDirectionLeftToRightDefault 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.