Extra Modules for Pygame Projects

Pycon and the Camera

Note - this module soon to be obsolete. Projects are being converted to John Zelle's graphics module instead of pygame and also to be compatible for both Python v2 and v3.

The pycon module provides a somewhat simpler interface to pygame for the most of the graphic projects using it. It also provides a simple mechanism to generate little GIF movies. Pycon also uses the sarg module to extract control values.

Setting up the font.

16 Monofont = "ubuntumono"
17
18 import pygame as pg
19
20 pg.init()
21
22 def setfont(name, size) :
23     global fontsize, fontname, font
24     if name == "mono": name = Monofont
25     if name :
26         fontname = pg.font.match_font(name)
27     else : fontname = None
28     fontsize = size
29     font     = pg.font.Font(fontname,fontsize)
30
31 setfont ( sarg.Str("fontname",""), sarg.Int("fontsize",20))
32

The fontname and fontsize may be passed as sarg arguments on the command line. (line 31). No fontname becomes None, the default font. A generic fontname=mono is best when text needs to align vertically. In line 16 that becomes ubuntumono. If you're not using Ubuntu you could change this or just let None do its thing.

Here is the class definition for Pgcon:

33 class Pgcon :
34     def __init__ (self) :
35         self.pg     = pg
36         self.size   = sarg.Str("pixels",600)
37         self.delay  = sarg.Float("delay",.5)
38         self.frame  = 0
39         self.camera = camera.Camera (pg)
40         self.size   = eval(self.size)
41         if type(self.size) == type(5) :
42             self.size = (self.size,self.size)
43         self.screen = pg.display.set_mode(self.size)

Initialization set up the pygame connection. The attribute pg points back to the pygame module. The size is the window size. If square it can just a number, otherwise a tuple in the form (width,height). line 40-42. A display screen is created.

44
45     def newScreen (self, background=BGCOLOR) :
46         self.screen.fill(background)
47
48     def lite(self, color) :
49         # for example white (255,255,255) becomes gray (127,127,127)
50         return [x/2 for x in color]

For each picture or frame in the animation newScreen is called with an optional background color. The method lite returns a color at 1/2 the intensity given.

51
52     def textDraw(self, color, pos, text,center=True) :
53         xp,yp = pos
54         for line in text.split("\n") :
55             rend  = font.render(line,True,color)
56             tw,th = font.size(line)
57
58             if center : pos2 = (xp-tw/2, yp-th/2)
59             else : pos2 = (xp,yp)
60             self.screen.blit(rend, pos2)
61             yp += th # pixel equivalent to font size

The method textDraw draws text in the chosen font and fontsize. The default is to center the text around a point. For the projects used this is usually the most appropriate. But setting center=False puts the text just below and to the right of the point. If the text has newlines it will make a column something like in a newspaper.

62
63     def lineDraw(self,color,apos,bpos,width=1) :
64         self.pg.draw.line(self.screen, color, apos, bpos, width)
65
66     def writeScreen (self, delay=None) :
67         self.pg.display.flip()
68         if delay == None : delay = self.delay
69         time.sleep(delay)
70         self.camera.takePicture(self.screen)

Line drawing is straight-forward. The width parameter is generally 1. Method writeScreen takes an optional delay parameter to wait between frames. (line 69). If the camera is initialized a .PNG image is created (line 70).

71
72     def close (self, pause=True) :
73         if pause : raw_input ("Hit Return to Continue")
74         self.camera.makeGif(delay=int(self.delay*100))
75         self.pg.quit()

Closing the connection first leaves the last frame on the screen. After getting permission to continue (line 73), the camera (see below) may have saved the frames to ".PNG" files and if the sarg arguments are appropriate, a GIF file may be produced from them.

The Camera

A Camera instance is always attached to the Pycon instance. Pygame has a nifty function image.save to convert an image to a standard format (like jpeg or png) and write it to the disk. This file can then by opened by a program like the linux eog to display it on the screen. The file can also be loaded and viewed in a browser like firefox or chrome.

The camera typically captures a set of images that can be played back either as a slide show or little movie. The latter is done using the ImageMagick program convert. You must have ImageMagick installed on your computer to use this.

When the display is about to be updated, the camera may be armed to save the image to disk. At the end of the run the images saved may be converted into a gif animation. Both of these steps are optional. If using the camera you need to set maxpics=n where n is a maximum of images to capture. This prevents runaway programs from eating your disk. prefix=xx where xx is arbitrary also is needed to name the images. In addition, to generate a GIF animation, gif=1 must be included. The camera has a number of attributes to control what it does. These are set through sarg explained above in the current implementation. So to recap:

  • maxpics: the maximum number of images to capture.
  • prefix: a name prefix for both the png files and the gif animation.
  • gif: set to 1 if you want the camera to create a gif from the images saved
  • keep_pngs: if a gif is made, setting this to 1 keeps the pngs from being removed.
  • skip: set to number of frames to ignore at the beginning. This is rarely used.

The following is a simple example. It captures 12 frames, converts the png files to a single gif and then deletes the png files. Adding keep_pngs=1 to the command lines would leave both pngs and the gif. On the other hand, leaving out gif=1 would generate the pngs but not the gif.

$ python kmeans.py seed=180 pixels=300 prefix=km maxpics=40 gif=1
Just captured frame: 1, km_001.png
Just captured frame: 2, km_002.png
Just captured frame: 3, km_003.png
Just captured frame: 4, km_004.png
Just captured frame: 5, km_005.png
Just captured frame: 6, km_006.png
Just captured frame: 7, km_007.png
Just captured frame: 8, km_008.png
Just captured frame: 9, km_009.png
Just captured frame: 10, km_010.png
Just captured frame: 11, km_011.png
Just captured frame: 12, km_012.png
Hit Return to Continue
Making uniform GIF
convert -delay 50 -loop 1 km_*.png km.gif
km.gif has 12 frames

The following is the class description for the camera.

05 class Camera :
06     def __init__ (self, pg) :
07         self.maxpics   = sarg.Int("maxpics",0)
08         self.prefix    = sarg.Str("prefix")
09         self.gif       = sarg.Int("gif",0)
10         self.skip      = sarg.Int("skip",0)
11         self.picsTaken= 0
12         self.armed = False
13         self.pg    = pg

Four values (lines 7-10) are extracted from the command line with sarg (or defaulted) and 3 attributes set (line 11-13). pg is a reference to the pygame module.

14
15     def takePicture(self, screen) :
16         if self.picsTaken>=self.maxpics or not self.armed or not self.prefix :
17             return False
18         self.picsTaken += 1
19         file = "%s_%03d.png" % (self.prefix, self.picsTaken)
20         if self.skip <= self.picsTaken :
21             self.pg.image.save(screen, file)
22             print "Just captured frame: %d, %s"%(self.picsTaken, file)
23         self.armed = False
24         return True

Method takePicture checks that the necessary are turned on and then uses image.save to save the frame. The following must hold.

25
26     def makeGif(self, loop=1, delay=50) :
27         import os
28         if not self.picsTaken or not self.gif : return
29         prefix = self.prefix
30         print "Making GIF"
31         cmd = "convert -delay %d -loop %d %s_*.png %s.gif"
32         cmd = cmd % (delay, loop, prefix,prefix)
33         print cmd  # print the imageMagick convert command
34         # create the .gif file with ImageMagick
35         print "%s.gif has %d frames" % (prefix,self.picsTaken)
36         os.system(cmd)
37         if not sarg.Int("keep_pngs", 0) :
38             os.system("rm %s_*.png" % prefix)

Finally, the method makeGif will generate a GIF animation by building a command line to invoke the ImageMagick convert utility. The variable loop defaults to 1 for a single run of the animation. The delay variable is the time between frames and is in units of 1/100 of a second. makeGif is called from Pycon.close and the delay is converted from the floating point seconds used in the rest of the programs.

You can download the zip file for pglib here

If you have comments or suggestions You can email me at mail me

Copyright © 2014-2018 Chris Meyers

.