How to Blit a Png with Some Transparency Onto a Surface in Pygame

Need to blit transparency on a surface in Pygame

You can create a surface with an alpha channel (pass the pygame.SRCALPHA flag), fill it with an opaque color and then draw a shape with a transparent color onto it (alpha value 0).

import pygame as pg

pg.init()
screen = pg.display.set_mode((800, 600))
clock = pg.time.Clock()
BLUE = pg.Color('dodgerblue4')
# I just create the background surface in the following lines.
background = pg.Surface(screen.get_size())
background.fill((90, 120, 140))
for y in range(0, 600, 20):
for x in range(0, 800, 20):
pg.draw.rect(background, BLUE, (x, y, 20, 20), 1)

# This dark gray surface will be blitted above the background surface.
surface = pg.Surface(screen.get_size(), pg.SRCALPHA)
surface.fill(pg.Color('gray11'))

done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
elif event.type == pg.MOUSEMOTION:
surface.fill(pg.Color('gray11')) # Clear the gray surface ...
# ... and draw a transparent circle onto it to create a hole.
pg.draw.circle(surface, (255, 255, 255, 0), event.pos, 90)

screen.blit(background, (0, 0))
screen.blit(surface, (0, 0))

pg.display.flip()
clock.tick(30)

pg.quit()

You can also achieve this effect with another surface instead of pygame.draw.circle. For example you could create a white image with some transparent parts in your graphics editor and pass BLEND_RGBA_MIN as the special_flags argument to Surface.blit when you blit it onto the gray surface.

brush = pg.image.load('brush.png').convert_alpha()

# Then in the while or event loop.
surface.fill(pg.Color('gray11'))
surface.blit(brush, event.pos, special_flags=pg.BLEND_RGBA_MIN)

Pygame image transparency confusion

If you copy a transparent Surface to another Surface the target Surface has to provide transparency respectively per pixel alpha.

You can enable additional functions when creating a new surface. Set the SRCALPHA flag to create a surface with an image format that includes a per-pixel alpha. The initial value of the pixels is (0, 0, 0, 0):

my_surface = pygame.Surface((width, height), pygame.SRCALPHA)

Use the following image

Sample Image

and adapt the method image_at of the class SpriteSheet. Use pygame.SRCALPHA:

class SpriteSheet:
# [...]

def image_at(self, rectangle, colorkey = None):
"""Load a specific image from a specific rectangle."""
# Loads image from x, y, x+offset, y+offset.
rect = pygame.Rect(rectangle)

image = pygame.Surface(rect.size, pygame.SRCALPHA) # <----

image.blit(self.sheet, (0, 0), rect)
if colorkey is not None:
if colorkey == -1:
colorkey = image.get_at((0,0))
image.set_colorkey(colorkey, pygame.RLEACCEL)
return image

Or use convert_alpha():

class SpriteSheet:
# [...]

def image_at(self, rectangle, colorkey = None):
"""Load a specific image from a specific rectangle."""
# Loads image from x, y, x+offset, y+offset.
rect = pygame.Rect(rectangle)

image = pygame.Surface(rect.size).convert_alpha() # <----
image.fill((0, 0, 0, 0)) # <---

image.blit(self.sheet, (0, 0), rect)
if colorkey is not None:
if colorkey == -1:
colorkey = image.get_at((0,0))
image.set_colorkey(colorkey, pygame.RLEACCEL)
return image

See also:

  • How can I make an Image with a transparent Backround in Pygame?
  • How do I blit a PNG with some transparency onto a surface in Pygame?

Note that chess pieces can also be drawn through a Unicode text.

See Displaying unicode symbols using pygame

png images with transparent background don't work in pygame 2.0.0

PNGs have per pixel alpha. It is not necessary to set a color key. Simply blit the protector on the tank. convert() changes the pixel format to a format without alpha per pixel and removes the transparency information. Use convert_alpha() instead:

class Player(pygame.sprite.Sprite):
def __init__(self, pos_x, pos_y):
super().__init__(player_group, all_sprites)
slef.image = pygame.image.load('baloon.png').convert_alpha()
self.image = pygame.transform.scale(slef.image, (42, 94))

Sample Image


I suggest to modify the load_image function:

def load_image(name, per_pixel_alpha = False, color_key = None):
fullname = os.path.join('textures', name)
try:
image = pygame.image.load(fullname)
except pygame.error as message:
print('Cannot load image:', name)
raise SystemExit(message)

if per_pixel_alpha:
image = image.convert_alpha()
else:
image = image.convert()

if color_key is not None:
if color_key == -1:
color_key = image.get_at((0, 0))
image.set_colorkey(color_key)

return image
class Player(pygame.sprite.Sprite):
def __init__(self, pos_x, pos_y):
super().__init__(player_group, all_sprites)
self.image = pygame.transform.scale(load_image('baloon.png', True), (42, 94))

self.rect = self.image.get_rect().move(pos_x, pos_y)

def update(self, *args):
pass

Transparent Image in Pygame

First, your image/surface needs to use per-pixel alpha, therefore call the convert_alpha() method when you load it. If you want to create a new surface (as in the example), you can also pass pygame.SRCALPHA to pygame.Surface.

The second step is to create another surface (called alpha_surface here) which you fill with white and the desired alpha value (the fourth element of the color tuple).

Finally, you have to blit the alpha_surface onto your image and pass pygame.BLEND_RGBA_MULT as the special_flags argument. That will make
the opaque parts of the image translucent.

import pygame as pg

pg.init()
screen = pg.display.set_mode((800, 600))
clock = pg.time.Clock()
BLUE = pg.Color('dodgerblue2')
BLACK = pg.Color('black')

# Load your image and use the convert_alpha method to use
# per-pixel alpha.
# IMAGE = pygame.image.load('circle.png').convert_alpha()
# A surface with per-pixel alpha for demonstration purposes.
IMAGE = pg.Surface((300, 300), pg.SRCALPHA)
pg.draw.circle(IMAGE, BLACK, (150, 150), 150)
pg.draw.circle(IMAGE, BLUE, (150, 150), 130)

alpha_surface = pg.Surface(IMAGE.get_size(), pg.SRCALPHA)
# Fill the surface with white and use the desired alpha value
# here (the fourth element).
alpha_surface.fill((255, 255, 255, 90))
# Now blit the transparent surface onto your image and pass
# BLEND_RGBA_MULT as the special_flags argument.
IMAGE.blit(alpha_surface, (0, 0), special_flags=pg.BLEND_RGBA_MULT)

done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True

screen.fill((50, 50, 50))
pg.draw.rect(screen, (250, 120, 0), (100, 300, 200, 100))
screen.blit(IMAGE, (150, 150))

pg.display.flip()
clock.tick(60)

pg.quit()

Using image transaprency make appear black things

convert_alpha() does not convert the format of the surface itself, but creates a new surface with a format that provides a per pixel alpha format.

either

surface = pygame.Surface((tileSize, tileSize))
surface = surface.convert_alpha()

or

surface = pygame.Surface((tileSize, tileSize)).convert_alpha() 

There are 3 ways to create a transparent Surface:

  • Set a transparent color key with set_colorkey()

    The color key specifies the color that is treated as transparent. For example, if you have an image with a black background that should be transparent, set a black color key:

    surface.set_colorkey((0, 0, 0))
  • You can enable additional functions when creating a new surface. Set the SRCALPHA flag to create a surface with an image format that includes a per-pixel alpha. The initial value of the pixels is (0, 0, 0, 0):

    surface = pygame.Surface((tileSize, tileSize), pygame.SRCALPHA)
  • Use convert_alpha() to create a copy of the Surface with an image format that provides alpha per pixel.

    However, if you create a new surface and use convert_alpha(), the alpha channels are initially set to maximum. The initial value of the pixels is (0, 0, 0, 255). You need to fill the entire surface with a transparent color before you can draw anything on it:

    surface = pygame.Surface((tileSize, tileSize))
    surface = surface.convert_alpha()
    surface.fill((0, 0, 0, 0))


Related Topics



Leave a reply



Submit