The PostScript programming language is designed to describe the layout of graphics and text on the printed page. Its history is a good example of the intersection of theory and marketplace that drives so much of software design. We'll take a look at the language for two reasons. From a practical standpoint, it can be an effective way to define geometric forms and text for inclusion in our digital imagery. But the PostScript language is also based on a fundamentally different programming paradigm than Python. Software design can be more varied than you would suspect simply by learning a single programming language.
The following is a brief description of some PostScript concepts that will serve as an introduction to other tutorials and resources on the Web:
Like Python, PostScript is typically an interpreted language. That means that the there is a process, called the PostScript interpreter, that will "read" a PostScript program and perform the actions the program describes.
However, the way that PostScript executes a program is quite different than Python. Each argument for an operator is put on the PostScript stack. The stack is, like its name implies, a pile of sorts, in which you can only remove items in the reverse order that you put them there. Think about placing playing cards down in a pile one at a time — if you deal them out, they will be handed out in reverse. (In computer science, this is called a "last in, first out" structure, or LIFO.)
When an operator is encountered in the PostScript program, it uses the values on the stack as its arguments. Those values are removed from the stack, and if the operator returns a value, it is placed on the stack after the operator has performed its action.
For example, the add operator adds two numbers together, and places that sum on the stack when it is done. In the PostScript program, to add 2 and 3 you would write:
2 3 add
After this is executed, the number 5 would be left on the stack. This number could then be used as an argument for another operator. So to take the result of adding 2 and 3 and multiply it by 4, you would write:
2 3 add 4 mul
The idea of the stack can take some getting used to. To get a better feeling for how the stack is used in PostScript programming, it can be helpful to write down what the stack looks like after each argument or operator has been read by the PostScript interpreter. For example, the previous example involves five separate changes to the contents of the stack:
| Postscript executed | Stack contents |
| 2 | 2 |
| 3 | 3 2 |
| add | 5 |
| 4 | 4 5 |
| mul | 20 |
In the above table, the stack is displayed with new values placed on top, which corresponds to the intuitive sense of the stack as a pile with only the object on top being availble.
PostScript programming does not consist of calculations that only affectd the current value of the top of the stack. Many PostScript operators affect the graphics state, including the creation of shapes and text that will be printed on the page when it is finally produced by the printer.:p:
A basic graphical concept in PostScript is the current position. You can set the current position with the moveto operator:
72 72 moveto
Just like add and mul, the arguments to moveto precede it, in this case, the new X and Y values of the current position. The units for the graphical operations are measured in points, with 72 points per inch. The PostScript coordinate system defines the 0 0 position to be at the lower left corner of the page, so 72 72 is one inch from the left, and one inch up from the bottom. For a standard 8.5x11" letter-sized sheet of paper, the upper right corner is therefore 612 792.
Once you have set the current position with moveto, you can draw a line with the lineto operator. Like the moveto operator, lineto takes two arguments for the X and Y position to which a line should be drawn. For example, to draw a line from the lower left corner to the upper right corner of a ltter-sized piece of paper, you would write:
0 0 moveto 612 792 lineto
However, a line has not been drawn yet; you have only specified a current path. To draw a line, you use the stroke operator:
0 0 moveto 612 792 lineto stroke
The stroke operator doesn't require any arguments; it just draws a line based on the current path.
We've now specifed a path and drawn it, but in order to generate a printed page, we need to use the showpage operator. Like stroke, showpage doesn't need any arguments:
0 0 moveto 612 792 lineto stroke showpage
We'd like to use this PostScript code to print a page containing our corner-to-corner line. But if we send a file containing this code to a printer, how does the printer know to draw a line, rather than just printing out the text? We need to put two characters on the first line of the file which identifies it as containing PostScript code so the printer will behave accordingly. Those two characters are %! (the percent and exclamation point characters). So now our PostScript code looks like this:
%!
0 0 moveto 612 792 lineto stroke showpage
Since the PostScript interpreter reads the arguments and operators one a time and immediately modifies the stack or the graphics state, the way we arrange our PostScript code is not significant. We could clarify our program by dividing it across multiple lines:
%!
0 0 moveto
612 792 lineto
stroke
showpage
To see a page with this line drawn in it, create a file called "line.ps" and cut and paste the above PostScript code into it. (Remove the leading spaces from the first line, though.) In OS X, you can display a PostScript file with the open command. This converts the PostScript code to a PDF file, and displays it using Preview. For example, if your file is called "line.ps", enter the following in a Terminal window:
open line.ps
(In the various versions of Windows, viewing PostScript files is not quite so simple. The best solution is to use Ghostscript, a free PostScript interpreter.)
The stroke operator draws a line along the current path. The lineto operator can be called repeatedly to create a complex path (try this in a file):
100 100 moveto 200 200 lineto 300 100 lineto stroke
The closepath operator will connect the last point specifed by lineto to the first point in the path. To make explicit that you are starting a new path, you use the newpath operator:
newpath 100 100 moveto 200 200 lineto 300 100 lineto closepath stroke
To use the path as an outline that will be filled, you use the fill operator instead of stroke:
newpath 100 100 moveto 200 200 lineto 300 100 lineto closepath fill
Some operators make complex paths. The arc operator draws an arc of some number of degrees, with a given radius and center. PostScript documentation describes operators by naming the types of values that should be used with an operator, and the resulting value left on the stack. The arguments and result are specified on a single line, like this:
x y r ang1 ang2 arc -
The arc operator doesn't leave anything on the stack, indicated by the "-".
PostScript doesn't provide a "circle" operator — you use the arc operator and specify 0 to 360 degrees. For example, to draw a two-inch circle in the middle of a letter-sized page, you would write:
newpath 306 396 144 0 360 arc closepath
This only specifies the path, however. To draw a circular line, you would draw it with the stroke operator:
newpath 306 396 144 0 360 arc closepath stroke
A filled circle uses the fill operator:
newpath 306 396 144 0 360 arc closepath fill
To display text with PostScript, you need to perform three actions:
A font is described by a name that is preceded by a slash character (/). The slash indicates to the PostScript interpreter that the following word is a symbol, and not an operator. (In many programming languages, this is called a literal.) The findfont operator takes a font name and places the actual font object on the stack. For example, to place the Helvetica font object on the stack, you would write:
/Helvetica findfont
The size of a font needs to be specified. The scalefont operator takes a font object and a numeric size and creates a font that is the given size. For example, to make a font that is half an inch tall, you would write:
/Helvetica findfont 36 scalefont
Now there is a scaled font object on the stack. To specify that it should be used for displaying text, you use the setfont operator:
/Helvetica findfont 36 scalefont setfont
Before we display text, we need to set the current position, which will be the location of the lower left corner of the text string. We use the moveto operator to position our text half an inch from the left and two inches from the bottom of our paper:
/Helvetica findfont 36 scalefont setfont
36 144 moveto
To display text, we use the show argument. It takes a text value on the top of the stack and displays it at the current position. Text is an argument, just like the numbers we specified for add and mul, but since we don't want our text to be interpreted as a series of PostScript operators, we surround the entire text with parentheses. The parentheses actually create a single text object which will be the argument to the show operator:
/Helvetica findfont 36 scalefont setfont
36 144 moveto
(The text that is displayed.) show
Add the identifying %! characters and the showpage operator and create a file containing this PostScript code as we did with the line drawing example to see how text is displayed:
%!
/Helvetica findfont 36 scalefont setfont
36 144 moveto
(The text that is displayed.) show
showpage
Try changing the text and the position and redisplaying your modified PostScript code.
PostScript is not just a way of drawing shapes and text, but is a complete programming language. The tutorials listed at the beginning of this page show further examples of how you can repeat a series of operations in a loop, allow for conditional execution, and even define your own operators to augment the set defined by PostScript itself.