The painting operators take only geometry. S strokes the current path without being told a color or a width: it uses whatever the graphics state holds at that moment. The graphics state is the reader's current settings for transformation, clip, color, line style, font and opacity. Operators like rg, w and cm each change one setting, which stays in effect until something changes it again. The model comes from PostScript, where q and Q are called gsave and grestore.
0 0 1 RG 4 w % blue, 4 wide, from here on 72 700 m 272 700 l S % a blue line q 1 0 0 RG [6 3] 0 d % red and dashed, until Q 1 0 0 1 0 -40 cm % and moved down 40 72 700 m 272 700 l S % a red dashed line, drawn at y = 660 Q 72 620 m 272 620 l S % blue and solid again, still 4 wide
What it holds
The spec splits the parameters in two. Device-independent ones affect what you see on any output. Device-dependent ones fine-tune a particular printer or screen, and most files never set them.
| Kind | Parameter | Set with | Initial value |
|---|---|---|---|
| Device-independent | Current transformation matrix (CTM) | cm | Default user space: 1/72-inch units, y up |
| Clipping path | W W* | The whole page | |
| Color space, stroking and nonstroking | CS cs, or G g RG rg K k | DeviceGray | |
| Color, stroking and nonstroking | SC SCN sc scn G g RG rg K k | Black | |
| Text state: font and size, spacing, scaling, leading, rendering mode, rise | Tf Tc Tw Tz TL Tr Ts; /Font | No font; scaling 100, the rest 0 | |
| Line width, cap, join, miter limit, dash | w J j M d; /LW /LC /LJ /ML /D | 1, butt, miter, 10, solid | |
| Rendering intent | ri; /RI | RelativeColorimetric | |
| Stroke adjustment | /SA | Off | |
| Transparency: blend mode, soft mask, alpha, alpha source | /BM /SMask /CA /ca /AIS | Normal, None, 1, off | |
| Device-dependent | Overprint and overprint mode | /OP /op /OPM | Off, 0 |
| Black generation, undercolor removal | /BG /BG2 /UCR /UCR2 | The device's own | |
| Transfer function, halftone | /TR /TR2 /HT | The device's own | |
| Flatness, smoothness | i; /FL /SM | 1; the device's own |
Names with a slash are keys in an ExtGState dictionary.
The graphics state stack
q pushes a copy of the whole graphics state onto a stack, and Q pops the most recent copy and makes it current again. Pairs nest. They must balance within a content stream, or across a page's /Contents array taken together, and they can't appear inside BT … ET.
A clip can only get smaller, so Q is the only way back to a larger one. cm only ever multiplies onto the CTM, so writers wrap it in q … Q rather than undo it with the inverse matrix.
Parameters without an operator: ExtGState
About half the parameters have no operator of their own. They are set from a graphics state parameter dictionary, a named entry in the /ExtGState resources, applied with gs (PDF 1.2). A dictionary changes only the parameters it has keys for. Some keys repeat an operator: /LW is w, and /Font [font size] is Tf. The rest are the only way to set overprint, transparency, stroke adjustment and the device-dependent parameters.
% Resources: /ExtGState << /GS0 << /LW 2 /LC 1 /OP true /op true >> >> q /GS0 gs % the same as "2 w 1 J", plus overprint, which no operator sets 72 600 200 100 re S Q
What starts fresh, and what carries over
- Each page starts from the initial values. Nothing set on one page carries over to the next. Within a page, a
/Contentsarray is read as one stream, so the state carries across the joins. - A form XObject inherits the state at its
Do.Dosaves the state asqwould, multiplies the form's/Matrixonto the CTM, clips to its/BBox, runs its content stream, then restores the state asQwould. A form that never sets a color paints in the caller's color, and nothing it sets leaks out. - Text state is part of the graphics state; the text matrix isn't. The font, spacing and rendering mode outlast
ET. The text matrix exists only inside a text object and is reset by everyBT. - The current path isn't part of it either. A path has to be painted, or ended with
n, before any state operator can run.
Read:
cm, a clip or a color still in effect, and anything you append is drawn under it. Wrap the original first: add a stream holding q before it in /Contents and one holding Q after it. If the original leaves some q unmatched, close each with an extra Q. Or turn the original content into a form XObject and paint it with Do, which saves and restores the state for you.