Pygame Tutorials
Surfarray Introduction

by Pete Shinners
pete@shinners.org

Revision 1.02, Sep 7, 2001



Introduction

This tutorial will attempt to introduce users to both Numeric and the pygame Surfarray module. To beginners, the code that uses surfarray can be quite intimidating. But actually there are only a few concepts to understand and you will be up and running. Using the surfarray module, it becomes possible to perform pixel level operations from straight python code. The performance can become quite close to the level of doing the code in C.
 
You may just want to jump down to the "Examples" section to get an idea of what is possible with this module, then start at the beginning here to work your way up.
 
Now I won't try to fool you into thinking everything is very easy. To get more advanced effects by modifying pixel values is very tricky. Just mastering Numeric Python takes a lot of learning. In this tutorial I'll be sticking with the basics and using a lot of examples in an attempt to plant seeds of wisdom. After finishing the tutorial you should have a basic handle on how the surfarray works.

Numeric Python

If you do not have the python Numeric package installed, you will need to do that now. You can download the package from the Numeric Downloads Page. To make sure Numeric is working for you, you should get something like this from the interactive python prompt.
>>> from Numeric import *                  #import numeric
>>> a = array((1,2,3,4,5))                 #create an array
>>> a                                      #display the array
array([1, 2, 3, 4, 5])
>>> a[2]                                   #index into the array
3
>>> a*2                                    #new array with twiced values
array([ 2,  4,  6,  8, 10])

As you can see, the Numeric module gives us a new data type, the array. This object holds an array of fixed size, and all values inside are of the same type. The arrays can also be multidimensional, which is how we will use them with images. There's a bit more to it than this, but it is enough to get us started.
 
If you look at the last command above, you'll see that mathematical operations on Numeric arrays apply to all values in the array. This is called "elementwise operations". These arrays can also be sliced like normal lists. The slicing syntax is the same as used on standard python objects. (so study up if you need to :] ). Here are some more examples of working with arrays.
>>> len(a)                                 #get array size
5
>>> a[2:]                                  #elements 2 and up
array([3, 4, 5])
>>> a[:-2]                                 #all except last 2
array([1, 2, 3])
>>> a[2:] + a[:-2]                         #add first and last
array([4, 6, 8])
>>> array((1,2,3)) + array((3,4))          #add arrays of wrong sizes
Traceback (innermost last):
  File "<interactive input>", line 1, in ?
ValueError: frames are not aligned

We get an error on the last commend, because we try add together two arrays that are different sizes. In order for two arrays two operate with each other, including comparisons and assignment, they must have the same dimensions. It is very important to know that the new arrays created from slicing the original all reference the same values. So changing the values in a slice also changes the original values. It is important how this is done.
>>> a                                      #show our starting array
array([1, 2, 3, 4, 5])
>>> aa = a[1:3]                            #slice middle 2 elements
>>> aa                                     #show the slice
array([2, 3])
>>> aa[1] = 13                             #chance value in slice
>>> a                                      #show change in original
array([ 1, 2, 13,  4,  5])
>>> aaa = array(a)                         #make copy of array
>>> aaa                                    #show copy
array([ 1, 2, 13,  4,  5])
>>> aaa[1:4] = 0                           #set middle values to 0
>>> aaa                                    #show copy
array([1, 0, 0, 0, 5])
>>> a                                      #show original again
array([ 1, 2, 13,  4,  5])

Now we will look at small arrays with two dimensions. Don't be too worried, getting started it is the same as having a two dimensional tuple (a tuple inside a tuple). Let's get started with two dimensional arrays.
>>> row1 = (1,2,3)                         #create a tuple of vals
>>> row2 = (3,4,5)                         #another tuple
>>> (row1,row2)                            #show as a 2D tuple
((1, 2, 3), (3, 4, 5))
>>> b = array((row1, row2))                #c