diff options
Diffstat (limited to 'lib/pygame/_numpysurfarray.py')
-rwxr-xr-x | lib/pygame/_numpysurfarray.py | 472 |
1 files changed, 0 insertions, 472 deletions
diff --git a/lib/pygame/_numpysurfarray.py b/lib/pygame/_numpysurfarray.py deleted file mode 100755 index 8eac04d..0000000 --- a/lib/pygame/_numpysurfarray.py +++ /dev/null @@ -1,472 +0,0 @@ -## pygame - Python Game Library -## Copyright (C) 2007 Marcus von Appen -## -## This library is free software; you can redistribute it and/or -## modify it under the terms of the GNU Library General Public -## License as published by the Free Software Foundation; either -## version 2 of the License, or (at your option) any later version. -## -## This library is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -## Library General Public License for more details. -## -## You should have received a copy of the GNU Library General Public -## License along with this library; if not, write to the Free -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -## -## Marcus von Appen -## mva@sysfault.org - -"""pygame module for accessing surface pixel data using numpy - -Functions to convert pixel data between pygame Surfaces and Numpy -arrays. This module will only be available when pygame can use the -external Numpy package. - -Note, that numpyarray is an optional module. It requires that Numpy is -installed to be used. If not installed, an exception will be raised when -it is used. eg. ImportError: no module named numpy - -Every pixel is stored as a single integer value to represent the red, -green, and blue colors. The 8bit images use a value that looks into a -colormap. Pixels with higher depth use a bit packing process to place -three or four values into a single number. - -The Numpy arrays are indexed by the X axis first, followed by the Y -axis. Arrays that treat the pixels as a single integer are referred to -as 2D arrays. This module can also separate the red, green, and blue -color values into separate indices. These types of arrays are referred -to as 3D arrays, and the last index is 0 for red, 1 for green, and 2 for -blue. - -In contrast to Numeric Numpy does use unsigned 16bit integers, images -with 16bit data will be treated as unsigned integers. -""" - -import pygame -import numpy -import re - -def array2d (surface): - """pygame.numpyarray.array2d (Surface): return array - - copy pixels into a 2d array - - Copy the pixels from a Surface into a 2D array. The bit depth of the - surface will control the size of the integer values, and will work - for any type of pixel format. - - This function will temporarily lock the Surface as pixels are copied - (see the Surface.lock - lock the Surface memory for pixel access - method). - """ - bpp = surface.get_bytesize () - if bpp <= 0 or bpp > 4: - raise ValueError("unsupported bit depth for 2D array") - - # Taken from Alex Holkner's pygame-ctypes package. Thanks a lot. - data = surface.get_buffer ().raw - - # Remove extra pitch from each row. - width = surface.get_width () - pitchdiff = surface.get_pitch () - width * bpp - if pitchdiff > 0: - pattern = re.compile ('(%s)%s' % ('.' * width * bpp, '.' * pitchdiff), - flags=re.DOTALL) - data = ''.join (pattern.findall (data)) - - if bpp == 3: - # Pad each triplet of bytes with another zero - pattern = re.compile ('...', flags=re.DOTALL) - data = '\0'.join (pattern.findall (data)) - if pygame.get_sdl_byteorder () == pygame.LIL_ENDIAN: - data += '\0' - else: - data = '\0' + data - bpp = 4 - - typecode = (numpy.uint8, numpy.uint16, None, numpy.int32)[bpp - 1] - array = numpy.fromstring (data, typecode) - array.shape = (surface.get_height (), width) - array = numpy.transpose (array) - return array - - -def pixels2d (surface): - """pygame.numpyarray.pixels2d (Surface): return array - - reference pixels into a 2d array - - Create a new 2D array that directly references the pixel values in a - Surface. Any changes to the array will affect the pixels in the - Surface. This is a fast operation since no data is copied. - - Pixels from a 24-bit Surface cannot be referenced, but all other - Surface bit depths can. - - The Surface this references will remain locked for the lifetime of - the array (see the Surface.lock - lock the Surface memory for pixel - access method). - """ - bpp = surface.get_bytesize () - if bpp == 3 or bpp < 1 or bpp > 4: - raise ValueError("unsupported bit depth for 2D reference array") - - typecode = (numpy.uint8, numpy.uint16, None, numpy.int32)[bpp - 1] - array = numpy.frombuffer (surface.get_buffer (), typecode) - array.shape = surface.get_height (), surface.get_pitch () / bpp - - # Padding correction for certain depth due to padding bytes. - array = array[:,:surface.get_width ()] - array = numpy.transpose (array) - return array - -def array3d (surface): - """pygame.numpyarray.array3d (Surface): return array - - copy pixels into a 3d array - - Copy the pixels from a Surface into a 3D array. The bit depth of the - surface will control the size of the integer values, and will work - for any type of pixel format. - - This function will temporarily lock the Surface as pixels are copied - (see the Surface.lock - lock the Surface memory for pixel access - method). - """ - bpp = surface.get_bytesize () - array = array2d (surface) - - # Taken from from Alex Holkner's pygame-ctypes package. Thanks a - # lot. - if bpp == 1: - palette = surface.get_palette () - # Resolve the correct values using the color palette - pal_r = numpy.array ([c[0] for c in palette]) - pal_g = numpy.array ([c[1] for c in palette]) - pal_b = numpy.array ([c[2] for c in palette]) - planes = [numpy.choose (array, pal_r), - numpy.choose (array, pal_g), - numpy.choose (array, pal_b)] - array = numpy.array (planes, numpy.uint8) - array = numpy.transpose (array, (1, 2, 0)) - return array - elif bpp == 2: - # Taken from SDL_GetRGBA. - masks = surface.get_masks () - shifts = surface.get_shifts () - losses = surface.get_losses () - vr = (array & masks[0]) >> shifts[0] - vg = (array & masks[1]) >> shifts[1] - vb = (array & masks[2]) >> shifts[2] - planes = [(vr << losses[0]) + (vr >> (8 - (losses[0] << 1))), - (vg << losses[1]) + (vg >> (8 - (losses[1] << 1))), - (vb << losses[2]) + (vb >> (8 - (losses[2] << 1)))] - array = numpy.array (planes, numpy.uint8) - return numpy.transpose (array, (1, 2, 0)) - else: - masks = surface.get_masks () - shifts = surface.get_shifts () - losses = surface.get_losses () - planes = [((array & masks[0]) >> shifts[0]), # << losses[0], Assume 0 - ((array & masks[1]) >> shifts[1]), # << losses[1], - ((array & masks[2]) >> shifts[2])] # << losses[2]] - array = numpy.array (planes, numpy.uint8) - return numpy.transpose (array, (1, 2, 0)) - -def pixels3d (surface): - """pygame.numpyarray.pixels3d (Surface): return array - - reference pixels into a 3d array - - Create a new 3D array that directly references the pixel values in a - Surface. Any changes to the array will affect the pixels in the - Surface. This is a fast operation since no data is copied. - - This will only work on Surfaces that have 24-bit or 32-bit - formats. Lower pixel formats cannot be referenced. - - The Surface this references will remain locked for the lifetime of - the array (see the Surface.lock - lock the Surface memory for pixel - access method). - """ - bpp = surface.get_bytesize () - if bpp < 3 or bpp > 4: - raise ValueError("unsupported bit depth for 3D reference array") - lilendian = pygame.get_sdl_byteorder () == pygame.LIL_ENDIAN - - start = 0 - step = 0 - - # Check for RGB or BGR surface. - shifts = surface.get_shifts () - if shifts[0] == 16 and shifts[1] == 8 and shifts[2] == 0: - # RGB - if lilendian: - start = 2 - step = -1 - else: - start = 0 - step = 1 - elif shifts[2] == 16 and shifts[1] == 8 and shifts[0] == 0: - # BGR - if lilendian: - start = 0 - step = 1 - else: - start = 2 - step = -1 - else: - raise ValueError("unsupported colormasks for 3D reference array") - - if bpp == 4 and not lilendian: - start += 1 - - array = numpy.ndarray \ - (shape=(surface.get_width (), surface.get_height (), 3), - dtype=numpy.uint8, buffer=surface.get_buffer (), - offset=start, strides=(bpp, surface.get_pitch (),step)) - return array - -def array_alpha (surface): - """pygame.numpyarray.array_alpha (Surface): return array - - copy pixel alphas into a 2d array - - Copy the pixel alpha values (degree of transparency) from a Surface - into a 2D array. This will work for any type of Surface - format. Surfaces without a pixel alpha will return an array with all - opaque values. - - This function will temporarily lock the Surface as pixels are copied - (see the Surface.lock - lock the Surface memory for pixel access - method). - """ - if (surface.get_bytesize () == 1 or - surface.get_alpha () is None or - surface.get_masks ()[3] == 0): - # 1 bpp surfaces and surfaces without per-pixel alpha are always - # fully opaque. - array = numpy.empty (surface.get_width () * surface.get_height (), - numpy.uint8) - array.fill (0xff) - array.shape = surface.get_width (), surface.get_height () - return array - - array = array2d (surface) - if surface.get_bytesize () == 2: - # Taken from SDL_GetRGBA. - va = (array & surface.get_masks ()[3]) >> surface.get_shifts ()[3] - array = ((va << surface.get_losses ()[3]) + - (va >> (8 - (surface.get_losses ()[3] << 1)))) - else: - # Taken from _numericsurfarray.c. - array = array >> surface.get_shifts ()[3] << surface.get_losses ()[3] - array = array.astype (numpy.uint8) - return array - -def pixels_alpha (surface): - """pygame.numpyarray.pixels_alpha (Surface): return array - - reference pixel alphas into a 2d array - - Create a new 2D array that directly references the alpha values - (degree of transparency) in a Surface. Any changes to the array will - affect the pixels in the Surface. This is a fast operation since no - data is copied. - - This can only work on 32-bit Surfaces with a per-pixel alpha value. - - The Surface this array references will remain locked for the - lifetime of the array. - """ - if surface.get_bytesize () != 4: - raise ValueError("unsupported bit depth for alpha reference array") - lilendian = pygame.get_sdl_byteorder () == pygame.LIL_ENDIAN - - # ARGB surface. - start = 0 - - if surface.get_shifts ()[3] == 24 and lilendian: - # RGBA surface. - start = 3 - elif surface.get_shifts ()[3] == 0 and not lilendian: - start = 3 - else: - raise ValueError("unsupported colormasks for alpha reference array") - - array = numpy.ndarray \ - (shape=(surface.get_width (), surface.get_height ()), - dtype=numpy.uint8, buffer=surface.get_buffer (), - offset=start, strides=(4, surface.get_pitch ())) - return array - -def array_colorkey (surface): - """pygame.numpyarray.array_colorkey (Surface): return array - - copy the colorkey values into a 2d array - - Create a new array with the colorkey transparency value from each - pixel. If the pixel matches the colorkey it will be fully - tranparent; otherwise it will be fully opaque. - - This will work on any type of Surface format. If the image has no - colorkey a solid opaque array will be returned. - - This function will temporarily lock the Surface as pixels are - copied. - """ - colorkey = surface.get_colorkey () - if colorkey == None: - # No colorkey, return a solid opaque array. - array = numpy.empty (surface.get_width () * surface.get_height (), - numpy.uint8) - array.fill (0xff) - array.shape = surface.get_width (), surface.get_height () - return array - - # Taken from from Alex Holkner's pygame-ctypes package. Thanks a - # lot. - array = array2d (surface) - # Check each pixel value for the colorkey and mark it as opaque or - # transparent as needed. - val = surface.map_rgb (colorkey) - array = numpy.choose (numpy.equal (array, val), - (numpy.uint8 (0xff), numpy.uint8 (0))) - array.shape = surface.get_width (), surface.get_height () - return array - -def make_surface (array): - """pygame.numpyarray.make_surface (array): return Surface - - copy an array to a new surface - - Create a new Surface that best resembles the data and format on the - array. The array can be 2D or 3D with any sized integer values. - """ - # Taken from from Alex Holkner's pygame-ctypes package. Thanks a - # lot. - bpp = 0 - r = g = b = 0 - shape = array.shape - if len (shape) == 2: - # 2D array - bpp = 8 - r = 0xFF >> 6 << 5 - g = 0xFF >> 5 << 2 - b = 0xFF >> 6 - elif len (shape) == 3 and shape[2] == 3: - bpp = 32 - r = 0xff << 16 - g = 0xff << 8 - b = 0xff - else: - raise ValueError("must be a valid 2d or 3d array") - - surface = pygame.Surface ((shape[0], shape[1]), 0, bpp, (r, g, b, 0)) - blit_array (surface, array) - return surface - -def blit_array (surface, array): - """pygame.numpyarray.blit_array (Surface, array): return None - - blit directly from a array values - - Directly copy values from an array into a Surface. This is faster - than converting the array into a Surface and blitting. The array - must be the same dimensions as the Surface and will completely - replace all pixel values. - - This function will temporarily lock the Surface as the new values - are copied. - """ - bpp = surface.get_bytesize () - if bpp <= 0 or bpp > 4: - raise ValueError("unsupported bit depth for surface") - - shape = array.shape - width = surface.get_width () - - typecode = (numpy.uint8, numpy.uint16, None, numpy.uint32)[bpp - 1] - array = array.astype (typecode) - - # Taken from from Alex Holkner's pygame-ctypes package. Thanks a - # lot. - if len(shape) == 3 and shape[2] == 3: - array = numpy.transpose (array, (1, 0, 2)) - shifts = surface.get_shifts () - losses = surface.get_losses () - array = (array[:,:,::3] >> losses[0] << shifts[0]) | \ - (array[:,:,1::3] >> losses[1] << shifts[1]) | \ - (array[:,:,2::3] >> losses[2] << shifts[2]) - elif len (shape) == 2: - array = numpy.transpose (array) - else: - raise ValueError("must be a valid 2d or 3d array") - - if width != shape[0] or surface.get_height () != shape[1]: - raise ValueError("array must match the surface dimensions") - - itemsize = array.itemsize - data = array.tostring () - - if itemsize > bpp: - # Trim bytes from each element, keep least significant byte(s) - pattern = '%s(%s)' % ('.' * (itemsize - bpp), '.' * bpp) - if pygame.get_sdl_byteorder () == pygame.LIL_ENDIAN: - pattern = '(%s)%s' % ('.' * bpp, '.' * (itemsize - bpp)) - data = ''.join (re.compile (pattern, flags=re.DOTALL).findall (data)) - elif itemsize < bpp: - # Add pad bytes to each element, at most significant end - pad = '\0' * (bpp - itemsize) - pixels = re.compile ('.' * itemsize, flags=re.DOTALL).findall (data) - data = pad.join (pixels) - if pygame.get_sdl_byteorder () == pygame.LIL_ENDIAN: - data = data + pad - else: - data = pad + data - - # Add zeros pad for pitch correction - pitchdiff = surface.get_pitch () - width * bpp - if pitchdiff > 0: - pad = '\0' * pitchdiff - rows = re.compile ('.' * width * bpp, flags=re.DOTALL).findall (data) - data = pad.join (rows) + pad - - surface.get_buffer ().write (data, 0) - -def map_array (surface, array): - """pygame.numpyarray.map_array (Surface, array3d): return array2d - - map a 3d array into a 2d array - - Convert a 3D array into a 2D array. This will use the given Surface - format to control the conversion. Palette surface formats are not - supported. - - Note: arrays do not need to be 3D, as long as the minor axis has - three elements giving the component colours, any array shape can be - used (for example, a single colour can be mapped, or an array of - colours). - """ - # Taken from from Alex Holkner's pygame-ctypes package. Thanks a - # lot. - bpp = surface.get_bytesize () - if bpp <= 1 or bpp > 4: - raise ValueError("unsupported bit depth for surface array") - - shape = array.shape - if shape[-1] != 3: - raise ValueError("array must be a 3d array of 3-value color data") - - shifts = surface.get_shifts () - losses = surface.get_losses () - if array.dtype != numpy.int32: - array = array.astype(numpy.int32) - out = array[...,0] >> losses[0] << shifts[0] - out[...] |= array[...,1] >> losses[1] << shifts[1] - out[...] |= array[...,2] >> losses[2] << shifts[2] - if surface.get_flags() & pygame.SRCALPHA: - out[...] |= numpy.int32(255) >> losses[3] << shifts[3] - return out |