Skip to content

SDL_CreateRGBSurfaceWithFormatFrom silently failing when passed a sub-array of a bytes object #275

@TTimo

Description

@TTimo

What doesn't work?

I'm finding that SDL_CreateRGBSurfaceWithFormatFrom either throws or fails to take in the pixel data (but creates a valid empty SDL_Surface) when passed in a sub-array of a bytes object directly. But it works if I setup an intermediate python object first.

How To Reproduce

This test case stems from difficulties I ran into when adding support for setting the application's window icon:

#!/usr/bin/env python

import sys
import sdl2

if __name__ == '__main__':
    sdl2.SDL_Init(sdl2.SDL_INIT_VIDEO)
    window = sdl2.SDL_CreateWindow(
        'test'.encode(),
        sdl2.SDL_WINDOWPOS_CENTERED,
        sdl2.SDL_WINDOWPOS_CENTERED,
        640,
        480,
        0
        )

    assert sys.byteorder == 'little'
    # A dummy 4 bytes header, followed by an little endian ARGB solid green fill
    # For instance, say we loaded a TGA file with 18 bytes worth of header
    w = h= 256
    pixels = b'\xff\xff\xff\xff' b'\x00\xff\x00\xff' * w * h

    # Arch Linux, Python 3.11.7:       pixels don't get through, yields a blank/fully transparent icon
    # Arch Linux, Python 3.12.2 (AUR): pixels don't get through, yields a blank/fully transparent icon
    # Windows, Python 3.11.8:          OSError: exception: access violation reading [..]
    # Windows, Python 3.12.2:          works fine!
    # (all with PySDL2 0.9.16, current atm and SDL 2.30.0)
    icon = sdl2.SDL_CreateRGBSurfaceWithFormatFrom(pixels[4:4+w*h*4], w, h, 32, w*4, sdl2.SDL_PIXELFORMAT_ARGB8888)
    assert icon is not None
    assert icon.contents.format.contents.format == sdl2.SDL_PIXELFORMAT_ARGB8888

    sdl2.SDL_SetWindowIcon(window, icon)

    import time
    time.sleep(4)

    # Workaround: this..
    pixels2 = pixels[4:4+w*h*4]
    icon = sdl2.SDL_CreateRGBSurfaceWithFormatFrom(pixels2, w, h, 32, w*4, sdl2.SDL_PIXELFORMAT_ARGB8888)
    assert icon is not None
    assert icon.contents.format.contents.format == sdl2.SDL_PIXELFORMAT_ARGB8888

    sdl2.SDL_SetWindowIcon(window, icon)

    import time
    time.sleep(4)

On Windows with Python 3.12 the first SDL_CreateRGBSurfaceWithFormatFrom call works. Elsewhere it'll either ignore the pixels and yield a transparent/empty surface, or throw an OSErrror.

The workaround is what bugs me the most .. just .. pixels2 = pixels[4:4+w*h*4] and all platforms work.

Platform:

  • OS: Windows 11 64-bit, Arch Linux (have not tested others)
  • Python Version: 3.11.7 3.11.8 3.12.2
  • SDL2 Version: 2.0.30
  • Using pysdl2-dll: Yes on Windows

Additional context
Add any other context about the problem here.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions