Lenard Lindstrom avatar Lenard Lindstrom committed bb0a859

new _arraysurfarray module. blit_array bug 24 fix.
blit_array now sets alpha to 255 for 3D array blit onto a SRCALPHA surface.
_arraysurfarray is the foundation for adding new C surfarray C functions.
It uses the array interface so works with the Numeric 24.2 as well.
It has no NumPy specific code, doesn't include NumPy or Numeric headers.

Comments (0)

Files changed (8)

 mask src/mask.c src/bitmask.c $(SDL) $(DEBUG)
 bufferproxy src/bufferproxy.c $(SDL) $(DEBUG)
 pixelarray src/pixelarray.c $(SDL) $(DEBUG)
+_arraysurfarray src/_arraysurfarray.c $(SDL) $(DEBUG)
 

docs/ref/surfarray.html

 <big><b>pygame.surfarray.blit_array</big></b><br><ul>
   <i>Blit directly from a array values</i><br>
   <tt>pygame.surfarray.blit_array(Surface, array): return None</tt><br>
-<p>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. </p>
+<p>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. </p>
 <p>This function will temporarily lock the Surface as the new values are copied. </p>
 <!--COMMENTS:pygame.surfarray.blit_array--> &nbsp;<br> 
 <br></ul>

examples/arraydemo.py

                 raise SystemExit
 
     #allblack
-    allblack = N.zeros((128, 128))
+    allblack = N.zeros((128, 128), int32)
     surfdemo_show(allblack, 'allblack')
 
 

lib/surfarray.doc

 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.
+values. Only integer, ascii character and record arrays are accepted.
 
 This function will temporarily lock the Surface as the new values are
 copied.
 if not __hasnumpy and not __hasnumeric:
     raise ImportError, "no module named numpy or Numeric found"
 
+from _arraysurfarray import blit_array
+
 def array2d (surface):
     """pygame.surfarray.array2d (Surface): return array
 
         return numpysf.make_surface (array)
     raise NotImplementedError, "surface arrays are not supported"
 
-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.
-
-    This function will temporarily lock the Surface as the new values
-    are copied.
-    """
-    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 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.
+##
+##    This function will temporarily lock the Surface as the new values
+##    are copied.
+##    """
+##    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 map_array (surface, array):
     """pygame.surfarray.map_array (Surface, array3d): return array2d

src/_arraysurfarray.c

+/*
+  pygame - Python Game Library
+  Copyright (C) 2000-2001  Pete Shinners
+
+  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
+
+  Pete Shinners
+  pete@shinners.org
+*/
+
+#include <stddef.h>
+#include "pygame.h"
+#include "pygamedocs.h"
+#include "pgarrinter.h"
+#include <SDL_byteorder.h>
+
+static int
+_get_array_interface(PyObject *obj,
+		     PyObject **cobj_p,
+		     PyArrayInterface **inter_p)
+{
+    if (!(*cobj_p = PyObject_GetAttrString(obj, "__array_struct__"))) {
+	if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+		PyErr_Clear();
+		PyErr_SetString(PyExc_ValueError,
+				"no C-struct array interface");
+	    }
+	return 0;
+    }
+
+    if (!PyCObject_Check(*cobj_p) ||  /* conditional 'or's */
+	!(*inter_p = PyCObject_AsVoidPtr(*cobj_p)) ||
+	(*inter_p)->two != 2) {
+	Py_DECREF(*cobj_p);
+	PyErr_SetString(PyExc_ValueError, "invalid array interface");
+	return 0;
+    }
+    return 1;
+}
+
+/*macros used to blit arrays*/
+#define COPYMACRO_2D(DST, SRC)                                           \
+    for (loopy = 0; loopy < sizey; ++loopy)                              \
+    {                                                                    \
+        DST* imgrow = (DST*)(((char*)surf->pixels)+loopy*surf->pitch);   \
+        Uint8* datarow = (Uint8*)array_data + stridey * loopy;           \
+        for (loopx = 0; loopx < sizex; ++loopx)                          \
+            *(imgrow + loopx) = (DST)*(SRC*)(datarow + stridex * loopx); \
+    }
+
+#if SDL_BYTEORDER == SDL_LIL_ENDIAN
+#define COPYMACRO_2D_24_PIXEL(pix, data, SRC)    			\
+    *pix++ = *data;					                \
+    *pix++ = *(data + 1);					        \
+    *pix++ = *(data + 2);
+#else
+#define COPYMACRO_2D_24_PIXEL(pix, data, SRC)    			\
+    *pix++ = *(data + sizeof (SRC) - 1);				\
+    *pix++ = *(data + sizeof (SRC) - 2);				\
+    *pix++ = *(data + sizeof (SRC) - 3);
+#endif
+
+#define COPYMACRO_2D_24(SRC)                                            \
+    for (loopy = 0; loopy < sizey; ++loopy)                             \
+    {                                                                   \
+        Uint8 *pix = ((Uint8 *)surf->pixels) + loopy * surf->pitch;     \
+        Uint8 *data = (Uint8 *)array_data + stridey * loopy;            \
+        Uint8 *end = pix + 3 * sizex;                                   \
+        while (pix != end) {                                            \
+            COPYMACRO_2D_24_PIXEL(pix, data, SRC)			\
+            data += stridex;                                            \
+        }                                                               \
+    }
+
+#define COPYMACRO_3D(DST, SRC)                                          \
+    for (loopy = 0; loopy < sizey; ++loopy)                             \
+    {                                                                   \
+        DST* pix = (DST*)(((char*)surf->pixels) + surf->pitch * loopy); \
+        char* data = array_data + stridey * loopy;                      \
+        for (loopx = 0; loopx < sizex; ++loopx) {                       \
+            *pix++ = (DST)(*(SRC*)(data) >> Rloss << Rshift) |          \
+                (*(SRC*)(data+stridez) >> Gloss << Gshift) |            \
+                (*(SRC*)(data+stridez2) >> Bloss << Bshift) |           \
+                alpha;                                                  \
+            data += stridex;                                            \
+        }                                                               \
+    }
+
+#define COPYMACRO_3D_24(SRC)                                            \
+    for (loopy = 0; loopy < sizey; ++loopy)                             \
+    {                                                                   \
+        Uint8 *pix = ((Uint8*)surf->pixels) + surf->pitch * loopy;      \
+        Uint8 *data = (Uint8*)array_data + stridey * loopy;             \
+	Uint8 *end = pix + 3 * sizex;                                   \
+        while (pix != end) {                                            \
+            *pix++ = (Uint8)*(SRC*)(data + stridez_0);                  \
+            *pix++ = (Uint8)*(SRC*)(data + stridez_1);                  \
+            *pix++ = (Uint8)*(SRC*)(data + stridez_2);                  \
+            data += stridex;                                            \
+        }                                                               \
+    }
+
+static PyObject*
+blit_array(PyObject* self, PyObject* arg)
+{
+    PyObject *surfobj, *arrayobj;
+    PyObject *cobj;
+    PyArrayInterface *inter;
+    void *array_data;
+    SDL_Surface* surf;
+    SDL_PixelFormat* format;
+    int loopx, loopy;
+    int stridex, stridey, stridez=0, stridez2=0, sizex, sizey;
+    int Rloss, Gloss, Bloss, Rshift, Gshift, Bshift;
+    char typekind, *cptr;
+    const char *validtypekinds = "iuSV";
+    
+    if (!PyArg_ParseTuple(arg, "O!O", &PySurface_Type, &surfobj, &arrayobj)) {
+        return NULL;
+    }
+    surf = PySurface_AsSurface(surfobj);
+    format = surf->format;
+    
+    if (!_get_array_interface(arrayobj, &cobj, &inter)) {
+        return 0;
+    }
+
+    typekind = inter->typekind;
+    for (cptr = validtypekinds; *cptr && *cptr != typekind; ++cptr) {
+	;
+    }
+    if (!*cptr) {
+	Py_DECREF(cobj);
+	PyErr_Format(PyExc_ValueError, "unsupported array type '%c'",
+		     typekind);
+	return NULL;
+    }
+
+    if (!(inter->nd == 2 || (inter->nd == 3 && inter->shape[2] == 3)))
+        return RAISE(PyExc_ValueError, "must be a valid 2d or 3d array\n");
+
+    if (surf->format->BytesPerPixel <= 0 || surf->format->BytesPerPixel > 4)
+        return RAISE(PyExc_ValueError, "unsupport bit depth for surface");
+
+    stridex = inter->strides[0];
+    stridey = inter->strides[1];
+    if (inter->nd == 3) {
+        stridez = inter->strides[2];
+        stridez2 = stridez*2;
+    }
+    sizex = inter->shape[0];
+    sizey = inter->shape[1];
+    Rloss = format->Rloss; Gloss = format->Gloss; Bloss = format->Bloss;
+    Rshift = format->Rshift; Gshift = format->Gshift; Bshift = format->Bshift;
+
+    if (sizex != surf->w || sizey != surf->h) {
+        Py_DECREF(cobj);
+        return RAISE(PyExc_ValueError, "array must match surface dimensions");
+    }
+    if (!PySurface_LockBy(surfobj, (PyObject *) arrayobj)) {
+        Py_DECREF(cobj);
+        return NULL;
+    }
+    
+    array_data = inter->data;
+
+    switch (surf->format->BytesPerPixel) {
+    case 1:
+        if (inter->nd == 2) {
+            switch (inter->itemsize) {
+            case sizeof (Uint8):
+                COPYMACRO_2D(Uint8, Uint8);
+                break;
+            case sizeof (Uint16):
+                COPYMACRO_2D(Uint8, Uint16);
+                break;
+            case sizeof (Uint32):
+                COPYMACRO_2D(Uint8, Uint32);
+                break;
+            case sizeof (Uint64):
+                COPYMACRO_2D(Uint8, Uint64);
+                break;
+            default:
+                Py_DECREF(cobj);
+                if (!PySurface_UnlockBy(surfobj, (PyObject *) arrayobj)) {
+                    return NULL;
+                }
+                return RAISE(PyExc_ValueError,
+                             "unsupported datatype for array\n");
+            }
+        }
+        else {
+            Py_DECREF(cobj);
+            if (!PySurface_UnlockBy(surfobj, (PyObject *) arrayobj)) {
+                return NULL;
+            }
+            return RAISE(PyExc_ValueError,
+                         "unsupported datatype for array\n");
+        }
+        break;
+    case 2:
+        if (inter->nd == 2) {
+            switch (inter->itemsize) {
+            case sizeof (Uint16):
+                COPYMACRO_2D(Uint16, Uint16);
+                break;
+            case sizeof (Uint32):
+                COPYMACRO_2D(Uint16, Uint32);
+                break;
+            case sizeof (Uint64):
+                COPYMACRO_2D(Uint16, Uint64);
+                break;
+            default:
+                Py_DECREF(cobj);
+                if (!PySurface_UnlockBy(surfobj, (PyObject *) arrayobj)) {
+                    return NULL;
+                }
+                return RAISE(PyExc_ValueError,
+                             "unsupported datatype for array\n");
+            }
+        }
+        else {
+	    Uint16 alpha = 0;
+	    if (format->Amask) {
+		alpha = 255 >> format->Aloss << format->Ashift;
+	    }
+            switch (inter->itemsize) {
+            case sizeof (Uint8):
+                COPYMACRO_3D(Uint16, Uint8);
+                break;
+            case sizeof (Uint16):
+                COPYMACRO_3D(Uint16, Uint16);
+                break;
+            case sizeof (Uint32):
+                COPYMACRO_3D(Uint16, Uint32);
+                break;
+            case sizeof (Uint64):
+                COPYMACRO_3D(Uint16, Uint64);
+                break;
+            default:
+                Py_DECREF(cobj);
+                if (!PySurface_UnlockBy(surfobj, (PyObject *) arrayobj)) {
+                    return NULL;
+                }
+                return RAISE(PyExc_ValueError,
+                             "unsupported datatype for array\n");
+            }
+        }
+        break;
+    case 3:
+        /* Assumption: The rgb components of a 24 bit pixel are in
+           separate bytes.
+	*/
+        if (inter->nd == 2) {
+            switch (inter->itemsize) {
+            case sizeof (Uint32):
+                COPYMACRO_2D_24(Uint32);
+                break;
+            case sizeof (Uint64):
+                COPYMACRO_2D_24(Uint64);
+                break;
+            default:
+                Py_DECREF(cobj);
+                if (!PySurface_UnlockBy(surfobj, (PyObject *) arrayobj)) {
+                    return NULL;
+                }
+                return RAISE(PyExc_ValueError,
+                             "unsupported datatype for array\n");
+            }
+        }
+        else {
+#if SDL_BYTEORDER == SDL_LIL_ENDIAN
+	    size_t stridez_0 = (format->Rmask & 0x0000ff ? 0        : 
+			        format->Gmask & 0x0000ff ? stridez  :
+                                                           stridez2   );
+	    size_t stridez_1 = (format->Rmask & 0x00ff00 ? 0        :
+			        format->Gmask & 0x00ff00 ? stridez  :
+                                                           stridez2   );
+	    size_t stridez_2 = (format->Rmask & 0xff0000 ? 0        :
+			        format->Gmask & 0xff0000 ? stridez  :
+                                                           stridez2   );
+#else
+	    size_t stridez_2 = (format->Rmask & 0x0000ff ? 0        : 
+			        format->Gmask & 0x0000ff ? stridez  :
+                                                           stridez2   );
+	    size_t stridez_1 = (format->Rmask & 0x00ff00 ? 0        :
+			        format->Gmask & 0x00ff00 ? stridez  :
+                                                           stridez2   );
+	    size_t stridez_0 = (format->Rmask & 0xff0000 ? 0        :
+			        format->Gmask & 0xff0000 ? stridez  :
+                                                           stridez2   );
+#endif
+            switch (inter->itemsize) {
+            case sizeof (Uint8):
+                COPYMACRO_3D_24(Uint8);
+                break;
+            case sizeof (Uint16):
+                COPYMACRO_3D_24(Uint16);
+                break;
+            case sizeof (Uint32):
+                COPYMACRO_3D_24(Uint32);
+                break;
+            case sizeof (Uint64):
+                COPYMACRO_3D_24(Uint64);
+                break;
+            default:
+                Py_DECREF(cobj);
+                if (!PySurface_UnlockBy(surfobj, (PyObject *) arrayobj)) {
+                    return NULL;
+                }
+                return RAISE(PyExc_ValueError,
+                             "unsupported datatype for array\n");
+            }
+        }
+        break;
+    case 4:
+        if (inter->nd == 2) {
+            switch (inter->itemsize) {
+            case sizeof (Uint32):
+                COPYMACRO_2D(Uint32, Uint32);
+                break;
+            case sizeof (Uint64):
+                COPYMACRO_2D(Uint32, Uint64);
+                break;
+            default:
+                Py_DECREF(cobj);
+                if (!PySurface_UnlockBy(surfobj, (PyObject *) arrayobj)) {
+                    return NULL;
+                }
+                return RAISE(PyExc_ValueError,
+                            "unsupported datatype for array\n");
+            }
+        }
+        else {
+	    Uint32 alpha = 0;
+	    if (format->Amask) {
+		alpha = 255 >> format->Aloss << format->Ashift;
+	    }
+            switch (inter->itemsize) {
+            case sizeof (Uint8):
+                COPYMACRO_3D(Uint32, Uint8);
+                break;
+            case sizeof (Uint16):
+                COPYMACRO_3D(Uint32, Uint16);
+                break;
+            case sizeof (Uint32):
+                COPYMACRO_3D(Uint32, Uint32);
+                break;
+            case sizeof (Uint64):
+                COPYMACRO_3D(Uint32, Uint64);
+                break;
+            default:
+                Py_DECREF(cobj);
+                if (!PySurface_UnlockBy(surfobj, (PyObject *) arrayobj)) {
+                    return NULL;
+                }
+                return RAISE(PyExc_ValueError,
+                             "unsupported datatype for array\n");
+            }
+        }
+        break;
+    default:
+        Py_DECREF(cobj);
+        if (!PySurface_UnlockBy(surfobj, (PyObject *) arrayobj)) {
+            return NULL;
+        }
+        return RAISE(PyExc_RuntimeError, "unsupported bit depth for image");
+    }
+    
+    Py_DECREF(cobj);
+    if (!PySurface_UnlockBy(surfobj, (PyObject *) arrayobj)) {
+        return NULL;
+    }
+    Py_RETURN_NONE;
+}
+
+static PyMethodDef surfarray_builtins[] =
+{
+    { "blit_array", blit_array, METH_VARARGS, DOC_PYGAMESURFARRAYBLITARRAY },
+    { NULL, NULL, 0, NULL}
+};
+
+PYGAME_EXPORT
+void init_arraysurfarray(void)
+{
+    PyObject *module;
+    
+    module = Py_InitModule3("_arraysurfarray", surfarray_builtins,
+                            DOC_PYGAMESURFARRAY);
+    import_pygame_base();
+    import_pygame_surface();
+}
+/* array structure interface version 3 declarations */
+
+const int PAI_CONTIGUOUS = 0x01;
+const int PAI_FORTRAN = 0x02;
+const int PAI_ALIGNED = 0x100;
+const int PAI_NOTSWAPPED = 0x200;
+const int PAI_WRITEABLE = 0x400;
+
+typedef struct {
+    int two;              /* contains the integer 2 -- simple sanity check */
+    int nd;               /* number of dimensions */
+    char typekind;        /* kind in array -- character code of typestr */
+    int itemsize;         /* size of each element */
+    int flags;            /* flags indicating how the data should be */
+                          /* interpreted */
+    Py_intptr_t *shape;   /* A length-nd array of shape information */
+    Py_intptr_t *strides; /* A length-nd array of stride information */
+    void *data;           /* A pointer to the first element of the array */
+    PyObject *descr;      /* NULL or a data-description */
+} PyArrayInterface;

test/surfarray_test.py

 else:
     from test.test_utils import test_not_implemented, unittest
 import pygame
+from pygame.locals import *
+
+# Needed for 8 bits-per-pixel color palette surface tests
+pygame.init()
+if pygame.surfarray.get_arraytype() == 'numpy':
+    from numpy import \
+         uint8, uint16, uint32, uint64, zeros, float64
+else:
+    from Numeric import \
+         UInt8 as uint8, UInt16 as uint16, UInt32 as uint32, zeros, \
+         Float64 as float64
 
 class SurfarrayModuleTest (unittest.TestCase):
+
     def test_import(self):
         'does it import'
         import pygame.surfarray
 
+    pixels2d = {8: True, 16: True, 24: False, 32: True}
+    pixels3d = {8: False, 16: False, 24: True, 32: True}
+    array2d = {8: True, 16: True, 24: True, 32: True}
+    array3d = {8: False, 16: False, 24: True, 32: True}
+
+    test_palette = [(0, 0, 0, 255),
+                    (10, 30, 60, 255),
+                    (25, 75, 100, 255),
+                    (100, 150, 200, 255),
+                    (0, 100, 200, 255)]
+    surf_size = (10, 12)
+    test_points = [((0, 0), 1), ((4, 5), 1), ((9, 0), 2),
+                   ((5, 5), 2), ((0, 11), 3), ((4, 6), 3),
+                   ((9, 11), 4), ((5, 6), 4)]
+
+    def _make_surface(self, bitsize, srcalpha=False):
+        flags = 0
+        if srcalpha:
+            flags |= SRCALPHA
+        surf = pygame.Surface(self.surf_size, flags, bitsize)
+        if bitsize == 8:
+            surf.set_palette([c[:3] for c in self.test_palette])
+        return surf
+
+    def _fill_surface(self, surf):
+        surf.fill(self.test_palette[1], (0, 0, 5, 6))
+        surf.fill(self.test_palette[2], (5, 0, 5, 6))
+        surf.fill(self.test_palette[3], (0, 6, 5, 6))
+        surf.fill(self.test_palette[4], (5, 6, 5, 6))
+
+    def _make_src_surface(self, bitsize, srcalpha=False):
+        surf = self._make_surface(bitsize, srcalpha)
+        self._fill_surface(surf)
+        return surf
+
+    def _assert_surface(self, surf, palette=None, msg=""):
+        if palette is None:
+            palette = self.test_palette
+        if surf.get_bitsize() == 16:
+            palette = [surf.unmap_rgb(surf.map_rgb(c)) for c in palette]
+        for posn, i in self.test_points:
+            self.failUnlessEqual(surf.get_at(posn), palette[i],
+                                 "%s != %s: flags: %i, bpp: %i, posn: %s%s" %
+                                 (surf.get_at(posn),
+                                  palette[i], surf.get_flags(),
+                                  surf.get_bitsize(), posn, msg))
+
+    def _make_array3d(self, dtype):
+        return zeros((self.surf_size[0], self.surf_size[1], 3), dtype)
+
+    def _fill_array3d(self, arr):
+        palette = self.test_palette
+        arr[:5,:6] = palette[1][:3]
+        arr[5:,:6] = palette[2][:3]
+        arr[:5,6:] = palette[3][:3]
+        arr[5:,6:] = palette[4][:3]
+
+    def _make_src_array3d(self, dtype):
+        arr = self._make_array3d(dtype)
+        self._fill_array3d(arr)
+        return arr
+
+    def _make_array2d(self, dtype):
+        return zeros(self.surf_size, dtype)
+
     def todo_test_array2d(self):
 
         # __doc__ (as of 2008-08-02) for pygame.surfarray.array2d:
 
         self.fail() 
 
-    def todo_test_blit_array(self):
+    def test_blit_array(self):
+        # bug 24 at http://pygame.motherhamster.org/bugzilla/
+        if 'numpy' in pygame.surfarray.get_arraytypes():
+            prev = pygame.surfarray.get_arraytype()
+            # This would raise exception:
+            #  File "[...]\pygame\_numpysurfarray.py", line 381, in blit_array
+            #    (array[:,:,1::3] >> losses[1] << shifts[1]) | \
+            # TypeError: unsupported operand type(s) for >>: 'float' and 'int'
+            pygame.surfarray.use_arraytype('numpy')
+            s = pygame.Surface((10,10), 0, 24)
+            a = pygame.surfarray.array3d(s)
+            pygame.surfarray.blit_array(s, a)
+            prev = pygame.surfarray.use_arraytype(prev)
 
-        # __doc__ (as of 2008-08-02) for pygame.surfarray.blit_array:
+        # target surfaces
+        targets = [self._make_surface(8),
+                   self._make_surface(16),
+                   self._make_surface(16, srcalpha=True),
+                   self._make_surface(24),
+                   self._make_surface(32),
+                   self._make_surface(32, srcalpha=True),
+                   ]
+        
+        # source arrays
+        arrays3d = []
+        dtypes = [(8, uint8), (16, uint16), (32, uint32)]
+        try:
+            dtypes.append((64, uint64))
+        except NameError:
+            pass
+        arrays3d = [(self._make_src_array3d(dtype), None)
+                    for __, dtype in dtypes]
+        for bitsize in [8, 16, 24, 32]:
+            palette = None
+            if bitsize == 16:
+                s = pygame.Surface((1,1), 0, 16)
+                palette = [s.unmap_rgb(s.map_rgb(c))
+                           for c in self.test_palette]
+            if self.pixels3d[bitsize]:
+                surf = self._make_src_surface(bitsize)
+                arr = pygame.surfarray.pixels3d(surf)
+                arrays3d.append((arr, palette))
+            if self.array3d[bitsize]:
+                surf = self._make_src_surface(bitsize)
+                arr = pygame.surfarray.array3d(surf)
+                arrays3d.append((arr, palette))
+                for sz, dtype in dtypes:
+                    arrays3d.append((arr.astype(dtype), palette))
 
-          # 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.
-          # 
-          # This function will temporarily lock the Surface as the new values
-          # are copied.
-          # 
-          # 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. 
+        # tests on arrays
+        def do_blit(surf, arr):
+            pygame.surfarray.blit_array(surf, arr)
 
-        self.fail() 
+        for surf in targets:
+            bitsize = surf.get_bitsize()
+            for arr, palette in arrays3d:
+                surf.fill((0, 0, 0, 0))
+                if bitsize == 8:
+                    self.failUnlessRaises(ValueError, do_blit, surf, arr)
+                else:
+                    pygame.surfarray.blit_array(surf, arr)
+                    self._assert_surface(surf, palette)
 
+            if self.pixels2d[bitsize]:
+                surf.fill((0, 0, 0, 0))
+                s = self._make_src_surface(bitsize, surf.get_flags())
+                arr = pygame.surfarray.pixels2d(s)
+                pygame.surfarray.blit_array(surf, arr)
+                self._assert_surface(surf)
+
+            if self.array2d[bitsize]:
+                s = self._make_src_surface(bitsize, surf.get_flags())
+                arr = pygame.surfarray.array2d(s)
+                for sz, dtype in dtypes:
+                    surf.fill((0, 0, 0, 0))
+                    if sz >= bitsize:
+                        pygame.surfarray.blit_array(surf, arr.astype(dtype))
+                        self._assert_surface(surf)
+                    else:
+                        self.failUnlessRaises(ValueError, do_blit,
+                                              surf, self._make_array2d(dtype))
+
+        # Check alpha for 2D arrays
+        surf = self._make_surface(16, srcalpha=True)
+        arr = zeros(surf.get_size(), uint16)
+        arr[...] = surf.map_rgb((0, 128, 255, 64))
+        color = surf.unmap_rgb(arr[0, 0])
+        pygame.surfarray.blit_array(surf, arr)
+        self.failUnlessEqual(surf.get_at((5, 5)), color)
+
+        surf = self._make_surface(32, srcalpha=True)
+        arr = zeros(surf.get_size(), uint32)
+        color = (0, 111, 255, 63)
+        arr[...] = surf.map_rgb(color)
+        pygame.surfarray.blit_array(surf, arr)
+        self.failUnlessEqual(surf.get_at((5, 5)), color)
+        
+        # Invalid arrays
+        surf = pygame.Surface((1,1), 0, 32)
+        t = 'abcd'
+        self.failUnlessRaises(ValueError, do_blit, surf, t)
+
+        surf_size = self.surf_size
+        surf = pygame.Surface(surf_size, 0, 32)
+        arr = zeros([surf_size[0], surf_size[1] + 1, 3], uint32)
+        self.failUnlessRaises(ValueError, do_blit, surf, arr)
+        arr = zeros([surf_size[0] + 1, surf_size[1], 3], uint32)
+        self.failUnlessRaises(ValueError, do_blit, surf, arr)
+
+        surf = pygame.Surface((1, 4), 0, 32)
+        arr = zeros((4,), uint32)
+        self.failUnlessRaises(ValueError, do_blit, surf, arr)
+        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)
+        
     def todo_test_get_arraytype(self):
 
         # __doc__ (as of 2008-08-02) for pygame.surfarray.get_arraytype:
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.