PostScript as a Programming Language

PostScript is a Programming Language. The appearance of a page is described by a program creating points, lines, and other blobs of color on the page.

For example, the following PostScript program:

%!PS-Adobe-3.0
%%Creator:  Anton Tandiono, Florian Nykrin
%%Title: Devilish Smiley

% horns
newpath 250 370 moveto -50 40 rlineto 250 310 lineto fill
newpath 350 370 moveto  50 40 rlineto 350 310 lineto fill

1 0 0 setrgbcolor

% face
newpath 300 300 100 0 360 arc fill

0 0 0 setrgbcolor

% eyes
newpath 250 350 10 0 360 arc fill
newpath 325 325 moveto 350 350 lineto stroke

% smile
newpath 300 300 70 230 350 arc stroke

% comment
showpage
quit

How to do that will be explained here.

PostScript is an interpreted language, i.e. there is a interpreter reading the source text (PostScript) and executing it. One such interpreter is e.g. ghostscript. ghostscript can be invoked by the command gs.

For example:
$gs smily.ps
will produce a visual rendering of the content of the postscript file smily.ps on the screen.

You can use ghostscript also interactively. Especially while learning PostScript this is very useful. You use the command gs without a file name and get:
$gs
AFPL Ghostscript 7.04 (2002-01-31)
Copyright (C) 2001 artofcode LLC, Benicia, CA.  All rights reserved.
This software comes with NO WARRANTY: see the file PUBLIC for details.
GS>

Then the interpreter waits for input.

Executing PostScript Code

PostScript consists of data and operators (this is not entirely true. Operators in PostScript are data as well.)

PostScript pushes data on a stack. Operators take operands from the stack and put results back on the stack

The following example uses the data 10 and 5 as well as the operator mul (Multiplication). The operator stack can be used to display the stack The number if entries on the stack is indicated in pointed brackets.
GS> 10
GS<1> stack
10
GS<1> 5
GS<2> stack
5
10
GS<2> mul
GS<1> stack
50
GS<1>

Numbers and Arithmetic Operators

Integers as well as floating point numbers are understood by PostScript.

These are the most important arithmetic operators:

Arguments Name Description
x y add x + y
x y sub x - y
x neg - x
x y mul x * y
x y div x / y
x y idiv int(x / y)
x y mod x modulo y
x sin sin(x)
x cos cos(x)
x y atan arctan(x /y)
x sqrt square root(x)

Boolean Expressions

Arguments Name Description
x y gt x greater than y
x y lt x less than y
x y ge x greater or equal than y
x y le x less or equal than y
x y eq x equal to y
x y ne x not equal to y
true true
false false
x not not x
x y and x and y
x y or x or y

Stack Manipulation

Arguments Name Description
x dup x x (duplicating x)
x1...xn n copy x1...xn x1...xn (duplicating n elements)
x y exch y x (swap x and y)
x pop delete x from the stack
n index copy the n-th entry to the top of the stack

Arrays

Arrays are created in PostScript dynamically, but have a fixed length. Elements of an Array have an arbitrary type (PostScript is a dynamically typed language) and are index from 0 to length-1.

Arguments Name Description
n array creates a Array with n Elements
a i get push element i of Array a on the stack
a i x put store x at position i in the array a
a length push the length of array a on the stack

Procedures and Control-Operators

In normal mode, operators are not put on the stack but are executed immediately. If you put one or more operators in curly braces, however, you create a new data object, a procedure, that is pushed on the stack. Later you can execute this procedure using operators.

Example: the procedure {20 add} is put on the stack and executed by the operator exec
GS>10
GS<1>{20 add}
GS<2>stack
--nostringval--
10
GS<2>exec
GS<1>stack
30

Arguments Name Description
p exec execute procedure p
b p if if b is true execute procedure p
b p q ifelse if b is true execute procedure p else execute procedure q
n p repeat execute procedure p n-times
a s e p for for all values from a to e with step s, put the value on the stack and the execute procedure p.
a p forall execute procedure p for all elements of array a
p loop repeat procedure p forever
  exit exit innermost procedure

Drawing with PostScript

Drawings are made in PostScript by defining a path. A path is made visible either as a line or by filling the inside. A path starts with the operator newpath and ends either with the operator stroke (Line) or fill. Several paths can be placed one after the other on a page. Finally, the command showpage will clear the page again and advances to the next page for multi page documents.

A path can be constructed with the following operators:

Arguments Name Description
  newpath start a new path
  stroke finish the path and draw a line
  closepath closes the path from the current point to the beginning
  fill finish the path and fill the interior.
x y moveto move the current position to x,y
x y lineto continue the path from the current position to x,y
x y rmoveto move the current position (relative) by x,y
x y rlineto continue the path (relative) from the current position by x,y
x y r a e arc continue the path with an arc from angle a to angle e with a center at x y and radius r
x1 y1 x2 y2 x3 y3 a e curveto make a Bezier Curve to x3 y3.
For the curveto operator some more explanation seems in order. It draws a Bezier curve from the current position to (x3,y3). The points (x1,y1) and (x2,y2) are control points. The resulting curve is the trajectory of a stone, thrown from the current position with velocity vector (x1, y1) arriving at the final position (x3, y3) with velocity vector (x2, y2) keeping the necessary acceleration along the path as small as possible.

The Graphics Machine and its State

The PostScript Graphic Machine, responsible for the drawing of paths and fonts, can be parameterized. For example the with of a line or the color for filling can be set with setlinewidth or setrgbcolor.

Then there are commands to change the origin of the coordinate system (translate), to scale it (scale) or to rotate it (rotate). The best, however, is that you can save (gsave) and restore (grestore) the state of the machine on a separate stack. This allows nesting of command sequences.

Another interesting feature is clipping (which is beyond the scope of this simple summary).

Arguments Name Description
w setlinewidth set the linewidth for stroke
r g b setrgbcolor set the rgb color; r, g, and b values are in the range 0.0 to 1.0
x y translate set the origin of the coordinate system
x rotate rotate the coordinate system by x degree counterclockwise
fx fy scale scale the coordinate system with a factor for the x and a factor for the y direction
  gsave save the graphics state
  grestore restore the graphics state
  currentpoint put the current x and y coordinate on the stack

Variables and Dictionaries

To store values in variables, in PostScript you use dictionaries. A variables is referenced by its name. Names are separate data type. You recognize a name because it starts with a slash. For instance /counter.

A simple command is def. It takes a name and a value from the stack and stored the value under this name in the dictionary. You can put the value back on the stack simply by writing the name without the slash.

For example:

GS>/counter 50 def
GS>counter
GS<1>stack
50

You can create your own dictionaries by using the command dict. This command takes the initial size of the dictionary from the stack, creates a dictionary and puts it back on the stack.

To store a value you can use the command def. It stores the name value pair in the current dictionary. PostScript uses a separate stack for dictionaries. The command def always uses the topmost dictionary on this stack. To look up a value, PostScript will search the whole stack from top to bottom to find a suitable name-value pair.

To manage the dictionary stack there are two commands: begin and end. The command begin takes a dictionary from the value stack and puts it on the dictionary stack. The command end removes the topmost dictionary from the dictionary stack.

For example:
GS>/hallo 111 def
GS>hallo
GS<1>5 dict begin
GS<1>/hallo 222 def
GS<2>hallo
GS<2>end
GS<3>hallo
GS<3>stack
111
222
111

Another important command in this context is the store command. It works similar to def It needs a name and a value and stores the value under the given name. def, however, always uses the topmost dictionary, creating an entry if necessary, while store searches the whole dictionary stack from top to bottom for a matching name. Only if no entry is found, a new entry is created in the topmost dictionary.

Arguments Name Description
i dict creates a dictionary with i entries
d begin moves dictionary d to the dictionary stack
end removes the topmost dictionary from the dictionary stack
n x def stores value x under name n in the topmost dictionary
n x store searches the dictionary stack for name n and stores x there if n is found. otherwise like def

Dictionaries can also be specified explicitly. You can keep dictionaries in variables (inside other dictionaries) for that purpose and use the following commands.

Arguments Name Description
d n w put store value w under name n in dictionary d
d n get get the value of name n in dictionary d, and put it on the stack

Example:
GS>/mydict 10 dict def
GS>mydict /x 123 put
GS>mydict /x get
GS<1>stack
123

Strings and Fonts

Fonts are nothing but collections of code, producing an outline path for individual characters. There are, however, some high-level functions to manipulate fonts.

Fonts and Strings are data types. Fonts are created with the operator findfont and literal strings are created by enclosing character sequences in parentheses.
Arguments Name Description
n findfont searches for a font with name n and puts it on the stack
f i scalefont takes font f and number i, scales the font to i point size and puts it back on the stack
f setfont takes font f from the stack and makes it the current font
s show takes a string s from the stack and draws it using the current font
Example:
GS>/Helvetica findfont
Loading Helvetica ...
GS<1>36 scalefont
GS<1>setfont
GS>100 100 moveto
GS>(Hello world!) show

Format of PostScript Files

Comments start with a Percent sign. A specialty is the comment %!PS. Every PostScript File should start with this comment, to enable programs processing it to handle it properly. Other special comments are commonly used at the beginning of a PostScript file to ease processing.

For example:
%!PS-Adobe-2.0
%%Creator: I myself, Copyright 2005 Martin Ruckert
%%Title: The explanation file
%%Pages: 5
%%PageOrder: Ascend
%%BoundingBox: 0 0 596 842