How to layout PDF pages
PdfDocumentBuilder.Generate
method provides an object of Document
type to its delegate. Use
Pages
method of that object to construct your document pages. You must provide a delegate that
accepts a parameter of PageLayout
type to the method.
One call to the method is enough if all pages in your PDF document have the same layout. In case
you have different layouts in your document, use more than one call to Pages
method. For example,
you can call the method once to layout a cover page. Then call the method again to describe the
report body.
Each call to Pages
creates at least one page. The created page can be empty if there is no
content provided for it.
This article is part of a series about Layout API for PDF generation. If you are new to the API, read the Getting Started with Layout API part first.
9.3.17105-dev 9.3.17105-dev14,681 passed Total NuGet downloads 4,234,061
Content slots
To describe the layout of pages, use pre-defined containers. I also call them content slots. You
can access these containers by calling methods of a PageLayout
object.
There are three main slots: Content
, Header
, and Footer
. And two slots for additional
content: Background
and Foreground
. By default, all five containers are empty and occupy no
page space. You distribute your page content between the slots according to your requirements.
Read Containers and their content article to know how to layout your pages using containers.
Header and footer
You won't be surprised to know that the header and footer content goes into Header
and Footer
slots, respectively. The API repeats these slots above and below the main content on each generated
page. Layout API never splits header or footer content between pages. You will get a
LayoutException
if a header or a footer does not fit on a page.
Main content
The main page content, like images, tables, and text, goes into Content
slot. Layout API
automatically splits that content into pages.
The following code assigns simple text content to all main content slots. The code also sets background colors for the slots.
PdfDocumentBuilder.Create().Generate("pages-main-slots.pdf", doc => doc.Pages(pages => {
pages.Header()
.Text("This text goes to the header")
.BackgroundColor(new PdfRgbColor(66, 135, 245));
pages.Content()
.Text("The main content goes in this slot")
.BackgroundColor(new PdfRgbColor(242, 233, 206));
pages.Footer()
.Text("This is the footer contents")
.BackgroundColor(new PdfRgbColor(194, 192, 188));
}));
Check the result of the code in pages-main-slots.pdf.
As you can see, each slot occupies only part of the page. The exact area depends on the content
inside the slot. Header
slot sticks to the top of the page. Content
slot starts immediately
after the Header
. Footer
slot sticks to the bottom.
Additional content
Background
and Foreground
provide containers usable for watermarks, overlays, and backgrounds.
All content in Background
slot goes below the header, the footer, and the main content of a page.
The content in Foreground
slot covers everything added to the page.
These containers occupy the whole page. This is the unique feature of these containers. The API repeats their contents on each generated page. Exactly like it does for header and footer containers.
I added some lines to the above code to show how to use Foreground
and Background
containers.
PdfDocumentBuilder.Create().Generate("pages-all-slots.pdf", doc => doc.Pages(pages => {
// ...
pages.Background()
.Background(new PdfRgbColor(208, 227, 204));
pages.Foreground()
.Rotate(45)
.Text(new string(' ', 30) + "Your watermark could go here, in the foreground");
}));
For Background
container, I do not provide any text or something. I only specify background
color. Everything below the header, the main content, and the footer will show that shade of green.
I rotate the content in Foreground
container and add some text to it. Because of the leading
spaces, the text does not cover the header or the footer contents. Content in all containers is
visible on the page.
You can see the result of the code in pages-all-slots.pdf.
Settings
So far, all code snippets were focusing on containers that make up the pages. It's time to look at how you can customize the pages themselves, rather than their content slots.
To set up pages, use methods of PageLayout
class. Remember that a PageLayout
object can
describe more than one page. Methods calls will affect all the pages you describe.
Size
Probably, the most basic setting is the page size. You can use Size
method to specify one of the
predefined sizes for your pages. There are all the usual sizes like A4, Ledger, or Monarch
Envelope.
Optionally, you can specify an orientation for the pages. It's possible to set a custom pages size by providing its width and height in points.
Margins
Page margins may contribute to readability, aesthetics, and overall composition of your pages.
Set all margins to the same value in points using Margin
method. Use MarginVertical
and
MarginHorizontal
methods to set only vertical or horizontal margins. Use
MarginLeft/Top/Right/Bottom
methods to specify each margin independently.
Text style
Layout API provides TextStyle
class for creating text styles. You create and apply styles to text
to achieve the desired appearance.
There are cases when a large part of a text on your pages uses the same style. You can set that style as the default text style for the pages. The default style affects all the text in the main content slots. But you can override the default style for certain elements. Just apply another style to pieces of text that should look different.
PdfDocumentBuilder.Create().Generate("pages-text-styles.pdf", doc =>
{
var defaultStyle = TextStyle.Parent.FontSize(30);
var tightSpacing = TextStyle.Parent.LetterSpacing(-0.1);
doc.Pages(pages =>
{
pages.TextStyle(defaultStyle);
pages.Content().Text(t =>
{
t.Line("This line uses the default text style.");
t.Line("This line uses a tight letter spacing.").Style(tightSpacing);
t.Line("This line uses the default text style, again.");
});
});
});
You can see the result of the code in pages-text-styles.pdf.
Please note that you can set up document-wide text styles using Document.Typography
method. Each
property in Typography
class defines a style for a use case. These styles override the style
specified by PageLayout.TextStyle
method. For example, Body
property overrides the default
style for text in Content
containers.
Content direction
There are languages written from right to left. Layout API handles text in these languages just fine. But you would need to specify the text direction explicitly.
If most of the text on your pages is in an RTL language, you can set the right-to-left as the default content direction for the pages. You'll be able to specify different direction for any container in your pages.
PdfDocumentBuilder.Create().Generate("pages-content-direction.pdf", doc =>
{
var defaultTextStyle = doc.TextStyleWithFont(SystemFont.Family("Calibri"));
doc.Pages(pages =>
{
pages.Size(PdfPaperSize.A6).TextStyle(defaultTextStyle);
pages.ContentFromRightToLeft();
pages.Content().Column(column =>
{
column.Item()
.ContentFromLeftToRight()
.Text("There are languages written from right to left.");
column.Item()
.Text("هناك لغات تكتب من اليمين إلى اليسار.");
column.Item()
.Text("יש שפות שנכתבות מימין לשמאל.");
});
});
});
In the code above, I set right-to-left as the default content direction. For the container with the English version of the phrase, I change the direction to left-to-right. You can see the result of the code in pages-content-direction.pdf.
Page numbers
When generating PDF, Layout API automatically calculates the current page number. It also calculate
the total number of pages in the document. You can get the numbers by calling CurrentPageNumber
and PageCount
methods of any text container. No matter if the container is in the header, footer
or main content slot.
PdfDocumentBuilder.Create().Generate("pages-page-numbers.pdf", doc => doc.Pages(pages =>
{
pages.Content().Text(t =>
{
t.Span("This line is on page ");
t.CurrentPageNumber();
t.Line();
t.Line("Check the footer.");
});
pages.Footer().Row(r =>
{
r.AutoItem().Text("Created with Docotic.Pdf Layout API");
r.RelativeItem(2).Text(t =>
{
t.AlignRight();
t.Span("Page ");
t.CurrentPageNumber();
t.Span(" of ");
t.PageCount();
});
});
}));
The result of the code is in pages-page-numbers.pdf.
Both methods return TextPageNumber
that you can use to format the numbers.
Add header and footer to PDF documents example shows how to apply a custom formatting to page numbers.
Sample code
We have some sample apps that cover the aforementioned features in greater detail. Please spend some time checking them out.