How to draw a transparent image in pygame? - python

Consider a chess board, i have a transparent image of queen(queen.png) of size 70x70 and i want to display it over a black rectangle.
Code:
BLACK=(0,0,0)
queen = pygame.image.load('queen.png')
pygame.draw.rect(DISPLAYSURF, BLACK, (10, 10, 70, 70))
DISPLAYSURF.blit(queen, (10, 10))
Error: i am not getting transparent image ie black rectangle is not visible at all, only queen with white background.
Please suggest

Try changing the line where you load in the queen to:
queen = pygame.image.load('queen.png').convert_alpha()

When you call the pygame.image.load() method, Pygame reads an image file from your hard drive and returns a surface object containing the image data.
This surface instance is the same type of object as your display surface, but it represents an image stored in memory.
By calling the convert() method of an (image-) surface instance with no arguments passed, Pygame converts the image surface to the same format as your main display surface. This is recommended, because it is faster to draw or blit images which have the same pixel format (depth, flags etc.) as the display surface. When you use this method, the converted surface will have no alpha information.
Fortunately Pygame surface objects provide also a convert_alpha() method, which converts an (image-) surface to a fast format that preserves any alpha information.
This means you need to call the convert_alpha() method of your queen instance for preserving any alpha information of the original image:
BLACK=(0,0,0)
#load the image and convert the returned surface using the convert_alpha() method
queen = pygame.image.load('queen.png').convert_alpha()
pygame.draw.rect(DISPLAYSURF, BLACK, (10, 10, 70, 70))
DISPLAYSURF.blit(queen, (10, 10))
pygame.display.update()

I don't think pygame.draw.rect supports alpha channels. You should use pygame.Surface
queen = pygame.Surface([10, 10], pygame.SRCALPHA, 32)

Related

How do i properly rescale an image on PyGame without it being badly cropped?

I'm trying to rescale an image on pygame but it instead crops the image, I'm just looking to change the pixel width and height of the image.
I used pygame.transform.scale and used 1900, 600 as the parameters, the original image is a 1920x1080
mainmenu = pygame.image.load("Main_Menu.png")
mainmenu = pygame.transform.scale(mainmenu, (1900,600))
screen.blit(background, (0, 0))
I expected the image to be rescaled to a 1900x600 image but it instead output a badly cropped image in the 1900x600 format.
You've to use pygame.transform.smoothscale() rather than pygame.transform.scale().
Use convert() or convert_alpha() to convert the surface to a surface with a with proper pixel format
mainmenu = pygame.image.load("Main_Menu.png")
mainmenu = pygame.transform.smoothscale(mainmenu.convert_alpha(), (1900,600))
screen.blit(background, (0, 0))
While scale() does a scaling operation, which is as fast as possible, smoothscale() scales smoothly and calculates area averages of the colors which cover the pixels.

Transparent Image in Pygame

I have a sprite in Pygame that is a blue circle. I want this image to be drawn to the screen "faded", e.g. translucent. However, I don't want a translucent rectangle to be drawn over it; instead, I want the actual image to be modified and made translucent. Any help is greatly appreciated!
Right now I have:
Class Circle(pygame.sprite.Sprite):
self.image = self.image = pygame.image.load("circle.png")
circle = Circle()
and eventually...
window.blit(pygame.transform.scale(circle.image, (zoom, zoom)), (100, 100))
How the circle.png looks:
How I want the image to look after making it transparent:
I am blitting the image onto the window, which is a white background.
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()
Create a new Surface with per-pixel alpha.
surf = pygame.Surface((circle_width, circle_height), pygame.SRCALPHA)
Make the surface transparent
surf.set_alpha(128) # alpha value
Draw the circle to that surface at (x=0, y=0)
surf.blit(pygame.transform.scale(circle.image, (zoom, zoom)), (0, 0))
Draw the surface to the window
window.blit(surf, (circle_x, circle_y))
As the Surface.set_alpha() documentation says, you can have surfaces with "homogeneous alpha" or per pixel alpha, but not both, wich I believe is what you want. It might work with colorkey transparency, but I'm not sure (I didn't tested that yet). Any non RGBA (without active alpha channel) pixel format might work if you use set_colorkey() and set_alpha() before blitting.
So, the code might look like:
class Circle(pygame.sprite.Sprite):
def __init__(self)
self.image = pygame.image.load("circle.png")
# get the surface's top-left pixel color and use it as colorkey
colorkey = self.image.get_at((0, 0))
self.image.set_colorkey(colorkey)
At some point in your code (immediately before rendering) you might want to set the transparency by calling:
circle.image.set_alpha(some_int_val)
And then you can scale and blit it as intended.

Pygame: How do I add an image to a rect?

I'm making my own game on Pygame, and I want to add images to rects instead of having a coloured rectangle.
I know how to add an image to pygame, but I want to know if there's some way to add the image and use the Pygame.rect properties such us rect.centerY and rect.centerX.
Does anyone know how?
Load your image, call its get_rect method to get a rect with the size of the image, then set the coordinates of the rect (there are several attributes like x, y, topleft, center, etc.) ...
IMAGE = pg.image.load('an_image.png').convert() # or .convert_alpha()
# Create a rect with the size of the image.
rect = IMAGE.get_rect()
rect.center = (200, 300)
... and pass the rect as the dest argument to pygame.Surface.blit to blit the image at the rect.topleft coordinates.
screen.blit(IMAGE, rect)

Drawn surface transparency in pygame?

I'm writing a predator-prey simulation using python and pygame for the graphical representation. I'm making it so you can actually "interact" with a creature (kill it, select it and follow it arround the world, etc). Right now, when you click a creature, a thick circle(made of various anti-aliased circles from the gfxdraw class) sorrounds it, meaning that you have succesfully selected it.
My goal is to make that circle transparent, but according to the documentation you can't set an alpha value for drawn surface. I have seen solutions for rectangles (by creating a separate semitransparent surface, blitting it, and then drawing the rectangle on it), but not for a semi-filled circle.
What do you suggest? Thank's :)
Have a look at the following example code:
import pygame
pygame.init()
screen = pygame.display.set_mode((300, 300))
ck = (127, 33, 33)
size = 25
while True:
if pygame.event.get(pygame.MOUSEBUTTONDOWN):
s = pygame.Surface((50, 50))
# first, "erase" the surface by filling it with a color and
# setting this color as colorkey, so the surface is empty
s.fill(ck)
s.set_colorkey(ck)
pygame.draw.circle(s, (255, 0, 0), (size, size), size, 2)
# after drawing the circle, we can set the
# alpha value (transparency) of the surface
s.set_alpha(75)
x, y = pygame.mouse.get_pos()
screen.blit(s, (x-size, y-size))
pygame.event.poll()
pygame.display.flip()

PyGame: translucent sprites with per pixel alpha

Is it possible to display PyGame surfaces with controllable alpha? I would like to take a surface with its own per pixel alpha and display it with variable level of translucency without affecting the surface data and keep the transparency intact i.e. the objects on the surface would keep their shapes but their "contents" becoming more or less translucent.
In other words I want to combine per-pixel alpha from the source image with per-surface alpha calculated at the runtime.
The Pygame documentation says that you can't combine surface alpha with per-pixel alpha, but if you're using Pygame 1.8.1 or newer, you can work around this by using the special_flags parameter to .blit().
Here's how I did it:
# Load an image with per-pixel alpha
s = pygame.image.load('spam.png')
s = s.convert_alpha()
# Simulate s.set_alpha(alpha)
alpha_img = pygame.Surface(s.get_rect().size, pygame.SRCALPHA)
alpha_img.fill((255, 255, 255, alpha))
s.blit(alpha_img, (0, 0), special_flags=pygame.BLEND_RGBA_MULT)
The way this works is to create a second surface the same size as the first, and blit it on to the first using RGBA multiplication. By having the R, G and B components of the second image equal to 255, the multiplication won't affect the colour of the image, but it will scale the alpha channel by the given alpha factor.
Note that the method above differs from calling set_alpha() in that set_alpha() can be reversed by calling set_alpha(255). If you use the method above it will result in the pixel alphas of every pixel being changed, so the process cannot be straightforwardly reversed.
Yes you can. The documentation of the Surface class explains how to do it. It boils down to two cases only:
Either you set a flag during the creation of the Surface object:
s = pygame.Surface((16, 16), flags=pygame.SRCALPHA)
Or you give an alpha channel to a surface that doesn't have one yet:
s = pygame.image.load('spam.png')
s.convert_alpha()
The documentation of the pygame.image module says that applying convert_alpha is necessary for PNGs with transparency.
If you want you can modify the alpha value of each pixel with the modules draw and surfarray. When specifying a color, use then a tuple of four integers: (red, green, blue, alpha). The alpha parameter ranges from 0 (totally transparent) to 255 (totally opaque).
import pygame
pygame.init()
screen = pygame.display.set_mode((320, 200))
screen.fill((200, 100, 200))
s = pygame.Surface((64, 64), flags=pygame.SRCALPHA)
for i in range(64):
pygame.draw.line(s, (0, 0, 0, i*4), (0, i), (64, i))
screen.blit(s, (50, 30))
pygame.display.flip()
After checking both PyGame and SDL documentations I came to conclusion that what I asked wasn't doable in PyGame using standard functions.
SDL docs state that per-pixel alpha and per-surface alpha cannot be combined with the former always taking the precedence. The only way to achieve the effect I want is by writing a code which updates per-pixel alpha values of the source surface before the blit.
If your input image has per-pixel alpha enabled, but is only using a single bit for transparency (e.g., .png sprites with a transparent background or text), you can convert the transparent background to a colorkey-alpha background pretty easily, and then use set_alpha() to blend the whole texture onto whatever.
This is a quick and dirty helper function I used for fading text effects and other things:
def convert_to_colorkey_alpha(surf, colorkey=pygame.color.Color("magenta")):
newsurf = surface.Surface(surf.get_size())
newsurf.fill(colorkey)
newsurf.blit(surf, (0, 0))
newsurf.set_colorkey(colorkey)
return newsurf
A couple of other tricks potentially solve this problem might be:
Doing per-pixel editing to modify the alpha channel before blitting
Blitting a white or black-filled, semi-transparent surface with special_flags=BLEND_RGBA_MULT or BLEND_RGBA_SUB onto your source surface.

Categories