PostScript

prog ps

Table of Contents

Stack based graphics Programming Language .

REPL

  • gs (in the ghostscript package)
  • gsnd (no graphical output, "no display")

PostScript File

  • %! in the beginning, to mark as PS file

Syntax

  • Booleans: true , false
  • Numbers: 1 , 1.23
  • Arrays: [1 2 3] (note that there is no "," between elements)

Moving Around

  • moveto
  • rmoveto (relative)

Drawing Lines

  • lineto
  • rlineto (relative)
  • <n> setlinewidth

Line Caps

Controlled via the linecap variable, 0 by default.

<n> setlinecap

  • 0, no linecaps
  • 1, round linecaps
  • 2, square linecaps

Infinite Lines

Given a line defined by the equation postscript_c473a0bf66b4e0ab2c93d0c0fdb5cd75c733f99b.svg ,

newpath
[a b c] mkline
stroke

Example

I'm working on a page of size 1000 x 700.

newpath
100 100 moveto 800 0 rlineto
stroke

10 setlinewidth
newpath
100 200 moveto 800 0 rlineto
stroke

20 setlinewidth
newpath
100 300 moveto 800 0 rlineto
stroke

30 setlinewidth
newpath
100 400 moveto 800 0 rlineto
stroke

1 setlinecap
newpath
100 500 moveto 800 0 rlineto
stroke

2 setlinecap
newpath
100 600 moveto 800 0 rlineto
stroke
lines.png

Polygons

Defining Paths

newpath
% define path with "(r)moveto" and "(r)lineto"
closepath
fill

Function for Drawing Rectangles

/rectpath {
  2 dict begin
  /y exch def
  /x exch def
  newpath
  0 0 moveto
  x 0 rlineto
  0 y rlineto
  x neg 0 rlineto
  closepath
  end
} def

/rect { rectpath fill } def
  • <width> <height> rectpath creates a rectangular path
  • <width> <height> rect draws a filled rectangle

Linejoin

How lines join can be controlled via the linejoin variable, 0 by default.

<n> setlinejoin

  • 0, no linejoin
  • 1, round linejoin
  • 2, square linejoin

Example


50 50 translate
newpath
100 100 rectpath
fill

200 0 translate
40 setlinewidth
100 100 rectpath
stroke

200 0 translate
1 setlinejoin
100 100 rectpath
stroke

200 0 translate
2 setlinejoin
100 100 rectpath
stroke

200 0 translate
2 setlinejoin
100 100 rectpath
gsave
stroke
grestore
fill
polygons.png

stroke and fill destroy the current path. To stroke and fill a path at the same time, we can save the graphics state before stroke it, then restore it to fill .

Colors

  • <gray> setgray
  • <r> <g> <b> setrgbcolor

Example

% initial step limit
0 0.10 1 {
    % the current value is on top of the stack
    setgray
    rect
    100 0 translate
} for
colors.png
% initial step limit
0 0.10 1 {
  /g exch def
  gsave
  0 0.10 1 {
    % the current value is on top of the stack
    g 1 setrgbcolor
    rect
    100 0 translate
  } for
  grestore
  0 100 translate
} for
colors2.png

Transformations

Moving and Scaling

Basic unit: points, 72 points per inch

  • <sx> <sy> scale to change the scale
  • <x> <y> translate

Example


rect

200 0 translate
gsave
0.5 1.0 scale
rect
grestore

200 0 translate
gsave
1.0 0.5 scale
rect
grestore

200 0 translate
gsave
0.5 0.5 scale
rect
grestore
scale.png

Rotation

  • <deg> rotate

Example


500 500 translate
28 {
  rectpath stroke
  0.86 0.86 scale
  10 rotate
} repeat
rotate.png

Mathematical Functions

Results are placed on the stack.

  • <x> <y> add
  • <x> <y> sub
  • <x> <y> mul
  • <x> <y> div
  • <x> <y> idiv , integer division
  • <x> <y> mod
  • <x> neg , negation postscript_6fb3a9d4451e0a59a071fcb6c3ea1464e52be1e2.svg
  • <y> <x> atan , polar angle of postscript_81fa0990a5e663a852ab4150daae166d7e3def3b.svg
  • <x> sqrt
  • <x> sin
  • <x> cos
  • <x> <y> exp , postscript_aa03bc10250a1a8e4da5a9e503eac6e48b58cae0.svg
  • x ln , postscript_743fbd033046c706a5a506f882081d140bf53aac.svg
  • x abs , absolute value postscript_9ffafd4beda5a75e479e24ed287c516ceb19b06f.svg
  • x round
  • x floor , postscript_89e2c2f279b06ff6a6091a9bb927a8839f1a7164.svg
  • x ceiling , postscript_12f80bc3d410b6062bb7f008640a9a5079a39c3f.svg

Comparison, Boolean Arithmetic

  • eq ( postscript_d72ade22d1cadfad295e56adf6a20303a428b534.svg )
  • lt , gt , ( postscript_3ddd3c7a7d11ad52c37edb8543a7faf51446da2b.svg , postscript_48493762a362c8956d3eb300aee126508cbfc9b5.svg )
  • le , ge , ( postscript_3e4f8a8c09542bb30d3dac481dce4af8b691c7f0.svg , postscript_2d366a602de1ddbe88d3b9670aa1f0a75d038143.svg )

Manipulating the Stack

  • exch , exchange top two items of stack to make them y x
  • pop , remove top item of stack
  • dup , duplicate item on top of stack
  • clear , clear the stack
  • = , == , removes and displays value on top of stack. according to a pdf I've read, == should be preferred
  • pstack , print stack contents without removing them
  • <n> <direction> roll , rotate n elements of the stack

TODO Find out Difference between = and ==

Examples

  • 2 dup add -> 4
  • 4 2 div -> 2
  • 4 2 exch div -> 0.5

Pages

  • showpage to show & begin a new page

Graphical State

Storing / Restoring

Contains scaling, translation, rotation etc.

  • gsave to save
  • grestore to restore

When working with multiple pages, the following combination might be useful:

gsave
% draw page
grestore
showpage

gsave
% draw next page
grestore
showpage

The graphical state also includes unfinished paths and the current color.

To fill and stroke a shape:

  • define a path
  • save the state
  • fill it
  • restore the state
  • stroke it

TODO Current Position

Variables

Variable names are written as /foo , /bar

  • /foo 1 def defines a variable foo with value 1

Variables stored in dictionaries placed on a dictionary stack (similar to variable environments in other languages).

To create a dictionary for 2 local variables (not 100% sure this is correct):

2 dict
begin
% ...
end

TODO What exactly is the effect of begin and end ?

Procedures

/my-proc {
  % instructions
} def

Procedures are called by "inserting" the instructions between the {} .

Arguments can be passed to procedures through the stack. To bind them to variables inside the procedure, we can use the following trick:

/my-proc {
  /arg2 exch def
  /arg1 exch def
  % ...
}

Combined with the pattern for local variables, this turns into

/my-proc {
  2 dict
  begin
  /arg2 exch def
  /arg1 exch def
  % ...
  end
}

Control Structures

If, If-Else

boolean
{
  % ...
}
if
boolean
{
  % ...
}
{
  % ...
}
ifelse

Repeat-Loop

N {
  % ...
} repeat

For-Loop

initial step limit {
  % ...
} for

The value is placed on top of the stack before the "body" is executed.

Forall-Loop

[a b c d] {
  % ...
} forall

The "body" is executed once for each element of the array, which is placed on top of the stack.

Loop-Loop

{
  % ...
} loop

exit breaks out of the loop.

Working with Arrays

  • <array> aload places all elements of <array> on the stack

    It seems like it also places the array back on the stack so we have to remove it with pop .

Examples


/positions [
  [50 30]
  [250 40]
  [450 50]
  [650 60]
  [850 70]
] def

positions {
  gsave
  aload pop translate
  100 100 rect
  grestore
} forall
arrays.png

Working with Text

  • <text> stringwidth , pushes width & height of text in the current font on the stack

Page Size

<< /PageSize [1920 1080] >> setpagedevice
curretpagedevice /PageSize get

PDF to GIF Conversion

convert -delay 10 input.pdf prison.gif
  • -alpha off to disable transparency (white background)
  • -loop 0 to loop the gif

Other

  • <n> string , create string of n characters
  • <ob> <str> cvs -> <str>, convert to string

Backlinks


If you have an idea how this page could be improved or a comment send me a mail.