Brief Postscript tutorial for 15-462 and 15-463


This is a tutorial written to help with a homework problems involving Bezier curves in Postscript.

What you need to know about Postscript for the assignment

Postscript is a programming language for page description (text & graphics). Usually programs (not humans) write Postscript and printers (not humans) read it, but it's actually a fun language for creating static 2-D images.

Postscript is a stack-based language. That is, instead of saying "1+2" as in C or "(+ 1 2)" as in lisp, you say "1 2 add" -- you push 1 and 2 on the stack, the "add" operator pops two items off the stack, adds them, and pushes their sum on the stack. That's why Postscript looks backwards: operands always come before operators. You probably won't need to use Postscript's arithmetic, conditionals, looping, or procedures for this assignment, however. Your "programs" can be straight line code. (If you find that you want to see more, there are more complete tutorials available).

Here's a minimal Postscript program to draw a line segment

%!
144 72 moveto
288 216 lineto
stroke
showpage
On UNIX, run the program "gs" (ghostscript) and cut and paste the above into its standard input. Try it now! It should create a window and draw a line (if you get an error message "Cannot open X display" then try running "setenv DISPLAY :0" and try again). Note: don't paste into the window that pops up, but the window in which you typed the "gs" command.

Postscript's units are points (72nds of an inch), which explains the funny large numbers in the code above. If we call (0,0) the lower left of the page and (8.5,11) the upper right, the above will draw a thin line segment from (2,1) to (4,3). Or send it into the standard input of the UNIX printer spooler "lpr" and it should print this on paper to the default printer (whatever your shell variable $PRINTER is set to).

The "%!" is a "magic number" on the file that tells lpr and other programs that it's a Postscript file. If it's not the first characters of the file then lpr will give you a listing, not a run!

If you'd rather not have to multiply everything by 72, the following first redefines the coordinate system so that 1 unit is an inch, not a point, and translates the origin to be 2 inches from the lower left (so that the unprintable 1/4 inch around the outside of the page doesn't mess you up). Then it sets the line width to .1 units (inches) and draws the same line segment

%!
72 72 scale
2 2 translate
.1 setlinewidth
2 1 moveto
4 3 lineto
stroke
showpage

Summary of the operators you'll need most:

The graphics state includes: pen position, color, pen width, and current transformation matrix. You need to set the line width before you call stroke.

And here is an example using cubic Beziers. Click here to run it.

%!
% Postscript program to draw some curves & text
% comments in Postscript proceed from '%' to end of line

% part 1: set up coordinate system
72 72 scale	% scale coordinate system so units are inches, not points
2 2 translate	% put origin 2 inches from lower left of page
% warning: if you leave off the above two lines, your picture will be tiny!

% part 2: draw a filled path

% counterclockwise path on the outside consisting of two Bezier segments
0 0 moveto
2.5 0   2 2  1 3 curveto
0 4  -1 0  0 0 curveto

% clockwise path on the inside consisting of one Bezier and two line segs
% this makes a "hole"
1 1 moveto	% because this is moveto and not lineto, "pen" is lifted
1 2 lineto
2 3   3 2  2 1 curveto
closepath

fill		% fill inbetween the outer & inner curves


% part 3: for reference, draw the control polygons for the curves used above.
% note that this is the same sequence of (x,y) points as above

.5 setgray
.03 setlinewidth	% set line width to .03 of current units (inches)

0 0 moveto
2.5 0 lineto  2 2 lineto  1 3 lineto
0 4 lineto -1 0 lineto  0 0 lineto

1 1 moveto
1 2 lineto
2 3 lineto   3 2 lineto  2 1 lineto
closepath
stroke % draw control polygon

% part 4: now we'll put up some text to label coordinates of a few points
/Helvetica findfont 12 72 div scalefont setfont
% 12 point Helvetica (we divide by 72 above because we scaled earlier)
1 setgray % white
0 0 moveto ((0,0)) show
0 setgray % black
1 1 moveto ((1,1)) show
1 3 moveto ((1,3)) show

1 -1 moveto (cubic Bezier curves in Postscript!) show

showpage	% don't forget this! (marks end of page)
Note that for this assignment you need not create a Postscript font.

I recommend that you design your shapes on graph paper with a pencil before you start typing. Don't have any graph paper? Make your own! (the Postscript program for this).


Debugging tips

Postscript can be tricky to debug, because the code is less readable than most other languages, and when you have a bug, you typically get no output. To debug, put your file in a text editor and try commenting out sections of it until it runs again, then use binary search, commenting and uncommenting, to locate the problem area. "gs" will give you some useful error messages (much better than lpr, which by default prints nothing on error!) Pay attention to gs's "Error" and "Operand stack" strings.

Extra stuff you don't need to know for the assignment

This shows off fancier things you can do with text:

%!
72 72 scale	% scale coordinate system so units are inches, not points
2 2 translate	% put origin 2 inches from lower left of page

/Symbol findfont 4 scalefont setfont
% current font is now Symbol about 4 inches high
gsave	% save graphics state (coordinate system & stuff)
.5 setgray
60 rotate
0 0 moveto (abcde) show
grestore	% restore previous graphics state

/Helvetica-Bold findfont .2 scalefont setfont
% current font is now slanted Helvetica about .2 inches high
0 4 moveto (Postscript is good at this stuff) show

/Times-Italic findfont 2 scalefont setfont
% current font is now italic Times about 2 inches high
1 0 0 setrgbcolor
0 6 moveto (yowza!) show

showpage
Note: as of late '97, some (all?) of the Andrew machines are running an old version of Ghostscript (2.6.2) with a very incomplete set of fonts. If the above looks lumpy to you (like a bitmap font), try the following instead, which substitutes some fonts that are available on the Andrew machines in outline form. See /usr/local/lib/ghostscript/Fontmap if you're curious how the system looks up font files.
%!
72 72 scale	% scale coordinate system so units are inches, not points
2 2 translate	% put origin 2 inches from lower left of page

/CharterBT-Italic findfont 4 scalefont setfont
% current font is now Symbol about 4 inches high
gsave	% save graphics state (coordinate system & stuff)
.5 setgray
60 rotate
0 0 moveto (abcde) show
grestore	% restore previous graphics state

/NimbusSansL-Regular findfont .3 scalefont setfont
% current font is now slanted Helvetica about .2 inches high
0 4 moveto (Postscript is good at this stuff) show

/URWGroteskT-Bold findfont 1.5 scalefont setfont
% current font is now italic Times about 2 inches high
1 0 0 setrgbcolor
0 6 moveto (yowza!) show

showpage
If you print either of the above versions, they should look quite nice, although with the latter, Courier font will get substituted.

Links to faraway Postscript info

Links to font info


15-462, Computer Graphics 1
15-463, Computer Graphics 2
Paul Heckbert, 18 Sept. 1997, last modified 4 Feb. 1998