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.
| Call | Returns |
|---|---|
page.MediaBox | The page’s own media box, or nil when inherited. |
page.GetMediaBox() | The effective media box, walking up the page tree. |
page.Rotate | The 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.000000This 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.