Coordinate space conversion
PDF pages and Android views use different coordinate spaces. Android views place the origin at the top-left, with y coordinates increasing downward. PDF pages place the origin at the bottom-left, with y coordinates increasing upward.
A crop box can offset PDF coordinates from the visible bottom-left corner. Page rotation can rotate the coordinate space. Cropping and rotation change page properties without modifying the content stream or annotations.
Nutrient normalizes page coordinates so the origin always matches the visible area’s bottom-left corner.

Instant JSON places the origin at the page’s top-left, with y coordinates increasing downward. For details, refer to the Instant JSON guide.
Use Nutrient’s projection API to convert between PDF and other coordinate spaces. The following example converts an annotation’s bounds to onscreen coordinates:
// Get the PDF coordinates of the annotation.val annotationRect = someAnnotation.boundingBox// Get the view projection for transforming between the view coordinates and PDF coordinates.val viewProjection = fragment.viewProjection// Convert the annotation's PDF coordinates to view coordinates (pixels).viewProjection.toViewRect(annotationRect, someAnnotation.pageIndex)// Get the PDF coordinates of the annotation.final RectF annotationRect = someAnnotation.getBoundingBox();// Get the view projection for transforming between the view coordinates and PDF coordinates.ViewProjection viewProjection = fragment.getViewProjection();// Convert the annotation's PDF coordinates to view coordinates (pixels).viewProjection.toViewRect(annotationRect, someAnnotation.getPageIndex());Each PDF page has its own coordinate space, so conversion methods require a pageIndex.
Understanding XFDF/PDF rects
XFDF and PDF files store an annotation’s bounding box as four edge coordinates. For example, export the XFDF of a rectangle annotation:
<!-- Other attributes omitted for clarity --><square rect="50.000000, 100.000000, 80.000000, 120.000000" />The rect attribute contains the following information in this order:
- The left side of the rectangle is 50 units from the left of the page.
- The bottom side of the rectangle is 100 units from the bottom of the page.
- The right side of the rectangle is 80 units from the left of the page.
- The top side of the rectangle is 120 units from the bottom of the page.
The width of the rectangle annotation is 30 units (80-50) and the height is 20 units (120-100).
Nutrient Android SDK uses the same orientation. Annotation#getBoundingBox() returns a RectF(opens in a new tab) with a bottom-left origin and top greater than bottom.
Without a crop offset or rotation, no coordinate conversion is necessary. The equivalent bounding box is:
// RectF(left, top, right, bottom), in PDF points.val boundingBox = RectF(50f, 120f, 80f, 100f)// RectF(left, top, right, bottom), in PDF points.final RectF boundingBox = new RectF(50f, 120f, 80f, 100f);Conversion methods
PdfFragment#getViewProjection() returns a ViewProjection for converting PDF and view coordinates. Points use PointF(opens in a new tab), and rectangles use RectF(opens in a new tab).
- Convert PDF points to view points with
toViewPoint(PointF, int). - Convert view points to PDF points with
toPdfPoint(PointF, int). - Convert PDF rectangles to view rectangles with
toViewRect(RectF, int). - Convert view rectangles to PDF rectangles with
toPdfRect(RectF, int).
PdfDocument#getPdfProjection() returns a PdfProjection for converting normalized and raw PDF coordinates.
- Convert normalized points to raw points with
toRawPoint(PointF, int). - Convert raw points to normalized points with
toNormalizedPoint(PointF, int). - Convert normalized rectangles to raw rectangles with
toRawRect(RectF, int). - Convert raw rectangles to normalized rectangles with
toPdfRect(RectF, int).
Convert between normalized and raw PDF coordinates
Nutrient’s normalized coordinates place the origin at the visible page area’s bottom-left corner. Use PdfProjection to convert raw PDF coordinates to normalized coordinates.
The following example places a 100-point square annotation at the PDF’s raw page origin:
val pageIndex = 0// Get the PDF projection for transforming between the raw coordinates and PDF coordinates.val pdfProjection = document.pdfProjectionval rawRect = RectF(0f, 100f, 100f, 0f)// Convert the raw PDF coordinates to normalized PDF coordinates.val normalizedPdfRect = pdfProjection.toPdfRect(rawRect, pageIndex)// Create a new square annotation using the normalized coordinates.val annotation = SquareAnnotation(pageIndex, normalizedPdfRect)int pageIndex = 0;// Get the PDF projection for transforming between the raw coordinates and PDF coordinates.PdfProjection pdfProjection = document.getPdfProjection();RectF rawRect = new RectF(0f, 100f, 100f, 0f);// Convert the raw PDF coordinates to normalized PDF coordinates.RectF normalizedPdfRect = pdfProjection.toPdfRect(rawRect, pageIndex);// Create a new square annotation using the normalized coordinates.SquareAnnotation annotation = new SquareAnnotation(pageIndex, normalizedPdfRect);A crop box offset can leave the annotation out of view.
For the reverse conversion, use PdfProjection#toRawPoint(PointF, int) or PdfProjection#toRawRect(RectF, int). The following example retrieves an annotation’s bounding box in raw PDF coordinates:
val pageIndex = 0// Get the PDF projection for transforming between the raw coordinates and PDF coordinates.val pdfProjection = document.pdfProjection// Get the annotation whose bounding box needs to be read.val annotation : SquareAnnotation = ...// Get the annotation bounding box.val normalizedRect = annotation.boundingBox// Convert the normalized PDF coordinates to raw PDF coordinates.val rawRect = pdfProjection.toRawRect(normalizedRect, pageIndex)int pageIndex = 0;// Get the PDF projection for transforming between the raw coordinates and PDF coordinates.PdfProjection pdfProjection = document.getPdfProjection();// Get the annotation whose bounding box needs to be read.SquareAnnotation annotation = ...// Get the annotation bounding box.RectF normalizedRect = annotation.getBoundingBox();// Convert the normalized PDF coordinates to raw PDF coordinates.RectF rawRect = pdfProjection.toRawRect(normalizedRect, pageIndex);Conversion matrix
Retrieve a transformation Matrix(opens in a new tab) for direct control over conversion:
- Normalized to raw — Use
PdfProjection#getNormalizedToRawTransformation(int). - Raw to normalized — Use
PdfProjection#getRawToNormalizedTransformation(int). - Page to view — Use
ViewProjection#getPageToViewTransformation(int, Matrix). - View to page — Use
ViewProjection#getViewToPageTransformation(int, Matrix).
For view transformations, pass an existing matrix as the second argument to reuse it. Pass null to create a new matrix.
How to convert between raster image pixels and points
Raster images have dimensions in pixels, while Nutrient returns PDF page sizes in points. By default, one inch equals 72 points. Divide the size in points by 72 to get inches. Divide the pixel count by that size in inches to calculate DPI (dots per inch).
Use these relationships:
- One inch = 72 points
- Size in inches = points / 72
- DPI = pixels / size in inches
Since PDF 1.6, the page dictionary’s UserUnit entry can scale user units beyond the default 1⁄72 inch. For details, refer to table 30 on page 79 of the PDF 1.7 specification(opens in a new tab).