Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Smooth PostScript animations

I would like to run animations in PostScript smoothly. To see what I want, let me switch to PostScript directly. Call ghostscript, and

200 dup scale .5 setgray 0 0 3 3 rectfill

We have now a gray square.

0 setgray 0 1 3 1 rectfill

With a black stripe in it. We will now fill that stripe, one time white and black in succession:

{1 setgray 0 1 3 1 rectfill 0 setgray 0 1 3 1 rectfill} loop

You will see now some flickering of black and white rectangles that are smaller than the original black stripe. Ideally, we would see the original grey square. Or almost. Where can I get such functionality today?

To see a more interesting animation sequence searching for magic squares of size 5:

wget http://www.complang.tuwien.ac.at/ulrich/gupu/l5.eps.gz
zcat l5.eps.gz | ghostscript -

A couple of years ago I did try to address these issues. But it never went into ghostscript or Xfree. See this page. Maybe there are some better ideas now?

Edit: After reading the responses so far, let me clarify one issue here. Essentially, there are two independent issues in this question:

  • How should an animation be viewed from the language level? I believe, the best way is to view each frame as a single page. With copypage incremental changes can be realized with low effort. Sadly, that semantics of copypage is only present in Level 1 and 2. In Level 3, the meaning of copypage changed to showpage. I did - many years ago - a little modification to ghostscript to delay all visible changes up to copypage or showpage. In this manner, a single XCopyArea containing the changed area is performed locally on the server (that is, the display).

  • How should actual changes on the visual display be synchronized to avoid artefacts that where not present in the graphics described? The irregular flicker you see is not a privilege of PostScript, it seems to be present in any double-buffered system I have seen so far. Just try to program this in whatever system you see fit.

Further edit:

To get the right language level, that is level 1 or 2 do (for ghostscript):

systemdict /.setlanguagelevel known {2 .setlanguagelevel} if

Edit: I am adding this comment to may attract some new postscript contributors.

like image 441
false Avatar asked Dec 05 '11 23:12

false


2 Answers

We explored some of these issues in this thread on comp.lang.postscript.

Since the release of the Level 2 standard, Postscript is a garbage-collected language. You can disable collection of user objects with the fragment -2 vmreclaim, but it doesn't accomplish much. You can disable ALL ghostscript garbage collection by invoking with the -dNOGC option. This should help prevent stalling and spitting with parts of the image.

Ghostscript has a non-standard operator called flushpage, which synchronizes the rendering with the execution. This helps make sure that everything is seen before it's gone.

- flushpage -
On displays, flushes any buffered output, so that it is guaranteed to
show up on the screen; on printers, has no effect

And for timing control, there doesn't seem to be a better way than simple busy-waiting.


/smallpause {
    /flushpage where{pop flushpage}if
    50 sleep } def
/pagepause {
    /flushpage where{pop flushpage}if
    1000 sleep } def

/sleep {
    usertime add {
        10 {
            1 100000 div pop %busy
            .1 sin 257 cos atan pop %busy busy
        } repeat
        dup usertime le {exit}if
    } loop pop
} def 

The where guards around flushpage allow you to send the same code to interpreters other than ghostscript (like a printer).

If you had an actual Display Postscript server, you could use the wait operator instead of busy-waiting.

like image 116
luser droog Avatar answered Sep 24 '22 02:09

luser droog


Although I like (and upvoted) @luserdroog's answer, I don't believe Postscript should be used for animations on this way - I'd rather use some language that can run widgets or display elements that are designed for real time display and user interation - that is not the case of postscript or ghostscript.

I think it would be nice, though, use postscript for aimations for rendering purposes - just rendering a page after each modification on the image, and using an external program to assemble the different pages as animation frames. Maybe even using postscript as a rendering engine, with the process in another language calling ghostscript to render each frame in realtime. A nice and easy to use multimedia framework to do that could be for example, the Python language with the Pygame module.

Here is a short example using "pure python + pygame".

#! /usr/bin/env python
# coding: utf-8

import pygame

size = 640,480 #(in pixels)

# multiplying factor so that the whole image is 5 units across
factor = size[0] / 5.0

# Inits pygame drawing window
screen = pygame.display.set_mode(size)

# Rectangle drawing function that scales drawing using the factor above
def draw_rect(color, rect):
    new_rect = [int (r * factor) for r in rect]
    return pygame.draw.rect(screen, color, new_rect)

def main():
    draw_rect((128,128,128), (0, 0, 3, 3))
    colors = ((255,255,255), (0,0,0))
    color_index = 0
    while True:
        draw_rect(colors[color_index], (0, 1, 3, 1))
        pygame.display.flip()
        color_index = 1 - color_index
        pygame.time.delay(50) # in miliseconds

try:
    main()
finally:
    pygame.quit()

To execute this, you have to have Python and Pygame (from http://pygame.org - there are ready packages on most linux systems for that)

Pygame's drawing API is much poorer than postscript - if you need more than rectangles (like bezies, scaling, rotating and shearing the coordinate system, and so on), the way to go is to use Cairo + python + some display library (which might be pygame, GTK+ or qt) . Cairo is a 2D drawing library that inherits from the postscript way. - or, as I said above, to drive a ghostscript external process using Python, having it generating a rle compressed image file to stdout or a ramdrive, and that image read and displayed frame by frame using python + pygame.

Another option is to use HTML5's Canvas, and do everything in Javascript, viewable on a browser. HTML5's Canvas also inherits the Postscript way of drawing.

like image 28
jsbueno Avatar answered Sep 26 '22 02:09

jsbueno