What is the difference between pdfview.GetDeviceTransform(), page.GetTextMatrix(), element.GetCTM(), and GState.GetTransform()?

Q: Could you please explain the difference between
getDeviceTransform() in PDFView, getCTM() for an element and
getTextMatrix() - for Text, gs.getTransform() - for any Element etc.
-----
A: PDFView.GetDeviceTransform returns the device transformation matrix
maps the page coordinate system to screen (or device) coordinate
system. For example, you can use this matrix to map points from page
coordinate system (e.g. as returned by pdftron.Annot.GetRect()) to
screen coordinates. The inverse of the device matrix (i.e.
pdfview.GetDeviceTransform().Inverse()) can be used to map point is
the other direction, from screen coordinates to page coordinates.

For a detailed description of 'Page.GetDefaultMatrix', please search
for "What is the purpose of the GetDefaultMatrix()" in this forum.

Element.GetCTM() returns the Current Transformation Matrix (CTM). CTM
is used to maps coordinates of graphical objects on the page to the
PDF user coordinate space (where 1pt = 1/72 inch). For example, to
obtain correct coordinates for a path or an image object on a page,
you would need to map the coordinates using the CTM.

Element.GSTate().GetTransform() is typically used only by advanced
users. It is used to obtain the topmost matrix from the graphics state
stack. Since this matrix is already accounted in CTM this information
is not that useful, unless you are trying to replicate PDF transform
in another graphics language (e.g. transform stack in OpenGL,
PostScript, SVG, etc).

Element.GetTextMatrix() returns the 'text matrix' associated with a
given text object. In order to obtain the correct page positioning
information for text the points must be first transformed using text
matrix, followed by CTM. Since you can use Element.GetBBox() to obtain
the bounding box for any Element (including text), GetTextMatrix() is
also rarely used.

if a PDF page has a rotation specified, the element.getPathPoints
gives co-ordinates in unrotated space. When I apply ctm (multiplied
with gs.getTransform) for the point, I do not get the correct points.

If you would like to account for page rotation, you also need to
transform the points using 'Page.GetDefaultMatrix' after applying the
CTM (element.GetCTM())

To obtain the path/image coordinates in 'rotated' page coordinate
system use GetDefaultMatrix as follows:

// In Java -----------------------------------------
Matrix2D ctm = element.getCTM();
Matrix2D page_rot_mtx = page.getDefaultMatrix(); Matrix2D page_mtx =
page_rot_mtx.multiply(ctm);

// p1 is a point in the 'rotated' page coordinate system.
java.awt.geom.Point2D.Double p1 = mtx.multPoint(x, y);

Matrix2D dev_mtx = pdfview.getDeviceTransform(); Matrix2D screen_mtx =
dev_mtx.multiply(page_mtx);

// p2 is a point on the screen.
java.awt.geom.Point2D.Double p2 = mtx.multPoint(x, y);

// In C++ -----------------------------------------
Matrix2D ctm = element.GetCTM();
Matrix2D page_rot_mtx = page.GetDefaultMatrix(); Matrix2D page_mtx =
page_rot_mtx * ctm;

// p1 is a point in the 'rotated' page coordinate system.
double p1_x=x, p1_y=y;
page_mtx.Mult(p1_x, p1_y);

Matrix2D dev_mtx = pdfview.GetDeviceTransform(); Matrix2D screen_mtx =
dev_mtx * page_mtx;

// p2 is a point on the screen.
double p2_x=x, p2_y=y;
page_mtx.Mult(p2_x, p2_y);

// In C#/VB.Net -----------------------------------------
Matrix2D ctm = element.GetCTM();
Matrix2D page_rot_mtx = page.GetDefaultMatrix(); Matrix2D page_mtx =
page_rot_mtx * ctm;

// p1 is a point in the 'rotated' page coordinate system.
double p1_x=x, p1_y=y;
page_mtx.Mult(ref p1_x, ref p1_y);

Matrix2D dev_mtx = pdfview.GetDeviceTransform(); Matrix2D screen_mtx =
dev_mtx * page_mtx;

// p2 is a point on the screen.
double p2_x=x, p2_y=y;
page_mtx.Mult(ref p2_x, ref p2_y);

Q: Thanks for the detailed explanation. I did figure out on my own
what you explained in the above email and tried using that. And that's
how I found out that the GetDeviceTransform is returning scaling
factor in Shear position and hence I was not able to achieve correct
positioning. Then I tried making my own CTM with Sx = Shx and Sy = Shy
and then got the correct positioning. I am attaching one of the PDF's
for your team to check out (mailer.pdf). However the same
DeviceTransform returns Sx, Sy correctly for another PDF which has a
rotation in it (flyer.pdf).
-----
A: The most likely problem is that the matrix also has a 90 def
rotation (hence the scale component is on shear position). To obtain
the scaling component from any Matrix2D you could use the following
pseudocode:

// Get the average scaling (by X and Y) from a given Matrix.
double MatrixScale(pdftron.Common.Matrix2D m) {
double x = 0.707106781 * m.getA() + 0.707106781 * m.getB();
double y = 0.707106781 * m.getC() + 0.707106781 * m.getD();
return Math.Sqrt(x*x + y*y);
}