Create pixel square and present later
Question: I’ve started working with Python and SDL2 a short time ago to program my
psychological experiments. My question, therefore, is probably very basic. I
would like to create a square filled with random pixels of two different
colors and show it in the middle of the screen. I’ve managed to create this
pixel square and show it but it takes up to one second to create it. Thus, I
would like to create the pixel square earlier, that is in a moment in which
the participant is occupied with something else, and later show it. I thought
about using SDL_CreateRenderer(window, -1, 0) twice but I was not able to do
it. Is there a very easy way to solve my problem? Maybe it’s possible to save
the created pixel square to a file and then load it later on? That’s how I
create my pixel square:

    
    
    def put_pixel(x,y, color):
          pixel = SDL_Rect(x, y,1,1)        
    
          if color == "orange":
              SDL_SetRenderDrawColor(sdlRenderer,255,100,0,255) 
          elif color == "blue": 
              SDL_SetRenderDrawColor(sdlRenderer,0,100,255,255)
    
          SDL_RenderFillRect(sdlRenderer,pixel)
          return sdlRenderer
    
    def pixel_square(n_pixel_x,n_pixel_y, n_pixel_blue):
    
        seq = range(n_pixel_x*n_pixel_y) 
        random.shuffle(seq)
    
        lst = range(n_pixel_x*n_pixel_y)
        pos=0
        for i in range(n_pixel_x):
            for j in range(n_pixel_y):
                    lst[seq[pos]] = [i,j]
                    pos = pos+1 
    
        #create orange square   
        square_orange=SDL_Rect(MAXX/2-n_pixel_x/2,MAXY/2-n_pixel_y/2,n_pixel_x,n_pixel_y)    
        SDL_SetRenderDrawColor(sdlRenderer,255,100,0,255) #orange
        SDL_RenderFillRect(sdlRenderer,square_orange)     
    
        #add blue pixels
        for i in range(n_pixel_blue):
           put_pixel(x=MAXX/2-n_pixel_x/2+lst[i][0], y=MAXY/2-n_pixel_y/2+lst[i][1], color="blue")      
    
        return sdlRenderer  
    

Later on I use

    
    
    SDL_RenderPresent(sdlRenderer)
    

to show the pixel square.

I’d be very happy if you could help me with that problem!! Thank you! Vero


Answer: Your procedure to create images is slow due to the overhead of calculations
and loops to process. Aside from optimizing them here and there and
precomputing, storing and loading images from elsewhere, I'd recommend to use
[Numpy](http://www.numpy.org/%20%22Numpy) to generate the image on the fly, if
applicable. It features random distribution arrays out of the box and is
heavily optimized for speed.

A fully working example could look like:

    
    
    import sys
    import sdl2
    import sdl2.ext
    import numpy
    
    SIZE_X = 400
    SIZE_Y = 300
    
    # RGB values
    RED = 0xFF0000
    GREEN = 0x00FF00
    
    def pixelate():
        choices = [RED, GREEN]
        pixelarray = numpy.random.choice(choices,(SIZE_X, SIZE_Y))
        buf = pixelarray.tostring()
        # Create a software surface from the array. The depth and pitch are really
        # important here, since we use a continuous byte buffer access.
        image = sdl2.SDL_CreateRGBSurfaceFrom(buf,
                                              SIZE_X, SIZE_Y,
                                              32,   # Bit depth, we use 32-bit RGB
                                              SIZE_X, # pitch (byte size of a single scanline) - for 32 bit it is SIZE_X
                                              0xFF0000,
                                              0x00FF00,
                                              0x0000FF,
                                              0x0)
        # required to avoid loosing buf. SDL_CreateRGBSurfaceFrom() will
        # reference the byte buffer, not copy it
        image._buffer = buf
        return image
    
    def main():
        sdl2.ext.init()
    
        window = sdl2.ext.Window("Pixel example", size=(800, 600))
        imgoffset = sdl2.SDL_Rect(200, 150, 0, 0)
        window.show()
    
        # Software rendering, we also could use hardware rending and use streaming
        # textures, but the example would become more complicated then.
        windowsurface = window.get_surface()
    
        running = True
        while running:
            events = sdl2.ext.get_events()
            for event in events:
                if event.type == sdl2.SDL_QUIT:
                    running = False
                    break
                if event.type == sdl2.SDL_MOUSEBUTTONDOWN:
                    image = pixelate()
                    sdl2.SDL_BlitSurface(image, None, windowsurface, imgoffset)
            window.refresh()
            sdl2.SDL_Delay(10)
        sdl2.ext.quit()
        return 0
    
    if __name__ == "__main__":
        sys.exit(main())
    

The most important part is the _pixelate()_ function, which creates a 2D array
of specified size filled with a random distribution of the passed values (your
colors). SDL2 allows you to create surfaces (images) from a byte buffer, so
the next step is to create a buffer from the 2D numpy array and create a
surface using that specific buffer. Once done with that it is a simple matter
of showing the image on the screen.

If [Numpy](http://www.numpy.org/%20%22Numpy) can't be used in your
environment, I would avoid to draw each pixel individually using your
_put_pixel()_ method, since this will cause at least one context switch on
each color change in the SDL2 renderer (worst case). Instead, precompute a 2D
array, fill it with the necessary values and create a software surface buffer
(or again, a streaming texture) based on it, which you then blit on the screen
in a single operation.

