Creating graphics with the PostScript language

Introduction

PostScript is a programming language for creating graphics on a variety of devices; it was introduced by Adobe Systems in the 1985 and quickly became a widely used language for laser printers. PostScript files can also be viewed on a computer display, using, e.g., the 'ghostview' program. There are also many programs available for converting PostScript files to virtually any other graphics format (e.g., the 'convert' program, which is part of the free open-source ImageMagick package). In scientific computation, PostScript is very useful as it enables easy creation of non-standard graphs (such as visualizations of simulations) that may be difficult to accomplish with standard graphing software. Using the ImageMagick convert program, a series of PostScript file can also be translated into a single gif file (with a specified delay time betweeen each image) to create an animation.

PostScript is a complete programming language with many elements. However, in order to produce simple (and even not so simple) graphs, we need only a relatively small subset of the language. Here we will only discusss the most essential elements; for more informtaion, consult one of the many books on the subject, or search the web. A good web-site with basic PostScript information is maintained by the Computer Science Department at Indiana University. A very extensive manual on PostScript drawing is the book (available on-line for free) Mathematical Illustrations by Bill Casselman.

Some basic notions

The graphics operations in PostScrip are carried out in a two-dimensional coordinate system; the user space. In this space one can draw lines and curves, fill regions enclosed by bounding curves by shades of gray or colors, print text in a large number of fonts, etc. Length in the user space is measured in 'points', a unit used generally in graphics, which corresponds to 1/72 of one inch when printed on paper. If you want your graph to fit on a letter-size paper, you should hence work within the limits of a coordinate system of size 612x792 (anything done outside these limits will simple not be visible). The coordinate system can be scaled by an arbitrary factor using the scale command, and it can also be rotated using rotate. The origin of the user space coordinate system (located by default at the low-left corner) can be changed using the translate command.

Within the user space there is a point, called the current point, which is the coordinate over which you can imagine currently holding the tip of a pen. There are commands for moving this point, drawing lines or curves originating from it, printing text starting from it, etc. As these operations are carried out, a path is created in the user space. The path can be thought of as initially being drawn with invisible ink. The command stroke completes the path and makes the drawn segments of it visible, while the command fill fills the area enclosed by a closed path with a shade of gray or color (which has been specified prior to the fill command; if no shade of gray or color is specified, everything is drawn or filled with black). After a stroke or fill has been executed, the current point becomes undefined; a new one is created using the moveto command.

The name "PostScrip" alludes to the fact that arguments (operands) in this language are written before the command (operator) using them, i.e., to move the current point to the coordinate (100,100), the statement 100 100 moveto is used, and to draw a line 100 points to the right and 10 points up relative to the current point 100 10 rlineto is used. The PostScript interpreter puts all operands encountered on a stack (a last-in-first-out list), and when an operator is encountered an appropriate number of operands are taken from the stack. If there are not enough operands on the stack an error message is produced. In elementary PostScript programs one normally puts all the operands needed by an operator right before the operator itself, but some times it may be necessary to load up operands on the stack and process them at a later stage. To give an example of how the stack works, the statements 100 50 moveto 20 30 rlineto are equivalent to 20 30 100 50 moveto rlineto.

PostScript files should be given the extension '.ps'. Code can be written in free format, with any number of commands per line. The character % denotes a comment, i.e., anything following this character (on the same line) is ignored by the interpreter. All PostScript files should begin with the two characters %!. Many devices need this in order to know that what follows is PostScript code. On some laser printers, if you do not begin the file with %! (exactly on the first position of the first line!), what is produced is not the intended graph, but a print-out of the actual PostScript code. A PostScript program should end with the showpage command, which indicates that a page has been completed; several different pages can be created by using multiple showpage statements.

We have now covered enough of the basics to show a first simple example.

Organization of the rest of this tutorial

This is a very brief tutorial, intended to quickly give the basic information needed to start producing PostScript graphs. The most important commands will be introduced below in groups of related commands, and in many cases examples demonstrating the use of these commands will be given (the examples can involve also other previosly introduced commands). The output produced by each example code is shown as well (the convert program was used to create the displayed gif files from the ps files containing the program statements shown).

An example of how a Fortran 90 program can produce PostScript output is given here.

PostScript Operators

Moving the current point

x y moveto
Moves the current point to (x,y).

x y rmoveto
Moves the current point by (x,y) relative to its present position.

Drawing lines and filling areas

When drawing a line, the starting point is the current point. The end point becomes the new current point. To make the line visible, the stroke command has to be used. The default line width is 1 point. If a closed path has been created by multiple line-draws, the area enclosed by it can be filled using fill.

x y lineto
Draws a line from the current point to (x,y).

x y rlineto
Draws a line from the current point to the point separated by (x,y) from the currentpoint.

w setlinewidth
Sets the line width to w points (default w=1).

v setlinecap
Sets the type of line endings; v=1 for straight cut (default), v=2 for rounded.

[Example]

Commands related to the current point and path

currentpoint
Puts the x and y values of the current point (x,y) on the stack (for use by a subsequent operator, e.g., after the current point has been destroyed by stroke or fill).

newpath
Begins a new path. Using this command is often not required, since a new path is started automatically by the moveto command after a stroke or fill has been executed (or by the first moveto). If a path already exists (stroke or fill have not been executed) it will be destroyed by newpath.

closepath
Draws a line from the current point to the first point of the path [example].

Commands for transforming the user space

x y translate
Moves the origin of the user space to the point (x,y).

x y scale
Scales the user space by a factor x in the x-direction and y in the y-direction.

a rotate
Rotates the user space by an angle a (in degrees) about the origin.

[Example]

Drawing arcs, circles, and curves

x y r a1 a2 arc
Draws an arc segment of a circle centerd at (x,y), with radius r, counter-clockwise from angle a1 to a2 (in degrees). The current path will also include a straight line from the current point to the start of the arc, if they are not the same. A full circle is obtained with, e.g., a1=0, a2=360 [example].

x1 y1 x2 y2 x y curveto
Draws a curve from the current point to (x,y), using the points (x1,y2) and (x2,y2) to fix the tangent of the curve at the current point and (x,y); the tangent at the current point is the line from it to (x1,x2), and at (x,y) the line from this point to (x2,y2). This is a so-called Bezier curve [example].

Changing the scale of gray or the color

c setgray
Sets the scale of gray to c (0-1; 0=black, 1=white) [example].

r g b setrgbcolor
Sets the color according to the RGB scheme; r,g,b are the strengths (0-1) of read, gree, and blue [example].

Defining new operators

/opname {statements} def
Defines opname to be the statements between { } [example].

Saving the graphical state

The graphical state corresponds the current path and all settings for parameters such as the line width, the color or shade of gray, the scaling and rotation of the user space, etc. The graphical state can be saved and later restored. This is useful if the state has to be locally changed for some operations and then set back to what it was before (e.g., in a definition of a new operator).

gsave
Saves the current graphical state.

grestore
Restores the graphical state prior to the previous gsave statement.

[Example].

Printing text

Text can be printed starting from the current point (whereby the current point is moved to the end of the printed string, using a variety of fonts, such as TimesRoman, Helvetica, and Symbol. Text is made visible using show (the current point is retained).

/Font findfont s scalefont setfont
Sets the current font to Font, scaled to size s

show (string)
Prints the character string string at the current point.

[example 1] [example 2]