1

I'm developing a PdfParser and I want to print the text content of the pdf on a coordinate plane. Below is the text object and matrices that are used to render text. How can I isolate the scaling, rotation and translation and use for printing the text content on exact coordinates on a canvas?

//Decoded text stream containing text objects
S
Q

q
0.000 0.750 0.750 -0.000 15.000 301.890 cm
0.000 g
/F10 16.000 Tf
0 Tr
0.000 Tc
BT
1 0 0 -1 20.000 13.600 Tm
[<007a>]TJ
ET
Q

q
0.000 0.750 0.750 -0.000 15.000 301.890 cm
1.000 0.416 0.000 rg
/F10 6.667 Tf
0 Tr
0.000 Tc
BT
1 0 0 -1 136.667 13.600 Tm
[<0024>12<0046><0046><0058><0055>6<0048><0003><0032><0058><0057><0053><0058><0057><0003><0036>-4<0052><004f><0058><0057><004c><0052><0051><0003><0026>3<004f><0052><0058><0047><0003><0048><0051>18<0059><004c><0055>6<0052><0051><0050><0048><0051>3<0057>7<000f><0003><0027><0028><0030><0032><0003><0044><0046><0046><0058><0055>6<0048>]TJ
ET
Q

q
0.000 0.750 0.750 -0.000 15.000 301.890 cm
0.000 g
/F10 16.000 Tf
0 Tr
0.000 Tc
BT
1 0 0 -1 603.333 13.600 Tm
[<007a>]TJ
ET
Q

q
mkl
  • 90,588
  • 15
  • 125
  • 265
Chiranga
  • 55
  • 8
  • 1
    What do you mean by "isolate the scaling, rotation and translation"? They are not independent after all! E.g. first scaling by a factor 2 and then translating by (1, 0) is obviously not the same as first translating by (1, 0) and then scaling by a factor of 2. Thus, you need to fix the order in which you want to decompose the transformation. Furthermore, you only mention *scaling, rotation and translation* but the transformation may include skewing and mirroring, too – mkl Dec 06 '19 at 11:51
  • 1
    Sounds like you are not just writing a PDFParse, but "printing the text content on exact coordinates on a canvas" rendering also. The information you are looking for are in sections 8 and 9 here: https://www.adobe.com/content/dam/acom/en/devnet/pdf/pdfs/PDF32000_2008.pdf – Ryan Dec 06 '19 at 22:19
  • 1
    If decomposing the matrices is important for you, then see something like this on how you could decompose 2D PDF matrix to scale, rotation, etc. https://stackoverflow.com/q/45159314/3761687 Though this is not a 100% solution as mkl pointed out. – Ryan Dec 06 '19 at 22:34
  • @mkl, what I want is to render these text on a canvas by using the operators like cm,Tm. I want to know the way to extract the exact x,y coordinates and rotation angle and other details, but coordinates and rotation angle are the most important for me. – Chiranga Dec 13 '19 at 09:44
  • *"coordinates and rotation angle are the most important for me"* - *coordinates* are trivial. Multiply all applicable **cm** matrices and the current text matrix in the correct order and then look at the bottom row. Concerning the *rotation* - do you mean the rotation of the **x** axis or of the **y** axis? If skewing is involved, those rotation angles will differ. – mkl Dec 13 '19 at 12:20
  • @mkl, both x and y axis. Concerning coordinates, I'm confused what CTM exactly is and how to calculate. – Chiranga Dec 16 '19 at 09:53
  • *"I'm confused what CTM exactly is and how to calculate."* - Have you studied the PDF specification Ryan linked to in his comment above? There is a definition of the ctm (and the text matrix and the text line matrix all of which you have to understand) and how applicable instructions operate on it. What exactly do you not understand there? – mkl Dec 16 '19 at 11:18
  • @mkl, as I understood, CTM is derived by concatenating every "cm" before. But then the CTM I calculated comes with big numbers and makes no sense. Even if I decompose the cm entry alone, I could calculate the rotation angle for only the pdfs generated using MS Word. When you consider Foxit PDF Editor, there is no cm entry. I could't find the rotation angle by decomposing the Tm entry either. Btw, does concatenating mean multiplying or just combining 2 matrices? – Chiranga Dec 17 '19 at 03:59
  • 1
    *Concatenating* means multiplying the argument from left to the current transformation matrix value. If your way of calculating this product comes up with wrong values, you should show an example and how you calculate the product. I'm not sure why you decompose at all but decomposing a single **cm** argument only won't be helpful at all, you'll need to decompose the product. That being said, it's only the concatenation of all cm arguments before if no **q** ... **Q** encloses some if those. – mkl Dec 17 '19 at 05:56
  • @mkl, if we do not take q .. Q enclosed "cm" entries for calculation, then here is the CTM; 0.000 0.750 0.750 -0.000 15.000 301.890 cm, and the corresponding Tm is ; 1 0 0 -1 136.667 13.600 Tm. How can I calculate the rotation angle ? – Chiranga Dec 17 '19 at 10:02

1 Answers1

2

The initial S Q is a leftover of a previous instruction block ending in some path stroking and graphics state restoring. As we don't know anything to the contrary, let's assume that 'Q' restores to the initial graphics state, in particular to an unmodified current transformation matrix (CTM).

As we are interested in coordinates according to the default user space coordinate system, we can assume accordingly that the current CTM is the identity matrix,

Let's take a look at the block

q
0.000 0.750 0.750 -0.000 15.000 301.890 cm
0.000 g
/F10 16.000 Tf
0 Tr
0.000 Tc
BT
1 0 0 -1 20.000 13.600 Tm
[<007a>]TJ
ET
Q

As you implied yourself in a comment, the only relevant instructions for the total transformation matrix at the time the text rendering instruction [<007a>]TJ begins to be executed are

0.000 0.750 0.750 -0.000 15.000 301.890 cm

and

1 0 0 -1 20.000 13.600 Tm

setting the current transformation matrix to

 0      0.75 0     1 0 0      0      0.75 0
 0.75   0    0  *  0 1 0  =   0.75   0    0
15.00 301.89 1     0 0 1     15.00 301.89 1

and the text and text line matrices both to

 1    0   0
 0   -1   0
20.0 13.6 1

Thus, the effects of text matrix and current transformation matrix combine to:

 1    0   0      0      0.75 0      0      0.75 0
 0   -1   0  *   0.75   0    0  =  -0.75   0    0
20.0 13.6 1     15.00 301.89 1     25.2  316.89 1

You can split up that combined matrix in a scaling, rotation, and translation like this:

 0      0.75 0     0.75 0    0      0 1 0      1      0    0
-0.75   0    0  =  0    0.75 0  *  -1 0 0  *   0      1    0
25.2  316.89 1     0    0    1      0 0 1     25.2  316.89 1

We have a scaling by .75, a rotation by 90° counterclockwise, and a translation by (25.2, 316.89).

(Of course this can still be subject to a page rotation...)

mkl
  • 90,588
  • 15
  • 125
  • 265
  • thank you very much for the answer. It cleared my doubts. I still like to know the way you split the combined matrix. Is there a specific order for all pdf generators or how can you know the order in which the matrix should be split? For example, here the order is scaling, rotation and translation. Could it be rotation, scaling and translation as well? – Chiranga Dec 18 '19 at 03:34
  • 1
    @Chiranga I chose the order in my answer. It was easiest to first separate the translation making it the last factor. And as the scaling in your example is by the same factor for **x** and **y**, the scaling and rotation remain the same if you switch their order. In general, though, the factors will change depending on the order, and as already said in the first comment to your question, **you have to decide in which order *you want to decompose* the whole transformation**. It depends on in which order you want to apply the different transformation types in drawing. – mkl Dec 18 '19 at 05:54
  • is there any way to decompose rotation matrix from a combined matrix with rotation and skew properties? – Chiranga Jan 02 '20 at 06:07
  • @Chiranga *"is there any way to..."* - most likely yes, but into what? – mkl Jan 02 '20 at 16:49
  • the problem is I want to get the translation, scaling and rotation from a particular Trm matrix. This text is subjected to skew as well. So far I was able to isolate the translation and scaling matrices by decomposing the Trm. I'm having difficulty in isolating the rotation matrix from the rest. Trm matrix : -0.000000044, -1, 1, -0.000000044, 130.44, 711.89 Can you please decompose the above matrix and explain the way to isolate the rotation matrix? – Chiranga Jan 06 '20 at 04:53
  • @Chiranga The rotation in your example is so minimally differing from a clockwise rotation by 90° that taking it as an example would mean either juggling with long number representations allowing one to see nothing, or rounding very very slightly resulting in said -90° rotation which is a boring example. – mkl Jan 09 '20 at 14:32