PostScript Specification
Overview
The PostScript language is a DSL for specifying printer output. The general idea is that a program which draws a box three inches square on a page—or draws the text of a document—can be much smaller than a bitmap that specifies the color of each pixel on the page. Furthermore, these programs can work without change on different printers with different resolutions.
For the purposes of this assignment, you need to know three main things about PostScript:
- PostScript is stack-based.
- PostScript has a coordinate system.
- PostScript has a path-based way to draw things.
Stack-Based Structure
PostScript is a stack-based language, just like the RPN example in Assignment 2. So, the code
6 4 2 sub mul
has the end result of pushing 12
on the stack: First the numbers 6
, 4
,
and 2
are pushed onto the stack (the “push” is implicit, and 2
becomes the
top value on the stack). Then the top two stack values (2
and 4
) are
subtracted (in the order 4-2
, obtaining
2
), and the result is pushed on the stack. Then 6
and 2
are multiplied, and
finally the result 12
is pushed on the stack.
The stack can hold any PostScript value, including numbers and strings.
A string is delimited with parentheses instead of quotes,
e.g., (Hello!)
.
All PostScript commands take their arguments, if any, on the stack. For
example, moveto
pops two stack values and uses them as
$(x,y)$ coordinates.
Coordinate Scheme
The default PostScript coordinate scheme puts $(0,0)$ at the lower left corner of the page, so that increasing the $x$-coordinate corresponds to moving rightwards on the page, while increasing the $y$-coordinate corresponds to moving upwards.
Although these coordinates are, by default, expected to be expressed in points (a point is $\frac{1}{72}$ of an inch), the coordinate system can be changed. In fact, the code you are given adjusts the coordinate system to use inches, so $(0,0)$ is the lower-left corner, and $(8.5,11)$ is the upper-right corner.
Paths and Drawing
To draw something in PostScript, you typically perform three steps:
-
Start a new shape, by executing the command
newpath
. -
Execute a series of drawing commands, including any of the following:
moveto
- Moves to the coordinates given by the top two stack values, e.g.,
3 14 moveto
goes to position $(3,14)$. lineto
- Draws from the previous point to the coordinates given by the top two stack values.
rmoveto
- Do a relative move; adds the top two stack values to the current position.
rlineto
- Like
rmoveto
, but adds a line along the way. closepath
- Takes no arguments; draws a line from the current position to the first
point in the current shape.
closepath
is preferred overlineto
when drawing the last edge of a closed figure (e.g., a box). show
- Draws a string at the current position.
arc
- Takes 5 numbers off the stack and draws an arc: the x
and y coordinates of the center, the radius of the arc, and the
starting and ending angles (e.g., 0 and 360 for a circle). WARNING 1: if
arc
is not the first drawing command afternewpath
, it also draws a line from the current position to the start angle on the arc. WARNING 2: The x-coordinate of the center is the lowest value taken from the stack, and the ending angle is taken from the top.
Note that
lineto
,rmoveto
,rlineto
, andshow
cannot be used until the first point of the path is set by amoveto
. -
Finally, draw the path by executing a command that describes what to do with the path: either
stroke
(draw the path as with a pen) orfill
(color in the interior of a closed path whose first and last points are the same). Thelineto
,rmoveto
,show
, etc., commands all specify a path, but the path doesn’t actually appear until astroke
orfill
command.
These steps are repeatable; a typical PostScript file has many
newpath ... stroke
pairs.
Other PostScript commands
-
Other PostScript commands that might be useful include:
translate
- Takes x and y coordinates; “translates” the whole coordinate system to make (x,y) (relative to the current coordinate system) be the new (0,0).
rotate
- Takes a number in degrees; “rotates” the whole coordinate system on the paper that many degrees, starting from the current coordinate system. WARNING: rotating then translating is different from translating before rotating! (The second command works relative to the coordinate system set by the first.)
scale
- Takes two numbers as a scaling factor: all coordinates are then multiplied by this factor. Repeated scalings, like repeated rotates or translates, are cumulative.
gsave ... grestore
- These two commands save a copy of the current coordinate system, and restore
the saved coordinate systems, respectively. This is useful if you want to
change coordinates only temporarily (in the “
...
” part of anewpath ... stroke
pair).
Whitespace
In PostScript, whitespace and line breaks are not significant (except in strings). Thus, for example,
newpath
2 4 moveto
1 3 lineto
stroke
will draw a line from (2,4) to (1,3).
This code
1 3 2 4 newpath moveto lineto stroke
would do the same thing, but is harder for people to read (and also uses more stack space).