postscript


comments

the sign % starts comments. a comment in PostScript is any text preceded by a %

the special comment %! as the first two characters of a PostScript program is seen as a tag marking the file as PostScript code by many systems (including Unix’s lpr command). it is a good idea to start every PostScript document with a %!

name

it is any sequence of characters that can not be interpreted as a number with the exception of spaces and certain reserved characters
( ) [ ] < > { } / %

a name is seen as being a reference to some value in a dictionary

  • if a name is preceded by a slash, PostScript will place the name on the operand stack
  • if the name has no slash, the interpreter will look up its value in the dictionary
    1. if the value is a procedure object, the procedure will be evaluated
    2. if the value is not a procedure, the value will be pushed onto the operand stack
    3. if the value is not a procedure and not an operand - the error takes place

    number

    PostScript supports integers and reals

    you can express numbers in two forms: radix form, and scientific notation

  • radix form: radix#value
  • scientific notation: mantissaEexponent

  • string

    there are two ways of expressing strings in PostScript

  • you can wrap your text in parentheses: (This is a string)
  • you can also express a string as hexadecimal codes in angle brackets. for example, for "ABC" string: <414243>
  • array

    arrays may contain objects of different type, and they are written as a list of objects surrounded by brackets

    for instance, [12 /Foo 5.3] is a three element array containing the number 12, the name Foo, and the number 5.3

    operators

    polish (backwards> notation is used in PostScript

    1 2 add 3 sub 4 div 5 mul % 0 in result

    27 4 idiv 3 mod % 0 in result

    abs a unary operator. absolute value is the result
    neg changes the sign of its only argument
    ceiling a unary operator which evaluates the integer value closest to its argument from above
    floor a unary operator which evaluates the integer value closest to its argument from below
    round a unary operator which evaluates the integer value closest to its argument
    truncate a unary operator which removes the fractional part of its argument
    sqrt a unary operator which evaluates the square root of its argument
    cos a unary operator which evaluates the cosine of its argument
    the argument is assumed to be given in degrees
    sin a unary operator which evaluates the sine of its argument
    the argument is assumed to be given in degrees
    ln a unary operator which evaluates the natural logarithm of its argument
    log a unary operator which evaluates the base-10 logarithm of its argument
    exp a binary operator which needs two parameters. the first is the base and the second is the exponent. it raises the value of the base to the power whose value is the exponent

    stacks

    there are four available stacks in PostScript:

    = pops one object from the operand stack and writes a text representation of its value to the stdout, followed by a newline
    == has a similar action but it writes syntactic representation of its operand

    pstack displays all elements of the operand stack in vertical order such that the last entered element is displayed first

    pop removes the top element from the operand stack and discards it

    exch exchanges the two topmost elements of the operand stack

    dup duplicates the topmost element of the operand stack

    clear discards all elements of the operand stack

    drawing

    command a4 will resize your drawing sheet to the appropriate size (595x842 px)

    x y moveto where x and y denote respectively the horizontal and vertical coordinates of the point where the cursor will be located. x and y are pure numbers and considered in pixel units

    xx yy lineto where xx and yy denote the location of the endpoint of the line segment

    the actual drawing necessitates the path definition newpath and stroke commands

    newpath 
    100 100 moveto 
    300 100 lineto 
    300 250 lineto 
    100 250 lineto 
    100 100 lineto 
    stroke
    

    save it in sample1.ps

    gs sample1.ps 
    
    you do not need to invoke gs interpreter at every time of displaying. instead:
    GS> (sample1.ps) run
    

    x y rmoveto
    x y rlineto
    where x and y are the horizontal and vertical distances between the initial and final points of each action. 'r' in rmove and rlineto stands for relative

    x setlinewidth (where x denotes the line width in pixels) defines the line width

    x y r a b arc where
    x, y - the horizontal and vertical coordinates of the center of the circular arc
    r - the radius of the arc
    a, b - the angles between the positive part of the horizontal axis and the central rays which pass through the beginning and the final points of the arc

    arcn draws arc clockwise

    newpath
    3 setlinewidth
    200 200 moveto
    100 200 100 0 75 arc
    stroke
    

    user can rescale of the horizontal and vertical units separately via command x y scale where x and y denote respectively the horizontal and vertical scaling factors.the next issued scaling command does not remove the effect of the previous one but it combines its own effect with

    x1 y1 x2 y2 x3 y3 curveto where the curve starts at the current point whose coordinates are assumed to be x0, y0. it is tangent to the line between the points x0, y0 and x1, y1 at the beginning point. the curve ends at the point x3, y3 and is tangent to the line between x2, y2 and x3, y3

    x y z setrgbcolor where x,y,z are the intensity parameters for the red, green and blue components

    c m y k setcmykcolor where c,m,y,k are the intensity parameters for the cyan, magenta, yellow and black components

    h s b sethsbcolor where h,s,b are the intensity parameters for the components. the first one corresponds to hue which determines the location of the color in the spectrum of the light. the second one, saturation and the third one, brightness corresponds to the saturation and the brightness of the color

    x setgray where x is the intensity of the graycolor and its value can change from 0, which corresponds to black, to 1 which corresponds to white

    closepath command closes an open path by joining two end points by a straight line

    fill serves to fill inside of the closed path with the current color

    0.2 setgray 
    10 setlinewidth 
    100 700 moveto 
    200 0 rlineto 
    stroke 
    newpath 
    0.3 setgray 
    100 600 moveto 
    200 0 rlineto 
    stroke 
    

    PostScript ejects a page with the showpage operator

    0.6 0.4 0.3 0.2 setcmykcolor
    /Times-Roman findfont 15 scalefont setfont 
    100 500 moveto (I love PostScript!) show 
    
    /Courier findfont 20 scalefont setfont 
    150 450 moveto (I love you too!) show 
    
    showpage
    

    text

    it consists of three steps:

    1. set up a font to use
    2. set the current point to where the lower left corner of the text will be
    3. give the string to print to the show operator

    the show operator takes a string and prints it out in the current font and with the lower left corner at the current point. after the text has been printed, the current point is at the lower right of the string

    fonts

    fonts in PostScript are actually dictionaries. a font dictionary contains several operators. most of these operators simply set up the path for a single character in the font. when PostScript needs to typeset an “A” in the current font, it finds the operator specified in the font for “A” and invokes it. this means that text is graphics. furthermore, since a font is essentially just a program to draw things, the current graphics state applies to text just as much as it applies to lines and curves. this is one of the most powerful features of PostScript

    the fonts themselves are stored in a special dictionary of fonts, and they are named. if you want to retrieve a font by name, you need to use the findfont operator. findfont retrieves the font from the dictionary (if it is there) and leaves the font on the stack. you can then specify how big the font should be and make it the current font. the basic process for setting the font is:

    scalefont takes two arguments, the lower argument on the stack is a font dictionary while the second is the size of the new font in points. scalefont returns a new font dictionary which is the same as the old one but scaled to the given size. setfont, on the other hand, takes a font dictionary and makes it the current font

    /Times-Roman findfont   % get the basic font
    20 scalefont            % scale the font to 20 points
    setfont                 % make it the current font
    

    since the font Times-Roman is stored in a dictionary, we search for it using its PostScript name. your printer will usually come with a set of built in fonts and will almost always allow you to add more. the names of the fonts available will vary from printer to printer, but Times is almost always present

    showing text

    the show operator is used to typeset text on the page. it takes a single argument: a string containing the text to be typeset. text can be considered to be part of the path, so you must also have set the current point with call to moveto or an equivalent operator. a typical call to show might look like this:

    newpath                 % start a new path
    72 72 moveto            % lower left corner of text at (72, 72)
    (Hello, world!) show    % typeset "Hello, world!"
    

    procedure / macro

    in PostScript, Procedure or Macro means an ordered set of objects. these objects must be collected inside of a pair of block delimiters { and }. they can be named by using key definition like /Macro1 {1 add 2 mul} def. if done, then the key /Macro and its value {1 add 2 mul} is added to the current dictionary which is located into dictionary stack as topmost element, as a key-value pair. then, when the object Macro1 is given at the interpreter prompt, its action takes place

    /inch {72 mul} def
    newpath
    1 inch 1 inch moveto
    

    loops

    repeat needs two parameters, the first of which is just an integer and denotes the number of the repetitions while the second one is generally a procedure which is a block of the actions. in PostScript a block is defined by the delimiters { and }. the instructions or the commands can be consecutively put between these delimiters. the syntax of the command is like n { ... } repeat
    GS>3 {1} repeat pstack
    1
    1
    1
    GS>
    

    for command needs four operands, first three of which are respectively Initial, Increment, and Limit. all these three parameters are expected to be numerical values, integers or decimal numbers. the fourth operand is the procedure which may be either a single command or a block of commands embraced by { and } respectively. the range or the interval of the counter variable must be non-empty. this means that Initial must be smaller than Limit when Increment is positive and vice versa

    GS>1 -0.5 -1 {} for pstack
    -1.0
    -0.5
    0.0
    0.5
    1.0
    GS>clear 0 1 1 4 {add} for pstack
    10
    GS>
    

    forall executes a procedure for each element of a given array. it uses a temporary counter variable to control the loop. the initial value of the counter variable is 0, its increment is 1 and its limit is the length of the given array. the command needs two operands, the first of which is the array whose elements each by each will be used by the procedure. the second operand is the procedure. the complete syntax of the command is Array Procedure forall . the following PostScript session which aims the evaluation of the sum of a given array and the pushing all elements of another array into the operand stack is presented for further explanation of the command.

    GS>0 [11 23 45 -89 26 12 0 -34] {add} forall pstack
    -6
    GS>[1 22 -12 0] {} forall pstack
    0
    -12
    22
    1
    -6
    GS<
    

    loop seeks only one operand which is the procedure to be executed. it repeatedly executes the procedure without stopping. if the procedure to be executed has either exit or stop command at somewhere then the loop cycling is stopped when one of these commands is encountered and the control returns to the next object of the interpretation. the syntax of the command is Procedure loop.

    concepts

    device space
    this is the coordinate space understood by the printer hardware
    there is really nothing that can be said about this space, as PostScript programs are typically not expressed using it
    user space
    this is the coordinate system used by PostScript programs to describe the location of points and lines
    user space is essentially the same as the first quadrant of the standard coordinate system used in high school math classes
    point (0, 0) is in the lower left corner. coordinates are real numbers
    the interpreter automatically converts user space coordinates to device space

    current transformation matrix
    the transformation of user space coordinates to device space coordinates is done through the current transformation matrix. this matrix is a three by three matrix that allows the user to rotate, scale, and translate the entire user space within the device space. this is the source of a lot of PostScript’s power

    path
    a path is a collection of (possibly disjoint) line segments and curves arranged on the page
    the path does not describe actual ink on the paper; it merely describes an imaginary tracing over the page
    there are operators which allow the user to draw ink along the path, fill an enclosed path with ink or clip out all future images that are outside the path
    current path
    this is the path that the PostScript program is creating at the moment. the current path is assembled piece by piece
    clipping path
    the PostScript rendering system will ignore any part of a line segment, curve, or bitmap that extends outside a certain region; it will only draw the parts of those elements which are within the region. the region is described by a path called the clipping path
    the clipping path is usually a rectangle about a quarter of an inch in from the edge of the page, but it can easily be set by the user to an arbitrary path

    graphics state
    this is a collection of various settings that describe the current state of the graphics system
    the current path, the current font, and the current transformation matrix make up the graphics state
    the way to temporarily save a graphics state is to push the state onto a special graphics state stack and pop it back later. this can be accomplished with the gsave, and grestore operators

    transformations

    the PostScript interpreter keeps track of a matrix called the current transformation matrix. when constructing an image, the interpreter uses this matrix to convert the world coordinates used by the program into device coordinates used by the printer itself. PostScript does provide a number of operators that transform the matrix in a device-independent way. these operators allow you to transform the way user space maps onto device space, and they modify the current transformation matrix with a simple matrix transformation

    the basic transformation operators are:

    the current transformation matrix (and, hence the effect of all these operators) is part of the current graphics state and can be saved and restored using the gsave, and grestore operators

    in addition, the transformations on the matrix affect path components constructed after the transformation. even if a path is only partially constructed when a transformation is invoked, the parts of the path that were in place before the transformation will be unaffected

    rotate

    the rotate operator takes a single, numerical operand. this operand specifies how many degrees to rotate the user space around its origin (positive values specify counter clockwise rotations)

    let’s say you want to draw lines in a circular pattern so that each line is ten degrees from its neighbors. rather than figure out the coordinates for each of the 36 lines, we can just draw a horizontal line and rotate it repeatedly to different angles. to do the repeated looping, we can use the for operator

    0 10 360 {          % go from 0 to 360 degrees in 10 degree steps
      newpath           % start a new path
      gsave             % keep rotations temporary
    

    next set the start of the line to (144, 144) and rotate the coordinates. you do not rotate before moving because (144, 144) would then be in a different location

      331 447 moveto rotate 
    

    next draw just a horizontal line:

      72 0 rlineto stroke
    

    finally, restore the old graphics state and end the loop:

      grestore      % get back the unrotated state
    } for           % iterate over angles
    

    translate

    the translate operator takes two operands: an x-coordinate, and a y-coordinate and sets the origin of user space to the point that was at the given coordinates in user space. the main use of the translate is to draw copies of a shape in different locations. typically, a shape will be constructed at the origin, and the shape will be translated to the correct location before it is to be drawn

    scale

    the scale operator takes two arguments: an x scale factor, and a y scale factor. the operator scales each coordinate by its associated scale factor. that is, if you have an x scale factor of 0.5 and a y scale factor of 3, the x coordinate will be reduced by a factor of two while the y coordinate will be magnified by a factor of 3. this operator allows you to change the size and dimensions of objects quite easily:

    gsave 72 72 moveto 0.5 1 scale (Narrow Text) show grestore
    

    you can make things tall:

    gsave 72 144 moveto 1 2 scale (Tall Text) show grestore
    

    you can distort the text completely:

    gsave 72 216 moveto 2 0.5 scale (Squeezed Text) show grestore
    

    combining transformations

    each of these transformations merely modifies the current transformation matrix. this means that these operators can be combined

    an important thing to remember is that translations are always relative to the current user space. this means that:

    0.5 0.5 scale
    72 72 translate
    

    will have a different effect on the image than does

    72 72 translate
    0.5 0.5 scale
    

    in the first case, the origin will be half an inch in from the bottom and left margins. in the second case, the origin will be an inch in from the two margins

    images

    vector graphics style is where the image is composed of lines and curves that are described mathematically. the advantage is that you can do all sorts of mathematical operations on the image (rotate, scale, etc) and still get a decent image. vector graphics are device independent, since they do not care about the device display resolution

    PostScript supports raster graphics and so it provides a set of operators

    you put images with x y translate

    but translate needs a little bit of chore around

        gsave 
        x y translate 
        % --- the image here ---
        grestore 
    

    roughly spoken:

  • gsave saves the current coordinates
  • translate moves all coordinates to new positions
  • grestore brings things back to normal
  • here is a example with a small black/white image (1 byte per pixel) placed side by side with text

    %!
    /Times-Roman findfont 16 scalefont setfont
    
    gsave                  % save before using translate
    105 210   translate    % these cordinates of the place of the image
    76.8 86.4 scale
    
    40 45 1 [40 0 0 -45 0 45]
    %   --- image begin ---
    {<fffff5ffffffffdeffffffffeaffffffffdeffffffffffffffffffeefffffffffefffffffffbffffffffffffffffffc
    cffffffff77bffffffeffdffffffdfff7fffffbfff7fffff77ffbffff5ebfbdfffafdbf7ebffbf3ff6fdfe9ef7ff7f3d6bff
    f7d55afff7efffafffffffffcffff7efffffffef7fffffffdf77fffffffeffffffffdf7bffffffbd7bfffffffbffffffff7f
    bbfffffef7bffffffeefbdfffffdef7bfffffffffbfffffbdefffffff7dff7fffff7bdffffffff7ff7ffff977e57ffffa5ff
    bffffff7feebffffdbff4bfffff7fffffffffffffffffffffffffff>}
    %   ---  image end  ---
    image
    
    grestore               %restore the settings 
    0 245 moveto (Text and image, ) show
    0 229 moveto (side by side. ) show 
    
    showpage
    

    PostScript uses different operators for black/white/grayscale and RGB color images. the first is image and the second is colorimage, but these two works basically in the same way

    the image operator needs five arguments in order to make the image show and one of these argument is a complex one consisting itself of six arguments

    w h b [d1 d2 d3 d4 d5 d6] p image where

    w - with of image
    h - hight of image
    b - byte per pixel. legal values are: 1 | 2 | 4 | 8 | 12
    [d1 d2 d3 d4 d5 d6] - a transformation matrix
    p - procedure (or string with hexadecimal numbers in <brackets>)

    the last operand p is the source of the actual image data. in Level 1 PostScript, this is a procedure

    this procedure is called to fetch all the data for the image, as needed. the procedure returns a string, and the bits within the string are taken and dismantled to create the image

    if the procedure does not return enough data to cover the whole image, it is called repeatedly until all the pixels are accounted for. the order at which the pixels are handled is left to right, bottom to top

    raster graphics basics

    the numbers of rows and columns gives you the resolution. if there are c columns and r rows, the image is referred to as a r x c image. if the image is to have a certain physical size, this size combined with the number of pixels give you the number of dots-per-inch (DPI) of the image, which is a measure of its resolution

    raster graphics are convenient in that they can represent photo-realistic images quite easily, but they have limitations. because the pixels are arranged in a regular pattern, weird patterns can appear if they are displayed on a monitor incorrectly, or if they represent an image with a regular pattern that interacts badly with the pattern of the pixels. likewise, if the resolution is too low and the contrast is too high, certain pixels can stand out and leave the image with the “jaggies.”

    let’s take a look at a simple example - let’s draw a simple smiley face

    take a look at how the smiley face will be laid out (wiht little end encoding):

    ..XXXX..C3
    .X....X.BD
    X.X..X.X5A
    X......X7E
    X.X..X.X5A
    X..XX..X66
    .X....X.BD
    ..XXXX..C3

    the “X” represents a black pixel, and the “.” represents a white pixel

    since black is represented by a 0 in PostScript, and white by a 1, we can convert this 8x8 matrix into an eight byte sequence

    now, let’s take this image data and try to build up an actual image

    
    gsave                   % we're mucking about with graphics state... save the original
    
    72 72 translate         % position the lower left at (72, 72)
    72 72 scale             % make the image 1 inch square
    
    %  set up the actual image data
    
    8                       % 8 columns in the image
    8                       % 8 rows in the image
    1                       % 1-bit per pixel: black and white
    [8 0 0 8 0 0]           % map the unit square to (0, 0) - (8, 8)
    {<C3BD665A7E5ABDC3>}    % the image data as a hex-encoded string (little-end)
    image                   % actually draw the image
    
    grestore
    

    gradient

    how do you deal with gray scale images? the procedure is similar, you just specify a different bit depth and lay out your data in a slightly different manner (instead of a single bit per pixel, you will now need to map multiple bits per pixel

    0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111

    sixteen different shades, four bits per pixel - it means that this data can be represented in 8 bytes. encoded in hexadecimal, the data for the above gradient is 0123456789ABCDEF

    
    gsave
    216 304 translate       % lower-left of image
    100 200 scale           % size of rendered image in pixs
    16                      % 16 pixels wide
    1                       % 1 pixel high
    4                       % 4 bits per pixel
    [16 0 0 1 0 0]          % transform array... maps unit square to pixels
    {<0123456789ABCDEF>}    % the image data itself (little endian encoding)
    image                   % let's draw!
    grestore
    

    note that, even though the image data is for a one line image, we can scale that single line to fill just about any area

    color

    what if you want to do color? PostScript does include a handy operator for color images called, creatively enough colorimage. this operator adds a number of operands to handle the addition of color and to provide for a number of ways of supplying the color data

    the first thing to consider is how you want to specify the colors. is your image GrayScale? RGB? CMYK? this information will indicate the number of color channels you need. GrayScale takes one. RGB takes three (one for red, one for green, and one for blue). finally, CMYK takes four: cyan, magenta, yellow, and black

    these channels are going to be provided to the colorimage operator; will they be interleaved into a single data source string, or will they be broken out into separate data sources? these two decisions will determine the number of additional operands to colorimage: one specifies the number of channels, one specifies whether the channels are separate or interleaved, and then there is one for each channel data source.

    let’s take a look at a color gradient, which will be a variant of the previous gradient:

    gradient:                                
    Red: 0000000000000000 0000000000000000
    Green: 1514131211100908 0706050403020100
    Blue: 0001020304050607 0809101112131415

    the next example will use three color channels, and they will be provided by separate data sources:

    gsave
    360 72 translate        % set lower left of image at (360, 72)
    50 150 scale            % size of rendered image in pixs 
    16                      % number of pixels per row
    1                       % number of pixels in each column 
    4                       % bits per color channel (1, 2, 4, or 8)
    [16 0 0 1 0 0]          % transform array... maps unit square to pixels
    {<0000000000000000>}    % the red image data
    {<FEDCBA9876543210>}    % the green image data (little end)
    {<0123456789ABCDEF>}    % the blue image data (little end)
    true                    % pull channels from separate sources
    3                       % 3 color channels (RGB)
    colorimage
    grestore
    

    note that the bits-per-pixel operand is really a bits-per-pixel-per-channel operand. this is really no different than for image, it is just that image always works with a single channel. in fact the call:

    
    w h bpp matrix data image
    

    is exactly equivalent to:

    
    w h bpp matrix data true 1 colorimage
    

    a b c [d1 d2 d3 d4 d5 d6] s f n colorimage where
    a - with of image
    b - hight of image
    c - byte per pixel. legal values are: 1 | 2 | 4 | 8 | 12
    [ d1 d2 d3 d4 d5 d6 ] - a transformation matrix
    s - procedure (or string with hexadecimal numbers in <brackets>)
    f - flag channels/nochannels
    n - number of channels

    EPS

    TODO