1. pygame
  2. pygame
  3. pygame

Commits

Lenard Lindstrom  committed d16c01f

Update pygame.pixelcopy functions to understand the new buffer protocol

Replace GetArrayInterface calls with PgObject_GetBuffer calls. This also adds
Python level array interface support.

  • Participants
  • Parent commits 1a514ee
  • Branches default

Comments (0)

Files changed (2)

File src/pixelcopy.c

View file
  • Ignore whitespace
 } _pc_pixel_t;
 
 static int
+_validate_view_format(const char *format)
+{
+    int i = 0;
+
+    switch (format[i]) {
+
+    case '@':
+    case '=':
+    case '<':
+    case '>':
+    case '!':
+        ++i;
+        break;
+    case '1':
+    case '2':
+    case '3':
+    case '4':
+    case '5':
+    case '6':
+    case '7':
+    case '8':
+    case '9':
+        if (format[i + 1] == 'x') {
+            ++i;
+        }
+        break;
+    default:
+        /* Unrecognized */
+        break;
+    }
+    switch (format[i]) {
+
+    case 'x':
+    case 'b':
+    case 'B':
+    case 'h':
+    case 'H':
+    case 'i':
+    case 'I':
+    case 'l':
+    case 'L':
+    case 'q':
+    case 'Q':
+        ++i;
+        break;
+    default:
+        /* Unrecognized */
+        break;
+    }
+    if (format[i] != '\0') {
+        PyErr_SetString(PyExc_ValueError, "Unsupport array item type");
+        return -1;
+    }
+
+    return 0;
+}
+
+static int
+_is_swapped(Py_buffer *view_p)
+{
+    char ch = view_p->format[0];
+
+#if SDL_BYTEORDER == SDL_LIL_ENDIAN
+    if (ch == '>' || ch == '!') {
+        return 1;
+    }
+#else
+    if (ch == '<') {
+        return 1;
+    }
+#endif
+    return 0;
+}
+
+static int
 _view_kind(PyObject *obj, void *view_kind_vptr)
 {
     unsigned long ch;
 }
 
 static int
-_copy_mapped(PyArrayInterface *inter, SDL_Surface *surf)
+_copy_mapped(Py_buffer *view_p, SDL_Surface *surf)
 {
     int pixelsize = surf->format->BytesPerPixel;
-    int intsize = inter->itemsize;
+    int intsize = view_p->itemsize;
     char *src = (char *)surf->pixels;
-    char *dst = (char *)inter->data;
+    char *dst = (char *)view_p->buf;
     int w = surf->w;
     int h = surf->h;
     Py_intptr_t dx_src = surf->format->BytesPerPixel;
     Py_intptr_t dy_src = surf->pitch;
     Py_intptr_t dz_src = 1;
-    Py_intptr_t dx_dst = inter->strides[0];
-    Py_intptr_t dy_dst = inter->strides[1];
+    Py_intptr_t dx_dst = view_p->strides[0];
+    Py_intptr_t dy_dst = view_p->strides[1];
     Py_intptr_t dz_dst = 1;
     Py_intptr_t x, y, z;
 
-    if (inter->shape[0] != w || inter->shape[1] != h) {
+    if (view_p->shape[0] != w || view_p->shape[1] != h) {
         PyErr_Format(PyExc_ValueError,
                      "Expected a (%d, %d) target: got (%d, %d)",
-                     w, h, (int)inter->shape[0], (int)inter->shape[1]);
+                     w, h, (int)view_p->shape[0], (int)view_p->shape[1]);
         return -1;
     }
     if (intsize < pixelsize) {
         return -1;
     }
 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
-    if (!(inter->flags & PAI_NOTSWAPPED)) {
+    if (_is_swapped(view_p)) {
         dst += intsize - 1;
         dz_dst = -1;
     }
 #else
-    if (inter->flags & PAI_NOTSWAPPED) {
+    if (!_is_swapped(view_p) {
         dst += intsize - 1;
         dz_dst = -1;
     }
 }
 
 static int
-_copy_colorplane(PyArrayInterface *inter,
+_copy_colorplane(Py_buffer *view_p,
                  SDL_Surface *surf,
                  _pc_view_kind_t view_kind,
                  Uint8 opaque,
     SDL_PixelFormat *format = surf->format;
     int pixelsize = surf->format->BytesPerPixel;
     Uint32 flags = surf->flags;
-    int intsize = inter->itemsize;
+    int intsize = (int)view_p->itemsize;
     char *src = (char *)surf->pixels;
-    char *dst = (char *)inter->data;
+    char *dst = (char *)view_p->buf;
     int w = surf->w;
     int h = surf->h;
     Py_intptr_t dx_src = surf->format->BytesPerPixel;
     Py_intptr_t dy_src = surf->pitch;
-    Py_intptr_t dx_dst = inter->strides[0];
-    Py_intptr_t dy_dst = inter->strides[1];
+    Py_intptr_t dx_dst = view_p->strides[0];
+    Py_intptr_t dy_dst = view_p->strides[1];
     Py_intptr_t dz_dst = 1;
     Py_intptr_t dz_pix;
     Py_intptr_t x, y, z;
     Uint8 r, g, b, a;
-    Uint8 *element;
+    Uint8 *element = 0;
     _pc_pixel_t pixel = { 0 };
     Uint32 colorkey;
 
-    if (inter->shape[0] != w || inter->shape[1] != h) {
+    if (view_p->shape[0] != w || view_p->shape[1] != h) {
         PyErr_Format(PyExc_ValueError,
                      "Expected a (%d, %d) target: got (%d, %d)",
-                     w, h, (int)inter->shape[0], (int)inter->shape[1]);
+                     w, h, (int)view_p->shape[0], (int)view_p->shape[1]);
         return -1;
     }
     if (intsize < 1) {
     }
 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
     dz_pix = 0;
-    if (!(inter->flags & PAI_NOTSWAPPED)) {
+    if (_is_swapped(view_p)) {
         dst += intsize - 1;
         dz_dst = -1;
     }
 #else
     dz_pix = (unsigned)(sizeof(Uint32) - pixelsize - 1);
-    if (inter->flags & PAI_NOTSWAPPED) {
+    if (!_is_swapped(view_p)) {
         dst += intsize - 1;
         dz_dst = -1;
     }
 }
 
 static int
-_copy_unmapped(PyArrayInterface *inter, SDL_Surface *surf)
+_copy_unmapped(Py_buffer *view_p, SDL_Surface *surf)
 {
     SDL_PixelFormat *format = surf->format;
     int pixelsize = surf->format->BytesPerPixel;
-    int intsize = inter->itemsize;
+    int intsize = (int)view_p->itemsize;
     char *src = (char *)surf->pixels;
-    char *dst = (char *)inter->data;
+    char *dst = (char *)view_p->buf;
     int w = surf->w;
     int h = surf->h;
     Py_intptr_t dx_src = surf->format->BytesPerPixel;
     Py_intptr_t dy_src = surf->pitch;
-    Py_intptr_t dx_dst = inter->strides[0];
-    Py_intptr_t dy_dst = inter->strides[1];
-    Py_intptr_t dp_dst = inter->strides[2];
+    Py_intptr_t dx_dst = view_p->strides[0];
+    Py_intptr_t dy_dst = view_p->strides[1];
+    Py_intptr_t dp_dst = view_p->strides[2];
     Py_intptr_t dz_dst = 1;
     Py_intptr_t dz_pix;
     Py_intptr_t x, y, z;
     _pc_pixel_t pixel = { 0 };
     Uint8 r, g, b;
 
-    if (inter->shape[0] != w ||
-        inter->shape[1] != h ||
-        inter->shape[2] != 3    ) {
+    if (view_p->shape[0] != w ||
+        view_p->shape[1] != h ||
+        view_p->shape[2] != 3    ) {
         PyErr_Format(PyExc_ValueError,
                      "Expected a (%d, %d, 3) target: got (%d, %d, %d)",
                      w, h,
-                     (int)inter->shape[0],
-                     (int)inter->shape[1],
-                     (int)inter->shape[2]);
+                     (int)view_p->shape[0],
+                     (int)view_p->shape[1],
+                     (int)view_p->shape[2]);
         return -1;
     }
     if (intsize < 1) {
     }
 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
     dz_pix = 0;
-    if (!(inter->flags & PAI_NOTSWAPPED)) {
+    if (_is_swapped(view_p)) {
         dst += intsize - 1;
         dz_dst = -1;
     }
 #else
     dz_pix = (unsigned)(sizeof(Uint32) - pixelsize - 1);
-    if (inter->flags & PAI_NOTSWAPPED) {
+    if (!_is_swapped(view_p)) {
         dst += intsize - 1;
         dz_dst = -1;
     }
 array_to_surface(PyObject *self, PyObject *arg)
 {
     PyObject *surfobj, *arrayobj;
-    PyObject *cobj;
-    PyArrayInterface *inter;
+    Pg_buffer pg_view;
+    Py_buffer *view_p = (Py_buffer *)&pg_view;
     char *array_data;
     SDL_Surface* surf;
     SDL_PixelFormat* format;
     surf = PySurface_AsSurface(surfobj);
     format = surf->format;
     
-    if (GetArrayInterface(arrayobj, &cobj, &inter)) {
+    if (PgObject_GetBuffer(arrayobj, &pg_view, PyBUF_RECORDS_RO)) {
         return 0;
     }
 
-    switch (inter->typekind) {
-    case 'i':  /* integer */
-        break;
-    case 'u':  /* unsigned integer */ 
-        break;
-    case 'S':  /* fixed length character field */
-        break;
-    case 'V':  /* structured element: record */
-        break;
-    default:
-        Py_DECREF(cobj);
-        PyErr_Format(PyExc_ValueError, "unsupported array type '%c'",
-                     inter->typekind);
-        return NULL;
+    if (_validate_view_format(view_p->format)) {
+        return 0;
     }
 
-    if (!(inter->nd == 2 || (inter->nd == 3 && inter->shape[2] == 3)))
+    if (!(view_p->ndim == 2 || (view_p->ndim == 3 && view_p->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];
+    stridex = view_p->strides[0];
+    stridey = view_p->strides[1];
+    if (view_p->ndim == 3) {
+        stridez = view_p->strides[2];
         stridez2 = stridez*2;
     }
-    sizex = inter->shape[0];
-    sizey = inter->shape[1];
+    sizex = view_p->shape[0];
+    sizey = view_p->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);
+        PgBuffer_Release(&pg_view);
         return RAISE(PyExc_ValueError, "array must match surface dimensions");
     }
     if (!PySurface_LockBy(surfobj, arrayobj)) {
-        Py_DECREF(cobj);
+        PgBuffer_Release(&pg_view);
         return NULL;
     }
     
-    array_data = (char *)inter->data;
+    array_data = (char *)view_p->buf;
 
     switch (surf->format->BytesPerPixel) {
     case 1:
-        if (inter->nd == 2) {
-            switch (inter->itemsize) {
+        if (view_p->ndim == 2) {
+            switch (view_p->itemsize) {
             case sizeof (Uint8):
                 COPYMACRO_2D(Uint8, Uint8);
                 break;
                 COPYMACRO_2D(Uint8, Uint64);
                 break;
             default:
-                Py_DECREF(cobj);
+                PgBuffer_Release(&pg_view);
                 if (!PySurface_UnlockBy(surfobj, arrayobj)) {
                     return NULL;
                 }
             }
         }
         else {
-            Py_DECREF(cobj);
+            PgBuffer_Release(&pg_view);
             if (!PySurface_UnlockBy(surfobj, arrayobj)) {
                 return NULL;
             }
         }
         break;
     case 2:
-        if (inter->nd == 2) {
-            switch (inter->itemsize) {
+        if (view_p->ndim == 2) {
+            switch (view_p->itemsize) {
             case sizeof (Uint16):
                 COPYMACRO_2D(Uint16, Uint16);
                 break;
                 COPYMACRO_2D(Uint16, Uint64);
                 break;
             default:
-                Py_DECREF(cobj);
+                PgBuffer_Release(&pg_view);
                 if (!PySurface_UnlockBy(surfobj, arrayobj)) {
                     return NULL;
                 }
             if (format->Amask) {
                 alpha = 255 >> format->Aloss << format->Ashift;
             }
-            switch (inter->itemsize) {
+            switch (view_p->itemsize) {
             case sizeof (Uint8):
                 COPYMACRO_3D(Uint16, Uint8);
                 break;
                 COPYMACRO_3D(Uint16, Uint64);
                 break;
             default:
-                Py_DECREF(cobj);
+                PgBuffer_Release(&pg_view);
                 if (!PySurface_UnlockBy(surfobj, arrayobj)) {
                     return NULL;
                 }
         /* Assumption: The rgb components of a 24 bit pixel are in
            separate bytes.
         */
-        if (inter->nd == 2) {
-            switch (inter->itemsize) {
+        if (view_p->ndim == 2) {
+            switch (view_p->itemsize) {
             case sizeof (Uint32):
                 COPYMACRO_2D_24(Uint32);
                 break;
                 COPYMACRO_2D_24(Uint64);
                 break;
             default:
-                Py_DECREF(cobj);
+                PgBuffer_Release(&pg_view);
                 if (!PySurface_UnlockBy(surfobj, arrayobj)) {
                     return NULL;
                 }
                                 Gshift == 16 ? stridez  :
                                                stridez2   );
 #endif
-            switch (inter->itemsize) {
+            switch (view_p->itemsize) {
             case sizeof (Uint8):
                 COPYMACRO_3D_24(Uint8);
                 break;
                 COPYMACRO_3D_24(Uint64);
                 break;
             default:
-                Py_DECREF(cobj);
+                PgBuffer_Release(&pg_view);
                 if (!PySurface_UnlockBy(surfobj, arrayobj)) {
                     return NULL;
                 }
         }
         break;
     case 4:
-        if (inter->nd == 2) {
-            switch (inter->itemsize) {
+        if (view_p->ndim == 2) {
+            switch (view_p->itemsize) {
             case sizeof (Uint32):
                 COPYMACRO_2D(Uint32, Uint32);
                 break;
                 COPYMACRO_2D(Uint32, Uint64);
                 break;
             default:
-                Py_DECREF(cobj);
+                PgBuffer_Release(&pg_view);
                 if (!PySurface_UnlockBy(surfobj, arrayobj)) {
                     return NULL;
                 }
             if (format->Amask) {
                 alpha = 255 >> format->Aloss << format->Ashift;
             }
-            switch (inter->itemsize) {
+            switch (view_p->itemsize) {
             case sizeof (Uint8):
                 COPYMACRO_3D(Uint32, Uint8);
                 break;
                 COPYMACRO_3D(Uint32, Uint64);
                 break;
             default:
-                Py_DECREF(cobj);
+                PgBuffer_Release(&pg_view);
                 if (!PySurface_UnlockBy(surfobj, arrayobj)) {
                     return NULL;
                 }
         }
         break;
     default:
-        Py_DECREF(cobj);
+        PgBuffer_Release(&pg_view);
         if (!PySurface_UnlockBy(surfobj, arrayobj)) {
             return NULL;
         }
         return RAISE(PyExc_RuntimeError, "unsupported bit depth for image");
     }
     
-    Py_DECREF(cobj);
+    PgBuffer_Release(&pg_view);
     if (!PySurface_UnlockBy(surfobj, arrayobj)) {
         return NULL;
     }
 {
     PyObject *arrayobj;
     PyObject *surfobj;
-    PyObject *cobj;
+    Pg_buffer pg_view;
+    Py_buffer *view_p = (Py_buffer *)&pg_view;
     _pc_view_kind_t view_kind = VIEWKIND_RGB;
     Uint8 opaque = 255;
     Uint8 clear = 0;
     SDL_Surface *surf;
-    PyArrayInterface *inter;
     char *keywords[] = {"array", "surface", "kind", "opaque", "clear", 0};
 
     if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO!|O&BB", keywords,
     }
     surf = PySurface_AsSurface(surfobj);
     
-    if (GetArrayInterface(arrayobj, &cobj, &inter)) {
+    if (PgObject_GetBuffer(arrayobj, &pg_view, PyBUF_RECORDS)) {
         PySurface_Unlock(surfobj);
         return 0;
     }
-    if (!(inter->flags & PAI_WRITEABLE)) {
-        PyErr_SetString(PyExc_ValueError, "target not writeable");
-        Py_DECREF(cobj);
-        PySurface_Unlock(surfobj);
-        return 0;
-    }
-    if (!(inter->typekind == 'u' || inter->typekind == 'i')) {
-        PyErr_SetString(PyExc_ValueError, "unsupported array item type");
-        Py_DECREF(cobj);
+    if (_validate_view_format(view_p->format)) {
+        PgBuffer_Release(&pg_view);
         PySurface_Unlock(surfobj);
         return 0;
     }
 
-    if (inter->nd == 2) {
+    if (view_p->ndim == 2) {
         if (view_kind == VIEWKIND_RGB) {
-            if (_copy_mapped(inter, surf)) {
-                Py_DECREF(cobj);
+            if (_copy_mapped(view_p, surf)) {
+                PgBuffer_Release(&pg_view);
                 PySurface_Unlock(surfobj);
                 return 0;
             }
         }
         else {
-            if (_copy_colorplane(inter, surf, view_kind, opaque, clear)) {
-                Py_DECREF(cobj);
+            if (_copy_colorplane(view_p, surf, view_kind, opaque, clear)) {
+                PgBuffer_Release(&pg_view);
                 PySurface_Unlock(surfobj);
                 return 0;
             }
         }
     }
-    else if (inter->nd == 3) {
+    else if (view_p->ndim == 3) {
         if (view_kind != VIEWKIND_RGB) {
             PyErr_SetString(PyExc_ValueError,
                             "color planes only supported for 2d targets");
-            Py_DECREF(cobj);
+            PgBuffer_Release(&pg_view);
             PySurface_Unlock(surfobj);
             return 0;
         }
-        if (_copy_unmapped(inter, surf)) {
-            Py_DECREF(cobj);
+        if (_copy_unmapped(view_p, surf)) {
+            PgBuffer_Release(&pg_view);
             PySurface_Unlock(surfobj);
             return 0;
         }
     }
     else {
-        Py_DECREF(cobj);
+        PgBuffer_Release(&pg_view);
         PySurface_Unlock(surfobj);
         PyErr_Format(PyExc_ValueError,
-                     "Unsupported array depth %d", (int)inter->nd);
+                     "Unsupported array depth %d", (int)view_p->ndim);
         return 0;
     }
 
-    Py_DECREF(cobj);
+    PgBuffer_Release(&pg_view);
     if (!PySurface_Unlock(surfobj)) {
         return 0;
     }
     PyObject *tar_array;
     PyObject *format_surf;
     SDL_PixelFormat *format;
-    PyObject *src_cobj = 0;
-    PyObject *tar_cobj = 0;
-    PyArrayInterface *src_inter;
+    Pg_buffer src_pg_view;
+    Py_buffer *src_view_p = 0;
     Uint8 *src;
     int src_ndim;
     Py_intptr_t src_strides[PIXELCOPY_MAX_DIM];
     const int src_red = 0;
     int src_green;
     int src_blue;
-    PyArrayInterface *tar_inter;
+    Pg_buffer tar_pg_view;
+    Py_buffer *tar_view_p = 0;
     Uint8 *tar;
     int ndim;
     Py_intptr_t *shape;
 
     /* Determine array shapes and check validity
      */
-    if (GetArrayInterface(tar_array, &tar_cobj, &tar_inter)) {
+    if (PgObject_GetBuffer(tar_array, &tar_pg_view, PyBUF_RECORDS)) {
         goto fail;
     }
-    if (!(tar_inter->flags & PAI_WRITEABLE)) {
-        PyErr_SetString(PyExc_ValueError, "target not writeable");
-        goto fail;
-    }
-    tar = (Uint8 *)tar_inter->data;
-    if (tar_inter->typekind != 'u' && tar_inter->typekind != 'i') {
+    tar_view_p = (Py_buffer *)&tar_pg_view;
+    tar = (Uint8 *)tar_view_p->buf;
+    if (_validate_view_format(tar_view_p->format)) {
         PyErr_SetString(PyExc_ValueError, "expected an integer target array");
         goto fail;
     }
-    ndim = tar_inter->nd;
-    tar_itemsize = tar_inter->itemsize;
-    shape = tar_inter->shape;
-    tar_strides = tar_inter->strides;
+    ndim = tar_view_p->ndim;
+    tar_itemsize = tar_view_p->itemsize;
+    shape = tar_view_p->shape;
+    tar_strides = tar_view_p->strides;
     if (ndim < 1) {
         PyErr_SetString(PyExc_ValueError, "target array must be at least 1D");
         goto fail;
                      (int)PIXELCOPY_MAX_DIM);
         goto fail;
     }
-    if (GetArrayInterface(src_array, &src_cobj, &src_inter)) {
+    if (PgObject_GetBuffer(src_array, &src_pg_view, PyBUF_RECORDS_RO)) {
         goto fail;
     }
-    if (src_inter->typekind != 'u' && src_inter->typekind != 'i') {
-        PyErr_SetString(PyExc_ValueError, "expected an integer source array");
+    src_view_p = (Py_buffer *)&src_pg_view;
+    if (_validate_view_format(src_view_p->format)) {
         goto fail;
     }
-    src = (Uint8 *)src_inter->data;
-    src_ndim = src_inter->nd;
+    src = (Uint8 *)src_view_p->buf;
+    src_ndim = src_view_p->ndim;
     if (src_ndim < 1) {
         PyErr_SetString(PyExc_ValueError, "source array must be at least 1D");
         goto fail;
     }
-    if (src_inter->shape[src_ndim - 1] != 3) {
+    if (src_view_p->shape[src_ndim - 1] != 3) {
         PyErr_Format(PyExc_ValueError,
                      "Expected a (..., 3) source array: got (..., %d)",
-                     src_inter->shape[src_ndim - 1]);
+                     src_view_p->shape[src_ndim - 1]);
         goto fail;
     }
     if (ndim < src_ndim - 1) {
     }
     dim_diff = ndim - src_ndim + 1;
     for (dim = dim_diff; dim != ndim; ++dim) {
-        if (src_inter->shape[dim - dim_diff] == 1) {
+        if (src_view_p->shape[dim - dim_diff] == 1) {
             src_strides[dim] = 0;
         }
-        else if (src_inter->shape[dim - dim_diff] == shape[dim]) {
-            src_strides[dim] = src_inter->strides[dim - dim_diff];
+        else if (src_view_p->shape[dim - dim_diff] == shape[dim]) {
+            src_strides[dim] = src_view_p->strides[dim - dim_diff];
         }
         else {
             PyErr_Format(PyExc_ValueError,
                         "target array itemsize is too small for pixel format");
         goto fail;
     }
-    src_green = src_inter->strides[src_ndim - 1];
+    src_green = src_view_p->strides[src_ndim - 1];
     src_blue = 2 * src_green;
     tar_byte4 = pix_bytesize;
     tar_bytes_end = tar_itemsize;
     pix_byte2 = tar_byte2;
     pix_byte3 = tar_byte3;
 
-#define NEED_BYTESWAP(inter) (!((inter)->flags & PAI_NOTSWAPPED))
+#define NEED_BYTESWAP(view_p) _is_swapped(view_p)
 #else
     pix_byte0 = 3 - tar_byte0;
     pix_byte1 = 3 - tar_byte1;
     pix_byte2 = 3 - tar_byte2;
     pix_byte3 = 3 - tar_byte3;
 
-#define NEED_BYTESWAP(inter) ((inter)->flags & PAI_NOTSWAPPED)
+#define NEED_BYTESWAP(view_p) (!_is_swapped(view_p))
 #endif
-    if (NEED_BYTESWAP(src_inter)) {
-        src += src_inter->strides[src_ndim - 1] - 1;
+    if (NEED_BYTESWAP(src_view_p)) {
+        src += src_view_p->strides[src_ndim - 1] - 1;
     }
-    if (NEED_BYTESWAP(tar_inter)) {
-        tar += tar_strides[ndim - 1] - 1;
+    if (NEED_BYTESWAP(tar_view_p)) {
+        tar += tar_view_p->strides[ndim - 1] - 1;
         tar_byte1 = -tar_byte1;
         tar_byte2 = -tar_byte2;
         tar_byte3 = -tar_byte3;
 
     /* Cleanup
      */
-    Py_DECREF(src_cobj);
-    Py_DECREF(tar_cobj);
+    PgBuffer_Release(&src_pg_view);
+    PgBuffer_Release(&tar_pg_view);
     if (!PySurface_Unlock(format_surf)) {
         return 0;
     }
     Py_RETURN_NONE;
 
   fail:
-    Py_XDECREF(src_cobj);
-    Py_XDECREF(tar_cobj);
+    if (src_view_p) {
+        PgBuffer_Release(&src_pg_view);
+    }
+    if (tar_view_p) {
+        PgBuffer_Release(&tar_pg_view);
+    }
     PySurface_Unlock(format_surf);
     return 0;
 }
 static PyObject*
 make_surface (PyObject* self, PyObject* arg)
 {
-    PyArrayInterface *inter;
-    PyObject *capsule;
+    Pg_buffer pg_view;
+    Py_buffer *view_p = (Py_buffer *)&pg_view;
     PyObject *surfobj;
     PyObject *args;
     PyObject *result;
     int sizex, sizey, bitsperpixel;
     Uint32 rmask, gmask, bmask;
 
-    if (GetArrayInterface(arg, &capsule, &inter)) {
+    if (PgObject_GetBuffer(arg, &pg_view, PyBUF_RECORDS_RO)) {
         return 0;
     }
     
-    if (!(inter->nd == 2 || (inter->nd == 3 && inter->shape[2] == 3))) {
+    if (!(view_p->ndim == 2 || (view_p->ndim == 3 && view_p->shape[2] == 3))) {
+        PgBuffer_Release(&pg_view);
         return RAISE (PyExc_ValueError, "must be a valid 2d or 3d array\n");
     }
-    switch (inter->typekind) {
-    case 'i':  /* integer */
-        break;
-    case 'u':  /* unsigned integer */ 
-        break;
-    case 'S':  /* fixed length character field */
-        break;
-    case 'V':  /* structured element: record */
-        break;
-    default:
-        Py_DECREF(capsule);
-        PyErr_Format(PyExc_ValueError, "unsupported array type '%c'",
-                     inter->typekind);
+    if (_validate_view_format(view_p->format)) {
+        PgBuffer_Release(&pg_view);
         return NULL;
     }
     
-    if (inter->nd == 2) {
+    if (view_p->ndim == 2) {
         bitsperpixel = 8;
         rmask = 0xFF >> 6 << 5;
         gmask = 0xFF >> 5 << 2;
         gmask = 0xFF << 8;
         bmask = 0xFF;
     }
-    sizex = inter->shape[0];
-    sizey = inter->shape[1];
+    sizex = view_p->shape[0];
+    sizey = view_p->shape[1];
 
     surf = SDL_CreateRGBSurface (0, sizex, sizey, bitsperpixel, rmask, gmask,
                                  bmask, 0);
     if (!surf) {
-        Py_DECREF(capsule);
+        PgBuffer_Release(&pg_view);
         return RAISE(PyExc_SDLError, SDL_GetError());
     }
     surfobj = PySurface_New(surf);
     if (!surfobj) {
-        Py_DECREF(capsule);
+        PgBuffer_Release(&pg_view);
         SDL_FreeSurface(surf);
         return 0;
     }
     
     args = Py_BuildValue("(OO)", surfobj, arg);
     if (!args) {
-        Py_DECREF(capsule);
+        PgBuffer_Release(&pg_view);
         Py_DECREF(surfobj);
         return 0;
     }
     
     result = array_to_surface(self, args);
-    Py_DECREF(capsule);
+    PgBuffer_Release(&pg_view);
     Py_DECREF(args);
 
     if (!result)

File test/pixelcopy_test.py

View file
  • Ignore whitespace
 from pygame.locals import *
 
 
-from pygame.pixelcopy import surface_to_array, map_array
+from pygame.pixelcopy import (surface_to_array, map_array, array_to_surface,
+                              make_surface)
+
+import ctypes
 
 def unsigned32(i):
     """cast signed 32 bit integer to an unsigned integer"""
     else:
         del numpy
 
+
+class PixelCopyTestWithArray(unittest.TestCase):
+    surface = pygame.Surface((3, 5), 0, 32)
+
+    class Array2D(pygame.bufferproxy.BufferProxy):
+        c_int_arr = ctypes.c_uint32 * 15
+        def __new__(cls, initializer):
+            content = cls.c_int_arr(*initializer)
+            d = {"shape": (3, 5),
+                 "typestr": '|u4',
+                 "strides": (20, 4),
+                 "data": (ctypes.addressof(content), False)}
+            MyType = PixelCopyTestWithArray.Array2D
+            obj = pygame.bufferproxy.BufferProxy.__new__(MyType, d)
+            obj.content = content
+            return obj
+        def _not_implemented(self):
+            raise AttributeError()
+        __array_interface__ = property(_not_implemented)
+        __array_struct__ = property(_not_implemented)
+        def __getitem__(self, key):
+            return self.content[5 * key[0] + key[1]]
+
+    class Array3D(pygame.bufferproxy.BufferProxy):
+        c_int_arr = ctypes.c_uint32 * 15
+        def __new__(cls, initializer):
+            content = cls.c_int_arr(*initializer)
+            if pygame.get_sdl_byteorder() == pygame.LIL_ENDIAN:
+                stride2 = 1
+                offset = 0
+            else:
+                stride2 = -1
+                offset = 2
+            d = {"shape": (3, 5, 3),
+                 "typestr": '|u1',
+                 "strides": (20, 4, stride2),
+                 "data": (ctypes.addressof(content) + offset, False)}
+            MyType = PixelCopyTestWithArray.Array3D
+            obj = pygame.bufferproxy.BufferProxy.__new__(MyType, d)
+            obj.int_content = content
+            obj.content = ctypes.cast(content, ctypes.POINTER(ctypes.c_uint8))
+            obj.stride2 = stride2
+            return obj
+        def _not_implemented(self):
+            raise AttributeError()
+        __array_interface__ = property(_not_implemented)
+        __array_struct__ = property(_not_implemented)
+        def __getitem__(self, key):
+            byte_index = key[0] * 20 + key[1] * 4 + key[2] * self.stride2
+            if not (0 <= byte_index < 60):
+                raise IndexError("%s is out of range", key)
+            return self.content[byte_index]
+
+    def setUp(self):
+        surf = self.surface
+        for y in range(5):
+            for x in range(3):
+                surf.set_at((x, y), (x + 1, 0, y + 1))
+
+    def assertCopy2D(self, surface, array):
+        for x in range(0, 3):
+            for y in range(0, 5):
+                self.assertEqual(surface.get_at_mapped((x, y)),
+                                 array[x, y])
+
+    def test_surface_to_array_newbuf(self):
+        array = self.Array2D(range(0, 15))
+        self.assertNotEqual(array.content[0],
+                            self.surface.get_at_mapped((0, 0)))
+        surface_to_array(array, self.surface)
+        self.assertCopy2D(self.surface, array)
+
+    def test_array_to_surface_newbuf(self):
+        array = self.Array2D(range(0, 15))
+        self.assertNotEqual(array.content[0],
+                            self.surface.get_at_mapped((0, 0)))
+        array_to_surface(self.surface, array)
+        self.assertCopy2D(self.surface, array)
+
+    def test_map_array_newbuf(self):
+        array2D = self.Array2D([0] * 15)
+        elements = [i + (255 - i << 8) + (99 << 16) for i in range(0,15)]
+        array3D = self.Array3D(elements)
+        map_array(array2D, array3D, self.surface)
+        for x in range(0, 3):
+            for y in range(0, 5):
+                p = array3D[x, y, 0], array3D[x, y, 1], array3D[x, y, 2]
+                self.assertEqual(self.surface.unmap_rgb(array2D[x, y]), p)
+
+    def test_make_surface_newbuf(self):
+        array = self.Array2D(range(10, 160, 10))
+        surface = make_surface(array)
+        self.assertCopy2D(surface, array)
+
+    if not pygame.HAVE_NEWBUF:
+        del test_surface_to_array_newbuf
+        del test_array_to_surface_newbuf
+        del test_map_array_newbuf
+        del test_make_surface_newbuf
+
+
 if __name__ == '__main__':
     unittest.main()