xxSirFartAlotxx
xxSirFartAlotxx

Reputation: 404

pygame.surfarray.pixels3d doesn’t give correct pixel values with a text surface

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

Answers (1)

Rabbid76
Rabbid76

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

Related Questions