Search code examples
pygamepixelpygame-surface

pygame.surface.get_at((x, y)) not returning correct pixel data


I have a simple program which allows the user to draw white pixels in a black box. when the user clicks the blue button I want my program to go through all the pixels in the draw box and add the pixel data to an array for later use in another project. However, it only returns black for each pixel even if the user has drawn an image on there.

import pygame
from pygame.locals import *
import sys

# set up the screen
pygame.init()
screen = pygame.display.set_mode((200, 200))
pygame.display.set_caption("drawTest")
clock = pygame.time.Clock()

# goes through the screen data and reads the pixel data
def GetPixelDataOfDrawScreen():
    for i in range(200):
        for j in range(200):
            if(i > 49 and i < 150):
                if(j > 49 and j < 150):

                    # gets the red, green, blue and alpha (RGBA) components of the pixel
                    pixelColor = screen.get_at((i, j))
                    print(i, pixelColor[0])

                    if(pixelColor[0] == 255):
                        pixelDataOfDrawBox.append(255)
                    else:
                        pixelDataOfDrawBox.append(0)

                    # dosen't work
    print(pixelDataOfDrawBox)

pixelDataOfDrawBox = []
rects = []

while True:

    for event in pygame.event.get(): 
            if event.type == pygame.QUIT: # adds close button to screen
                sys.exit()

    screen.fill((255, 255, 255))                                                    

    # gets the mouse position
    mouseX, mouseY = pygame.mouse.get_pos()

    # draw drawing box
    boxX = 50
    boxY = 50
    pygame.draw.rect(screen, (0, 0, 0), (boxX, boxY, 100, 100))

    if(mouseX >= boxX and mouseX <= boxX + 100 - 2): # check if drawing
        if(mouseY >= boxY and mouseY <= boxY + 100 - 2):
            if(pygame.mouse.get_pressed()[0]):
                rects.append([mouseX, mouseY, 2, 2])

    # blue button
    bButtonX = 100
    bButtonY = 150
    pygame.draw.rect(screen, (0, 0, 255), (bButtonX, bButtonY, 50, 20))

    if(mouseX >= bButtonX and mouseX <= bButtonX + 50): # check if pressed
        if(mouseY >= bButtonY and mouseY <= bButtonY + 20):
            pygame.draw.rect(screen, (0, 0, 180), (bButtonX, bButtonY, 50, 20))
            if(pygame.mouse.get_pressed()[0]):
                GetPixelDataOfDrawScreen()

    # red button
    rButtonX = 50
    rButtonY = 150
    pygame.draw.rect(screen, (255, 0, 0), (rButtonX, rButtonY, 50, 20))

    if(mouseX >= rButtonX and mouseX <= rButtonX + 50):
        if(mouseY >= rButtonY and mouseY <= rButtonY + 20):
            pygame.draw.rect(screen, (180, 0, 0), (rButtonX, rButtonY, 50, 20))

    # draw the rects
    for r in rects:
        pygame.draw.rect(screen, (255, 255, 255), (r[0], r[1], r[2], r[3]))

    pygame.display.flip()
    clock.tick(60)

Solution

  • The problem is that you check the pixels after the screen surface gets cleared and before you draw the white rects/pixels. The drawing box area is still black at this moment. A quick fix would be to call GetPixelDataOfDrawScreen below the code that draws the rects:

    # draw the rects
    for r in rects:
        pygame.draw.rect(screen, (255, 255, 255), (r[0], r[1], r[2], r[3]))
    
    if(mouseX >= bButtonX and mouseX <= bButtonX + 50): # check if pressed
        if(mouseY >= bButtonY and mouseY <= bButtonY + 20):
            pygame.draw.rect(screen, (0, 0, 180), (bButtonX, bButtonY, 50, 20))
            if(pygame.mouse.get_pressed()[0]):
                GetPixelDataOfDrawScreen()
    
    pygame.display.flip()
    clock.tick(60)
    

    Also, the program can be simplified. You could probably just serialize the rects list with the json or pickle modules, or create a separate surface for the drawing area and then just save it with pygame.image.save.

    Here's an example in which I draw onto another surface instead of the screen. You can save it with pygame.image.save and load it with pygame.image.load (press S and O). I also recommend creating pygame.Rect objects for the box and the buttons because they have useful collision detection methods like collidepoint:

    import sys
    import pygame
    
    
    pygame.init()
    screen = pygame.display.set_mode((200, 200))
    clock = pygame.time.Clock()
    
    box_surface = pygame.Surface((100, 100))
    box = box_surface.get_rect(topleft=(50, 50))
    blue_button = pygame.Rect(100, 150, 50, 20)
    red_button = pygame.Rect(50, 150, 50, 20)
    
    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_s:  # Press s to save the image.
                    pygame.image.save(box_surface, 'box.png')
                elif event.key == pygame.K_o:  # Press o to load the image.
                    box_surface = pygame.image.load('box.png').convert()
    
        mouse_pos = pygame.mouse.get_pos()
        if pygame.mouse.get_pressed()[0]:
            # Adjust the mouse positions because the box is positioned at (100, 100).
            mouse_x, mouse_y = mouse_pos[0]-box.x, mouse_pos[1]-box.y
            pygame.draw.rect(box_surface, (255, 255, 255), [mouse_x, mouse_y, 2, 2])
    
        # Draw everything.
        screen.fill((255, 255, 255))
        screen.blit(box_surface, box)
        pygame.draw.rect(screen, (0, 0, 255), blue_button)
        pygame.draw.rect(screen, (255, 0, 0), red_button)
        if red_button.collidepoint(mouse_pos):
            pygame.draw.rect(screen, (180, 0, 0), red_button)
        if blue_button.collidepoint(mouse_pos):
            pygame.draw.rect(screen, (0, 0, 180), blue_button)
    
        pygame.display.flip()
        clock.tick(60)