# PDF coordinates and units in PdfNetStack

> How PdfNetStack places things in points from the top left when you draw, and reports bottom left PDF user space when you extract text and images.

Available since 1.1.

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

## Short answer

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`.

```csharp
// 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");
```

## Units

| Unit | Points |
|---|---|
| 1 inch | 72 |
| 1 cm | 28.35 (72 / 2.54) |
| 1 mm | 2.835 (72 / 25.4) |
| CSS pixel | 0.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.

## Creating content: top left, y down

| API | Origin |
|---|---|
| `PdfPage.CreateGraphics()` and every `PdfGraphics` method | Top left corner of the media box, y down |
| Every `page.Annotations.Add...` method: links, notes, markup, free text, stamps, shapes, lines, ink, attachments | Same as the canvas |
| `doc.Form.AddTextField` and the other field methods | Same 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.

## Reading content: bottom left, y up

| API | Coordinates |
|---|---|
| `PdfPage.GetWords()`, `GetLetters()`: `Bounds`, `BaselineStart`, `BaselineEnd` | Default user space, before `/Rotate` |
| `PdfPage.GetImages()`: `Bounds`, `Transform` | Default user space, before `/Rotate` |
| `PdfAnnotation.Rectangle`, `PdfWidget.Rectangle` | PDF user space |
| `PdfPage.MediaBox`, `CropBox` | PDF user space, as `PdfRectangle(Left, Bottom, Right, Top)` |

```csharp
// 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.

## Rotated pages

`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.

## Media box and crop box

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.

## Related

- [Drawing](https://www.jadev-corp.com/guides/drawing/)
- [Extract text](https://www.jadev-corp.com/guides/extract-text/)
- [Annotations](https://www.jadev-corp.com/guides/annotations/)
- API: [PdfRectangle](https://www.jadev-corp.com/api/pdfnetstack/pdfrectangle/), [PdfPage](https://www.jadev-corp.com/api/pdfnetstack/pdfpage/), [PdfGraphics](https://www.jadev-corp.com/api/pdfnetstack-drawing/pdfgraphics/), [PdfWord](https://www.jadev-corp.com/api/pdfnetstack/pdfword/)

Source: https://www.jadev-corp.com/pdfnetstack/concepts/coordinates-and-units/
