Transparent Image in Pygame - python

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.

Related

How do I make a circle semi-transparent in pygame?

I want to make a partially transparent circle as an area of effect indicator, but I haven't found any way to do this in pygame.
I tried passing in an rgba 4-tuple as an argument (as suggested by this post), but it didn't change the transparency at all. On top of that, according to this other post, the method shouldn't work at all, since draw doesn't accept alpha values. That's conflicting information.
pygame.draw.circle(screen, (255, 0, 0, 100), (x, y), r)
I've also tried creating a new surface, drawing the circle onto that surface, and then blitting the new surface onto my game screen (as suggested by this post). It gives me a semi-transparent circle as requested, but since surfaces in pygame are rectangular, it also gives me a gray rectangle around the circle, which I don't want.
s = pygame.Surface((1000, 1000))
s.set_alpha(100)
pygame.draw.circle(s, (255, 0, 0), (x, y), r)
screen.blit(s, (0, 0))
Is there any way to make this circle semi-transparent without adding any other visible effects to my screen?
Here's a runnable version of the answer to the last question you linked to titled How to draw a semi-transparent circle in Pygame?. It seems to do what you want, as far as I can tell.
import pygame
width, height = 640, 480
pygame.init()
clock = pygame.time.Clock()
screen = pygame.display.set_mode((width,height))
surface = pygame.display.set_mode((width,height), pygame.SRCALPHA)
while True:
msElapsed = clock.tick(100)
screen.fill((255,255,255))
pygame.draw.circle(surface,(30,224,33,100),(250,100),10)
screen.blit(surface, (0,0))
pygame.display.update()
for event in pygame.event.get():
if event.type==pygame.QUIT:
exit()

Rotating An Image In Pygame Without Distortion

I have been trying to make an image rotate in pygame, using python 3.6, however when I do it either distorts the image into an unrecognizable image, or when it rotates it bumps all over the place
Just using pygame.transform.rotate(image, angle) makes the distorted mess.
And using something like:
pygame.draw.rect(gameDisplay, self.color, [self.x, self.y, self.width, self.height]) makes the image bump all over the place.
I have looked at many questions on this site and others and so far none of them have worked perfectly.
To anyone who is interested here is the link to my code so far.
https://pastebin.com/UQJJFNTy
My image is 64x64.
Thanks in advance!
Per the docs (http://www.pygame.org/docs/ref/transform.html):
Some of the transforms are considered destructive. These means every time they are performed they lose pixel data. Common examples of this are resizing and rotating. For this reason, it is better to re-transform the original surface than to keep transforming an image multiple times.
Each time you call transform.rotate you need to do it on the original image, not on the previously rotated one. For example, if I want the image rotated 10 degrees each frame:
image = pygame.image.load("myimage.png").convert()
image_clean = image.copy()
rot = 0
Then in your game loop (or object's update):
rot += 10
image = pygame.transform.rotate(image_clean, rot)
Here's a complete example. Don't modify the original image and in the while loop use pygame.transform.rotate or rotozoom to get a new rotated surface and assign it to another name. Use a rect to keep the center.
import sys
import pygame as pg
pg.init()
screen = pg.display.set_mode((640, 480))
BG_COLOR = pg.Color('darkslategray')
# Here I just create an image with per-pixel alpha and draw
# some shapes on it so that we can better see the rotation effects.
ORIG_IMAGE = pg.Surface((240, 180), pg.SRCALPHA)
pg.draw.rect(ORIG_IMAGE, pg.Color('aquamarine3'), (80, 0, 80, 180))
pg.draw.rect(ORIG_IMAGE, pg.Color('gray16'), (60, 0, 120, 40))
pg.draw.circle(ORIG_IMAGE, pg.Color('gray16'), (120, 180), 50)
def main():
clock = pg.time.Clock()
# The rect where we'll blit the image.
rect = ORIG_IMAGE.get_rect(center=(300, 220))
angle = 0
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
# Increment the angle, then rotate the image.
angle += 2
# image = pg.transform.rotate(ORIG_IMAGE, angle) # rotate often looks ugly.
image = pg.transform.rotozoom(ORIG_IMAGE, angle, 1) # rotozoom is smoother.
# The center of the new rect is the center of the old rect.
rect = image.get_rect(center=rect.center)
screen.fill(BG_COLOR)
screen.blit(image, rect)
pg.display.flip()
clock.tick(30)
if __name__ == '__main__':
main()
pg.quit()
sys.exit()

pygame.error: Couldn't allocate memory for PNG file or incompatible PNG dll [duplicate]

I'm trying to blit a PNG image onto a surface, but the transparent part of the image turns black for some reason, here's the simple code:
screen = pygame.display.set_mode((800, 600), pygame.DOUBLEBUF, 32)
world = pygame.Surface((800, 600), pygame.SRCALPHA, 32)
treeImage = pygame.image.load("tree.png")
world.blit(treeImage, (0,0), (0,0,64,64))
screen.blit(world, pygame.rect.Rect(0,0, 800, 600))
What do I have to do to solve the problem?
The image has alpha transparency, I've opened it up in PhotoShop and the background turns transparent, not black or white or any other color.
Thank you for your support :)
http://www.pygame.org/docs/ref/image.html recommends:
For alpha transparency, like in .png images use the convert_alpha() method after loading so that the image has per pixel transparency.
You did not flip the doublebuffer.
import pygame
from pygame.locals import Color
screen = pygame.display.set_mode((800, 600))
treeImage = pygame.image.load("tree.png").convert_alpha()
white = Color('white')
while(True):
screen.fill(white)
screen.blit(treeImage, pygame.rect.Rect(0,0, 128, 128))
pygame.display.flip()
This should work for your problem.
Images are represented by "pygame.Surface" objects. A Surface can be created from an image with pygame.image.load:
my_image_surface = pygame.load.image('my_image.jpg')
However, the pygame documentation notes that:
The returned Surface will contain the same color format, colorkey and alpha transparency as the file it came from. You will often want to call convert() with no arguments, to create a copy that will draw more quickly on the screen.
For alpha transparency, like in .png images, use the convert_alpha() method after loading so that the image has per pixel transparency.
Use the convert_alpha() method for best performance:
alpha_image_surface = pygame.load.image('my_icon.png').convert_alpha()
A Surface can be drawn on or blended with another Surface using the blit method. The first argument to blit is the Surface that should be drawn. The second argument is either a tuple (x, y) representing the upper left corner or a rectangle. With a rectangle, only the upper left corner of the rectangle is taken into account. It should be mentioned that the window respectively display is also represented by a Surface. Therefore, drawing a Surface in the window is the same as drawing a Surface on a Surface:
window_surface.blit(image_surface, (x, y))
window_surface.blit(image_surface,
image_surface.get_rect(center = window_surface.get_rect().center))
Minimal example: repl.it/#Rabbid76/PyGame-LoadTransparentImage
import pygame
pygame.init()
window = pygame.display.set_mode((300, 300))
clock = pygame.time.Clock()
pygameSurface = pygame.image.load('Porthole.png').convert_alpha()
background = pygame.Surface(window.get_size())
ts, w, h, c1, c2 = 50, *window.get_size(), (160, 160, 160), (192, 192, 192)
tiles = [((x*ts, y*ts, ts, ts), c1 if (x+y) % 2 == 0 else c2) for x in range((w+ts-1)//ts) for y in range((h+ts-1)//ts)]
for rect, color in tiles:
pygame.draw.rect(background, color, rect)
run = True
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
window.blit(background, (0, 0))
window.blit(pygameSurface, pygameSurface.get_rect(center = window.get_rect().center))
pygame.display.flip()
pygame.quit()
exit()
Your code looks like it should be correct. The SDL library does not support alpha to alpha blitting like this, but Pygame added support for it awhile ago. In Pygame 1.8 support was added for custom blending modes, and I wonder if that removed Pygame's internal alpha-to-alpha blitter?
Alas, further investigation will be required.

Keep Alpha in Pygame PixelArray

I wan't to change every colors in my image to grey;but I don't wan't to make any changes to my image alpha.I wan't to keep transparent pixels of my image.this is my code:
from pygame import *
init()
screen = display.set_mode([640, 640])
r = image.load('g.png')
r = transform.scale(r,(640,640))
ar = PixelArray (r)
ar.replace ((255, 255, 255), (110, 110, 110), 0.15)
del ar
screen.blit(r, (0,0))
display.update()
Here's a workaround: Paint all transparent pixels of your image-file g.png with a color you're never going to use, like magic-pink or pitch-black. Then just change ever color of the image but you're transparent color - and then, before you blit, convert your array to a surface and set the colorkey to your transparent color, like this: surface.set_colorkey((225, 0, 225))

How do I blit a PNG with some transparency onto a surface in Pygame?

I'm trying to blit a PNG image onto a surface, but the transparent part of the image turns black for some reason, here's the simple code:
screen = pygame.display.set_mode((800, 600), pygame.DOUBLEBUF, 32)
world = pygame.Surface((800, 600), pygame.SRCALPHA, 32)
treeImage = pygame.image.load("tree.png")
world.blit(treeImage, (0,0), (0,0,64,64))
screen.blit(world, pygame.rect.Rect(0,0, 800, 600))
What do I have to do to solve the problem?
The image has alpha transparency, I've opened it up in PhotoShop and the background turns transparent, not black or white or any other color.
Thank you for your support :)
http://www.pygame.org/docs/ref/image.html recommends:
For alpha transparency, like in .png images use the convert_alpha() method after loading so that the image has per pixel transparency.
You did not flip the doublebuffer.
import pygame
from pygame.locals import Color
screen = pygame.display.set_mode((800, 600))
treeImage = pygame.image.load("tree.png").convert_alpha()
white = Color('white')
while(True):
screen.fill(white)
screen.blit(treeImage, pygame.rect.Rect(0,0, 128, 128))
pygame.display.flip()
This should work for your problem.
Images are represented by "pygame.Surface" objects. A Surface can be created from an image with pygame.image.load:
my_image_surface = pygame.load.image('my_image.jpg')
However, the pygame documentation notes that:
The returned Surface will contain the same color format, colorkey and alpha transparency as the file it came from. You will often want to call convert() with no arguments, to create a copy that will draw more quickly on the screen.
For alpha transparency, like in .png images, use the convert_alpha() method after loading so that the image has per pixel transparency.
Use the convert_alpha() method for best performance:
alpha_image_surface = pygame.load.image('my_icon.png').convert_alpha()
A Surface can be drawn on or blended with another Surface using the blit method. The first argument to blit is the Surface that should be drawn. The second argument is either a tuple (x, y) representing the upper left corner or a rectangle. With a rectangle, only the upper left corner of the rectangle is taken into account. It should be mentioned that the window respectively display is also represented by a Surface. Therefore, drawing a Surface in the window is the same as drawing a Surface on a Surface:
window_surface.blit(image_surface, (x, y))
window_surface.blit(image_surface,
image_surface.get_rect(center = window_surface.get_rect().center))
Minimal example: repl.it/#Rabbid76/PyGame-LoadTransparentImage
import pygame
pygame.init()
window = pygame.display.set_mode((300, 300))
clock = pygame.time.Clock()
pygameSurface = pygame.image.load('Porthole.png').convert_alpha()
background = pygame.Surface(window.get_size())
ts, w, h, c1, c2 = 50, *window.get_size(), (160, 160, 160), (192, 192, 192)
tiles = [((x*ts, y*ts, ts, ts), c1 if (x+y) % 2 == 0 else c2) for x in range((w+ts-1)//ts) for y in range((h+ts-1)//ts)]
for rect, color in tiles:
pygame.draw.rect(background, color, rect)
run = True
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
window.blit(background, (0, 0))
window.blit(pygameSurface, pygameSurface.get_rect(center = window.get_rect().center))
pygame.display.flip()
pygame.quit()
exit()
Your code looks like it should be correct. The SDL library does not support alpha to alpha blitting like this, but Pygame added support for it awhile ago. In Pygame 1.8 support was added for custom blending modes, and I wonder if that removed Pygame's internal alpha-to-alpha blitter?
Alas, further investigation will be required.

Categories