File Archive

File download


File size:
941 878 bytes (919.80K)
File date:
2005-12-30 23:25:58
Download count:
all-time: 964

Screenshot (by pouë



  • PostShrink.pdf 157.62K
  • 3.99K
  • PostShrink.txt 1.21K
  • PostShrink_1024x768.png 745.02K
  • 4.08K
  • source/ dir
  • source/ 18.05K
  • source/fx/ dir
  • source/fx/ball.pp 1.36K
  • source/fx/koch.pp 696B
  • source/fx/landscape.pp 1.36K
  • source/fx/miniball.pp 405B
  • source/fx/pixelfunc.pp 619B
  • source/fx/sierpinski.pp 652B
  • source/fx/swirl.pp 947B
  • source/fx/torus.pp 1.98K
  • source/fx/wobble.pp 1.84K
  • source/lib/ dir
  • source/lib/3d.pp 500B
  • source/ 8.30K
  • source/PostShrink.pp 4.03K
  • source/ 580B
  • source/prepost.txt 5.88K


::: PS -- PostShrink
::: world's first PostScript 4k demo
::: by KeyJ / kakiarts

OK, now here's a ... uhm ... DIFFERENT entry. It was originally made for
the vector graphics compo at tUM'05, but the compo got canceled, so don't
be surprised to see these vector graphics files in the pixel competition.

This entry is actually some kind of a demo/intro -- a PostScript file of
only 4085 bytes, containing a simple 3D engine! And I didn't even exploit
PostScript's *real*, mighty compression capabilities ...

For the non-believers, there's the complete source code in the source/
subdirectory. To compile it, you need Python >= 2.2. Simply type
"python PostShrink.pp" to start compilation.

For the PDF fans, there's a PDF conversion available. But beware, it's
about 161k. And no, there's nothing I could do about that. PDF simply lacks
PostScript's magic ...

For those who have (access to) a PostScript printer, there's a version that
can be directly printed on A4 paper.

For those who simply want to see the "demo", there's a decent 1024x768
PNG pixel rendering.

And for the coders: I'd *really* like to see more of this sh*t in the

::: <>
PrePost, a PostScript pre-processing system and/or simplified wrapper language

(C) 2005 Martin J. Fiedler <>

Writing PostScript directly is cool, but it sucks quite hard because of that
peculiar stack management stuff. PrePost consists of two parts, each serving
one particular purpose:

ComPost -- A compiler for an artificial language that makes PostScript
           development much easier. Instead of managing the stack "by hand",
           the PrePost artificial language handles variables like in most other
           languages. Stack management is almost completely transparent.
OutPost -- An "optimizer" that strips all comments and unnecessary whitespace
           from a PostScript file. Additionally, it generates compact names for
           commonly used functions, compressing the output even further.

Both parts are available as stand-alone command-line Python programs. In
addition, PrePost itself is a "driver" that performs the tasks of ComPost and
OutPost in one step.

ComPost, the PrePost compiler

The PrePost language turns PostScript's postfix notation into a more concise
prefix notation (hence the name "PrePost"). For example, "1 2 3 mul add"
becomes "add(1,mul(2,3))". In addition, PrePost allows to use a Perl-like
variable syntax (read: "$var"). Stack management is done automatically, based
on variable usage inside the surrounding block. The code generated by PrePost
is quite sub-optimal, but the immense savings in development time usually
compensate that :)

Functions can be defined to create a "/functionname { ... } bind def" block:

  function foo($bar,$baz):$result
This generates "/foo{3 add mul}bind def". Note:
- Each statement is written on exactly one line.
- The function header specifies input and output variables.
- Each statement is written in the form "$destination=<expession>".
- Function names are exactly those of PostScript.

The most important pitfall in PrePost is that it does NOT know whether a
function name or the number of parameters or return values is correct. If you
write foo($a,$b), then /foo is expected to have exactly 2 parameters. If you
write "$a,$b=foo()", then /foo is expected to return exactly 2 parameters on the
stack. Also note that inside complex expressions, PrePost implicitly expects
functions to return exactly one scalar value. Otherwise, the automatic stack
management will fail.

In addition, PrePost supports if/then/else and for statements:

  if(gt($a,0))        % condition
  for($x,1,1,10)      % loop variable $x, count from 1 to 10, increment by 1
  stroke(closepath()) % some trickery on PrePost's stack manager:
                      % generates "closepath stroke"

Constants may be defined to hold numerical(!) values. Here, normal infix
formula notation and Python's math library functions may be used:

  const SQRT_2 = sqrt(2.0)
  const COS_SIN_45 = 0.5*SQRT_2

Any word encountered in the source code that is not a constant name is
interpreted as a function name, except for the following situations:
- $var = Variables
- /Name = PostScript names (are directly passed to the output file)
- 123.45 = Numbers (pass-through, too)
- &something = verbatim statement. The '&' prefix is stripped away, and the
               remainder of the is written to the output file

For more complex tasks, PrePost offers a 'raw' statement:

  raw $x,$y:$res

Like functions, raw statements accept input values that are put onto the stack,
in the order specified, prior to the execution of the raw block. The values
left on the stack after execution are then aliased to the result variables.
Both variable( set)s may be omitted.

The most common use of raw blocks is at the very beginning of the file. Because
comments are not stripped inside raw blocks, these can (and need to) be used to
generate the PostScript she-bang and/or DSC comments:

%%BoundingBox: 0 0 640 480

If you want to know more about PrePost, please read its source code or the
example PrePost code, or ask me via e-mail.

OutPost, the PostScript optimizer

OutPost transforms PostScript input files into a most compact representation,
stripping comments and unnecessary whitespace as much as possible. It accepts
default PostScript statements inclusing DSC, arrays and strings, but NOT hex

Additionally, OutPost supports some preprocessor statements that control
automatic remapping of symbol names to shorter representations. For example,
"/!{bind def}bind def" saves 7 bytes for each successive use of "bind def".

- %#remap <symbol name>
  If the specified symbol appears often enough in the file that a remapping
  would save bytes, an appropriate "bind def" statement is added at the
  position of the %#remap directive. Please note that remapping takes place
  globally, so the directive MUST precede the first usage of the symbol in

- %#remap all
  This automatically remaps ALL statements found in the file into a compact
  1- or 2-byte representation.

- %#noremap <symbol name>
  Excludes a symbol from automatic remapping. This is useful if OutPost
  accidentally remaps symbols that are deliberately used as names, like font
  names. So a "%#noremap Helvetica" statement might fix some strange problems.

- %#symbol <symbol name>
  Declares a symbol as "privately defined". This means that the symbol will
  be remapped, but no "bind def" statement will be issued. This is necessary
  for user-defined functions, constants and variables. Consequently, ComPost
  automatically adds a %#symbol directive at the beginning of each function.