diff src/pixelarray.c @ 960:3e118ec659d7

Fixed 24bpp access in PixelArray.
author marcus
date Thu, 13 Mar 2008 21:15:15 +0000
parents cbb061b8ff4c
children 68793bdcb85f
line wrap: on
line diff
--- a/src/pixelarray.c	Mon Mar 10 21:59:17 2008 +0000
+++ b/src/pixelarray.c	Thu Mar 13 21:15:15 2008 +0000
@@ -19,7 +19,7 @@
 */
 
 #define PYGAMEAPI_PIXELARRAY_INTERNAL
-
+        
 #include "pygame.h"
 #include "pygamedocs.h"
 #include "surface.h"
@@ -93,13 +93,12 @@
 static PyObject* _pxarray_inplace_repeat (PyPixelArray *array, Py_ssize_t n);
 
 /* Mapping methods */
-/*
-static int _get_subslice (SDL_Surface *surface, PyObject *op, Py_ssize_t *start,
-                          Py_ssize_t *stop, Py_ssize_t *step);
+
+static int _get_subslice (PyPixelArray *array, PyObject *op, Py_ssize_t length,
+    Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step);
 static PyObject* _pxarray_subscript (PyPixelArray *array, PyObject *op);
 static int _pxarray_ass_subscript (PyPixelArray *array, PyObject* op,
-                                   PyObject* value);
-*/
+    PyObject* value);
 
 /* C API interfaces */
 static PyObject* PyPixelArray_New (PyObject *surfobj);
@@ -143,12 +142,13 @@
 /**
  * Mapping interface support for the PyPixelArray.
  */
-/* static PyMappingMethods _pxarray_mapping = */
-/* { */
-/*     (inquiry) _pxarray_length,              /\*mp_length*\/ */
-/*     (binaryfunc) _pxarray_subscript,        /\*mp_subscript*\/ */
-/*     (objobjargproc) _pxarray_ass_subscript, /\*mp_ass_subscript*\/ */
-/* }; */
+
+static PyMappingMethods _pxarray_mapping =
+{
+    (inquiry) _pxarray_length,              /*mp_length*/
+    (binaryfunc) _pxarray_subscript,        /*mp_subscript*/
+    (objobjargproc) _pxarray_ass_subscript, /*mp_ass_subscript*/
+};
 
 static PyTypeObject PyPixelArray_Type =
 {
@@ -165,7 +165,7 @@
     (reprfunc) &_pxarray_repr,  /* tp_repr */
     0,                          /* tp_as_number */
     &_pxarray_sequence,         /* tp_as_sequence */
-    0, /*&_pxarray_mapping ,*/          /* tp_as_mapping */
+    0,/*&_pxarray_mapping,          /* tp_as_mapping */
     0,                          /* tp_hash */
     0,                          /* tp_call */
     0,                          /* tp_str */
@@ -326,7 +326,11 @@
     surface = PySurface_AsSurface (array->surface);
     bpp = surface->format->BytesPerPixel;
     pixels = (Uint8 *) surface->pixels;
-
+/*
+    printf ("ARRAY: %d:%d, %d:%d %d:%d %d\n",
+        array->start, array->end, array->xlen, array->xstep,
+        array->ylen, array->ystep, array->padding);
+*/
     string = PyString_FromString ("PixelArray(");
     switch (bpp)
     {
@@ -346,7 +350,8 @@
             }
             pixel = (Uint32) *((Uint8 *) pixels + array->start + x +
                 y * array->padding);
-            PyString_ConcatAndDel (&string, PyString_FromFormat ("%d]", pixel));
+            PyString_ConcatAndDel (&string,
+                PyString_FromFormat ("%d]", pixel));
         }
         break;
     case 2:
@@ -365,7 +370,8 @@
             }
             pixel = (Uint32)*((Uint16 *) (pixels + y * array->padding) +
                 array->start + x);
-            PyString_ConcatAndDel (&string, PyString_FromFormat ("%d]", pixel));
+            PyString_ConcatAndDel (&string,
+                PyString_FromFormat ("%d]", pixel));
         }
         break;
     case 3:
@@ -377,8 +383,8 @@
             for (x = 0; x < array->xlen - array->xstep; x += array->xstep)
             {
                 /* Construct the columns */
-                px24 = ((Uint8 *) (pixels + array->start + y * array->padding) +
-                    x * 3);
+                px24 = ((Uint8 *) (pixels + y * array->padding) +
+                    array->start * 3 + x * 3);
 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
                 pixel = (px24[0]) + (px24[1] << 8) + (px24[2] << 16);
 #else
@@ -387,14 +393,15 @@
                 PyString_ConcatAndDel (&string, PyString_FromFormat
                     ("%d, ", pixel));
             }
-            px24 = ((Uint8 *) (pixels + array->start + y * array->padding) +
-                    x * 3);
+            px24 = ((Uint8 *) (pixels + y * array->padding) +
+                array->start * 3 + x * 3);
 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
             pixel = (px24[0]) + (px24[1] << 8) + (px24[2] << 16);
 #else
             pixel = (px24[2]) + (px24[1] << 8) + (px24[0] << 16);
 #endif
-            PyString_ConcatAndDel (&string, PyString_FromFormat ("%d]", pixel));
+            PyString_ConcatAndDel (&string,
+                PyString_FromFormat ("%d]", pixel));
         }
         break;
     default: /* 4bpp */
@@ -413,7 +420,8 @@
             }
             pixel = *((Uint32 *) (pixels + y * array->padding) +
                 array->start + x);
-            PyString_ConcatAndDel (&string, PyString_FromFormat ("%d]", pixel));
+            PyString_ConcatAndDel (&string,
+                PyString_FromFormat ("%d]", pixel));
         }
         break;
     }
@@ -449,7 +457,8 @@
         longval = PyLong_AsLong (val);
         if ((longval < INT_MIN) || (longval > INT_MAX))
         {
-            PyErr_SetString(PyExc_ValueError, "index too big for array access");
+            PyErr_SetString(PyExc_ValueError,
+                "index too big for array access");
             return 0;
         }
         *color = (Uint32) longval;
@@ -614,9 +623,13 @@
     surface = PySurface_AsSurface (array->surface);
     bpp = surface->format->BytesPerPixel;
 
-    if (array->xlen == 1) /* Access of a single column. */
+     /* Access of a single column. */
+    if (array->xlen == 1)
         return _get_single_pixel ((Uint8 *) surface->pixels, bpp,
             array->start, _index * array->padding * array->ystep);
+    if (array->ylen == 1)
+        return _get_single_pixel ((Uint8 *) surface->pixels, bpp,
+            array->start + _index * array->xstep, _index * array->padding);
 
     return _array_slice_internal
         (array, (Uint32) _index, (Uint32) _index + 1, 1);
@@ -638,6 +651,9 @@
     else if (high > (Sint32) array->xlen)
         high = array->xlen;
 
+    if (low == high)
+        Py_RETURN_NONE;
+
     return _array_slice_internal (array, (Uint32) low, (Uint32) high, 1);
 }
 
@@ -723,7 +739,8 @@
 
                 *((Uint16 *) (pixels + y * padding) + offset) =
                     (Uint16)*((Uint16 *)
-                        ((Uint8*)valsf->pixels + vy * val->padding) + val->start + vx);
+                        ((Uint8*)valsf->pixels + vy * val->padding) +
+                        val->start + vx);
                 vx += val->xstep;
             }
             vy += val->ystep;
@@ -747,9 +764,12 @@
                     (val->start + vx) * 3;
 
 #if (SDL_BYTEORDER == SDL_LIL_ENDIAN)
-                *(px + (format->Rshift >> 3)) = *(vpx + (vformat->Rshift >> 3));
-                *(px + (format->Gshift >> 3)) = *(vpx + (vformat->Gshift >> 3));
-                *(px + (format->Bshift >> 3)) = *(vpx + (vformat->Bshift >> 3));
+                *(px + (format->Rshift >> 3)) =
+                    *(vpx + (vformat->Rshift >> 3));
+                *(px + (format->Gshift >> 3)) =
+                    *(vpx + (vformat->Gshift >> 3));
+                *(px + (format->Bshift >> 3)) =
+                    *(vpx + (vformat->Bshift >> 3));
 #else
                 *(px + 2 - (format->Rshift >> 3)) =
                     *(vpx + 2 - (vformat->Rshift >> 3));
@@ -774,7 +794,8 @@
 
                 *((Uint32 *) (pixels + y * padding) + offset) =
                     *((Uint32 *)
-                        ((Uint8*)valsf->pixels + y * val->padding) + val->start + vx);
+                        ((Uint8*)valsf->pixels + y * val->padding) +
+                        val->start + vx);
                 vx += val->xstep;
             }
             vy += val->ystep;
@@ -1190,157 +1211,246 @@
  * Internally used parser function for the 2D slices:
  * array[x,y], array[:,:], ...
  */
-/* static int */
-/* _get_subslice (SDL_Surface *surface, PyObject *op, Py_ssize_t *start, */
-/*                Py_ssize_t *stop, Py_ssize_t *step) */
-/* { */
-/*     *start = -1; */
-/*     *stop = -1; */
-/*     *step = -1; */
+static int
+_get_subslice (PyPixelArray *array, PyObject *op, Py_ssize_t length,
+    Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step)
+{
+    *start = -1;
+    *stop = -1;
+    *step = -1;
 
-/*     if (PyInt_Check (op)) */
-/*     { */
-/*         printf ("Found int\n"); */
-/*         /\* Plain index: array[x, *\/ */
-/*         *start = PyInt_AsLong (op); */
-/*         return 1; */
-/*     } */
-/*     else if (PyLong_Check (op)) */
-/*     { */
-/*         long long val = -1; */
-/*         /\* Plain index: array[x, *\/ */
+    if (PyInt_Check (op))
+    {
+        /* Plain index: array[x, */
+        *start = PyInt_AsLong (op);
+        *stop = (*start) + 1;
+        *step = 1;
+    }
+    else if (PyLong_Check (op))
+    {
+        long long val = -1;
+        /* Plain index: array[x, */
 
-/*         printf ("Found long\n"); */
-/*         val = PyLong_AsLong (op); */
-/*         if ((val < INT_MIN) || (val > INT_MAX)) */
-/*         { */
-/*             PyErr_SetString(PyExc_ValueError, "index too big for array access"); */
-/*             return -1; */
-/*         } */
-/*         *start = (int) val; */
-/*     } */
-/*     else if (op == Py_Ellipsis) */
-/*     { */
-/*         /\* Operator is the ellipsis: array[..., *\/ */
-/*         printf ("Found ellipsis\n"); */
-/*         /\* TODO *\/ */
-/*     } */
-/*     else if (PySlice_Check (op)) */
-/*     { */
-/*         Py_ssize_t slicelen; */
+        val = PyLong_AsLong (op);
+        if ((val < INT_MIN) || (val > INT_MAX))
+        {
+            PyErr_SetString(PyExc_ValueError,
+                "index too big for array access");
+            return 0;
+        }
+        *start = (int) val;
+        *stop = *start + 1;
+        *step = 1;
+    }
+    else if (PySlice_Check (op))
+    {
+        Py_ssize_t slicelen;
 
-/*         /\* Operator is a slice: array[x::, *\/ */
-/*         printf ("Found slice\n"); */
-/*         if (PySlice_GetIndicesEx ((PySliceObject *) op, surface->w * surface->h, */
-/*                                   start, stop, step, &slicelen) < 0) */
-/*         { */
-/*             return 0; */
-/*         } */
-/*     } */
-/*     return 0; */
-/* } */
+        /* Operator is a slice: array[x::, */
+        if (PySlice_GetIndicesEx ((PySliceObject *) op, length,
+                start, stop, step, &slicelen) < 0)
+        {
+            return 0;
+        }
+    }
+    return 1;
+}
 
 /**
  * Slicing support for 1D and 2D access.
  * array[x,y] is only supported for 2D arrays.
  */
-/* static PyObject* */
-/* _pxarray_subscript (PyPixelArray *array, PyObject *op) */
-/* { */
-/*     Py_ssize_t step; */
-/*     Py_ssize_t start; */
-/*     Py_ssize_t stop; */
-/*     SDL_Surface *surface = PySurface_AsSurface (array->surface); */
+static PyObject*
+_pxarray_subscript (PyPixelArray *array, PyObject *op)
+{
+    SDL_Surface *surface = PySurface_AsSurface (array->surface);
 
-/*     /\* Note: order matters here. */
-/*      * First check array[x,y], then array[x:y:z], then array[x] */
-/*      * Otherwise it'll fail. */
-/*      *\/ */
-/*     if (PySequence_Check (op)) */
-/*     { */
-/*         PyObject *sub; */
-/*         Py_ssize_t i; */
+    /* Note: order matters here.
+     * First check array[x,y], then array[x:y:z], then array[x]
+     * Otherwise it'll fail.
+     */
+    if (PySequence_Check (op))
+    {
+        PyObject *obj;
+        Py_ssize_t size = PySequence_Size (op);
+        Py_ssize_t xstart, xstop, xstep;
+        Py_ssize_t ystart, ystop, ystep;
+        Py_ssize_t lenx, leny;
+        
+        if (size == 0)
+        {
+            /* array[,], array[()] ... */
+            Py_INCREF (array);
+            return (PyObject *) array;
+        }
+        if (size > 2 || (size == 2 && array->xlen == 1))
+            return RAISE (PyExc_IndexError, "too many indices for the array");
 
-/*         if (PySequence_Size (op) > 2) */
-/*             return RAISE (PyExc_IndexError, */
-/*                           "too many indices for the 2D array"); */
+        lenx = (array->xlen > 1) ? array->xlen / array->xstep : -1;
+        leny = array->ylen / array->ystep;
 
-/*         for (i = 0; i < PySequence_Size (op); i++) */
-/*         { */
-/*             sub = PySequence_GetItem (op, i); */
-/*             if (!_get_subslice (surface, sub, &start, &stop, &step)) */
-/*             { */
-/*                 /\* Error on retrieving the subslice. *\/ */
-/*                 printf ("Error\n"); */
-/*                 Py_DECREF (sub); */
-/*                 return NULL; */
-/*             } */
+        obj = PySequence_Fast_GET_ITEM (op, 0);
+        if (obj == Py_Ellipsis || obj == Py_None)
+        {
+            /* Operator is the ellipsis or None
+             * array[...,XXX], array[None,XXX]
+             */
+            xstart = array->start;
+            xstop = array->xlen;
+            xstep = array->xstep;
+        }
+        else if (!_get_subslice (array, obj, lenx, &xstart, &xstop, &xstep))
+        {
+            /* Error on retrieving the subslice. */
+            return NULL;
+        }
 
-/*             if (stop == -1) */
-/*             { */
-/*                 /\* Not an index *\/ */
-/*                 printf ("Slice: %d:%d:%d\n", start, stop, step); */
-/*             } */
+        if (size == 2)
+        {
+            obj = PySequence_Fast_GET_ITEM (op, 1);
+            if (obj == Py_Ellipsis || obj == Py_None)
+            {
+                /* Operator is the ellipsis or None
+                 * array[XXX,...], array[XXX,None]
+                 */
+                ystart = 0;
+                ystop = array->ylen;
+                ystep = array->ystep;
+            }
+            else if (!_get_subslice (array, obj, leny, &ystart, &ystop, &ystep))
+            {
+                /* Error on retrieving the subslice. */
+                return NULL;
+            }
+        }
+        else
+        {
+            ystart = 0;
+            ystop = array->ylen;
+            ystep = array->ystep;
+        }
 
-/*             Py_DECREF (sub); */
-/*         } */
-/*         Py_DECREF (sub); */
-/*     } */
-/*     else if (PySlice_Check (op)) */
-/*     { */
-/*         /\* A slice *\/ */
-/*         PyObject *result; */
-/*         Py_ssize_t slicelen; */
+        /* Null value? */
+        if (xstart == xstop || ystart == ystop)
+            Py_RETURN_NONE;
+
+        /* Check boundaries. */
+        if (xstart + xstep >= xstop)
+        {
+            xstop = xstart + 1;
+            xstep = 1;
+        }
+
+        if (ystart + ystep >= ystop)
+        {
+            ystop = ystart + 1;
+            ystep = 1;
+        }
 
-/*         if (PySlice_GetIndicesEx ((PySliceObject *) op, surface->w * surface->h, */
-/*                                   &start, &stop, &step, &slicelen) < 0) */
-/*             return NULL; */
-        
-/*         if (slicelen < 0) /\* TODO: empty surface with 0x0 px? *\/ */
-/*             return NULL; */
-/* /\* */
-/*         result = (PyObject *) _pxarray_new_internal */
-/*             (&PyPixelArray_Type, array->surface, (Uint32) start, (Uint32) stop, */
-/*              1, step, 1, (PyObject *) array); */
-/* *\/ */
-/*         return result; */
-/*     } */
-/*     else if (PyIndex_Check (op)) */
-/*     { */
-/*         /\* A simple index. *\/ */
-/*         Py_ssize_t i = PyNumber_AsSsize_t (op, PyExc_IndexError); */
+        /* Single value? */
+        if (xstart + xstep >= xstop && ystart + ystep >= ystop)
+        {
+            return  _get_single_pixel ((Uint8 *) surface->pixels,
+                surface->format->BytesPerPixel, array->start + xstart,
+                ystart * array->padding * array->ystep);
+        }
+/*
+        printf ("X: %d:%d:%d Y: %d:%d:%d\n", xstart, xstop, xstep,
+            ystart, ystop, ystep);
+*/
+/*
+static PyPixelArray* _pxarray_new_internal (PyTypeObject *type,
+    PyObject *surface, Uint32 start, Uint32 end, Uint32 xlen, Uint32 ylen,
+    Uint32 xstep, Uint32 ystep, Uint32 padding, PyObject *parent);
+*/
+        return (PyObject *) _pxarray_new_internal (&PyPixelArray_Type,
+            array->surface,
+            (Uint32) array->start + ystart * array->padding + xstart,
+            (Uint32) array->start + ystop * array->padding + xstop,
+            (Uint32) xstop - xstart,
+            (Uint32) ystop - ystart,
+            (Uint32) xstep,
+            (Uint32) ystep,
+            (Uint32) array->padding, (PyObject *) array);
+    }
+    else if (PySlice_Check (op))
+    {
+        /* A slice */
+        PyObject *result;
+        Py_ssize_t slicelen;
+        Py_ssize_t step;
+        Py_ssize_t start;
+        Py_ssize_t stop;
+        int retval;
 
-/*         if (i == -1 && PyErr_Occurred ()) */
-/*             return NULL; */
+        if (array->xlen > 1)
+        {
+            /* 2D array - slice along the x axis */
+            retval = PySlice_GetIndicesEx ((PySliceObject *) op,
+                array->xlen / array->xstep, &start, &stop, &step, &slicelen);
+        }
+        else
+        {
+            /* 1D array - use the y axis. */
+            retval = PySlice_GetIndicesEx ((PySliceObject *) op,
+                array->ylen / array->ystep, &start, &stop, &step, &slicelen);
+        }
+        if (retval < 0)
+            return NULL;
 
-/*         if (i < 0) */
-/*             i += surface->w * surface->h; */
-/*         return _pxarray_item (array, i); */
-/*     } */
+        if (slicelen < 0) /* TODO: empty surface with 0x0 px? */
+            return NULL;
 
-/*     return RAISE (PyExc_TypeError, */
-/*                   "index must be an integer, sequence or slice"); */
-/* } */
+        return (PyObject *) _array_slice_internal
+            (array, (Uint32) start, (Uint32) stop, (Uint32) step);
+/*
+        result = (PyObject *) _pxarray_new_internal
+            (&PyPixelArray_Type, array->surface,
+                (Uint32) start, (Uint32) stop * array->ylen,
+                1, stop - start, 1, step, (PyObject *) array);
+        return result;
+*/
+    }
+    else if (PyIndex_Check (op))
+    {
+        /* A simple index. */
+        Py_ssize_t i = PyNumber_AsSsize_t (op, PyExc_IndexError);
 
-/* static int */
-/* _pxarray_ass_subscript (PyPixelArray *array, PyObject* op, PyObject* value) */
-/* { */
-/*     SDL_Surface *surface = PySurface_AsSurface (array->surface); */
+        if (i == -1 && PyErr_Occurred ())
+            return NULL;
+
+        if (i < 0)
+            i += (array->xlen > 1) ? array->xlen / array->xstep :
+                array->ylen / array->ystep;
 
-/*     if (PyIndex_Check (op)) */
-/*     { */
-/*         /\* A simple index. *\/ */
-/*         Py_ssize_t i = PyNumber_AsSsize_t (op, PyExc_IndexError); */
-/*         if (i == -1 && PyErr_Occurred ()) */
-/*             return -1; */
+        return _pxarray_item (array, i);
+    }
+
+    return RAISE (PyExc_TypeError,
+        "index must be an integer, sequence or slice");
+}
 
-/*         if (i < 0) */
-/*             i += surface->w * surface->h; */
-/*         return _pxarray_ass_item (array, i, value); */
-/*     } */
-/*     PyErr_SetString (PyExc_NotImplementedError, "method not implemented"); */
-/*     return -1; */
-/* } */
+static int
+_pxarray_ass_subscript (PyPixelArray *array, PyObject* op, PyObject* value)
+{
+    SDL_Surface *surface = PySurface_AsSurface (array->surface);
+    
+    if (PyIndex_Check (op))
+    {
+        /* A simple index. */
+        Py_ssize_t i = PyNumber_AsSsize_t (op, PyExc_IndexError);
+        if (i == -1 && PyErr_Occurred ())
+            return -1;
+
+        if (i < 0)
+            i += (array->xlen > 1) ? array->xlen / array->xstep :
+                array->ylen / array->ystep;
+
+        return _pxarray_ass_item (array, i, value);
+    }
+    PyErr_SetString (PyExc_NotImplementedError, "method not implemented");
+    return -1;
+}
 
 /**** C API interfaces ****/
 static PyObject* PyPixelArray_New (PyObject *surfobj)
@@ -1354,12 +1464,12 @@
     if (surface->format->BytesPerPixel < 1  ||
         surface->format->BytesPerPixel > 4)
         return RAISE (PyExc_ValueError,
-                      "unsupport bit depth for reference array");
+            "unsupport bit depth for reference array");
 
     return (PyObject *) _pxarray_new_internal
         (&PyPixelArray_Type, surfobj, 0, (Uint32) surface->w * surface->h,
-         (Uint32) surface->w, (Uint32) surface->h, 1, 1, (Uint32) surface->w,
-         NULL);
+            (Uint32) surface->w, (Uint32) surface->h, 1, 1,
+            (Uint32) surface->pitch, NULL);
 }
 
 PYGAME_EXPORT
@@ -1387,7 +1497,6 @@
     PyDict_SetItemString (dict, PYGAMEAPI_LOCAL_ENTRY, apiobj);
     Py_DECREF (apiobj);
 
-
     /*imported needed apis*/
     import_pygame_base ();
     import_pygame_surface ();