Generation
Create New Document - DocumentCreation
The following sample illustrates how to use the Layout::FlowDocument API to create documents from scratch. Instead of positioning every element on a page, the content is described as a tree of paragraphs, tables, lists, shapes, charts, and floats, which is then paginated into a PDF document. \
Each function below produces a document:
An invoice: Tables, cell merging, styling, headers/footers, images.
A report: Sections, page setup, lists, charts, page numbers.
A newsletter: Shapes, shape text boxes, floats, hyperlinks, tab stops.
A content tree walk: Post-processing of an existing content tree.
//
// Copyright (c) 2001-2026 by Apryse Software Inc. All Rights Reserved.
//
using System;
using System.Globalization;
using pdftron;
using pdftron.Common;
using pdftron.SDF;
using pdftron.PDF;
using pdftron.Layout;
namespace DocumentCreationTestCS
{
class Class1
{
private static pdftron.PDFNetLoader pdfNetLoader = pdftron.PDFNetLoader.Instance();
static Class1() { }
static readonly string input_path = "../../../../../../../../../Samples/TestFiles/";
static readonly string output_path = "../../../../../../../../../Samples/TestFiles/Output/";
static string IntToString(int val) => val.ToString(CultureInfo.InvariantCulture);
static string MoneyToString(double val) => "$" + val.ToString("F2", CultureInfo.InvariantCulture);
static Paragraph AddHeading(ContentContainer container, string text, double fontSize, byte r, byte g, byte b)
{
Paragraph heading = container.AddParagraph(text);
TextStyledElement style = heading.GetTextStyledElement();
style.SetFontSize(fontSize);
style.SetBold(true);
style.SetTextColor(r, g, b);
heading.SetSpaceBefore(12);
heading.SetSpaceAfter(6);
return heading;
}
static TableRow AddTableRowWithText(Table table, string[] texts, bool bold, byte backR, byte backG, byte backB)
{
TableRow row = table.AddTableRow();
for (int i = 0; i < texts.Length; ++i)
{
TableCell cell = row.AddTableCell();
cell.SetBackgroundColor(backR, backG, backB);
cell.SetVerticalAlignment(TableCell.CellAlignmentVertical.e_center);
Paragraph para = cell.AddParagraph(texts[i]);
para.SetStartIndent(3);
TextStyledElement style = para.GetTextStyledElement();
style.SetFontSize(10);
style.SetBold(bold);
para.SetJustificationMode(i == 0 ? Paragraph.TextJustification.e_left : Paragraph.TextJustification.e_right);
}
return row;
}
static void AddPageNumberFooter(Section section, string title)
{
Section.PageGroup[] groups = { Section.PageGroup.e_first_page, Section.PageGroup.e_even_pages, Section.PageGroup.e_odd_pages };
foreach (var group in groups)
{
ContentContainer footer = section.GetOrCreateFooter(group);
Paragraph para = footer.AddParagraph();
para.SetJustificationMode(Paragraph.TextJustification.e_center);
TextStyledElement style = para.GetTextStyledElement();
style.SetFontSize(9);
style.SetTextColor(120, 120, 120);
style.SetItalic(true);
para.AddText(title + " | Page ");
para.AddPageNumber(PageNumber.NumberType.e_current_page);
para.AddText(" of ");
para.AddPageNumber(PageNumber.NumberType.e_total_pages);
}
}
static int CreateInvoice()
{
try
{
using (FlowDocument doc = new FlowDocument())
{
doc.SetDefaultPageSize(612, 792);
doc.SetDefaultMargins(54, 54, 54, 54);
Section section = doc.GetCurrentSection();
ContentContainer header = section.GetOrCreateHeader(Section.PageGroup.e_odd_pages);
Paragraph headerPara = header.AddParagraph("SYH Supply Co.");
headerPara.SetJustificationMode(Paragraph.TextJustification.e_right);
headerPara.GetTextStyledElement().SetFontSize(9);
headerPara.GetTextStyledElement().SetTextColor(120, 120, 120);
AddPageNumberFooter(section, "Invoice INV-2025-0042");
Paragraph title = doc.AddParagraph();
Float logoFloat = title.AddFloat();
logoFloat.SetHorizontalReferencePoint(Float.FloatReferencePoint.e_reference_page);
logoFloat.SetVerticalReferencePoint(Float.FloatReferencePoint.e_reference_paragraph);
logoFloat.SetPositionX(400);
logoFloat.SetPositionY(0);
logoFloat.SetObstructionType(Float.FloatObstructionType.e_square);
logoFloat.AddParagraph().AddImage(96, 96, input_path + "logo_red.png");
title.AddText("INVOICE");
TextStyledElement titleStyle = title.GetTextStyledElement();
titleStyle.SetFontSize(28);
titleStyle.SetBold(true);
titleStyle.SetTextColor(0, 51, 102);
Paragraph subtitle = doc.AddParagraph("Invoice #INV-2025-0042\nIssued: March 14, 2025\nDue: April 13, 2025");
subtitle.GetTextStyledElement().SetFontSize(10);
subtitle.SetSpaceAfter(18);
Table addresses = doc.AddTable();
addresses.SetDefaultColumnWidth(240);
addresses.SetDefaultRowHeight(16);
TableRow addressRow = addresses.AddTableRow();
string[] addressTitles = { "BILL TO", "SHIP TO" };
string[] addressBodies = {
"Contoso Ltd.\n123 Maple Street\nVancouver, BC V6B 1A1\nCanada",
"Contoso Warehouse #4\n980 Industrial Way\nBurnaby, BC V5J 3J1\nCanada"
};
for (int i = 0; i < 2; ++i)
{
TableCell cell = addressRow.AddTableCell();
cell.SetBackgroundColor(240, 244, 248);
cell.SetBorder(0.5, 200, 210, 220);
Paragraph caption = cell.AddParagraph(addressTitles[i]);
caption.SetStartIndent(3);
TextStyledElement captionStyle = caption.GetTextStyledElement();
captionStyle.SetFontSize(9);
captionStyle.SetBold(true);
captionStyle.SetTextColor(0, 51, 102);
Paragraph body = cell.AddParagraph(addressBodies[i]);
body.SetStartIndent(3);
body.GetTextStyledElement().SetFontSize(10);
}
doc.AddParagraph(" ");
Table items = doc.AddTable();
items.SetDefaultColumnWidth(120);
items.SetDefaultRowHeight(18);
items.SetBorder(0.75, 0, 51, 102);
string[] headers = { "Description", "Qty", "Unit price", "Amount" };
TableRow headerRow = AddTableRowWithText(items, headers, true, 0, 51, 102);
for (ContentNodeIterator cellItr = headerRow.GetContentNodeIterator(); cellItr.HasNext(); cellItr.Next())
{
TableCell cell = cellItr.Current().AsTableCell();
if (cell == null) continue;
for (ContentNodeIterator paraItr = cell.GetContentNodeIterator(); paraItr.HasNext(); paraItr.Next())
{
Paragraph p = paraItr.Current().AsParagraph();
if (p != null) p.GetTextStyledElement().SetTextColor(255, 255, 255);
}
}
(string desc, int qty, double price)[] lineItems = {
("Height adjustable desk, oak finish", 2, 4800.00),
("Ergonomic office chair", 5, 950.00),
("Meeting room whiteboard, 180 cm", 1, 1200.00),
("On-site assembly and delivery", 1, 2500.00),
};
double subtotal = 0;
for (int i = 0; i < lineItems.Length; ++i)
{
double amount = lineItems[i].qty * lineItems[i].price;
subtotal += amount;
string[] cells = {
lineItems[i].desc,
IntToString(lineItems[i].qty),
MoneyToString(lineItems[i].price),
MoneyToString(amount)
};
bool even = (i % 2) == 0;
AddTableRowWithText(items, cells, false, even ? (byte)255 : (byte)240, even ? (byte)255 : (byte)244, even ? (byte)255 : (byte)248);
}
double tax = subtotal * 0.12;
(string label, double value, bool bold)[] totals = {
("Subtotal", subtotal, false),
("GST/PST (12%)", tax, false),
("Total due (CAD)", subtotal + tax, true),
};
for (int i = 0; i < totals.Length; ++i)
{
string[] cells = { "", "", totals[i].label, MoneyToString(totals[i].value) };
AddTableRowWithText(items, cells, totals[i].bold, 255, 255, 255);
items.GetTableCell(0, (uint)(lineItems.Length + 1 + i)).MergeCellsRight(1);
}
Paragraph notes = doc.AddParagraph("Payment is due within 30 days. Late payments are subject to a 1.5% monthly interest charge. Please reference the invoice number with your payment.");
notes.SetSpaceBefore(24);
notes.GetTextStyledElement().SetFontSize(9);
notes.GetTextStyledElement().SetItalic(true);
notes.GetTextStyledElement().SetTextColor(90, 90, 90);
Paragraph signature = doc.AddParagraph();
signature.SetSpaceBefore(18);
signature.AddImage(140, 50, input_path + "signature.jpg");
signature.AddText("\nAuthorized signature");
using (PDFDoc pdf = doc.PaginateToPDF())
{
pdf.Save(output_path + "created_invoice.pdf", SDFDoc.SaveOptions.e_linearized);
}
}
Console.WriteLine("Saved created_invoice.pdf");
return 0;
}
catch (PDFNetException e)
{
Console.WriteLine(e.Message);
return 1;
}
}
static int CreateReportWithChart()
{
try
{
using (FlowDocument doc = new FlowDocument())
{
doc.SetDefaultPageSize(612, 792);
doc.SetDefaultMargins(72, 72, 72, 72);
Section dataSection = doc.GetCurrentSection();
AddPageNumberFooter(dataSection, "Quarterly Revenue Report");
AddHeading(doc, "Quarterly Revenue Report 2025", 22, 0, 51, 102);
Paragraph intro = doc.AddParagraph("The table below summarizes the revenue by region for the first three quarters of the fiscal year. All figures are given in thousands of Canadian dollars and exclude intercompany transactions.");
intro.GetTextStyledElement().SetFontSize(11);
intro.SetSpaceAfter(12);
Table table = doc.AddTable();
table.SetDefaultColumnWidth(90);
table.SetDefaultRowHeight(18);
table.SetBorder(0.75, 120, 120, 120);
AddTableRowWithText(table, new[] { "Region", "Q1", "Q2", "Q3", "Total" }, true, 220, 230, 240);
(string region, int q1, int q2, int q3)[] rows = {
("North America", 1250, 1410, 1580),
("Europe", 910, 980, 1120),
("Asia Pacific", 640, 720, 905),
("Latin America", 310, 355, 390),
};
int t1 = 0, t2 = 0, t3 = 0;
foreach (var r in rows)
{
t1 += r.q1; t2 += r.q2; t3 += r.q3;
AddTableRowWithText(table, new[] { r.region, IntToString(r.q1), IntToString(r.q2), IntToString(r.q3), IntToString(r.q1 + r.q2 + r.q3) }, false, 255, 255, 255);
}
AddTableRowWithText(table, new[] { "All regions", IntToString(t1), IntToString(t2), IntToString(t3), IntToString(t1 + t2 + t3) }, true, 240, 240, 240);
AddHeading(doc, "Key observations", 14, 0, 51, 102);
List observations = doc.AddList();
observations.SetNumberFormat(List.NumberFormat.e_decimal, ".", true);
observations.GetLabelStyle().SetBold(true);
observations.AddItem().AddParagraph("Revenue grew in every region, with Asia Pacific showing the strongest quarter over quarter growth.");
observations.AddItem().AddParagraph("North America remains the largest market, contributing roughly 40% of the total revenue.");
ListItem risks = observations.AddItem();
risks.AddParagraph("Risks that may affect the Q4 forecast:");
List riskList = risks.AddList();
riskList.SetNumberFormat(List.NumberFormat.e_lower_letter, ")", true);
riskList.AddItem().AddParagraph("Currency fluctuations in Latin America.");
riskList.AddItem().AddParagraph("Longer sales cycles in the enterprise segment.");
Section chartSection = doc.AddSection();
chartSection.SetPageSize(792, 612);
chartSection.SetMargins(54, 54, 54, 54);
AddPageNumberFooter(chartSection, "Quarterly Revenue Report");
AddHeading(chartSection, "Revenue by region and quarter", 18, 0, 51, 102);
string chartDefinition = "{" +
"\"chartType\":\"bar\"," +
"\"title\":\"Revenue by region (thousands CAD)\"," +
"\"theme\":\"vivid\"," +
"\"data\":{" +
"\"categories\":{ \"data\": [\"Q1\", \"Q2\", \"Q3\"] }," +
"\"series\": [" +
"{ \"name\": { \"data\": [\"North America\"] }, \"data\": { \"data\": [1250, 1410, 1580] } }," +
"{ \"name\": { \"data\": [\"Europe\"] }, \"data\": { \"data\": [910, 980, 1120] } }," +
"{ \"name\": { \"data\": [\"Asia Pacific\"] }, \"data\": { \"data\": [640, 720, 905] } }," +
"{ \"name\": { \"data\": [\"Latin America\"] }, \"data\": { \"data\": [310, 355, 390] } }" +
"]" +
"}" +
"}";
Paragraph chartPara = chartSection.AddParagraph();
chartPara.SetJustificationMode(Paragraph.TextJustification.e_center);
Chart chart = chartPara.AddChart(560, 340, chartDefinition);
chart.SetWidth(600);
chart.SetHeight(360);
Paragraph caption = chartSection.AddParagraph("Figure 1: revenue distribution across the four sales regions.");
caption.SetJustificationMode(Paragraph.TextJustification.e_center);
caption.GetTextStyledElement().SetItalic(true);
caption.GetTextStyledElement().SetFontSize(10);
Console.WriteLine("Report sections: " + doc.GetNumSections() + ", second section page width: " + doc.GetSection(1).GetPageWidth().ToString(CultureInfo.InvariantCulture));
using (PDFDoc pdf = doc.PaginateToPDF())
{
pdf.Save(output_path + "created_report.pdf", SDFDoc.SaveOptions.e_linearized);
}
}
Console.WriteLine("Saved created_report.pdf");
return 0;
}
catch (PDFNetException e)
{
Console.WriteLine(e.Message);
return 1;
}
}
static int CreateNewsletter()
{
try
{
string bodyText = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.";
using (FlowDocument doc = new FlowDocument())
{
doc.SetDefaultPageSize(612, 792);
doc.SetDefaultMargins(60, 60, 60, 60);
Section section = doc.GetCurrentSection();
AddPageNumberFooter(section, "The Monthly Dispatch");
Paragraph mastheadPara = doc.AddParagraph();
Shape masthead = mastheadPara.AddShape(Shape.ShapeType.e_rectangle_rounded_corners, 492, 70);
masthead.SetCornerRadius(10);
masthead.SetBackgroundColor(0, 51, 102);
masthead.SetOutlineColor(0, 31, 62);
masthead.SetOutlineThickness(1.5);
ContentContainer mastheadText = masthead.GetTextBox();
Paragraph mastheadTitle = mastheadText.AddParagraph("The Monthly Dispatch");
mastheadTitle.SetJustificationMode(Paragraph.TextJustification.e_center);
TextStyledElement mastheadStyle = mastheadTitle.GetTextStyledElement();
mastheadStyle.SetFontSize(24);
mastheadStyle.SetBold(true);
mastheadStyle.SetTextColor(255, 255, 255);
Paragraph mastheadSub = mastheadText.AddParagraph("Issue 42 - March 2025");
mastheadSub.SetJustificationMode(Paragraph.TextJustification.e_center);
mastheadSub.GetTextStyledElement().SetFontSize(10);
mastheadSub.GetTextStyledElement().SetTextColor(200, 215, 230);
AddHeading(doc, "Documents, assembled", 16, 0, 51, 102);
Paragraph lead = doc.AddParagraph();
lead.SetJustificationMode(Paragraph.TextJustification.e_left);
lead.SetTextIndent(18);
lead.SetSpaceAfter(10);
Float pullQuote = lead.AddFloat();
pullQuote.SetHorizontalReferencePoint(Float.FloatReferencePoint.e_reference_page);
pullQuote.SetVerticalReferencePoint(Float.FloatReferencePoint.e_reference_paragraph);
pullQuote.SetPositionX(380);
pullQuote.SetPositionY(10);
pullQuote.SetObstructionType(Float.FloatObstructionType.e_square);
Paragraph quoteHolder = pullQuote.AddParagraph();
Shape quoteBox = quoteHolder.AddShape(Shape.ShapeType.e_rectangle_rounded_corners, 190, 70);
quoteBox.SetCornerRadius(6);
quoteBox.SetBackgroundColor(240, 246, 255);
quoteBox.SetOutlineColor(0, 51, 102);
quoteBox.SetOutlineThickness(1.0);
ContentContainer quoteText = quoteBox.GetTextBox();
Paragraph quote = quoteText.AddParagraph("\"The content tree lets you describe a document, not a page.\"");
quote.SetStartIndent(6);
quote.SetEndIndent(6);
TextStyledElement quoteStyle = quote.GetTextStyledElement();
quoteStyle.SetFontSize(12);
quoteStyle.SetItalic(true);
quoteStyle.SetTextColor(0, 51, 102);
lead.AddText(bodyText);
lead.AddText(" Read more about the API at ");
TextRun link = lead.AddHyperlink("apryse.com", "https://www.apryse.com");
link.GetTextStyledElement().SetTextColor(0, 102, 204);
lead.AddText(".");
Paragraph columnLeft = doc.AddParagraph(bodyText);
columnLeft.SetStartIndent(0);
columnLeft.SetEndIndent(260);
columnLeft.GetTextStyledElement().SetFontSize(10);
Paragraph columnRight = doc.AddParagraph(bodyText);
columnRight.SetStartIndent(260);
columnRight.SetEndIndent(0);
columnRight.GetTextStyledElement().SetFontSize(10);
AddHeading(doc, "Upcoming webinars", 14, 0, 51, 102);
(string date, string topic, string host)[] schedule = {
("Apr 02", "Building documents from scratch", "R. Fischer"),
("Apr 16", "Charts and data visualization", "M. Okafor"),
("Apr 30", "Accessible PDF output", "L. Tanaka"),
};
foreach (var w in schedule)
{
Paragraph row = doc.AddParagraph();
row.AddTabStop(80);
row.AddTabStop(360);
row.GetTextStyledElement().SetFontSize(10);
row.AddText(w.date + "\t" + w.topic + "\t" + w.host);
}
Paragraph gallery = doc.AddParagraph();
gallery.SetSpaceBefore(16);
gallery.SetJustificationMode(Paragraph.TextJustification.e_center);
Shape arrow = gallery.AddShape(Shape.ShapeType.e_arrow, 90, 40);
arrow.SetBackgroundColor(0, 153, 102);
arrow.SetOutlineColor(0, 102, 68);
arrow.SetOutlineThickness(1);
arrow.SetArrowHeadSize(18);
gallery.AddText(" ");
gallery.AddImage(160, 120, input_path + "butterfly.png");
using (PDFDoc pdf = doc.PaginateToPDF())
{
pdf.Save(output_path + "created_newsletter.pdf", SDFDoc.SaveOptions.e_linearized);
}
}
Console.WriteLine("Saved created_newsletter.pdf");
return 0;
}
catch (PDFNetException e)
{
Console.WriteLine(e.Message);
return 1;
}
}
static void RestyleContentTree(ContentNode node, ref bool highlight)
{
for (ContentNodeIterator itr = node.GetContentNodeIterator(); itr.HasNext(); itr.Next())
{
ContentElement el = itr.Current();
TextRun textRun = el.AsTextRun();
if (textRun != null)
{
if (highlight)
{
TextStyledElement style = textRun.GetTextStyledElement();
style.SetBold(true);
style.SetBackgroundColor(255, 245, 180);
}
highlight = !highlight;
continue;
}
TableCell cell = el.AsTableCell();
if (cell != null) cell.SetBorder(0.5, 150, 150, 150);
ContentNode child = el.AsContentNode();
if (child != null) RestyleContentTree(child, ref highlight);
}
}
static int RestyleExistingContent()
{
try
{
using (FlowDocument doc = new FlowDocument())
{
doc.SetDefaultPageSize(612, 792);
doc.SetDefaultMargins(72, 72, 72, 72);
AddHeading(doc, "Content tree post-processing", 18, 0, 51, 102);
for (int i = 0; i < 4; ++i)
{
Paragraph para = doc.AddParagraph();
para.SetSpaceAfter(8);
para.AddText("Sentence " + IntToString(i * 2) + ". ");
para.AddText("Sentence " + IntToString(i * 2 + 1) + ". ");
para.AddText("The style of these runs is decided after the fact.");
}
Table table = doc.AddTable();
table.SetDefaultColumnWidth(150);
table.SetDefaultRowHeight(16);
for (int rowIndex = 0; rowIndex < 3; ++rowIndex)
{
TableRow row = table.AddTableRow();
for (int colIndex = 0; colIndex < 3; ++colIndex)
{
TableCell cell = row.AddTableCell();
cell.AddParagraph("R" + IntToString(rowIndex) + " / C" + IntToString(colIndex));
}
}
bool highlight = false;
RestyleContentTree(doc, ref highlight);
Console.WriteLine("Table has " + table.GetNumRows() + " rows and " + table.GetNumColumns() + " columns.");
using (PDFDoc pdf = doc.PaginateToPDF())
{
pdf.Save(output_path + "created_restyled.pdf", SDFDoc.SaveOptions.e_linearized);
}
}
Console.WriteLine("Saved created_restyled.pdf");
return 0;
}
catch (PDFNetException e)
{
Console.WriteLine(e.Message);
return 1;
}
}
[STAThread]
static void Main(string[] args)
{
int ret = 0;
PDFNet.Initialize();
try
{
ret |= CreateInvoice();
ret |= CreateReportWithChart();
ret |= CreateNewsletter();
ret |= RestyleExistingContent();
}
catch (PDFNetException e)
{
Console.WriteLine(e.Message);
ret = 1;
}
catch (Exception e)
{
Console.WriteLine(e.Message);
ret = 1;
}
PDFNet.Terminate();
Console.WriteLine("Done.");
Environment.ExitCode = ret;
}
}
}