PyGame: Applying transparency to an image with alpha?
Asked Answered
S

4

10

I want to display an image with alpha with a specified transparency, but can't figure out how to do it.

To elaborate on how I'm struggling with this, the blurb below is a slightly modified hunk of code from this SO answer, but if you run it, you'll see that "image" loses it's native alpha, while the alpha of "image2" never changes! Yuck.

#!/usr/bin/env python

import pygame, sys

pygame.init()

window = pygame.display.set_mode((200, 200))
background = pygame.Surface((window.get_size()))
background.fill((255, 255, 255))
image = image2 = pygame.image.load('alpha.png')

image = image.convert()
rect = image.get_rect()

image2 = image2.convert_alpha()
rect2 = image2.get_rect()

rect2.left = rect.width + 1

i = 0
while True:
  for event in pygame.event.get():
    if event.type == 12:
      pygame.quit()
      sys.exit()

  image.set_alpha(i)
  image2.set_alpha(i)

  window.fill((255, 255, 255))
  window.blit(background, background.get_rect())
  window.blit(image, rect)
  window.blit(image2, rect2)

  if i == 255:
    i = 0
  else:
    i += 1

  pygame.display.update()
  pygame.time.Clock().tick(60)

So ... how is it done?

Sixfooter answered 14/10, 2012 at 4:10 Comment(3)
I don't know, but image = image2 = pygame.image.load('alpha.png') might be referencing the same instance, erasing the transparency for image 2.Glynda
Are you looking for per-pixel alpha, or one alpha value per surface?Glynda
If I declare image and image2 individually, I get the same result. And to be honest, I don't really care how I do it as long as it's efficient and I get the desired outcome: to alter the transparency of an image or surface while retaining the original alpha values.Sixfooter
P
16

Make a copy of the image you want to show (to not change the original) and use following:

self.image = self.original_image.copy()
# this works on images with per pixel alpha too
alpha = 128
self.image.fill((255, 255, 255, alpha), None, pygame.BLEND_RGBA_MULT)

Sorry, to not provide a full example.

Pinky answered 23/4, 2013 at 19:43 Comment(1)
I found that this only works with 8-bit palettized images if you push them through convert_alpha first. Which is fine; just convert the image beforehand. :DOgilvy
D
9

For what it's worth, I've seen varying results depending on the image itself. In my situation, I found that using Gimp to change the image allowed me to keep the code simple:

image = pygame.image.load('path/to/my.png').convert()
image.set_alpha(128)
surface.blit(image, (0, 0))

Using that code, the following sprites just don't work right: http://www.spriters-resource.com/resources/sheets/47/50365.png

However, it does work after using Gimp to change 2 things:

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

After saving the changes, it works for me in Ubuntu. I can't post an image of the result because I'm a new user...

Dynamo answered 16/5, 2015 at 13:33 Comment(1)
In Gimp 2.1 I didn't find the first option (Image -> Mode -> Convert to Color Profile) but doing just step 2 worked for me.Obelisk
L
6

If you are just looking to load an image in pygame so it has an alpha channel, this is how to do so:

self.image = pygame.image.load("image file path").convert_alpha()

When you draw this image on the screen, it should include the transparency.

Lifesize answered 17/11, 2013 at 22:18 Comment(2)
Not an answer. He already knows how to do this, but wants to know how to change the image wide alpha when using an image with pixel alpha values.Ryley
I know this is an old thread, but what if it doesn't include transparency when using this method?Chalk
B
2

your code is a bit convoluted :-) but nonetheless, "non-per-pixel" - or "global alpha" for a surface is tricky to get done right in Pygame.

It is all documented at http://www.pygame.org/docs/ref/surface.htm - but indeed, short in words or examples.

What happens is that if the surface you are blitting (the source) has alpha pixels values for the pixels itself (i.e. 32 bit depth), a "global alpha" value,as set by the surface's set_alpha method will be ignored.

For this "global" alpha to be used, your source surface must not have per pixel alpha. That is easy to achieve if your original image (inyour case the "alpha.png" file) uses no transparency itself - just a matter of:

import pygame
pygame.init()
window = pygame.display.set_mode((200, 200))
image = pygame.image.load('alpha.png').convert(24)
image.set_alpha(128)
window.fill((255,255,255))
window.blit(image, (0,0))
pygame.display.flip()

However, if your "alpha.png" does use transparency itself, and you intend to preserve it, gets trickier!

You have to: create another surface, with the same size of your image, with depth = 24 Fill that surface with a color not in use in your image (like "chroma key") - In video effects, normaly they use pure green or pure white for that, but you can choose any RGB value - if your image is a photo instead of pixel art, you won't be able to know witch value won't be in use. Just pick any, and hope not to have too much "failed pixels". So, fill your surface with this key color, and set it as the key color for the surface: that colro will render fully transparent when blitting. Then, just blit your original image on this intermediary surface, set the global alpha on it (set_alpha) and blitit to your destination surface

In code, it translates roughly to:

import pygame
pygame.init()
window = pygame.display.set_mode((200, 200))
image = pygame.image.load('alpha.png')
surface = pygame.Surface(image.get_size(), depth=24)
key = (0,255,0)
surface.fill(surface.get_rect(), key)
surface.set_colorkey(key)
surface.blit(image, (0,0))
surface.set_alpha(128) 
window.fill((255,255,255))
window.blit(surface, (0,0))
pygame.display.flip()
Baudin answered 14/10, 2012 at 7:44 Comment(7)
actually pink/purple is the color used as the keyPippas
Since the aforementioned alpha technique follows a color, does that mean that I cannot have varied alpha like in the original PNG? That would make things like anti-aliased edges and text have dirty edges, you know?Sixfooter
Yes, it means that. The upside is that since you are fading the object anyway, the aliasing artifacts are not likely to be that perceivable.Baudin
And the aliasing can be further mitigated if the the colorkey is close to the color in the background on the destination surface (the screen)Baudin
@BartlomiejLewandowski I don't know about that - but if you try to chroma key filtering out Pink tones in footage with live humans on it, you are in for a surprise. Not a good one unless you are filming a sequence to the Invisible Man.Baudin
With chroma key you don't get semitransparency, right? That sucks :(Ryley
Good news: In Pygame 2.0, quoting the docs, "per-surface alpha can be combined with per-pixel alpha." :-)Judon

© 2022 - 2024 — McMap. All rights reserved.