Skip to content

PDF coordinates and units in PdfNetStack

Since 1.1View as Markdown

Two coordinate systems, one unit: what each API uses, and how to convert between them.

Everything is in points, 1/72 inch. When you create content (drawing, annotations, form fields), the origin is the top left corner of the page and y points down. When you read content back (text, images, annotation and widget rectangles), positions are in PDF default user space: origin bottom left, y up, before the page’s /Rotate.

// One point is 1/72 inch. Convert once, draw in points.
static double Mm(double millimetres) => millimetres * 72 / 25.4;
static double Inches(double inches) => inches * 72;
PdfDocument doc = PdfDocument.Create();
PdfPage page = doc.Pages.Add(PdfRectangle.A4); // 595 x 842 points, about 210 x 297 mm
using (PdfGraphics g = page.CreateGraphics())
{
// A box 20 mm from the left and 30 mm from the top: y grows downward on the canvas.
g.DrawRectangle(PdfPen.Black, null, Mm(20), Mm(30), Mm(80), Mm(15));
g.DrawString("Hello", PdfStandardFont.Helvetica, 12, PdfColor.Black, Mm(20) + 6, Mm(30) + 26);
g.DrawLine(PdfPen.Black, Inches(1), Inches(2), Inches(3), Inches(2));
}
doc.Save("coordinates.pdf");
UnitPoints
1 inch72
1 cm28.35 (72 / 2.54)
1 mm2.835 (72 / 25.4)
CSS pixel0.75 (96 per inch)

PdfRectangle.A4 is 595 by 842 points (210 by 297 mm, rounded), PdfRectangle.Letter 612 by 792. PdfRectangle.FromSize(width, height) makes any other size, such as FromSize(842, 595) for A4 landscape. Images drawn at their natural size use the resolution the file records, else 96 pixels per inch.

APIOrigin
PdfPage.CreateGraphics() and every PdfGraphics methodTop left corner of the media box, y down
Every page.Annotations.Add... method: links, notes, markup, free text, stamps, shapes, lines, ink, attachmentsSame as the canvas
doc.Form.AddTextField and the other field methodsSame as the canvas
PdfForm.CreateGraphics()Top left corner of the form
PdfTextLayout lines (Top, Baseline, Left)Top left corner of the laid out paragraph

Two details matter when placing text:

  • DrawString(text, font, size, brush, x, y) puts the start of the baseline at (x, y). Add font.Ascent * size to y to place the top of the line instead.
  • DrawText(paragraph, x, y, width) puts the top left corner of the paragraph at (x, y).

Canvas transforms (TranslateTransform, RotateTransform and the others) change where later drawing lands. Positive rotation angles turn clockwise on the canvas. PdfGraphics.AddLink follows the current transform; the annotation methods on page.Annotations do not.

APICoordinates
PdfPage.GetWords(), GetLetters(): Bounds, BaselineStart, BaselineEndDefault user space, before /Rotate
PdfPage.GetImages(): Bounds, TransformDefault user space, before /Rotate
PdfAnnotation.Rectangle, PdfWidget.RectanglePDF user space
PdfPage.MediaBox, CropBoxPDF user space, as PdfRectangle(Left, Bottom, Right, Top)
// Extraction reports default user space: origin bottom left, y up.
PdfWord word = PdfDocument.Open("coordinates.pdf").Pages[0].GetWords()[0];
Console.WriteLine($"{word.Text}: left {word.Bounds.Left:F1}, bottom {word.Bounds.Bottom:F1}, top {word.Bounds.Top:F1}");
// Back to canvas coordinates: y from the top is the page height minus y from the bottom.
double canvasTop = page.MediaBox.Top - word.Bounds.Top;
Console.WriteLine($"On the canvas the word's top is {canvasTop:F1} points from the top");

To convert a point from user space to the canvas: x = pdfX - page.MediaBox.Left and y = page.MediaBox.Top - pdfY. For a rectangle, its canvas top is MediaBox.Top - rect.Top and its height stays rect.Height. That is how you place a highlight over a word that text extraction found.

PdfPage.Rotation is the clockwise rotation a viewer applies when it displays the page: 0, 90, 180 or 270. Rotate(degrees) adds to it.

  • The canvas does not apply /Rotate: coordinates are those of the unrotated page. On a page rotated by 90 degrees, what you draw at the canvas top shows on the right side in a viewer.
  • Extraction positions are also before /Rotate.
  • PdfForm.FromPage shows a page upright, as its rotation shows it, so placing a rotated page on another page needs no extra turn.

The media box is the page boundary; it defaults to US Letter when a file does not define one. The crop box is the visible region and defaults to the media box. The canvas origin is the top left of the media box, and PdfForm.FromPage shows the crop box.