Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pygame, set transparency on an image imported using convert_alpha()

in my pygame game, to import jpeg image, I use convert() http://www.pygame.org/docs/ref/surface.html#pygame.Surface.convert

then, to play with the image transparency (how much we can see trough the image), I use set_alpha() http://www.pygame.org/docs/ref/surface.html#pygame.Surface.set_alpha

However, to import my png image, which have a tranparent background, I use convert_alpha() http://www.pygame.org/docs/ref/surface.html#pygame.Surface.convert_alpha

but with this way of importing, I can't play with the general transparency using set_alpha(). Any other idea to adjust the transparency (how much we see trough the image) ?

like image 429
n0tis Avatar asked Feb 11 '16 07:02

n0tis


People also ask

How do I change the opacity of a picture in pygame?

Image -> Mode -> Convert to Color Profile... and use the defaults. Image -> Mode -> Indexed... and use the defaults.

What does Convert_alpha do in pygame?

convert and convert_alpha are both used to convert surfaces to the same pixel format as used by the screen. This ensures that you won't lose performance because of conversions when you're blitting them to the screen.

How do I change the opacity of text in pygame?

You can change the transparency of the entire surface using a individual alpha value. Use surf=pygame. Surface((size,pygame. SRCALPHA) .


2 Answers

When you read the documentation for set_alpha you can read this : If the Surface format contains per pixel alphas, then this alpha value will be ignored.

%In your case, with a png image, it's a per pixel alphas. So, you must manage alpha "per pixel". For example, you can do that (not the best code, but easy to understand. Work with png with no/yes transparency only):

def change_alpha(img,alpha=255):
  width,height=img.get_size()
  for x in range(0,width):
    for y in range(0,height):
      r,g,b,old_alpha=img.get_at((x,y))
      if old_alpha>0:
        img.set_at((x,y),(r,g,b,alpha))

Be carefull, it's "slow", because you manage each pixel which is not at 0 (transparent from your png). If your png has multiple level of transparency, you should manage the transparency with a better formula, like this:

      r,g,b,old_alpha=img.get_at((x,y))
      img.set_at((x,y),(r,g,b,(alpha*old_alpha)/255))

And in this case, never modify the original image, but work on a copy to never lose your original alpha.

I hope it will help

===================== EDIT =================== Add some optimisation because asking in comment

With some caching methodology:

class image_with_alpha(object):
    def __init__(self,name=None):
        self.img=None
        self.alpha={}
        if name:
            self.load_image(name)

    def load_image(self,name):
        self.img=pygame.image.load(name)
        self.alpha[255]=self.img
        #self.pre_compute_alpha()

    def pre_compute_alpha(self):
        for alpha in range(0,10):
            self.alpha[alpha]=change_alpha(self.img,alpha)

    def get_img(self,a=255):
        try:
            return self.alpha[a]
        except:
            self.alpha[a]=change_alpha(self.img,a)
        return self.alpha[a]

And use it like this : Load image:

    image=image_with_alpha("test.png")

Blit with 60 for alpha:

    screen.blit(image.get_img(60),(0,0))

And now, it's fast I hope

like image 145
A.H Avatar answered Sep 19 '22 04:09

A.H


The fastest solution is probably to use numpy array manipulation, it should be fast enough to avoid the need for caching. What's really slow about calculating the alpha value pixel-wise is iterating in Python, while numpy does it all in C.

Start out by referencing the image's alpha channel into a numpy array. This will create a lock on the image surface; let's remember that for later. Then take the minimum (pixel-wise) of your original alpha and an array full of ones (that will leave you with an array of only ones and zeros), multiply that (pixel-wise) by your desired alpha and copy the result back to the image's alpha channel (still represented by that array reference). Before you can blit the image to the screen, the array reference to the alpha array must be cleared, releasing the lock on the image surface.

def change_alpha(img, alpha=255):
    chan = pygame.surfarray.pixels_alpha(img)
    chan2 = numpy.minimum(chan, numpy.ones(chan.shape, dtype=chan.dtype)) * alpha
    numpy.copyto(chan, chan2)
    del chan
like image 37
Thomas Lotze Avatar answered Sep 22 '22 04:09

Thomas Lotze