Coordinate Space Conversions

By specification, PDF documents have their own coordinate space, which is different from the coordinate space used by Android’s views. While Android views have their origin in the top-left corner, with y coordinates increasing in a downward direction, the y coordinates in PDF documents increase upward, starting in the bottom-left corner.

PSPDFKit provides a set of easy-to-use methods for transforming between PDF and view coordinate spaces. For example, the following code uses the PSPDFKit conversion API to retrieve the onscreen coordinates of an annotation:

Copy
1
2
3
4
5
6
// 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)
Copy
1
2
3
4
5
6
// 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());

ℹ️ Note: Since every page of a PDF document has its own coordinate space, the conversion method also takes a page argument.

Conversion Methods

ViewProjection can be accessed by PdfFragment#getViewProjection() and has a set of convenient methods for converting between PDF and view coordinates.

PdfProjection can be accessed by PdfDocument#getPdfProjection() and has a set of convenient methods for converting between PDF and raw coordinates.

Converting between the Normalized PDF Coordinate Space and the Raw PDF Coordinate Space

The PSPDFKit API uses a normalized page coordinate space, which always puts the origin in the bottom-left corner of the visible area of the page.

You can convert from the raw PDF coordinate space to PSPDFKit’s normalized space using the conversion methods in PdfProjection. For example, to place a 100-point by 100-point square annotation at the page origin stored in the PDF, use code like the following:

Copy
1
2
3
4
5
6
7
8
val pageIndex = 0
// Get the PDF projection for transforming between the raw coordinates and PDF coordinates.
val pdfProjection = document.pdfProjection
val 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)
Copy
1
2
3
4
5
6
7
8
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);

ℹ️ Note: The annotation might not end up visible if there is a crop box offset.

To convert from the normalized PDF coordinate space used by PSPDFKit to the raw PDF coordinate space, use the PdfProjection#toRawPoint(PointF, int) or PdfProjection#toRawRect(RectF, int) conversion method. For example, to read an annotation’s bounding box as it would be serialized in the PDF, use the following:

Copy
1
2
3
4
5
6
7
8
9
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)
Copy
1
2
3
4
5
6
7
8
9
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

If you need more control over the coordinate conversion, you can also retrieve a Matrix object using:

How to Convert between Raster Image Pixels and Points

The concept of resolution does not apply to PDF documents unless they have been converted into raster images, e.g. images whose dimensions are expressed in pixels. The default unit PSPDFKit returns for page sizes is the point, which is easily converted into inches by taking into account the fact that 1 inch is equal to 72 points. Inch separation results from dividing the size in points of a particular page by 72. Resolution, expressed in DPI (dots per inch), is thus the result of dividing the page size in points by the inch separation. To summarize, these are the relations you have to consider when you need to convert between points/inches and pixels in PDF:

1 inch = 72 points
Inch separation = points / 72
DPI (resolution) = pixels / inch separation

Note that, since PDF 1.6, the relationship between inches and points may be specified as greater than 1⁄72 by means of the UserUnit entry of the page dictionary. See table 30 on page 79 of the PDF 1.7 specification for more information.