Skip to content

Get Page Info

Before you crop, rotate, stamp or place anything on an existing page you need its dimensions and its rotation. Both are available two ways, and the two disagree often enough that it is worth knowing which to use: the PdfPage struct fields hold only what the page dictionary itself declares, while the Get* accessors resolve values inherited from the page tree.

Doing it

page, err := pdfReader.GetPage(pageNum)
if err != nil {
    return err
}

width, height, err := page.Size()
if err != nil {
    return err
}

rotation, err := page.GetRotate() // error when no Rotate entry exists anywhere
mediaBox, err := page.GetMediaBox()

fmt.Printf("%.0f x %.0f, rotation %d\n", width, height, rotation)

Size() is what you want in almost every case. It resolves the inherited media box, then applies the page rotation, swapping width and height at 90 and 270 degrees, so it reports the page as a viewer displays it. GetMediaBox() gives you the unrotated rectangle if you need the corners rather than the extents.

CallReturns
page.MediaBoxThe page’s own media box, or nil when inherited.
page.GetMediaBox()The effective media box, walking up the page tree.
page.RotateThe page’s own rotation, or nil when inherited or absent.
page.GetRotate()The effective rotation, or an error if no page in the chain declares one.
page.Size()Width and height as displayed, rotation applied.

Limitations

The nil case is the one that bites. Many producers put MediaBox and Rotate on the root Pages node instead of on each page, and for those documents page.MediaBox is nil and page.Rotate is nil even though the page has a definite size and rotation. Printing the fields directly, as the example does, reports <nil> and 0 respectively. That is why the accessors exist.

GetRotate() returns the error “rotate not defined” when nothing in the chain declares a rotation. That is not a failure - it means the rotation is zero. Size() treats it that way, logging and continuing.

Rotation is not normalized. A page may legitimately declare -90 or 450, and GetRotate returns exactly what is written. Size() handles the arithmetic; your own code comparing against 90 should not assume the value is already in range.

page.CropBox has no Get accessor and is nil when the page does not declare one, in which case the crop box is the media box by definition.

Run the example

printPdfPageProperties takes an input path and an optional page number, and prints the rotation, media box, height and width for that page or for all of them. processPage is where the printing happens.

git clone https://github.com/unidoc/unipdf-examples.git
cd unipdf-examples/pages
go run pdf_page_info.go input.pdf [page num]

If this is your first time using UniPDF, follow the getting started guide to create an API key and set up your development environment.

View the full source

Sample output

All values are in points, the unit UniPDF uses throughout. The struct dump is trimmed here; the example prints the whole PdfPage.

-- Page 1
 Page: &{Parent:Ref(3 0) LastModified:<nil> Resources:0x... CropBox:<nil> ...}
 Page rotation: 0
 Page mediabox: &{Llx:0 Lly:0 Urx:612 Ury:792}
 Page height: 612.000000
 Page width: 792.000000

This is a portrait page whose rotation is declared on the parent Pages node. The reported rotation is 0 because page.Rotate is nil, while the reported width and height are swapped because Size() resolved the inherited rotation of 90 degrees. The two lines contradict each other, which is the nil case in practice.

Last updated on