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:

  1. PostScript is stack-based.
  2. PostScript has a coordinate system.
  3. 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:

  1. Start a new shape, by executing the command newpath.

  2. 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 over lineto 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 after newpath, 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, and show cannot be used until the first point of the path is set by a moveto.

  3. 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) or fill (color in the interior of a closed path whose first and last points are the same). The lineto, rmoveto, show, etc., commands all specify a path, but the path doesn’t actually appear until a stroke or fill 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 a newpath ... 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).