Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

How can I color a Pygame image surface? I either want to change every pixel that is color A into color B, or else change every pixel into color B. Either works, so long as transparent regions remain the same.

share|improve this question
    
I've edited your post, but I can't tell whether you're trying to colour a texture or a primitive polygon. Please update your question to reflect which one you mean. –  Jonathan Hobbs Apr 1 '12 at 1:09
    
Sorry, I'm trying to color a texture -- the texture just happens to be a polygon. –  Juicy Apr 1 '12 at 2:49

1 Answer 1

What you're looking for are surfarrays. A simple tutorial on how to get started with them can be found here.

Essentially what a surfarray does is directly modify the pixel values of pygame surfaces, and can operate on each of the R, G, and B channels for every pixel "simultaneously," which I put in quotes because I just mean you can change all the pixels with just one line of code. Ordinarily, this would be a very slow operation, but surfarrays use numpy/numeric as their core, so the operation is quite fast. I should still note that in practice, I've found it not to be fast enough for some applications, such as operating on large images, but if you're only operating on small particle sprites, you should be fine.

I did a bit of toying around to make sure that this works as you need it. Below is a code example of what you're looking to do. Some credit goes to the poster who answered this question.

def color_surface(surface, red, green, blue):
    arr = pygame.surfarray.pixels3d(surface)
    arr[:,:,0] = red
    arr[:,:,1] = green
    arr[:,:,2] = blue

In that function, I use pygame.surfarray.pixels3d because it references the pixels into an array, rather than copy them, making it a faster operation. The tutorial I posted also uses an additional instruction, something like:

iarray = numpy.array(arr)

which I also left out because I've found this to be a startlingly slow call in practice. It might be necessary if you try to do more complicated things with the surface.

So, the last few steps are actually taking your original surface and coloring it the way you need:

origSurface = pygame.image.load('images/blue_circle.png')
origSurface.convert_alpha()

coloredSurface = origSurface.copy()
color_surface(coloredSurface, 120, 78, 240)

A couple of notes about this code: the call to convert_alpha on the surface seems to be unnecessary if the image already has per-pixel alphas defined. The StackOverflow question that I referenced details the two ways to ensure a surface has alphas which are unaffected by surfarray operations. Also, copying a surface may not necessarily preserve the alphas, but like the last point, I've found that it does when the alphas are already defined in the original image. Just a few things to watch out for.

This ended up rather long... One last note... If you're feeling adventurous, you can look into the gfxdraw libraries for pygame. The pygame.gfxdraw.textured_polygon function caught my attention. I know very little about how it works or it's performance though.

Hope this helps :)

share|improve this answer
    
Great! That looks like what I want. And yes, this is for a particle system. –  Juicy Apr 1 '12 at 7:40
    
Also, thanks for going into all the detail. It really does help. –  Juicy Apr 1 '12 at 7:41

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.