Pages, sizes and orientation
A PdfDocument starts with no pages. You add each page with AddPage, set its size and
orientation, and then draw on it through an XGraphics. This page covers page sizes, landscape
pages, the /Rotate setting, units, and the page boxes.
Add a page and set its size
AddPage returns the new page. Set its Size and Orientation before you draw anything on it,
then create an XGraphics for it:
var page = document.AddPage();
// Size and Orientation are set before anything is drawn. The Size setter throws
// on a page that already has content, because writing a new media box would
// crop what is there rather than scale it - see the PageResize demo for what
// to do when the page has already been drawn on.
page.Size = size;
page.Orientation = orientation;
var gfx = XGraphics.FromPdfPage(page);
var width = page.Width.Point;
var height = page.Height.Point;
PageSize has the ISO A, B and C series (A0 to A10, B0 to B10, C0 to C10), the RA and
SRA printing sizes, and the North American sizes Letter, Legal, Ledger, Tabloid,
Executive and Statement. PageSizeConverter.ToSize(PageSize.A4) gives the size in points as an
XSize.
InsertPage(index) adds a page at a position instead of at the end.
Custom sizes
For a size that is not in PageSize, set Width and Height. Both are XUnit values, so you can
give them in any unit:
PdfPage label = document.AddPage();
label.Width = XUnit.FromMillimeter(100);
label.Height = XUnit.FromMillimeter(150);
After this, label.Size is PageSize.Undefined.
Portrait and landscape
PageOrientation.Landscape turns the page on its side: A4 landscape is 842 points wide and 595
high. Width and Height report the page as the reader sees it, so read them after you set the
orientation and draw inside them.
Units
PDF measures in points. One point is 1/72 inch, so an A4 page is about 595 by 842 points. An XUnit
holds a length and converts it to other units:
var pageWidth = page.Width;
var pageHeight = page.Height;
string[] lines =
{
$"{pageWidth.Point:0.#} x {pageHeight.Point:0.#} points",
$"{pageWidth.Millimeter:0.#} x {pageHeight.Millimeter:0.#} mm",
$"{pageWidth.Inch:0.00} x {pageHeight.Inch:0.00} inches",
$"PageSizeConverter.ToSize({size}) = {PageSizeConverter.ToSize(size)}"
};
To create a length, use XUnit.FromPoint, FromMillimeter, FromCentimeter or FromInch. An
XUnit converts to and from double without a cast, and the double is always in points.
XGraphics draws in points by default. To draw in another unit, pass an XGraphicsUnit when you
create it:
XGraphics gfx = XGraphics.FromPdfPage(page, XGraphicsUnit.Millimeter);
gfx.DrawRectangle(XPens.Black, 20, 20, 170, 257); // millimetres
The origin is the top left corner of the page, and y increases down the page.
Rotate a page for display
Rotate asks the PDF reader to turn the page when it shows or prints it. It does not change the
page size, and it must be a multiple of 90 degrees:
if (size == PageSize.A6)
{
page.Rotate = 90;
// Broken over two lines by hand. A6 is 298pt wide and this is the one page
// here where the measure is tight enough that a single line of it would run
// to the frame - DrawString does not wrap, so nothing would break it.
gfx.DrawString("page.Rotate = 90: the reader turns this,", small,
XBrushes.Crimson, new XPoint(56, y + 8));
gfx.DrawString("the drawing did not.", small,
XBrushes.Crimson, new XPoint(56, y + 20));
}
When Rotate changes, what you already drew turns with the page. In the demo, the reader shows the
A6 page on its side, and its text too.
If the page already has a Rotate value when you first draw on it, XGraphics allows for it. It
turns its own coordinates so that the origin is the corner the reader sees at the top left. What you
draw is then upright for the reader. This matters most for pages you import from another PDF.
For a page that should be wider than it is high, use Orientation, not Rotate.
Page boxes
Each page has up to five boxes, all PdfRectangle values in points:
MediaBoxis the whole sheet.Size,WidthandHeightset it for you.CropBoxis the area a reader shows.BleedBox,TrimBoxandArtBoxare for print production: the area the printing reaches, the finished page after cutting, and the meaningful content.
For documents that go to a printer with bleed and crop marks, TrimMargins does this work for you.
See Page resizing and bleed.
Things to know
- The default page size depends on the machine. A new page is A4 if the current region uses
metric measurements, and Letter if it does not. A server and a developer's laptop can produce
different sizes. Set
Sizeon every page. - Set the size before you draw. Setting
Size,WidthorHeighton a page that already has content throwsInvalidOperationException, because a new media box would crop the drawing, not scale it. To change the size of a finished page, usePdfPage.Resize. See Page resizing and bleed. - Keep the page that
AddPagereturns. EachXGraphicsdraws on one page. For a second page, callAddPageagain and create a newXGraphicsfrom the new page. - One
XGraphicsfor each page at a time. Creating a secondXGraphicsfor a page throws until you dispose the first one. To draw on a page again later, dispose the firstXGraphics, then create a new one. - Draw behind existing content.
XGraphics.FromPdfPage(page, XGraphicsPdfPageOptions.Prepend)draws beneath what is on the page.Append, the default, draws on top, andReplacestarts with a blank page. DrawStringdoes not wrap. On a small page, a line of text can run past the edge. Use XTextFormatter or a PinataLayout document for text that must fit a width.- For long documents, PinataLayout adds pages for you. It breaks lines and pages and repeats headers and footers. See Documents, sections and styles.
See it in action
The Orientation demo makes six pages in different sizes and both orientations. Each page shows its size in points, millimetres and inches, and one page is rotated.
The full Orientation demo
var document = new PdfDocument();
var title = new XFont("Liberation Sans", 22, XFontStyle.Bold);
var label = new XFont("Liberation Sans", 10);
var small = new XFont("Liberation Sans", 8);
(PageSize Size, PageOrientation Orientation, string Note)[] pages =
{
(PageSize.A4, PageOrientation.Portrait, "the ISO default"),
(PageSize.A4, PageOrientation.Landscape, "the same page, turned"),
(PageSize.A3, PageOrientation.Portrait, "twice A4"),
(PageSize.A6, PageOrientation.Portrait, "an eighth of A3"),
(PageSize.Letter, PageOrientation.Portrait, "North American"),
(PageSize.Legal, PageOrientation.Landscape, "North American, turned")
};
foreach ((var size, var orientation, var note) in pages)
{
var page = document.AddPage();
// Size and Orientation are set before anything is drawn. The Size setter throws
// on a page that already has content, because writing a new media box would
// crop what is there rather than scale it - see the PageResize demo for what
// to do when the page has already been drawn on.
page.Size = size;
page.Orientation = orientation;
var gfx = XGraphics.FromPdfPage(page);
var width = page.Width.Point;
var height = page.Height.Point;
// A frame, corner ticks and a diagonal, so the shape of the page and which way
// up it is can be read at a glance.
gfx.DrawRectangle(new XPen(XColors.Gainsboro, 1), 24, 24, width - 48, height - 48);
gfx.DrawLine(new XPen(XColors.WhiteSmoke, 1), 24, 24, width - 24, height - 24);
foreach (var corner in new[]
{
new XPoint(24, 24), new XPoint(width - 24, 24),
new XPoint(24, height - 24), new XPoint(width - 24, height - 24)
})
{
gfx.DrawRectangle(XBrushes.SteelBlue, corner.X - 3, corner.Y - 3, 6, 6);
}
gfx.DrawString($"{size} {orientation}", title, XBrushes.Black,
new XPoint(56, 90));
gfx.DrawString(note, label, XBrushes.DimGray, new XPoint(56, 112));
// XUnit is what the page's Width and Height are, and it converts rather than
// being converted: the same measurement read three ways.
var pageWidth = page.Width;
var pageHeight = page.Height;
string[] lines =
{
$"{pageWidth.Point:0.#} x {pageHeight.Point:0.#} points",
$"{pageWidth.Millimeter:0.#} x {pageHeight.Millimeter:0.#} mm",
$"{pageWidth.Inch:0.00} x {pageHeight.Inch:0.00} inches",
$"PageSizeConverter.ToSize({size}) = {PageSizeConverter.ToSize(size)}"
};
double y = 148;
foreach (var line in lines)
{
gfx.DrawString(line, label, XBrushes.Black, new XPoint(56, y));
y += 16;
}
// Rotate asks the reader to turn the page when it displays it. The drawing is
// untouched - the words below are laid down the same way as every other page
// here, and it is the viewer that turns them.
if (size == PageSize.A6)
{
page.Rotate = 90;
// Broken over two lines by hand. A6 is 298pt wide and this is the one page
// here where the measure is tight enough that a single line of it would run
// to the frame - DrawString does not wrap, so nothing would break it.
gfx.DrawString("page.Rotate = 90: the reader turns this,", small,
XBrushes.Crimson, new XPoint(56, y + 8));
gfx.DrawString("the drawing did not.", small,
XBrushes.Crimson, new XPoint(56, y + 20));
}
}