I have a Surface in PyGame. I want to modify the alpha values of pixels directly. I've tried doing it with the various methods that access the alpha values, but they don't seem to work.
from screeninfo import get_monitors
import pygame, os, numpy.random, pygame.surfarray
pygame.init()
FPS = 60
CLOCK = pygame.time.Clock()
monitor_info = get_monitors()
x = 0
y = 0
width = monitor_info[0].width
height = monitor_info[0].height
if len(monitor_info) > 1:
if monitor_info[0].x < 0:
x = 0
else:
x = monitor_info[0].width
width = monitor_info[1].width
height = monitor_info[1].height
os.environ['SDL_VIDEO_WINDOW_POS'] = "{},0".format(x)
pygame.display.init()
pygame.mouse.set_visible(False)
screen_info = pygame.display.Info()
screen_size = width, height
base_screen = pygame.display.set_mode(screen_size, pygame.NOFRAME)
base_screen.fill([100, 100, 100])
board_size = (int(min(width, height)*0.75), int(min(width, height)*0.75))
surface = pygame.Surface(board_size, pygame.SRCALPHA)
surface.fill([255, 255, 255, 255])
base_screen.blit(surface, (0,0))
pygame.display.flip()
pixels = numpy.random.uniform(low=0, high=255, size=(board_size[0], board_size[1], 3))
transparency = numpy.random.uniform(low=0, high=255, size=board_size).astype('uint8')
while True:
events = pygame.event.get()
ms = CLOCK.tick(FPS)
print('\r {} '.format(ms), end='')
# pygame.surfarray.blit_array(surface, pixels)
aa = pygame.surfarray.pixels_alpha(surface)
aa = numpy.random.uniform(low=0, high=255, size=board_size).astype('uint8')
del aa
# for i in range(board_size[0]):
# for j in range(board_size[1]):
# a = surface.get_at((i,j))
# a[3] = 0
# surface.set_at((i,j), a)
base_screen.blit(surface, (0,0))
pygame.display.flip()
I've tried both things in the loop (pixels_array, and get_at/set_at) but neither works--the image just stays white (if I set the initial alpha to 0, it stays transparent). Does anyone know how to set per-pixel alpha values for a Surface?
I found your problem!! The reason why you can't see alpha is:
a) you first set surface
alpha to 255
, surface.fill([255, 255, 255, 255])
b) I believe aa = pygame.surfarray.pixels_alpha(surface)
aa = numpy.random.uniform(low=0, high=255, size=board_size).astype('uint8')
aren't working, however pygame.surfarray.blit_array(surface, pixels)
do work (produce colours) but I don't think they have any actual Alpha.
c) you need to fill the base_screen and THEN blit you surface. Such a common mistake but this is the main the problem.
And finally, Tim Robert's comment about the for loop, will definitely get you your alpha!
Here is it re-written to work (without screeninfo
as I don't have that library currently):
import pygame, os, numpy.random, pygame.surfarray
from random import randint
pygame.init()
FPS = 60
CLOCK = pygame.time.Clock()
x = 50
y = 50
width = 500
height = 500
os.environ['SDL_VIDEO_WINDOW_POS'] = "{},0".format(x)
#pygame.display.init(), don't actually need this
pygame.mouse.set_visible(False)
screen_info = pygame.display.Info()
screen_size = width, height
base_screen = pygame.display.set_mode(screen_size, pygame.NOFRAME)
base_screen.fill([100, 100, 100])
board_size = (int(min(width, height)*0.75), int(min(width, height)*0.75))
surface = pygame.Surface(board_size, pygame.SRCALPHA)
surface.fill([255, 0, 0]) ###could also be surface.fill([255,0,0,255]) to set the whole surface's alpha straight up if you didn't want to change each pixel later
while True:
#just so you can quit this program
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
raise SystemExit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
pygame.quit()
raise SystemExit()
ms = CLOCK.tick(FPS)
for i in range(board_size[0]):
for j in range(board_size[1]):
a = surface.get_at((i,j))
a[3] = randint(0, 128)#OR SET TO REQUIRED ALPHA VALUE
surface.set_at((i,j), a)
##################################################
base_screen.fill([100, 100, 100]) #NEED TO DO THIS
##################################################
base_screen.blit(surface, (0,0))
pygame.display.flip()
(by the way, I used red as the second surface colour as I thought it would stand out better)
Edit
As Eternal Ambiguity stated in the comments, here is the much, much faster version, in place of the for
loops:
aa = pygame.surfarray.pixels_alpha(surface)
aa[:] = numpy.random.uniform(low=0, high=255, size=board_size).astype('uint8')
del aa