allblack = N.zeros((128, 128))
surfdemo_show(allblack, 'allblack')

Our first example creates an all black array. Whenever you need
to create a new numeric array of a specific size, it is best to use the
zeros function. Here we create a 2D array of all zeros and display
it.

striped = N.zeros((128, 128, 3))
striped[:] = (255, 0, 0)
striped[:,::3] = (0, 255, 255)
surfdemo_show(striped, 'striped')

Here we are dealing with a 3D array. We start by creating an all red image.
Then we slice out every third row and assign it to a blue/green color. As you
can see, we can treat the 3D arrays almost exactly the same as 2D arrays, just
be sure to assign them 3 values instead of a single mapped integer.

imgsurface = pygame.image.load('surfarray.png')
rgbarray = surfarray.array3d(imgsurface)
surfdemo_show(rgbarray, 'rgbarray')

Here we load an image with the image module, then convert it to a 3D
array of integer RGB color elements. An RGB copy of a surface always
has the colors arranged as a[r,c,0] for the red component,
a[r,c,1] for the green component, and a[r,c,2] for blue. This can then
be used without caring how the pixels of the actual surface are configured,
unlike a 2D array which is a copy of the
mapped
(raw) surface pixels.
We will use this image in the rest of the samples.

flipped = rgbarray[:,::1]
surfdemo_show(flipped, 'flipped')

Here we flip the image vertically. All we need to do is take the original
image array and slice it using a negative increment.

scaledown = rgbarray[::2,::2]
surfdemo_show(scaledown, 'scaledown')

Based on the last example, scaling an image down is pretty logical. We just
slice out all the pixels using an increment of 2 vertically and horizontally.

shape = rgbarray.shape
scaleup = N.zeros((shape[0]*2, shape[1]*2, shape[2]))
scaleup[::2,::2,:] = rgbarray
scaleup[1::2,::2,:] = rgbarray
scaleup[:,1::2] = scaleup[:,::2]
surfdemo_show(scaleup, 'scaleup')

Scaling the image up is a little more work, but is similar to the previous
scaling down, we do it all with slicing. First we create an array that is
double the size of our original. First we copy the original array into every
other pixel of the new array. Then we do it again for every other pixel doing
the odd columns. At this point we have the image scaled properly going across,
but every other row is black, so we simply need to copy each row to the one
underneath it. Then we have an image doubled in size.

redimg = N.array(rgbarray)
redimg[:,:,1:] = 0
surfdemo_show(redimg, 'redimg')

Now we are using 3D arrays to change the colors. Here we
set all the values in green and blue to zero.
This leaves us with just the red channel.

factor = N.array((8,), N.int32)
soften = N.array(rgbarray, N.int32)
soften[1:,:] += rgbarray[:1,:] * factor
soften[:1,:] += rgbarray[1:,:] * factor
soften[:,1:] += rgbarray[:,:1] * factor
soften[:,:1] += rgbarray[:,1:] * factor
soften //= 33
surfdemo_show(soften, 'soften')

Here we perform a 3x3 convolution filter that will soften our image.
It looks like a lot of steps here, but what we are doing is shifting
the image 1 pixel in each direction and adding them all together (with some
multiplication for weighting). Then average all the values. It's no gaussian,
but it's fast. One point with NumPy arrays, the precision of arithmetic
operations is determined by the array with the largest data type.
So if factor was not declared as a 1 element array of type numpy.int32,
the multiplications would be performed using numpy.int8, the 8 bit integer
type of each rgbarray element. This will cause value truncation. The soften
array must also be declared to have a larger integer size than rgbarray to
avoid truncation.

src = N.array(rgbarray)
dest = N.zeros(rgbarray.shape)
dest[:] = 20, 50, 100
diff = (dest  src) * 0.50
xfade = src + diff.astype(N.uint)
surfdemo_show(xfade, 'xfade')

Lastly, we are cross fading between the original image and a solid blueish
image. Not exciting, but the dest image could be anything, and changing the 0.50
multiplier will let you choose any step in a linear crossfade between two images.
