Reputation: 404
So, I was trying to get all the pixels occupied by some text, but I realised pygame.surfarray.pixels3d
doesn’t give the expected output.
Here is what I tried:
import pygame
# import numpy as np
pygame.init()
width, height = 800, 800
win = pygame.display.set_mode((width, height))
font = pygame.font.SysFont("Monospace", 100, True)
text = font.render("test", True, (255, 255, 255))
# saves the correct image with text
pygame.image.save(text,"image.png")
# gives all (255,255,255)?!
pixels = pygame.surfarray.pixels3d(text).copy()
# remake surface from these pixels - doesn’t give the text.
text = pygame.surfarray.make_surface(pixels)
text_rect = text.get_rect(center=(width // 2, height // 2))
def main():
run = True
win.fill((0, 0, 0))
win.blit(text, text_rect)
pygame.display.update()
while run:
for e in pygame.event.get():
if e.type == pygame.QUIT:
run = False
break
if __name__ == "__main__":
main()
pygame.surfarray.pixels3d
works perfectly for other surfaces, so I don’t understand if this is a bug in pygame or am I doing something wrong?
Thanks in advance.
EDIT:
I have also tried using surfarray.array3d
, but no luck.
Upvotes: 2
Views: 416
Reputation: 210880
You only read the color channels of the Surface also has an alpha channel. Get the color channels (array3d
or pixels3d
) and the alpha channel (array_alpha
or pixels_alpha
) and stick them together. Recreate the Surface with pygame.image.frombuffer
:
pixels_rgb = pygame.surfarray.array3d(text)
pixels_alpha = pygame.surfarray.array_alpha(text).reshape((*pixels_rgb.shape[0:2], 1))
pixels_rgba = np.concatenate((pixels_rgb, pixels_alpha), 2)
text = pygame.image.frombuffer(pixels_rgba.transpose((1, 0, 2)).copy(order='C'), text.get_size(), 'RGBA')
Alternatively you can create a text with an opaque black background. Set a black color key (set_colorkey
) and convert it with convert_alpha
:
text = font.render("test", True, (255, 255, 255), (0, 0, 0))
text.set_colorkey(0)
text = text.convert_alpha()
Complete code
import pygame
import numpy as np
pygame.init()
width, height = 800, 800
win = pygame.display.set_mode((width, height))
font = pygame.font.SysFont("Monospace", 100, True)
text1 = font.render("test 1", True, (255, 255, 255))
text2 = font.render("test 2", True, (255, 255, 255), (0, 0, 0))
text2.set_colorkey(0)
text2 = text2.convert_alpha()
pixels_rgb = pygame.surfarray.array3d(text1)
pixels_alpha = pygame.surfarray.array_alpha(text1).reshape((*pixels_rgb.shape[0:2], 1))
pixels_rgba = np.concatenate((pixels_rgb, pixels_alpha), 2)
text1 = pygame.image.frombuffer(pixels_rgba.transpose((1, 0, 2)).copy(order='C'), text1.get_size(), 'RGBA')
pixels = pygame.surfarray.pixels3d(text2).copy()
text2 = pygame.surfarray.make_surface(pixels)
text1_rect = text1.get_rect(center=(width // 2, height // 2 - 50))
text2_rect = text1.get_rect(center=(width // 2, height // 2 + 50))
def main():
run = True
win.fill((0, 0, 0))
win.blit(text1, text1_rect)
win.blit(text2, text2_rect)
pygame.display.update()
while run:
for e in pygame.event.get():
if e.type == pygame.QUIT:
run = False
if __name__ == "__main__":
main()
Upvotes: 3