Question:
We are generating 300DPI images of PDF’s using PDFDraw. How do we translate PDF coordinates to this new image?
Answer:
By default PDF pages are in 72 dpi, which is called user space in the PDF spec. However, PDF pages can be rotated, have off set crop boxes (which essentially move the origin), and, while extremely rare, custom user space scale.
Also, PDF coordinate system is from the bottom left of the page, with y-axis going up, which might be the opposite your image coordinate system, in which case you need to flip it.
So, you want something like this, where page is from PDFDoc.GetPage(x) where x is the page you rendered.
// given page_num is page number, and x,y are PDF page (user space) coordinates.
Page page = doc.GetPage(page_num);
Matrix2D page_mtx = page.GetDefaultMatrix(flip_y_axis); // set flip_y_axis to true or false, as mentioned above.
double image_dpi = 300;
double pdf_dpi = page.GetUserUnitSize() * 72.0;
double scale = image_dpi / pdf_dpi;
Matrix2D scale_mtx(scale, 0, 0, scale);
Matrix2D mtx = scale_mtx * page_mtx;
mtx.Mult(x, y);
// x and y are now in image coordinates.
The following code will do the reverse, going from image coordinates to PDF coordinates.
Matrix2D page_mtx = page.GetDefaultMatrix(true).Inverse();
double image_dpi = 300;
double pdf_dpi = page.GetUserUnitSize() * 72.0;
double scale = pdf_dpi / image_dpi;
Matrix2D scale_mtx(scale, 0, 0, scale);
Matrix2D mtx = page_mtx * scale_mtx;
mtx.Mult(x, y);
// x and y now in PDF coordinates
Note, if you don’t know the image DPI, or it is incorrect, which is often the case, then the following will determine that for you (assuming aspect ratio was preseved).
// given image_width is width in pixels of image
Rect crop = page.GetCropBox();
double pdf_width = crop.Width();
double pdf_dpi = page.GetUserUnitSize() * 72.0;
double image_width = 2550;
double x_dpi = image_width / (pdf_width / pdf_dpi);