Lenard Lindstrom avatar Lenard Lindstrom committed 0d2f059

Let _numpysurfarray.blit_array and make_surface methods accept float arrays ( closes #81 )

As requested, surfarray once again excepts numpy arrays with a float dtype.
Float values are rounded to int with the numpy.rint ufunc.
In Pygame 1.9.1, floats were simply truncated.

Comments (0)

Files changed (3)

lib/_numpysurfarray.py

 
 import pygame
 from pygame.compat import bytes_
-from pygame.pixelcopy import array_to_surface, surface_to_array
-from pygame.pixelcopy import map_array as pix_map_array
+from pygame.pixelcopy import array_to_surface, surface_to_array, \
+    map_array as pix_map_array, make_surface as pix_make_surface
 import numpy
-from numpy import array as numpy_array, empty as numpy_empty
+from numpy import array as numpy_array, empty as numpy_empty, \
+                  rint as numpy_rint, uint32 as numpy_uint32, \
+                  ndarray as numpy_ndarray
+
+numpy_floats = [numpy.float, numpy.float32, numpy.float64, numpy.float96]
+
+def blit_array (surface, array):
+    """pygame.surfarray.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. Only integer, ascii character and record arrays are accepted.
+
+    This function will temporarily lock the Surface as the new values are
+    copied.
+    """
+    if isinstance(array, numpy_ndarray) and array.dtype in numpy_floats:
+        array = numpy_rint(array, numpy_empty(array.shape, dtype=numpy_uint32))
+    return array_to_surface(surface, array)
+
+def make_surface(array):
+    """pygame.surfarray.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.
+    """ 
+    if isinstance(array, numpy_ndarray) and array.dtype in numpy_floats:
+        array = numpy_rint(array, numpy_empty(array.shape, dtype=numpy_uint32))
+    return pix_make_surface (array)
 
 def array2d(surface):
     """pygame.numpyarray.array2d(Surface): return array
     This function will temporarily lock the Surface as the new values are
     copied.
     """
-    return array_to_surface(surface, array)
+    if __arraytype == "numeric":
+        return numericsf.blit_array (surface, array)
+    elif __arraytype == "numpy":
+        return numpysf.blit_array (surface, array)
+    raise NotImplementedError("surface arrays are not supported")
 
 def array2d (surface):
     """pygame.surfarray.array2d (Surface): return array
     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.
     """ 
-    return pc_make_surface(array)
+    if __arraytype == "numeric":
+        return numericsf.make_surface (array)
+    elif __arraytype == "numpy":
+        return numpysf.make_surface (array)
+    raise NotImplementedError("surface arrays are not supported")
 
 def map_array (surface, array):
     """pygame.surfarray.map_array (Surface, array3d): return array2d

test/surfarray_test.py

     arraytype = pygame.surfarray.get_arraytype()
     if arraytype == 'numpy':
         from numpy import \
-             uint8, uint16, uint32, uint64, zeros, float64, alltrue
+            uint8, uint16, uint32, uint64, zeros, \
+            float32, float64, alltrue, rint, arange
     elif arraytype == 'numeric':
         from Numeric import \
              UInt8 as uint8, UInt16 as uint16, UInt32 as uint32, zeros, \
         arr.shape = (1, 1, 1, 4)
         self.failUnlessRaises(ValueError, do_blit, surf, arr)
 
-        arr = zeros((10, 10), float64)
-        surf = pygame.Surface((10, 10), 0, 32)
-        self.failUnlessRaises(ValueError, do_blit, surf, arr)
-        
+        # Issue #81: round from float to int
+        try:
+            rint
+        except NameError:
+            pass
+        else:
+            surf = pygame.Surface((10, 10), pygame.SRCALPHA, 32)
+            w, h = surf.get_size()
+            length = w * h
+            for dtype in [float32, float64]:
+                surf.fill((255, 255, 255, 0))
+                farr = arange(0, length, dtype=dtype)
+                farr.shape = w, h
+                pygame.surfarray.blit_array(surf, farr)
+                for x in range(w):
+                    for y in range(h):
+                        self.assertEqual(surf.get_at_mapped((x, y)),
+                                         int(rint(farr[x, y])))
+            
     def test_get_arraytype(self):
         if not arraytype:
             self.fail("no array package installed")
             surf = pygame.surfarray.make_surface(self._make_src_array3d(dtype))
             self._assert_surface(surf)
 
+        # Issue #81: round from float to int
+        try:
+            rint
+        except NameError:
+            pass
+        else:
+            w = 9
+            h = 11
+            length = w * h
+            for dtype in [float32, float64]:
+                farr = arange(0, length, dtype=dtype)
+                farr.shape = w, h
+                surf = pygame.surfarray.make_surface(farr)
+                for x in range(w):
+                    for y in range(h):
+                        self.assertEqual(surf.get_at_mapped((x, y)),
+                                         int(rint(farr[x, y])))
+            
     def test_map_array(self):
         if not arraytype:
             self.fail("no array package installed")
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.