Skip to main content
Version: API v2 Preview

Positioning and Coordinates

PDF coordinates differ from the top-left coordinate system used by browsers and many image tools. Before placing or selecting content, establish the page number, page dimensions, coordinate origin, and units.

PDF page coordinates start at the bottom-left and increase rightward and upward

PDF points and page numbers

PDFDancer measures page coordinates and dimensions in points.

DistancePoints
1 inch72
1/2 inch36
1 millimetreapproximately 2.835
1 centimetreapproximately 28.346

Page numbers passed to API v2 methods are one-based: page 1 is the first page.

For an unrotated page, PDF user space normally works like this:

                         y increases



(0, 0) ───────────┼────────→ x increases
bottom-left

The page's crop box and rotation can affect how these coordinates correspond to what a PDF viewer displays. Do not assume that every PDF has an origin at the visible sheet's bottom-left corner; verify geometry-sensitive workflows with representative source files.

Convert top-left coordinates

If another system measures y downward from the top of an unrotated page, convert a point with:

pdfX = sourceX
pdfY = pageHeight - sourceY

For a rectangle whose source coordinates describe its top-left corner:

pdfX = sourceX
pdfY = pageHeight - sourceY - rectangleHeight

For example, US Letter is commonly 612 × 792 points. A point 72 points from the left and 72 points from the top converts to (72, 720). A 36-point-high rectangle at the same top-left position starts at (72, 684) in bottom-left coordinates.

These formulas assume an unrotated page and coordinate systems referring to the same visible page box.

Coordinates mean different things by operation

OperationMeaning of (x, y)
selectImageAt, selectPathAt, selectFormAt, or selectFormFieldAtA point used to find existing objects on one page
TextInsertRequest.atThe insertion position for new text
Image builder .at(...)The placement position for the new image
Path builder moveTo(...)The first or next point in the path being constructed
Selected object's moveTo(...)The object's new position on its current page

The same method name can have different meaning on a builder and on an existing object. For example, newPath().moveTo(...) begins a path segment; selectedImage.moveTo(...) relocates an image.

Select near a coordinate

Coordinate selection is available through a page client because (x, y) alone does not identify a page.

pdf.page(1).select…At(x, y, tolerance)

The default tolerance is 0.01 point. Use a larger value when input coordinates are rounded or approximate. Prefer a plural selector such as selectImagesAt while diagnosing a match: more than one object can occupy the same point. See Finding Existing Objects for complete examples and empty-result handling.

Inspect an existing object's bounds

Selected objects include position data. When available, the bounding rectangle provides x, y, width, and height. Its coordinates describe the object in PDF user space; they are not CSS pixels.

image = pdf.page(1).select_image()
if image is not None and image.position.bounding_rect is not None:
bounds = image.position.bounding_rect
print(bounds.x, bounds.y, bounds.width, bounds.height)

Position data describes the object when it was selected. After moving, scaling, rotating, or replacing the object, select it again if later calculations require current bounds.

Place text at a known coordinate

The following inserts a label one inch from the left edge and ten inches from the bottom of page 1. Coordinate insertion requires an explicit font and positive font size because there is no existing text from which to inherit those values.

request = TextInsertRequest.at(1, 72, 720, "Reviewed") \
.font("Helvetica-Bold").size(12).build()
response = pdf.text().insert(request)
if response.changed != 1 or response.errors:
raise RuntimeError(f"Could not insert label: {response}")

Use pdf.page(1).text() for page scope when inserting relative to an existing text anchor. Coordinate insertion already includes the page number in TextInsertRequest.at(...) and therefore uses pdf.text().

Move an existing object

Select the object first, then pass its new PDF coordinates to moveTo or move_to. The move keeps the object on its current page.

image = pdf.page(1).select_image_at(72, 680, tolerance=1.0)
if image is None or not image.move_to(144, 680):
raise RuntimeError("Image move failed")

Moving an object to another page is not the same operation as changing its coordinates. Page objects have their own moveTo(targetPageNumber) operation for reordering pages.

Affine transforms

A PDF matrix [a, b, c, d, e, f] maps points as:

x' = a*x + c*y + e
y' = b*x + d*y + f

Common matrices include:

EffectMatrix
Translate by (tx, ty)[1, 0, 0, 1, tx, ty]
Scale by (sx, sy)[sx, 0, 0, sy, 0, 0]
Rotate by angle θ[cos θ, sin θ, -sin θ, cos θ, 0, 0]

For text-to-image replacement, the supplied transform is relative to the matched range's visually leftmost boundary caret. It is not the page's current transformation matrix.

Troubleshooting misplaced content

  1. Confirm that the page number is one-based.
  2. Confirm that both axes are expressed in points rather than pixels.
  3. Check whether the source coordinates use a top-left origin.
  4. Check the page's crop box and rotation.
  5. Inspect the selected object's bounding rectangle before calculating offsets.
  6. Select the object again after a geometric change when current bounds matter.
  7. Save to a separate output file and inspect the rendered result.