Advanced PostScript
Stacks, dictionaries, graphics state, transformations
P.J. Drongowski
28 September 2004 (Updated: 4 October 2004)
PostScript stacks
* Operand stack: Holds operands for operations and results from
operations (such as arithmetic.)
* Dictionary stack: Provides a context for name searches (variable
names, procedure names.)
* Execution stack: Holds executable objects (procedures or files)
that are in partial stages of execution.
* Graphics state stack: Maintains current and nested graphics states
(positional information, color, line width.)
Operand stack
* Holds operands for most PostScript operators
* Arithmetic example
+ 3 4 add 7 mul
+ Answer: 49
+ Reverse Polish Notation (RPN)
+ We will see this again
+ = operator pops and displays item from operand stack
+ stack operator displays stack contents without side-effect
Dictionaries and dictionary stack
* A dictionary is an associative table containing key-value pairs
* A key is a symbolic name by which a value may be retrieved
* The table is "associative" because it is not indexed in the
conventional sense; it uses user-/pre-defined keys instead
* Dictionary operators
+ n dict Create a new dictionary of at most n elements and return
the dictionary on the operand stack
+ key value def Define a new dictionary entry
+ key load Get topmost value associated with key
+ key value store Replace topmost definition of key
+ begin Pushes a dictionary on the dictionary stack
+ end Pops a dictionary from the dictionary stack
* Dictionaries usually store:
+ Variables
+ Procedure definitions
+ Font dictionary
* Interpreter maintains a dictionary stack defining the current
dynamic name space
+ Dictionaries can be pushed (begin operator) and popped (end operator)
+ Interpreter searches for definition of a name beginning with dictionary
on top of the dictionary stack and works downward
+ Provides nested symbol scopes, e.g., local variables for nested calls
- What is a "local variable?" Draw analogy to C/C++ local variables
- See arrow procedure for another dictionary example
Example: Create new dictionary once; add to local scope (Cookbook, pg. 130)
/localdict 1 dict def % Define new dictionary named "localdict"
/sampleproc {
localdict begin % Push localdict on dictionary stack
/localvariable 6 def
end % Pop localdict from dictionary stack
} def
Example: Create new dictionary/context on every call
/sampleproc {
1 dict begin % Create and push anonymous dictionary
/localvariable 6 def
end % Pop dictionary from dictionary stack
} def
Fonts
* Fonts are represented as dictionaries!
* Predefined fonts can be looked up in a system dictionary "FontDictionary"
+ The findfont operator obtains the font dictionary identified by the
key and pushed the associated font dictionary on the operand stack
+ Example: /Times-Roman findfont
* Fonts must be scaled before they can be used
+ The scalefont operator applies scale factor to font on the operand stack
+ Example: 15 scalefont
+ This produces a 12 *unit* font, not a 12 point font; if user space is
later scaled where one unit is a centimeter, a 12 unit character will be
12 centimeters high!
* A font must be made the current font in the graphics state before it
can be used
+ The setfont operator makes the font on the operand stack the current font
+ Example: setfont
* Common built-in fonts (keys)
Times-Roman Helvetica Courier Symbol
Times-Bold Helvetica-Bold Courier-Bold
Times-Italic Helvetica-Oblique Courier-Oblique
Times-BoldItalic Helvetica-BoldOblique Courier-BoldOblique
Execution stack
* Usually transparent to the PostScript program
* Maintains intermediate execution state of functions, the interpreter, etc.
Graphics state
* Describes how PostScript operators affect the current page
* Includes current path, gray value, ..., and user coordinate system
* The initgraphics operator resets the graphics state to default values
* Current graphics state can be saved and restored using the graphics
state stack
+ gsave operator saves the current graphics state in order to
return to it later; the graphics state is saved on the graphics
state stack
+ grestore operator restores the most recently saved graphics state
* An important part of the graphics state is the Current Transformation
Matrix or CTM
Coordinate systems
* Graphics operators work within the user coordinate system
* User coordinate space can be changed using transformations
tx ty translate Moves the origin of user space to new position
angle rotate Rotates the coordinate axes (degrees, counterclockwise)
sx sy scale Changes the size of the coordinate space units
* Goal: Define each graphical element in its own coordinate system,
indpendent of any other element
* Each graphical element may be positioned, oriented and scaled by
temporarily modifying the user coordinate system
* Transformations can be represented as 3x3 matrices:
a b 0
c d 0
tx ty 1
* A point is represented as a vector, [x y 1]
* Points are transformed by post-multiplying the vector by a
transformation matrix:
[x y 1] | a b 0 | a,b,c,d scale and rotate
| c d 0 | tx,ty translate
| tx ty 1 |
* Alternatively, the transformation can be written as formulae:
x' = ax + cy + tx
y' = bx + dy + ty
* Translation matrix: Scaling matrix: Rotation matrix:
1 0 0 sx 0 0 cos a sin a 0
0 1 0 0 sy 0 -sin a cos a 0
tx ty 1 0 0 1 0 0 1
* Negative scale factors can be used to reflect a picture around an axis
* If a picture (graphical element) is not centered at the origin, then
scale and rotate also translate the image
* A sequence of matrix operations can be concatenated (through matrix
multiplication) to form a single matrix which achieves the same effect
* More efficient at runtime since only one vector X matrix mult is performed
* Each of the translate, scale and rotate operators concatenate the desired
transformation matrix to the Current Transformation Matrix (CTM)
CTM' = T X CTM where T is a transformation matrix
* We must apply transformations in the correct order -- matrix multiplication
is *not* commutative
* With multiple levels of graphical structure (e.g., a scene graph), we
must save the CTM before calling instancing transformations
* A "safe" sequence of operations is:
1. Save current (instancing) transformation (gsave)
2. Concatenate one or more instancing transformations (translate, ...)
3. Draw the subpart (call a function to draw something)
4. Restore the original (instancing) transformation (grestore)