Search code examples
pythonpygame

How do I change the colour of an image in Pygame without changing its transparency?


It sounds like a simple thing to do , but I'm struggling. I have a png image of a rectangle with a transparent centre called "zero". I want to change the colour of the visible part of the image. To try and change it, I have tried using "zero.fill" but no option I try changes only the non-transparent part, or it merges the new colour with the old and stays like that. I'm not keen on installing numpy as I wish to take the finished program to a friend who doesn't have it. Any simple suggestions welcome.


Solution

  • I've got an example that works with per pixel alpha surfaces that can also be translucent. The fill function just loops over the surface's pixels and sets them to the new color, but keeps their alpha value. It's probably not recommendable to do this every frame with many surfaces. (Press f, g, h to change the color.)

    import sys
    import pygame as pg
    
    
    def fill(surface, color):
        """Fill all pixels of the surface with color, preserve transparency."""
        w, h = surface.get_size()
        r, g, b, _ = color
        for x in range(w):
            for y in range(h):
                a = surface.get_at((x, y))[3]
                surface.set_at((x, y), pg.Color(r, g, b, a))
    
    
    def main():
        screen = pg.display.set_mode((640, 480))
        clock = pg.time.Clock()
    
        # Uncomment this for a non-translucent surface.
        # surface = pg.Surface((100, 150), pg.SRCALPHA)
        # pg.draw.circle(surface, pg.Color(40, 240, 120), (50, 50), 50)
        surface = pg.image.load('bullet2.png').convert_alpha()
        surface = pg.transform.rotozoom(surface, 0, 2)
    
        done = False
    
        while not done:
            for event in pg.event.get():
                if event.type == pg.QUIT:
                    done = True
                if event.type == pg.KEYDOWN:
                    if event.key == pg.K_f:
                        fill(surface, pg.Color(240, 200, 40))
                    if event.key == pg.K_g:
                        fill(surface, pg.Color(250, 10, 40))
                    if event.key == pg.K_h:
                        fill(surface, pg.Color(40, 240, 120))
    
            screen.fill(pg.Color('lightskyblue4'))
            pg.draw.rect(screen, pg.Color(40, 50, 50), (210, 210, 50, 90))
            screen.blit(surface, (200, 200))
    
            pg.display.flip()
            clock.tick(30)
    
    
    if __name__ == '__main__':
        pg.init()
        main()
        pg.quit()
        sys.exit()
    

    bullet2.png