The order of transformations in a PDF document
I read the following paragraph in the PDF Reference, 6th edition (2006).
Figure 4.6 shows the effect of the order in which transformations are applied. The figure shows two sequences of transformations applied to a coordinate system. After each successive transformation, an outline of the letter n is drawn.
I don't understand how step 2 in the second line is gotten by changing the order of the transformations in the first line.
$\endgroup$ 92 Answers
$\begingroup$It’s very easy to misinterpret Figure 4.6. It might appear as if each step shows the result of transforming the preceding image, but that’s not what’s being shown. Rather, each step shows the result of re-executing the same operations with a further transformation added to the cascade. Of course there’s no rotation that will produce the Step 2 image on the second line from the Step 1 image, but re-rendering the outline of the ‘n’ after concatenating a rotation to the current transformation does.
With that in mind, the keys to understanding the effects of the transformations are that, they are applied to the coordinate system, not the points, and that they effectively represent how to map from the new coordinate system to the old, i.e., the inverse of what one might normally think of as the matrix of a coordinate system transformation. When it’s the coordinate system being transformed, points are transformed according to the inverse of that transformation, which together with the preceding means that when transforming a point from user space to device space, it is multiplied by the matrices in reverse order. For example, if, in PDF terms, we scale the $x$-direction by 3 and then rotate counterclockwise by 30°, i.e., set the current transformation to [3 0 0 1 0 0] ct [30 cos 30 sin -30 sin 30 cos 0 0] ct, points are transformed by the matrix $$\left(\begin{bmatrix}\frac{\sqrt3}2&\frac12&0\\-\frac12&\frac{\sqrt3}2&0\\0&0&1\end{bmatrix}\begin{bmatrix}\frac13&0&0\\0&1&0\\0&0&1\end{bmatrix}\right)^{-1}=\begin{bmatrix}3&0&0\\0&1&0\\0&0&1\end{bmatrix}\begin{bmatrix}\frac{\sqrt3}2&-\frac12&0\\\frac12&\frac{\sqrt3}2&0\\0&0&1\end{bmatrix}=\begin{bmatrix}\frac{3\sqrt3}2 & -\frac32 & 0 \\ \frac12 & \frac{\sqrt3}2 & 0 \\ 0&0&1 \end{bmatrix},$$ which transforms the unit square into the following parallelogram:
(Just to make things more confusing, I’m using the common mathematical convention of points as column vectors so that transformations are effected by left-multiplication by a matrix—the transpose of the PDF convention.) This is pretty much what you have at step 2 in the second sequence illustrated in your question. In effect, by rotating the points first, the scaling transformation becomes a shear.
Here are a couple of other ways to think about what’s going on. The color of a pixel in the page is determined by sampling the graphics. The mapping from page pixel coordinates to those in the graphics is determined by the current transformation, which warps the grid that’s used to locate points in the graphics. After scaling $x$ by 3, for instance, that grid becomes three times as dense in the in the $x$-direction, i.e., it goes from this
to this
which has the effect of stretching the image horizontally on the page. If you then rotate the coordinate system 30° counterclockwise, you end up with this grid:
To determine the color of a pixel on the page, sample the corresponding point in the graphics, using the transformed grid.
Instead of “pulling” pixels from the graphics to the page, we can instead think of “pushing” the graphics out to the page. This involves warping the graphics grid so that it aligns with the grid on the page, i.e., undoing the transformations that were done to the graphics grid, while bringing the image along through the same transformation. If you imagine warping the last grid so that it is once again uniform and aligned with the page, you should be able to see that the square will be transformed into the paralellogram in the first illustration above. Mathematically, this involves applying the inverse of the transformation that was used to change to coordinate system. As with any compound “undo” operation, the individual changes must be undone in the reverse order in which they were applied, which is why the order of the component transformations is reversed when inverting them.
$\endgroup$ 11 $\begingroup$For every physical page, the PDF engine sets up a coordinate system that makes it possible to refer to every point on the page. For all intents and purposes, this coordinate system is immutable and is the only coordinate system that the engine's core "understands".
PDF transformations are handled by an intermediate layer between the user and the engine's core; the core itself is oblivious to the concept of transformations. The intermediate layer intercepts all the coordinates generated by the user, and resolves them to their absolute representations in the core's coordinate system, before passing them on to the core.
The intermediate layer composes a sequence of transformations on a last come, first applied basis. Thus, if the following sequence of transformations is applied by the user: $T_1, \dots, T_n$, the effective transformation applied by the intermediate layer is $T_1\circ\cdots\circ T_n$.
In the diagram's example, the transformations executed in the second line are: scaling ($S$), rotation ($R$), and translation ($T$), in this order. Therefore, the effective transformations applied by the intermediate layer after each step are: $S$, $S\circ R$ and $S\circ R\circ T$, respectively. In particular, if, once the rotation is executed, a coordinate $v$ is mentioned by the user, it will be resolved by the intermediate layer to the point at absolute coordinates $S\big(R(v)\big)$.
Suppose the scaling transformation scales the $x$-axis by $2$, but leaves the $y$ axis unchanged, and suppose the rotation transformation rotates by $45^\circ$ counter-clockwise. Let's see how the unit vectors $u=(1,0)$ and $v=(0,1)$ are transformed.
Firstly the unit vectors are rotated by $45^\circ$ counter-clockwise. Since rotation preserves angles, the resulting vectors $u'=Ru$ and $v'=Ru$ will be perpendicular to each other, and symmetric about the $y$-axis.
Next, scaling is performed. Since the scaling is not uniform, and the scaling factor along the $y$-axis is $1$, the effect will be a shearing parallel to the $x$-axis, and $u'$ and $v'$ will be "pulled" in opposite directions, which will cause the angle between them to increase. In particular, the resulting vectors $u''=S(u')$ and $v''=S(v')$ will no longer be perpendicular to each other.
It is important to understand that all transformations are interpreted relative to the original coordinate system understood by the engine's core. For instance, in our example the scaling $S$ is not interpreted relative to the coordinate system determined by the rotated unit vectors $u'$ and $v'$. If this were the case, then $S$ would map $u'$ to $2u'$ and map $v'$ to itself, so that the new unit vectors $u''$ and $v''$ would remain perpendicular to each other. Instead $S$ maps $u$ to $2u$ and $v$ to itself, causing the angle between $u''$ and $v''$ to increase, as described in the previous paragraph.
I have applied this theory to recreate the illustration from the PDF manual using XeLaTeX with TikZ/PGF. I don't know what font was used in the manual, so I used the best approximation I could find, but it's not quite the same.
The transformation matrices used are:
- $T$: A translation by $(.5cm,.9cm)$.
- $R$: A rotation by $30^\circ$ counter-clockwise.
- $S$: A scaling by $3$ along the $x$-axis.
To recreate the first line, the following transformation matrices were applied: 1. $T$, 2. $TR$, 3. $TRS$.
To recreate the second line, the following transformation matrices were applied: 1. $S$, 2. $SR$, 3. $SRT$.
Here's the complete code.
\documentclass[landscape]{article}
\usepackage[hmargin=2cm,vmargin=1.5in]{geometry}
\usepackage{fontspec}
\setmainfont{heroout}[
Extension = .ttf,
Path = /Users/evanaad/Fonts/
]
\usepackage{tikz}
\begin{document} \fontsize{50}{50}\selectfont \begin{tikzpicture} \matrix { \draw[dashed] (-.99,-.99) grid (.99,.99); \draw[red] (0,0) rectangle (1.2,1); \node[anchor=south west,inner sep=0pt] at (0,0.01) {n}; &[.5cm] \tikzset{cm={1,0,0,1,(.5,.9)}} \draw[dashed] (-.99,-.99) grid (.99,.99); \draw[red] (0,0) rectangle (1.2,1); \tikzset{reset cm} \makeatletter \pgfsys@transformcm{1}{0}{0}{1}{.5cm}{.9cm} \makeatother \draw[dashed] (-.99,-.99) grid (.99,.99); \node[anchor=south west,inner sep=0pt] at (0,0.01) {n}; &[0.2cm] \tikzset{cm={.866,.5,-.5,.866,(.5,.9)}} \draw[dashed] (-.99,-.99) grid (.99,.99); \draw[red] (0,0) rectangle (1.2,1); \tikzset{reset cm} \makeatletter \pgfsys@transformcm{1}{0}{0}{1}{.5cm}{.9cm} \pgfsys@transformcm{.866}{.5}{-.5}{.866}{0pt}{0pt} \makeatother \draw[dashed] (-.99,-.99) grid (.99,.99); \node[anchor=south west,inner sep=0pt] at (0,0.01) {n}; &[0.4cm] \tikzset{cm={2.598,1.5,-.5,.866,(.5cm,.9cm)}} \draw[dashed] (-.99,-.99) grid (.99,.99); \draw[red] (0,0) rectangle (1.2,1); \tikzset{reset cm} \makeatletter \pgfsys@transformcm{1}{0}{0}{1}{.5cm}{.9cm} \pgfsys@transformcm{.866}{.5}{-.5}{.866}{0pt}{0pt} \pgfsys@transformcm{3}{0}{0}{1}{0pt}{0pt} \makeatother \draw[dashed] (-.99,-.99) grid (.99,.99); \node[anchor=south west,inner sep=0pt] at (0,0.03) {n}; \\[3cm] \draw[dashed] (-.99,-.99) grid (.99,.99); \draw[red] (0,0) rectangle (1.2,1); \node[anchor=south west,inner sep=0pt] at (0,0.01) {n}; & \tikzset{cm={3,0,0,1,(0,0)}} \draw[dashed] (-.99,-.99) grid (.99,.99); \draw[red] (0,0) rectangle (1.2,1); \tikzset{reset cm} \makeatletter \pgfsys@transformcm{3}{0}{0}{1}{0pt}{0pt} \makeatother \draw[dashed] (-.99,-.99) grid (.99,.99); \node[anchor=south west,inner sep=0pt] at (0,0.01) {n}; & \tikzset{cm={2.598,.5,-1.5,.866,(0,0)}} \draw[dashed] (-.99,-.99) grid (.99,.99); \draw[red] (0,0) rectangle (1.2,1); \tikzset{reset cm} \makeatletter \pgfsys@transformcm{3}{0}{0}{1}{0pt}{0pt} \pgfsys@transformcm{.866}{.5}{-.5}{.866}{0pt}{0pt} \makeatother \draw[dashed] (-.99,-.99) grid (.99,.99); \node[anchor=south west,inner sep=0pt] at (0,0.01) {n}; & \tikzset{cm={2.598,.5,-1.5,.866,(-1pt,29pt)}} \draw[dashed] (-.99,-.99) grid (.99,.99); \draw[red] (0,0) rectangle (1.2,1); \tikzset{reset cm} \makeatletter \pgfsys@transformcm{3}{0}{0}{1}{0pt}{0pt} \pgfsys@transformcm{.866}{.5}{-.5}{.866}{0pt}{0pt} \pgfsys@transformcm{1}{0}{0}{1}{.5cm}{.9cm} \makeatother \draw[dashed] (-.99,-.99) grid (.99,.99); \node[anchor=south west,inner sep=0pt] at (0,0.03) {n}; \\ }; \end{tikzpicture} \end{document} $\endgroup$