| name | pdfium-core-coordinates |
| description | Use when working with page sizes, object positions, rendering dimensions, or click-to-document mapping in pdfium-render, and you need to know which unit a value is in and how to convert it. Prevents the unit-confusion bugs: treating PdfPoints as pixels, converting points to pixels without a render config, forgetting the bottom-left to top-left y-axis flip when overlaying PDF coordinates on a raster image, and the 0.8.28 bounds() return-type change. Covers PdfPoints (the 1/72 inch document unit), Pixels (the raster unit, i32), PdfPage::points_to_pixels and pixels_to_points, PdfRect versus PdfQuadPoints, and the PDF coordinate origin. Keywords: pdfium-render, coordinates, units, PdfPoints, Pixels, points_to_pixels, pixels_to_points, PdfRect, PdfQuadPoints, bounds, page size, DPI, scale, origin, y-axis flip, bounding box, "wrong size", "object in wrong place", "coordinates upside down", "image is too small", "bounds does not compile", "expected PdfRect found PdfQuadPoints", "how big is a PDF page", "convert points to pixels", "where did the user click".
|
| license | MIT |
| compatibility | Designed for Claude Code. Requires pdfium-render 0.8,0.9. |
| metadata | {"author":"OpenAEC-Foundation","version":"1.0"} |
pdfium-render Coordinates and Units
pdfium-render uses two coordinate systems with different units and different
origins. Mixing them is the root cause of "object in the wrong place",
"rendered image is the wrong size", and "coordinates are upside down" bugs.
This skill states which unit each value is in and how to convert correctly.
Quick Reference: Two Coordinate Systems
| Aspect | PDF user space | Raster space |
|---|
| Unit type | PdfPoints (f32, 1/72 inch) | Pixels (type Pixels = i32) |
| Origin | Bottom-left of the page | Top-left of the bitmap |
| Y axis | Increases upward | Increases downward |
| Used by | PdfPage::width(), object bounds(), PdfRect, PdfQuadPoints | PdfBitmap::width(), PdfRenderConfig targets |
| Resolution | Resolution-independent | Depends on the render config |
ALWAYS know which system a value belongs to before doing arithmetic with it.
NEVER add or compare a PdfPoints value to a Pixels value directly,
because they are different units with different origins.
1. PdfPoints: the Document Unit
PdfPoints is the device-independent unit of the PDF document interior. The
docs define it: "the internal coordinate system inside a PdfDocument is
measured in Points, a device-independent unit equal to 1/72 inches, roughly
0.358 mm. Points are converted to pixels when a PdfPage is rendered into a
PdfBitmap."
pub struct PdfPoints { pub value: f32 }
PdfPoints wraps a single f32 in its public value field. It carries
constants ZERO, MAX, MIN and physical-unit conversions
from_inches/from_cm/from_mm and to_inches/to_cm/to_mm. These
types return PdfPoints and stay inside PDF user space:
PdfPage::width() and height() return PdfPoints.
PdfRect and PdfQuadPoints measure their corners in PdfPoints.
PdfPageObjectCommon::bounds(), width(), height() return PdfPoints.
A US Letter page is 612.0 x 792.0 points (8.5 x 11 inches). A4 is
595.28 x 841.89 points. ALWAYS read a page size as PdfPoints and use the
physical-unit helpers when a real-world measurement is required.
2. Pixels: the Raster Unit
Pixels is the unit of a rendered raster image. It is a plain type alias:
pub type Pixels = i32;
Pixels appear only after rendering. PdfBitmap::width() and height()
return Pixels. PdfRenderConfig builder methods (set_target_width,
set_maximum_height, the set_fixed_* family) take Pixels. A page has no
pixel size until a PdfRenderConfig decides one.
NEVER treat PdfPage::width() as a pixel count. It is points. The pixel size
is whatever the render config produces. See pdfium-syntax-rendering.
3. Converting Between Points and Pixels
Conversion is config-dependent: the same point value maps to different
pixel values depending on the render config's scale and target size. Two
PdfPage methods do the conversion, both added in 0.8.12, both requiring
a &PdfRenderConfig:
pub fn points_to_pixels(
&self,
x: PdfPoints,
y: PdfPoints,
config: &PdfRenderConfig,
) -> Result<(Pixels, Pixels), PdfiumError>
pub fn pixels_to_points(
&self,
x: Pixels,
y: Pixels,
config: &PdfRenderConfig,
) -> Result<(PdfPoints, PdfPoints), PdfiumError>
ALWAYS use the same PdfRenderConfig for conversion that you use (or will
use) to render the page. The conversion is only meaningful relative to that
config. NEVER hardcode a points-to-pixels factor such as "multiply by 72" or
"multiply by 96 / 72"; that ignores the config's scale and target dimensions
and produces values that do not match the actual bitmap.
Note: there is no PdfPoints::from_pixels constructor. Pixels become
points only through PdfPage::pixels_to_points with a config.
4. The Origin Flip
The two systems do not share an origin. This is the most common silent bug.
PDF user space (points) Raster space (pixels)
y +---------------> x
^ |
| |
| |
+---------------> x v
(0,0) bottom-left y (0,0) top-left
When PDFium renders a page to a PdfBitmap it performs this flip for
you: the rendered image looks correct. The flip becomes your responsibility
when you take a coordinate from PDF user space (an object's bounds(), a
PdfRect) and want to draw or hit-test it on the raster image with an
external library.
To map a PDF y-coordinate onto raster pixels:
raster_y_px = page_height_px - pdf_y_px
ALWAYS flip the y-axis when overlaying point-space geometry on a raster
image. NEVER assume a bounds() rectangle can be drawn directly with a
top-left-origin image library; its y values grow the opposite direction.
The x-axis does not flip.
5. PdfRect vs PdfQuadPoints
Two rectangle-like types exist, both measured in PdfPoints.
PdfRect is an axis-aligned rectangle. Its corners are named by edge:
bottom, left, top, right.
PdfRect::new(bottom: PdfPoints, left: PdfPoints, top: PdfPoints, right: PdfPoints) -> Self
PdfRect::new_from_values(bottom: f32, left: f32, top: f32, right: f32) -> Self
PdfRect::ZERO
fn width(&self) -> PdfPoints
fn height(&self) -> PdfPoints
fn contains(&self, x: PdfPoints, y: PdfPoints) -> bool
fn is_inside(&self, other: &PdfRect) -> bool
fn does_overlap(&self, other: &PdfRect) -> bool
fn to_quad_points(&self) -> PdfQuadPoints
PdfQuadPoints is a quadrilateral: four independent vertices in
counter-clockwise order, (x1,y1) through (x4,y4). It can represent a
rotated box, which an axis-aligned PdfRect cannot.
PdfQuadPoints::new(x1, y1, x2, y2, x3, y3, x4, y4)
PdfQuadPoints::new_from_values(x1, y1, x2, y2, x3, y3, x4, y4)
PdfQuadPoints::from_rect(rect: &PdfRect) -> Self
fn to_rect(&self) -> PdfRect
fn width(&self) -> PdfPoints
fn height(&self) -> PdfPoints
Convert between them with PdfRect::to_quad_points() and
PdfQuadPoints::to_rect(). ALWAYS use to_rect() when you need a simple
axis-aligned box from a bounds() result. NEVER assume a PdfQuadPoints is
axis-aligned; a rotated text object has a slanted quadrilateral, and reading
only x1/y1 as a corner of an upright box gives the wrong region.
6. Version Traps
| Item | 0.8.x | 0.9.x | Consequence |
|---|
PdfPageObjectCommon::bounds() return | PdfRect before 0.8.28, Result<PdfQuadPoints, _> from 0.8.28 | Result<PdfQuadPoints, PdfiumError> | Code reading bounds() as a PdfRect fails to compile against 0.8.28+ |
points_to_pixels / pixels_to_points | added 0.8.12; absent before | present | Not available on pre-0.8.12 |
When upgrading and the compiler reports "expected PdfRect, found
PdfQuadPoints" on a bounds() call, append .to_rect() to restore an
axis-aligned rectangle, or rework the code to handle the quadrilateral.
Decision Tree: Which Conversion
I have a value and need another unit.
Page size in a physical unit (mm, inches)
-> PdfPage::width()/height() give PdfPoints
-> PdfPoints::to_mm() / to_inches()
Object position for drawing on the rendered image
-> bounds() gives PdfQuadPoints (points)
-> .to_rect() for an axis-aligned PdfRect
-> PdfPage::points_to_pixels(x, y, &config) per corner
-> flip y : raster_y = bitmap_height - y_px
User clicked pixel (px, py) on the rendered image, need the PDF location
-> flip y back : pdf_y_px = bitmap_height - py
-> PdfPage::pixels_to_points(px, pdf_y_px, &config)
Rotated bounding box
-> keep PdfQuadPoints, do NOT collapse to PdfRect
ALWAYS / NEVER
- ALWAYS know whether a value is
PdfPoints or Pixels before arithmetic.
- ALWAYS convert points to pixels with
points_to_pixels and the actual
PdfRenderConfig; the result is config-dependent.
- ALWAYS flip the y-axis when mapping point-space geometry onto a
top-left-origin raster image.
- ALWAYS use
PdfQuadPoints::to_rect() to get an axis-aligned box from a
bounds() result.
- NEVER treat
PdfPage::width()/height() as pixel counts; they are points.
- NEVER hardcode a points-to-pixels multiplier; it ignores the render config.
- NEVER look for
PdfPoints::from_pixels; it does not exist. Use
pixels_to_points.
- NEVER read a
PdfQuadPoints as if it were axis-aligned.
- NEVER read
bounds() as a PdfRect on 0.8.28 or later.
Cross-References
- pdfium-syntax-rendering :
PdfRenderConfig, PdfBitmap, how target
dimensions and scale determine the pixel size.
- pdfium-syntax-page-objects :
PdfPageObjectCommon::bounds() and object
geometry.
- pdfium-impl-page-manipulation : page boundary boxes and cropping, which
also use
PdfPoints.
- pdfium-core-architecture : where
PdfPage and page objects sit in the
ownership tree.
Reference Files
references/methods.md : signatures of PdfPoints, Pixels, PdfRect,
PdfQuadPoints, and the PdfPage conversion methods with version notes.
references/examples.md : verified Rust code for reading sizes, converting
units, the y-axis flip, and quadrilateral handling.
references/anti-patterns.md : real unit-confusion failures with the cause
and the fix.
Sources
API names and signatures verified on 2026-05-20 via WebFetch against the
package SOURCES.md:
https://docs.rs/pdfium-render/latest/pdfium_render/prelude/struct.PdfPoints.html
https://docs.rs/pdfium-render/latest/pdfium_render/prelude/type.Pixels.html
https://docs.rs/pdfium-render/latest/pdfium_render/prelude/struct.PdfRect.html
https://docs.rs/pdfium-render/latest/pdfium_render/prelude/struct.PdfQuadPoints.html
https://docs.rs/pdfium-render/latest/pdfium_render/prelude/struct.PdfPage.html
https://docs.rs/pdfium-render/latest/pdfium_render/prelude/trait.PdfPageObjectCommon.html