Source code for sdl2.ext.image

"""Image loaders."""
from .common import SDLError
from .compat import UnsupportedError, byteify
from .. import endian, surface, pixels

_HASPIL = True
try:
    from PIL import Image
except ImportError:
    _HASPIL = False

_HASSDLIMAGE = True
try:
    from .. import sdlimage
except ImportError:
    _HASSDLIMAGE = False

__all__ = ["get_image_formats", "load_image"]


[docs]def get_image_formats(): """Gets the formats supported in the default installation.""" if not _HASPIL and not _HASSDLIMAGE: return ("bmp", ) return ("bmp", "cur", "gif", "ico", "jpg", "lbm", "pbm", "pcx", "pgm", "png", "pnm", "ppm", "svg", "tga", "tif", "webp", "xcf", "xpm")
[docs]def load_image(fname, enforce=None): """Creates a SDL_Surface from an image file. This function makes use of the Python Imaging Library, if it is available on the target execution environment. The function will try to load the file via sdl2 first. If the file could not be loaded, it will try to load it via sdl2.sdlimage and PIL. You can force the function to use only one of them, by passing the enforce as either "PIL" or "SDL". Note: This will call sdl2.sdlimage.init() implicitly with the default arguments, if the module is available and if sdl2.SDL_LoadBMP() failed to load the image. """ if enforce is not None and enforce not in ("PIL", "SDL"): raise ValueError("enforce must be either 'PIL' or 'SDL', if set") if fname is None: raise ValueError("fname must be a string") name = fname if hasattr(fname, 'encode'): name = byteify(fname, "utf-8") if not _HASPIL and not _HASSDLIMAGE: imgsurface = surface.SDL_LoadBMP(name) if not imgsurface: raise UnsupportedError(load_image, "cannot use PIL or SDL for image loading") return imgsurface.contents if enforce == "PIL" and not _HASPIL: raise UnsupportedError(load_image, "cannot use PIL (not found)") if enforce == "SDL" and not _HASSDLIMAGE: imgsurface = surface.SDL_LoadBMP(name) if not imgsurface: raise UnsupportedError(load_image, "cannot use SDL_image (not found)") return imgsurface.contents imgsurface = None if enforce != "PIL" and _HASSDLIMAGE: sdlimage.IMG_Init(sdlimage.IMG_INIT_JPG | sdlimage.IMG_INIT_PNG | sdlimage.IMG_INIT_TIF | sdlimage.IMG_INIT_WEBP) imgsurface = sdlimage.IMG_Load(name) if not imgsurface: # An error occured - if we do not try PIL, break out now if not _HASPIL or enforce == "SDL": raise SDLError(sdlimage.IMG_GetError()) else: imgsurface = imgsurface.contents if enforce != "SDL" and _HASPIL and not imgsurface: image = Image.open(fname) mode = image.mode width, height = image.size rmask = gmask = bmask = amask = 0 if mode in ("1", "L", "P"): # 1 = B/W, 1 bit per byte # "L" = greyscale, 8-bit # "P" = palette-based, 8-bit pitch = width depth = 8 elif mode == "RGB": # 3x8-bit, 24bpp if endian.SDL_BYTEORDER == endian.SDL_LIL_ENDIAN: rmask = 0x0000FF gmask = 0x00FF00 bmask = 0xFF0000 else: rmask = 0xFF0000 gmask = 0x00FF00 bmask = 0x0000FF depth = 24 pitch = width * 3 elif mode in ("RGBA", "RGBX"): # RGBX: 4x8-bit, no alpha # RGBA: 4x8-bit, alpha if endian.SDL_BYTEORDER == endian.SDL_LIL_ENDIAN: rmask = 0x000000FF gmask = 0x0000FF00 bmask = 0x00FF0000 if mode == "RGBA": amask = 0xFF000000 else: rmask = 0xFF000000 gmask = 0x00FF0000 bmask = 0x0000FF00 if mode == "RGBA": amask = 0x000000FF depth = 32 pitch = width * 4 else: # We do not support CMYK or YCbCr for now raise TypeError("unsupported image format") pxbuf = image.tobytes() imgsurface = surface.SDL_CreateRGBSurfaceFrom(pxbuf, width, height, depth, pitch, rmask, gmask, bmask, amask) if not imgsurface: raise SDLError() imgsurface = imgsurface.contents # the pixel buffer must not be freed for the lifetime of the surface imgsurface._pxbuf = pxbuf if mode == "P": # Create a SDL_Palette for the SDL_Surface def _chunk(seq, size): for x in range(0, len(seq), size): yield seq[x:x + size] rgbcolors = image.getpalette() sdlpalette = pixels.SDL_AllocPalette(len(rgbcolors) // 3) if not sdlpalette: raise SDLError() SDL_Color = pixels.SDL_Color for idx, (r, g, b) in enumerate(_chunk(rgbcolors, 3)): sdlpalette.contents.colors[idx] = SDL_Color(r, g, b) ret = surface.SDL_SetSurfacePalette(imgsurface, sdlpalette) # This will decrease the refcount on the palette, so it gets # freed properly on releasing the SDL_Surface. pixels.SDL_FreePalette(sdlpalette) if ret != 0: raise SDLError() # If the image has a single transparent palette index, set # that index as the color key to make blitting correct. if 'transparency' in image.info and isinstance(image.info['transparency'], int): surface.SDL_SetColorKey(imgsurface, True, image.info['transparency']) return imgsurface