diff src/pixelarray_methods.c @ 1007:9e42170b0f2e

Added PixelArray.compare().
author marcus
date Fri, 11 Apr 2008 19:45:27 +0000
parents 7355da1a6df6
children 61a09a2965b0
line wrap: on
line diff
--- a/src/pixelarray_methods.c	Fri Apr 11 06:44:47 2008 +0000
+++ b/src/pixelarray_methods.c	Fri Apr 11 19:45:27 2008 +0000
@@ -193,6 +193,13 @@
         return RAISE (PyExc_SDLError, SDL_GetError ());
     }
     SDL_FreeSurface (tmpsf);
+    
+    newsf = PySurface_New (newsurf);
+    if (!newsf)
+    {
+        SDL_FreeSurface (newsurf);
+        return NULL;
+    }
 
     /* Acquire a temporary lock. */
     if (SDL_MUSTLOCK (newsurf) == 0)
@@ -314,9 +321,6 @@
 
     if (SDL_MUSTLOCK (newsurf) == 0)
         SDL_UnlockSurface (newsurf);
-    newsf = PySurface_New (newsurf);
-    if (!newsf)
-        return NULL;
     return newsf;
 }
 
@@ -644,21 +648,23 @@
     if (distance < 0 || distance > 1)
         return RAISE (PyExc_ValueError,
             "distance must be in the range from 0.0 to 1.0");
+    if (!_get_weights (weights, &wr, &wg, &wb))
+        return NULL;
 
     surface = PySurface_AsSurface (array->surface);
     if (!_get_color_from_object (excolor, surface->format, &color))
         return NULL;
 
-    if (!_get_weights (weights, &wr, &wg, &wb))
-        return NULL;
-
     /* Create the b/w mask surface. */
     sf = _make_surface (array);
     if (!sf)
         return NULL;
     newarray = (PyPixelArray *) PyPixelArray_New (sf);
     if (!newarray)
+    {
+        Py_DECREF (sf);
         return NULL;
+    }
     surface = PySurface_AsSurface (newarray->surface);
 
     black = SDL_MapRGBA (surface->format, 0, 0, 0, 255);
@@ -677,7 +683,7 @@
     case 1:
     {
         Uint8 *pixel;
-        while (posy < array->ylen)
+        while (posy < newarray->ylen)
         {
             x = newarray->xstart;
             posx = 0;
@@ -708,7 +714,7 @@
         Uint16 *pixel;
         while (posy < newarray->ylen)
         {
-            x = array->xstart;
+            x = newarray->xstart;
             posx = 0;
             while (posx < newarray->xlen)
             {
@@ -854,3 +860,288 @@
     Py_END_ALLOW_THREADS;
     return (PyObject *) newarray;
 }
+
+static PyObject*
+_compare (PyPixelArray *array, PyObject *args, PyObject *kwds)
+{
+    PyPixelArray *array2 = NULL;
+    PyPixelArray *newarray = NULL;
+    PyObject *weights = NULL;
+    PyObject *sf = NULL;
+    SDL_Surface *surface1 = NULL;
+    SDL_Surface *surface2 = NULL;
+    Uint32 black;
+    Uint32 white;
+    float distance = 0;
+    Uint8 r1, g1, b1, a1, r2, g2, b2, a2;
+    float wr, wg, wb;
+
+    Uint32 x = 0;
+    Uint32 y = 0;
+    Uint32 vx = 0;
+    Uint32 vy = 0;
+    Uint32 posx = 0;
+    Uint32 posy = 0;
+    Sint32 absxstep;
+    Sint32 absystep;
+    Uint8 *pixels1;
+    Uint8 *pixels2;
+
+    static char *keys[] = { "array", "distance", "weights", NULL };
+
+    if (!PyArg_ParseTupleAndKeywords (args, kwds, "O|fO", keys, &newarray,
+            &distance, &weights))
+        return NULL;
+
+    if (!PyPixelArray_Check (newarray))
+        return RAISE (PyExc_TypeError, "invalid array type");
+    array2 = (PyPixelArray *) newarray;
+    newarray = NULL;
+    if (distance < 0 || distance > 1)
+        return RAISE (PyExc_ValueError,
+            "distance must be in the range from 0.0 to 1.0");
+    if (!_get_weights (weights, &wr, &wg, &wb))
+        return NULL;
+
+    if (array->ylen / ABS (array->ystep) != array2->ylen / ABS (array2->ystep)
+       || array->xlen / ABS (array->xstep) != array2->xlen / ABS (array2->xstep))
+    {
+        /* Bounds do not match. */
+        PyErr_SetString (PyExc_ValueError, "array sizes do not match");
+        return NULL;
+    }
+
+    surface1 = PySurface_AsSurface (array->surface);
+    surface2 = PySurface_AsSurface (array2->surface);
+    if (surface2->format->BytesPerPixel != surface1->format->BytesPerPixel)
+        return RAISE (PyExc_ValueError, "bit depths do not match");
+
+    /* Create the b/w mask surface. */
+    sf = _make_surface (array);
+    if (!sf)
+        return NULL;
+    newarray = (PyPixelArray *) PyPixelArray_New (sf);
+    if (!newarray)
+    {
+        Py_DECREF (sf);
+        return NULL;
+    }
+    surface1 = PySurface_AsSurface (newarray->surface);
+    
+    black = SDL_MapRGBA (surface1->format, 0, 0, 0, 255);
+    white = SDL_MapRGBA (surface1->format, 255, 255, 255, 255);
+
+    pixels1 = surface1->pixels;
+    pixels2 = surface2->pixels;
+    absxstep = ABS (array2->xstep);
+    absystep = ABS (array2->ystep);
+    y = array2->ystart;
+
+    Py_BEGIN_ALLOW_THREADS;
+    switch (surface1->format->BytesPerPixel)
+    {
+    case 1:
+    {
+        Uint8 *pixel1, *pixel2;
+        while (posy < newarray->ylen)
+        {
+            vx = array2->xstart;
+            x = newarray->xstart;
+            posx = 0;
+            while (posx < newarray->xlen)
+            {
+                pixel1 = ((Uint8 *) pixels1 + y * surface1->pitch + x);
+                pixel2 = ((Uint8 *) pixels2 + vy * surface2->pitch + vx);
+                if (distance)
+                {
+                    GET_PIXELVALS_1 (r1, g1, b1, a1, pixel1, surface1->format);
+                    GET_PIXELVALS_1 (r2, g2, b2, a2, pixel2, surface2->format);
+                    if (COLOR_DIFF_RGB (wr, wg, wb, r1, g1, b1, r2, g2, b2) >
+                        distance)
+                        *pixel1 = (Uint8) white;
+                    else
+                        *pixel1 = (Uint8) black;
+                }
+                else
+                    *pixel1 = (*pixel1 == *pixel2) ? (Uint8) white :
+                        (Uint8) black;
+                vx += array2->xstep;
+                x += newarray->xstep;
+                posx += absxstep;
+            }
+            vy += array2->ystep;
+            y += newarray->ystep;
+            posy += absystep;
+        }
+        break;
+    }
+    case 2:
+    {
+        Uint16 *pixel1, *pixel2;
+        while (posy < newarray->ylen)
+        {
+            vx = array2->xstart;
+            x = array->xstart;
+            posx = 0;
+            while (posx < newarray->xlen)
+            {
+                pixel1 = ((Uint16 *) (pixels1 + y * surface1->pitch) + x);
+                pixel2 = ((Uint16 *) (pixels2 + vy * surface2->pitch) + vx);
+                if (distance)
+                {
+                    GET_PIXELVALS (r1, g1, b1, a1, (Uint32) *pixel1,
+                        surface1->format);
+                    GET_PIXELVALS (r2, g2, b2, a2, (Uint32) *pixel2,
+                        surface1->format);
+                    if (COLOR_DIFF_RGB (wr, wg, wb, r1, g1, b1, r2, g2, b2) >
+                        distance)
+                        *pixel1 = (Uint16) white;
+                    else
+                        *pixel1 = (Uint16) black;
+                }
+                else
+                    *pixel1 = (*pixel1 == *pixel2) ? (Uint16) white :
+                        (Uint16) black;
+                vx += array2->xstep;
+                x += newarray->xstep;
+                posx += absxstep;
+            }
+            vy += array2->ystep;
+            y += newarray->ystep;
+            posy += absystep;
+        }
+        break;
+    }
+    case 3:
+    {
+        Uint8 *px1, *px2;
+        Uint32 pxcolor1, pxcolor2;
+        SDL_PixelFormat *format = surface1->format;
+        while (posy < newarray->ylen)
+        {
+            vx = array2->xstart;
+            x = newarray->xstart;
+            posx = 0;
+            while (posx < newarray->xlen)
+            {
+                px1 = (Uint8 *) (pixels1 + y * surface1->pitch) + x * 3;
+                px2 = (Uint8 *) (pixels2 + vy * surface2->pitch) + vx * 3;
+#if SDL_BYTEORDER == SDL_LIL_ENDIAN
+                pxcolor1 = (px1[0]) + (px1[1] << 8) + (px1[2] << 16);
+                pxcolor2 = (px2[0]) + (px2[1] << 8) + (px2[2] << 16);
+                if (distance)
+                {
+                    GET_PIXELVALS (r1, g1, b1, a1, pxcolor1, surface1->format);
+                    GET_PIXELVALS (r2, g2, b2, a2, pxcolor2, surface2->format);
+                    if (COLOR_DIFF_RGB (wr, wg, wb, r1, g1, b1, r2, g2, b2) >
+                        distance)
+                    {
+                        *(px1 + (format->Rshift >> 3)) = (Uint8) (white >> 16);
+                        *(px1 + (format->Gshift >> 3)) = (Uint8) (white >> 8);
+                        *(px1 + (format->Bshift >> 3)) = (Uint8) white;
+                    }
+                    else
+                    {
+                        *(px1 + (format->Rshift >> 3)) = (Uint8) (black >> 16);
+                        *(px1 + (format->Gshift >> 3)) = (Uint8) (black >> 8);
+                        *(px1 + (format->Bshift >> 3)) = (Uint8) black;
+                    }
+                }
+                else if (pxcolor1 != pxcolor2)
+                {
+                    *(px1 + (format->Rshift >> 3)) = (Uint8) (white >> 16);
+                    *(px1 + (format->Gshift >> 3)) = (Uint8) (white >> 8);
+                    *(px1 + (format->Bshift >> 3)) = (Uint8) white;
+                }
+                else
+                {
+                    *(px1 + (format->Rshift >> 3)) = (Uint8) (black >> 16);
+                    *(px1 + (format->Gshift >> 3)) = (Uint8) (black >> 8);
+                    *(px1 + (format->Bshift >> 3)) = (Uint8) black;
+                }
+#else
+                pxcolor1 = (px1[2]) + (px1[1] << 8) + (px1[0] << 16);
+                pxcolor2 = (px2[2]) + (px2[1] << 8) + (px2[0] << 16);
+                if (distance)
+                {
+                    GET_PIXELVALS (r1, g1, b1, a1, pxcolor1, surface1->format);
+                    GET_PIXELVALS (r2, g2, b2, a2, pxcolor2, surface2->format);
+                    if (COLOR_DIFF_RGB (wr, wg, wb, r1, g1, b1, r2, g2, b2) >
+                        distance)
+                    {
+                        *(px1 + 2 - (format->Rshift >> 3)) =
+                            (Uint8) (white >> 16);
+                        *(px1 + 2 - (format->Gshift >> 3)) =
+                            (Uint8) (white >> 8);
+                        *(px1 + 2 - (format->Bshift >> 3)) = (Uint8) white;
+                    }
+                    else
+                    {
+                        *(px1 + 2 - (format->Rshift >> 3)) =
+                            (Uint8) (black >> 16);
+                        *(px1 + 2 - (format->Gshift >> 3)) =
+                            (Uint8) (black >> 8);
+                        *(px1 + 2 - (format->Bshift >> 3)) = (Uint8) black;
+                    }
+                }
+                else if (pxcolor1 != pxcolor2)
+                {
+                    *(px1 + 2 - (format->Rshift >> 3)) = (Uint8) (white >> 16);
+                    *(px1 + 2 - (format->Gshift >> 3)) = (Uint8) (white >> 8);
+                    *(px1 + 2 - (format->Bshift >> 3)) = (Uint8) white;
+                }
+                else
+                {
+                    *(px1 + 2 - (format->Rshift >> 3)) = (Uint8) (black >> 16);
+                    *(px1 + 2 - (format->Gshift >> 3)) = (Uint8) (black >> 8);
+                    *(px1 + 2 - (format->Bshift >> 3)) = (Uint8) black;
+                }
+#endif
+                vx += array2->xstep;
+                x += newarray->xstep;
+                posx += absxstep;
+            }
+            vy += array2->ystep;
+            y += newarray->ystep;
+            posy += absystep;
+        }
+        break;
+    }
+    default:
+    {
+        Uint32 *pixel1, *pixel2;
+        while (posy < newarray->ylen)
+        {
+            vx = array2->xstart;
+            x = newarray->xstart;
+            posx = 0;
+            while (posx < newarray->xlen)
+            {
+                pixel1 = ((Uint32 *) (pixels1 + y * surface1->pitch) + x);
+                pixel2 = ((Uint32 *) (pixels2 + vy * surface2->pitch) + vx);
+                if (distance)
+                {
+                    GET_PIXELVALS (r1, g1, b1, a1, *pixel1, surface1->format);
+                    GET_PIXELVALS (r2, g2, b2, a2, *pixel2, surface2->format);
+                    if (COLOR_DIFF_RGB (wr, wg, wb, r1, g1, b1, r2, g2, b2) >
+                        distance)
+                        *pixel1 = white;
+                    else
+                        *pixel1 = black;
+                }
+                else
+                    *pixel1 = (*pixel1 == *pixel2) ? white : black;
+                vx += array2->xstep;
+                x += newarray->xstep;
+                posx += absxstep;
+            }
+            vy += array2->ystep;
+            y += newarray->ystep;
+            posy += absystep;
+        }
+        break;
+    }
+    }
+    Py_END_ALLOW_THREADS;
+    return (PyObject *) newarray;
+}