(c)  Copyright 1989 Commodore-Amiga, Inc.   All rights reserved.
The information contained herein is subject to change without notice, and 
is provided "as is" without warranty of any kind, either expressed or implied.  
The entire risk as to the use of this information is assumed by the user.




                 PostScript Primer for Programmers

                    by Carolyn Scheppner - CATS



PostScript is a programming language that provides a hardware-independent 
standard for representing the printed page.  PostScript objects include the
Adobe fonts which can be scaled, condensed, expanded, outlined, italicized
and rendered anywhere on a page.  PostScript can also draw lines and curves 
to create geometric shapes which may be outlined or filled with any shade.
In fact, any arbitrary image can be manipulated with PostScript.  Let's take
a closer look at these capabilities by trying a few simple examples.  


PostScript, like Forth, is a very stack-oriented language.  Most PostScript 
commands take their arguments from the stack and the commands are given using 
postfix notation - that is, with operators following their operands.  Here 
are a few PostScript statements in postfix notation:


PostScript Statement             Meaning

   10  40 moveto        % Move to x,y position 10,40. 
                        %
   (Hi)   show          % Print the string "Hi".
                        %
   /LM 20 def           % Assign the value 20 to variable LM.
                        %
   3   5  add           % Push 3 then 5 on stack and add them, 
                        %   leaving 8 on stack.


Some operations like "moveto" return no result.  Instead they change the state
of internal PostScript variables.  For instance "moveto" changes your position
in the co-ordinate system used by PostScript for drawing operations.  This is 
similar to moving the pen in Logo with the SETXY command.  Other operations 
like "add" and "currentpoint" place results on the stack where subsequent 
operations can make use of the results.  Here is an example which moves to
a new position in the PostScript co-ordinate system:

    currentpoint     %  Places the current x,y co-ordinate on the stack
                     %    (y on top).
    10 add           %  Adds 10 to the item on top of the stack 
                     %    (the y position).
    moveto           %  Moves to the new x,y co-ordinates which 
                     %     are on top of the stack (x,y+10). 


Sometimes the results of an operation are not in the order you need for the
next operation.  In this case, the operands on the stack can be duplicated, 
discarded, exchanged or assigned to variables.  Here is a longer example
which assigns the length of the string "Hello" to a variable:

    (Hello)          % Pushes the string "Hello" onto the stack.
                     %
    dup              % Duplicates the top stack entry and pushes
                     %      it onto the stack.
    stringwidth      % Takes the duplicate entry off of the stack 
                     %      and uses it to calculate width and height.
                     %      Width and height are pushed onto the stack.
    pop              % Throw away the height, leaving width on stack.
                     %
    /strw            % Pushes the variable name strw onto the stack.
                     %
    exch             % Swaps the top 2 stack items - now the order is  
                     %        /strw, width.
    def              % Assigns the value of width to the variable strw.
                     %        (i.e. /strw width def)

PostScript control structures are also stack oriented.  You create a control 
structure by pushing a condition on the stack, followed by a procedure,
followed by a control operator.  The procedure can be any number of statements
delimited by the curly braces {}.  The example below will print "Is 3", if 
the varible xyz is equal to 3:

    xyz 3 eq          % Checks if the variable xyz equals 3.  If so, TRUE is
                      %    pushed onto the stack.  Otherwise FALSE is pushed.
    {(Is 3) show} if  % Executes the statements in curly braces if TRUE is on 
                      %    the top of the stack.
 
The use of curly braces is not limited to control statements.  You can use 
them with the "def" operator to group together several operations that define
a complex new procedure which you can use just like the built-in operators.
This lets you build powerful commands that can be included at the start of 
your code, allowing your "main" program to be just a sequence of simple 
procedure calls.  Here's an example:

    % === Variables
    /TM   740 def    % set top margin variable
    /LM    20 def    % set left margin variable

    % === Procedures
    /topofpage  { LM TM moveto } def    % move to top left corner       

This code makes a new "topofpage" command that you can use in your programs.
Note that in PostScript co-ordinate system, (0,0) is at the lower left corner 
of the page, and unless scaled, each unit represents 1/72 of an inch.

Now that you have a better idea of how PostScript works, let's consider a 
more complicated example.  A complete PostScript program which generates
a company letterhead is shown below.  The example contains a variety of 
procedures that simplify the selection and styling of fonts and the centering
and justification of strings.

If you do not have a PostScript printer, you may want to try the PostScript 
interpreter by Greg Lee on Fish Disk #101.  You can use this to test out
your own PostScript code and preview the layout of pages you create.  I have 
included conditional code for Greg's interpreter in the letterhead example. 
Activate it by setting the InterpFlag variable to 1.  

You may have to fiddle a bit with the value I add to the right margin (RM) in 
the conditional code for the interpreter.  I scale the output so that the 
whole page is compressed to fit on the Amiga's screen, but an adjustment to 
the right margin variable seems to be needed to match the printer's horizontal
layout.  Larger font sizes seem to need larger adjustments. 

The front end of the letterhead example could be used as a base for your own
letterhead, overhead, report cover or sign making programs.  Add your own 
procedures for new features such as graphic elements or shade-filled outline 
text.  To learn more about programming in PostScript, see the PostScript 
Language Reference Manual or the PostScript Language Tutorial and Cookbook, 
by Adobe Systems Incorporated.
      
(PostScript is a registered trademark of Adobe Systems Inc.)



----------------- Lauren, code starts here ---------------------------

%! PostScript (R) Letterhead Example  by  C. Scheppner
%  PostScript and fontnames are registered trademarks of Adobe Systems Inc.

% === Save the initial state
save

% === Conditional Flag for Greg Lee's ps interpreter, Fish Disk #101
/InterpFlag 0 def        % Set to 1 for interpreter, 0 for printer


% === My margins (RM modified in Interpreter Changes)
/TM 740 def    % top margin
/BM 20 def     % bottom margin
/RM 582 def    % right margin
/LM 20 def     % left margin


% === Start of Conditional Changes for Interpreter
InterpFlag 1 eq {
2 pencolor 
/showpage {
   % do nothing
   } def
/RM RM 260 add def  % fixes spacing somehow
.54 .65 scale       % scale to fit page on screen
erasepage } if
% === End of Changes for Interpreter


% === My Variables initialized to defaults (Note: Margins defined above)
/pagenum 0 def     % Keep track of page numbers
/fsize 20 def      % Font size (height)
/fwidth 20 def     % Font width
/ftilt 0 def       % Font tilt
/outline 0 def     % Outline flag
/cpx LM def        % Currentpoint X for user savecp/restorecp
/cpy TM def        % Currentpoint Y for user savecp/restorecp
/tcpx LM def       % Temp cpx for oshow
/tcpy TM def       % Temp cpy for oshow


% === My Subroutines

% === Save/Restore X/Y position
/savecp    { currentpoint /cpy exch def /cpx exch def } def
/restorecp { cpx cpy moveto } def

% === Perform a newline based on font size
/newline
 { currentpoint fsize sub
   exch pop
   LM exch
   moveto } def

% === Move to top left corner
/topofpage { LM TM moveto } def

% === Move to top left corner, increment pagenum
/newpage
 { topofpage
   /pagenum pagenum 1 add def } def

% === Called by myshow if outline flag is set  (string on stack)
% === Note: stroke kills currentpoint so I must save/adjust/restore
/oshow
  { currentpoint /tcpy exch def /tcpx exch def
    dup stringwidth pop
    tcpx add
    /tcpx exch def
    true charpath stroke
    tcpx tcpy moveto } def

% === Move in X to center string between LM and RM  (string on stack)
/center
 { dup stringwidth pop
   RM LM sub exch sub
   2 div LM add
   currentpoint exch pop
   moveto } def

% === Move in X to right justify string against RM  (string on stack)
/rjust
 { dup stringwidth pop
   RM exch sub
   currentpoint exch pop
   moveto } def

% === Line show rtns, with and without newline (string on stack)
% === "c" means centered, "r" right justified, 
% === myshow is like normal "show" but does solid or outline on printer

/myshow { outline 0 eq { show } {oshow} ifelse } def
/cshow  { center myshow } def
/rshow  { rjust myshow } def
/showline  { myshow newline } def
/cshowline { cshow newline } def
/rshowline { rshow newline } def

% === Set pointsize of basefont  (pointsize on stack)
/setsize
  { /fsize exch def
    /fwidth /fsize def
    /ftilt 0 def
    basefont findfont fsize scalefont setfont } def

% === Set custom style of basefont  (height width tilt on stack)
/setstyle     % stack = high wide tilt
  { /ftilt exch def
    /fwidth exch def
    /fsize exch def
    basefont findfont [fwidth 0 ftilt fsize 0 0] makefont setfont } def

% === Select a font as current basefont  (/Font-Name on stack)
% === For the interpreter, I change all font requests to /simplex
/selectfont
  { InterpFlag 1 eq
      {pop /basefont /simplex def}
      {/basefont exch def} ifelse
    fsize fwidth ftilt setstyle } def

% === Turn font outline-only rendering on and off
/setoutline { /outline 1 def } def
/setsolid   { /outline 0 def } def

% === Draws a big underline from left to right margin
/bigline {
   newline
   gsave
   0 fsize 3 div rmoveto
   RM LM sub 0 rlineto
   stroke
   grestore
   } def


% =========================  MAIN PROGRAM  =============================
newpage                           % go to top of page
/AvantGarde-Book selectfont       % select a font

36 24 8 setstyle                  % make condensed italic style
(Propeller Soft  ) show           % show this at current position
20 14 0 setstyle                  % smaller condensed non-italic
                                  % show next line right-justified
(Creators of "Editor Wars", the game programmers play) rshow
bigline                           % now call big underline subroutine

14 12 0 setstyle                  % smaller condensed non-italic
newline                           % move down a (size 14) line
savecp                            % save current x/y position for below
newline                           % move down a line
(Max E. Byte) cshowline           % show this centered, then newline
(Programming Genius) cshowline    % show this centered, then newline

12 10 0 setstyle                  % even smaller condensed non-italic
restorecp                         % move back to saved x/y position
(12 Speedbump Lane) showline      % show these 3 lines at left
(West Chester, PA.) showline
(19380   USA) showline

restorecp                         % move back to saved x/y again
(Phone: (900) 555-1212) rshowline % show these 3 lines at right
(FAX: (900) 555-4321) rshowline
(Telex: 5551010110) rshowline

% === Show (print) the page, then restore the initial state
showpage
restore


