Home | History | Annotate | Download | only in Modules
      1 
      2 /* imageopmodule - Various operations on pictures */
      3 
      4 #ifdef sun
      5 #define signed
      6 #endif
      7 
      8 #include "Python.h"
      9 
     10 #if SIZEOF_INT == 4
     11 typedef int Py_Int32;
     12 typedef unsigned int Py_UInt32;
     13 #else
     14 #if SIZEOF_LONG == 4
     15 typedef long Py_Int32;
     16 typedef unsigned long Py_UInt32;
     17 #else
     18 #error "No 4-byte integral type"
     19 #endif
     20 #endif
     21 
     22 #define CHARP(cp, xmax, x, y) ((char *)(cp+y*xmax+x))
     23 #define SHORTP(cp, xmax, x, y) ((short *)(cp+2*(y*xmax+x)))
     24 #define LONGP(cp, xmax, x, y) ((Py_Int32 *)(cp+4*(y*xmax+x)))
     25 
     26 static PyObject *ImageopError;
     27 static PyObject *ImageopDict;
     28 
     29 /**
     30  * Check a coordonnate, make sure that (0 < value).
     31  * Return 0 on error.
     32  */
     33 static int
     34 check_coordonnate(int value, const char* name)
     35 {
     36     if ( 0 < value)
     37         return 1;
     38     PyErr_Format(PyExc_ValueError, "%s value is negative or nul", name);
     39     return 0;
     40 }
     41 
     42 /**
     43  * Check integer overflow to make sure that product == x*y*size.
     44  * Return 0 on error.
     45  */
     46 static int
     47 check_multiply_size(int product, int x, const char* xname, int y, const char* yname, int size)
     48 {
     49     if ( !check_coordonnate(x, xname) )
     50         return 0;
     51     if ( !check_coordonnate(y, yname) )
     52         return 0;
     53     if ( size == (product / y) / x )
     54         return 1;
     55     PyErr_SetString(ImageopError, "String has incorrect length");
     56     return 0;
     57 }
     58 
     59 /**
     60  * Check integer overflow to make sure that product == x*y.
     61  * Return 0 on error.
     62  */
     63 static int
     64 check_multiply(int product, int x, int y)
     65 {
     66     return check_multiply_size(product, x, "x", y, "y", 1);
     67 }
     68 
     69 /* If this function returns true (the default if anything goes wrong), we're
     70    behaving in a backward-compatible way with respect to how multi-byte pixels
     71    are stored in the strings.  The code in this module was originally written
     72    for an SGI which is a big-endian system, and so the old code assumed that
     73    4-byte integers hold the R, G, and B values in a particular order.
     74    However, on little-endian systems the order is reversed, and so not
     75    actually compatible with what gl.lrectwrite and imgfile expect.
     76    (gl.lrectwrite and imgfile are also SGI-specific, however, it is
     77    conceivable that the data handled here comes from or goes to an SGI or that
     78    it is otherwise used in the expectation that the byte order in the strings
     79    is as specified.)
     80 
     81    The function returns the value of the module variable
     82    "backward_compatible", or 1 if the variable does not exist or is not an
     83    int.
     84  */
     85 
     86 static int
     87 imageop_backward_compatible(void)
     88 {
     89     static PyObject *bcos;
     90     PyObject *bco;
     91     long rc;
     92 
     93     if (ImageopDict == NULL) /* "cannot happen" */
     94         return 1;
     95     if (bcos == NULL) {
     96         /* cache string object for future use */
     97         bcos = PyString_FromString("backward_compatible");
     98         if (bcos == NULL)
     99             return 1;
    100     }
    101     bco = PyDict_GetItem(ImageopDict, bcos);
    102     if (bco == NULL)
    103         return 1;
    104     if (!PyInt_Check(bco))
    105         return 1;
    106     rc = PyInt_AsLong(bco);
    107     if (PyErr_Occurred()) {
    108         /* not an integer, or too large, or something */
    109         PyErr_Clear();
    110         rc = 1;
    111     }
    112     return rc != 0;             /* convert to values 0, 1 */
    113 }
    114 
    115 static PyObject *
    116 imageop_crop(PyObject *self, PyObject *args)
    117 {
    118     char *cp, *ncp;
    119     short *nsp;
    120     Py_Int32 *nlp;
    121     int len, size, x, y, newx1, newx2, newy1, newy2, nlen;
    122     int ix, iy, xstep, ystep;
    123     PyObject *rv;
    124 
    125     if ( !PyArg_ParseTuple(args, "s#iiiiiii", &cp, &len, &size, &x, &y,
    126                       &newx1, &newy1, &newx2, &newy2) )
    127         return 0;
    128 
    129     if ( size != 1 && size != 2 && size != 4 ) {
    130         PyErr_SetString(ImageopError, "Size should be 1, 2 or 4");
    131         return 0;
    132     }
    133     if ( !check_multiply_size(len, x, "x", y, "y", size) )
    134         return 0;
    135 
    136     xstep = (newx1 < newx2)? 1 : -1;
    137     ystep = (newy1 < newy2)? 1 : -1;
    138 
    139     nlen = (abs(newx2-newx1)+1)*(abs(newy2-newy1)+1)*size;
    140     if ( !check_multiply_size(nlen, abs(newx2-newx1)+1, "abs(newx2-newx1)+1", abs(newy2-newy1)+1, "abs(newy2-newy1)+1", size) )
    141         return 0;
    142     rv = PyString_FromStringAndSize(NULL, nlen);
    143     if ( rv == 0 )
    144         return 0;
    145     ncp = (char *)PyString_AsString(rv);
    146     nsp = (short *)ncp;
    147     nlp = (Py_Int32 *)ncp;
    148     newy2 += ystep;
    149     newx2 += xstep;
    150     for( iy = newy1; iy != newy2; iy+=ystep ) {
    151         for ( ix = newx1; ix != newx2; ix+=xstep ) {
    152             if ( iy < 0 || iy >= y || ix < 0 || ix >= x ) {
    153                 if ( size == 1 )
    154                     *ncp++ = 0;
    155                 else
    156                     *nlp++ = 0;
    157             } else {
    158                 if ( size == 1 )
    159                     *ncp++ = *CHARP(cp, x, ix, iy);
    160                 else if ( size == 2 )
    161                     *nsp++ = *SHORTP(cp, x, ix, iy);
    162                 else
    163                     *nlp++ = *LONGP(cp, x, ix, iy);
    164             }
    165         }
    166     }
    167     return rv;
    168 }
    169 
    170 static PyObject *
    171 imageop_scale(PyObject *self, PyObject *args)
    172 {
    173     char *cp, *ncp;
    174     short *nsp;
    175     Py_Int32 *nlp;
    176     int len, size, x, y, newx, newy, nlen;
    177     int ix, iy;
    178     int oix, oiy;
    179     PyObject *rv;
    180 
    181     if ( !PyArg_ParseTuple(args, "s#iiiii",
    182                       &cp, &len, &size, &x, &y, &newx, &newy) )
    183         return 0;
    184 
    185     if ( size != 1 && size != 2 && size != 4 ) {
    186         PyErr_SetString(ImageopError, "Size should be 1, 2 or 4");
    187         return 0;
    188     }
    189     if ( !check_multiply_size(len, x, "x", y, "y", size) )
    190         return 0;
    191     nlen = newx*newy*size;
    192     if ( !check_multiply_size(nlen, newx, "newx", newy, "newy", size) )
    193         return 0;
    194 
    195     rv = PyString_FromStringAndSize(NULL, nlen);
    196     if ( rv == 0 )
    197         return 0;
    198     ncp = (char *)PyString_AsString(rv);
    199     nsp = (short *)ncp;
    200     nlp = (Py_Int32 *)ncp;
    201     for( iy = 0; iy < newy; iy++ ) {
    202         for ( ix = 0; ix < newx; ix++ ) {
    203             oix = ix * x / newx;
    204             oiy = iy * y / newy;
    205             if ( size == 1 )
    206                 *ncp++ = *CHARP(cp, x, oix, oiy);
    207             else if ( size == 2 )
    208                 *nsp++ = *SHORTP(cp, x, oix, oiy);
    209             else
    210                 *nlp++ = *LONGP(cp, x, oix, oiy);
    211         }
    212     }
    213     return rv;
    214 }
    215 
    216 /* Note: this routine can use a bit of optimizing */
    217 
    218 static PyObject *
    219 imageop_tovideo(PyObject *self, PyObject *args)
    220 {
    221     int maxx, maxy, x, y, len;
    222     int i;
    223     unsigned char *cp, *ncp;
    224     int width;
    225     PyObject *rv;
    226 
    227 
    228     if ( !PyArg_ParseTuple(args, "s#iii", &cp, &len, &width, &maxx, &maxy) )
    229         return 0;
    230 
    231     if ( width != 1 && width != 4 ) {
    232         PyErr_SetString(ImageopError, "Size should be 1 or 4");
    233         return 0;
    234     }
    235     if ( !check_multiply_size(len, maxx, "max", maxy, "maxy", width) )
    236         return 0;
    237 
    238     rv = PyString_FromStringAndSize(NULL, len);
    239     if ( rv == 0 )
    240         return 0;
    241     ncp = (unsigned char *)PyString_AsString(rv);
    242 
    243     if ( width == 1 ) {
    244         memcpy(ncp, cp, maxx);                  /* Copy first line */
    245         ncp += maxx;
    246         for (y=1; y<maxy; y++) {                /* Interpolate other lines */
    247             for(x=0; x<maxx; x++) {
    248                 i = y*maxx + x;
    249                 *ncp++ = ((int)cp[i] + (int)cp[i-maxx]) >> 1;
    250             }
    251         }
    252     } else {
    253         memcpy(ncp, cp, maxx*4);                        /* Copy first line */
    254         ncp += maxx*4;
    255         for (y=1; y<maxy; y++) {                /* Interpolate other lines */
    256             for(x=0; x<maxx; x++) {
    257                 i = (y*maxx + x)*4 + 1;
    258                 *ncp++ = 0;                     /* Skip alfa comp */
    259                 *ncp++ = ((int)cp[i] + (int)cp[i-4*maxx]) >> 1;
    260                 i++;
    261                 *ncp++ = ((int)cp[i] + (int)cp[i-4*maxx]) >> 1;
    262                 i++;
    263                 *ncp++ = ((int)cp[i] + (int)cp[i-4*maxx]) >> 1;
    264             }
    265         }
    266     }
    267     return rv;
    268 }
    269 
    270 static PyObject *
    271 imageop_grey2mono(PyObject *self, PyObject *args)
    272 {
    273     int tres, x, y, len;
    274     unsigned char *cp, *ncp;
    275     unsigned char ovalue;
    276     PyObject *rv;
    277     int i, bit;
    278 
    279 
    280     if ( !PyArg_ParseTuple(args, "s#iii", &cp, &len, &x, &y, &tres) )
    281         return 0;
    282 
    283     if ( !check_multiply(len, x, y) )
    284         return 0;
    285 
    286     rv = PyString_FromStringAndSize(NULL, (len+7)/8);
    287     if ( rv == 0 )
    288         return 0;
    289     ncp = (unsigned char *)PyString_AsString(rv);
    290 
    291     bit = 0x80;
    292     ovalue = 0;
    293     for ( i=0; i < len; i++ ) {
    294         if ( (int)cp[i] > tres )
    295             ovalue |= bit;
    296         bit >>= 1;
    297         if ( bit == 0 ) {
    298             *ncp++ = ovalue;
    299             bit = 0x80;
    300             ovalue = 0;
    301         }
    302     }
    303     if ( bit != 0x80 )
    304         *ncp++ = ovalue;
    305     return rv;
    306 }
    307 
    308 static PyObject *
    309 imageop_grey2grey4(PyObject *self, PyObject *args)
    310 {
    311     int x, y, len;
    312     unsigned char *cp, *ncp;
    313     unsigned char ovalue;
    314     PyObject *rv;
    315     int i;
    316     int pos;
    317 
    318 
    319     if ( !PyArg_ParseTuple(args, "s#ii", &cp, &len, &x, &y) )
    320         return 0;
    321 
    322     if ( !check_multiply(len, x, y) )
    323         return 0;
    324 
    325     rv = PyString_FromStringAndSize(NULL, (len+1)/2);
    326     if ( rv == 0 )
    327         return 0;
    328     ncp = (unsigned char *)PyString_AsString(rv);
    329     pos = 0;
    330     ovalue = 0;
    331     for ( i=0; i < len; i++ ) {
    332         ovalue |= ((int)cp[i] & 0xf0) >> pos;
    333         pos += 4;
    334         if ( pos == 8 ) {
    335             *ncp++ = ovalue;
    336             ovalue = 0;
    337             pos = 0;
    338         }
    339     }
    340     if ( pos != 0 )
    341         *ncp++ = ovalue;
    342     return rv;
    343 }
    344 
    345 static PyObject *
    346 imageop_grey2grey2(PyObject *self, PyObject *args)
    347 {
    348     int x, y, len;
    349     unsigned char *cp, *ncp;
    350     unsigned char ovalue;
    351     PyObject *rv;
    352     int i;
    353     int pos;
    354 
    355 
    356     if ( !PyArg_ParseTuple(args, "s#ii", &cp, &len, &x, &y) )
    357         return 0;
    358 
    359     if ( !check_multiply(len, x, y) )
    360         return 0;
    361 
    362     rv = PyString_FromStringAndSize(NULL, (len+3)/4);
    363     if ( rv == 0 )
    364         return 0;
    365     ncp = (unsigned char *)PyString_AsString(rv);
    366     pos = 0;
    367     ovalue = 0;
    368     for ( i=0; i < len; i++ ) {
    369         ovalue |= ((int)cp[i] & 0xc0) >> pos;
    370         pos += 2;
    371         if ( pos == 8 ) {
    372             *ncp++ = ovalue;
    373             ovalue = 0;
    374             pos = 0;
    375         }
    376     }
    377     if ( pos != 0 )
    378         *ncp++ = ovalue;
    379     return rv;
    380 }
    381 
    382 static PyObject *
    383 imageop_dither2mono(PyObject *self, PyObject *args)
    384 {
    385     int sum, x, y, len;
    386     unsigned char *cp, *ncp;
    387     unsigned char ovalue;
    388     PyObject *rv;
    389     int i, bit;
    390 
    391 
    392     if ( !PyArg_ParseTuple(args, "s#ii", &cp, &len, &x, &y) )
    393         return 0;
    394 
    395     if ( !check_multiply(len, x, y) )
    396         return 0;
    397 
    398     rv = PyString_FromStringAndSize(NULL, (len+7)/8);
    399     if ( rv == 0 )
    400         return 0;
    401     ncp = (unsigned char *)PyString_AsString(rv);
    402 
    403     bit = 0x80;
    404     ovalue = 0;
    405     sum = 0;
    406     for ( i=0; i < len; i++ ) {
    407         sum += cp[i];
    408         if ( sum >= 256 ) {
    409             sum -= 256;
    410             ovalue |= bit;
    411         }
    412         bit >>= 1;
    413         if ( bit == 0 ) {
    414             *ncp++ = ovalue;
    415             bit = 0x80;
    416             ovalue = 0;
    417         }
    418     }
    419     if ( bit != 0x80 )
    420         *ncp++ = ovalue;
    421     return rv;
    422 }
    423 
    424 static PyObject *
    425 imageop_dither2grey2(PyObject *self, PyObject *args)
    426 {
    427     int x, y, len;
    428     unsigned char *cp, *ncp;
    429     unsigned char ovalue;
    430     PyObject *rv;
    431     int i;
    432     int pos;
    433     int sum = 0, nvalue;
    434 
    435 
    436     if ( !PyArg_ParseTuple(args, "s#ii", &cp, &len, &x, &y) )
    437         return 0;
    438 
    439     if ( !check_multiply(len, x, y) )
    440         return 0;
    441 
    442     rv = PyString_FromStringAndSize(NULL, (len+3)/4);
    443     if ( rv == 0 )
    444         return 0;
    445     ncp = (unsigned char *)PyString_AsString(rv);
    446     pos = 1;
    447     ovalue = 0;
    448     for ( i=0; i < len; i++ ) {
    449         sum += cp[i];
    450         nvalue = sum & 0x180;
    451         sum -= nvalue;
    452         ovalue |= nvalue >> pos;
    453         pos += 2;
    454         if ( pos == 9 ) {
    455             *ncp++ = ovalue;
    456             ovalue = 0;
    457             pos = 1;
    458         }
    459     }
    460     if ( pos != 0 )
    461         *ncp++ = ovalue;
    462     return rv;
    463 }
    464 
    465 static PyObject *
    466 imageop_mono2grey(PyObject *self, PyObject *args)
    467 {
    468     int v0, v1, x, y, len, nlen;
    469     unsigned char *cp, *ncp;
    470     PyObject *rv;
    471     int i, bit;
    472 
    473     if ( !PyArg_ParseTuple(args, "s#iiii", &cp, &len, &x, &y, &v0, &v1) )
    474         return 0;
    475 
    476     nlen = x*y;
    477     if ( !check_multiply(nlen, x, y) )
    478         return 0;
    479     if ( (nlen+7)/8 != len ) {
    480         PyErr_SetString(ImageopError, "String has incorrect length");
    481         return 0;
    482     }
    483 
    484     rv = PyString_FromStringAndSize(NULL, nlen);
    485     if ( rv == 0 )
    486         return 0;
    487     ncp = (unsigned char *)PyString_AsString(rv);
    488 
    489     bit = 0x80;
    490     for ( i=0; i < nlen; i++ ) {
    491         if ( *cp & bit )
    492             *ncp++ = v1;
    493         else
    494             *ncp++ = v0;
    495         bit >>= 1;
    496         if ( bit == 0 ) {
    497             bit = 0x80;
    498             cp++;
    499         }
    500     }
    501     return rv;
    502 }
    503 
    504 static PyObject *
    505 imageop_grey22grey(PyObject *self, PyObject *args)
    506 {
    507     int x, y, len, nlen;
    508     unsigned char *cp, *ncp;
    509     PyObject *rv;
    510     int i, pos, value = 0, nvalue;
    511 
    512     if ( !PyArg_ParseTuple(args, "s#ii", &cp, &len, &x, &y) )
    513         return 0;
    514 
    515     nlen = x*y;
    516     if ( !check_multiply(nlen, x, y) ) {
    517         return 0;
    518     }
    519     if ( (nlen+3)/4 != len ) {
    520         PyErr_SetString(ImageopError, "String has incorrect length");
    521         return 0;
    522     }
    523 
    524     rv = PyString_FromStringAndSize(NULL, nlen);
    525     if ( rv == 0 )
    526         return 0;
    527     ncp = (unsigned char *)PyString_AsString(rv);
    528 
    529     pos = 0;
    530     for ( i=0; i < nlen; i++ ) {
    531         if ( pos == 0 ) {
    532             value = *cp++;
    533             pos = 8;
    534         }
    535         pos -= 2;
    536         nvalue = (value >> pos) & 0x03;
    537         *ncp++ = nvalue | (nvalue << 2) |
    538                  (nvalue << 4) | (nvalue << 6);
    539     }
    540     return rv;
    541 }
    542 
    543 static PyObject *
    544 imageop_grey42grey(PyObject *self, PyObject *args)
    545 {
    546     int x, y, len, nlen;
    547     unsigned char *cp, *ncp;
    548     PyObject *rv;
    549     int i, pos, value = 0, nvalue;
    550 
    551     if ( !PyArg_ParseTuple(args, "s#ii", &cp, &len, &x, &y) )
    552         return 0;
    553 
    554     nlen = x*y;
    555     if ( !check_multiply(nlen, x, y) )
    556         return 0;
    557     if ( (nlen+1)/2 != len ) {
    558         PyErr_SetString(ImageopError, "String has incorrect length");
    559         return 0;
    560     }
    561 
    562     rv = PyString_FromStringAndSize(NULL, nlen);
    563     if ( rv == 0 )
    564         return 0;
    565     ncp = (unsigned char *)PyString_AsString(rv);
    566 
    567     pos = 0;
    568     for ( i=0; i < nlen; i++ ) {
    569         if ( pos == 0 ) {
    570             value = *cp++;
    571             pos = 8;
    572         }
    573         pos -= 4;
    574         nvalue = (value >> pos) & 0x0f;
    575         *ncp++ = nvalue | (nvalue << 4);
    576     }
    577     return rv;
    578 }
    579 
    580 static PyObject *
    581 imageop_rgb2rgb8(PyObject *self, PyObject *args)
    582 {
    583     int x, y, len, nlen;
    584     unsigned char *cp;
    585     unsigned char *ncp;
    586     PyObject *rv;
    587     int i, r, g, b;
    588     int backward_compatible = imageop_backward_compatible();
    589 
    590     if ( !PyArg_ParseTuple(args, "s#ii", &cp, &len, &x, &y) )
    591         return 0;
    592 
    593     if ( !check_multiply_size(len, x, "x", y, "y", 4) )
    594         return 0;
    595     nlen = x*y;
    596     if ( !check_multiply(nlen, x, y) )
    597         return 0;
    598 
    599     rv = PyString_FromStringAndSize(NULL, nlen);
    600     if ( rv == 0 )
    601         return 0;
    602     ncp = (unsigned char *)PyString_AsString(rv);
    603 
    604     for ( i=0; i < nlen; i++ ) {
    605         /* Bits in source: aaaaaaaa BBbbbbbb GGGggggg RRRrrrrr */
    606         if (backward_compatible) {
    607             Py_UInt32 value = * (Py_UInt32 *) cp;
    608             cp += 4;
    609             r = (int) ((value & 0xff) / 255. * 7. + .5);
    610             g = (int) (((value >> 8) & 0xff) / 255. * 7. + .5);
    611             b = (int) (((value >> 16) & 0xff) / 255. * 3. + .5);
    612         } else {
    613             cp++;                       /* skip alpha channel */
    614             b = (int) (*cp++ / 255. * 3. + .5);
    615             g = (int) (*cp++ / 255. * 7. + .5);
    616             r = (int) (*cp++ / 255. * 7. + .5);
    617         }
    618         *ncp++ = (unsigned char)((r<<5) | (b<<3) | g);
    619     }
    620     return rv;
    621 }
    622 
    623 static PyObject *
    624 imageop_rgb82rgb(PyObject *self, PyObject *args)
    625 {
    626     int x, y, len, nlen;
    627     unsigned char *cp;
    628     unsigned char *ncp;
    629     PyObject *rv;
    630     int i, r, g, b;
    631     unsigned char value;
    632     int backward_compatible = imageop_backward_compatible();
    633 
    634     if ( !PyArg_ParseTuple(args, "s#ii", &cp, &len, &x, &y) )
    635         return 0;
    636 
    637     if ( !check_multiply(len, x, y) )
    638         return 0;
    639     nlen = x*y*4;
    640     if ( !check_multiply_size(nlen, x, "x", y, "y", 4) )
    641         return 0;
    642 
    643     rv = PyString_FromStringAndSize(NULL, nlen);
    644     if ( rv == 0 )
    645         return 0;
    646     ncp = (unsigned char *)PyString_AsString(rv);
    647 
    648     for ( i=0; i < len; i++ ) {
    649         /* Bits in source: RRRBBGGG
    650         ** Red and Green are multiplied by 36.5, Blue by 85
    651         */
    652         value = *cp++;
    653         r = (value >> 5) & 7;
    654         g = (value     ) & 7;
    655         b = (value >> 3) & 3;
    656         r = (r<<5) | (r<<3) | (r>>1);
    657         g = (g<<5) | (g<<3) | (g>>1);
    658         b = (b<<6) | (b<<4) | (b<<2) | b;
    659         if (backward_compatible) {
    660             Py_UInt32 nvalue = r | (g<<8) | (b<<16);
    661             * (Py_UInt32 *) ncp = nvalue;
    662             ncp += 4;
    663         } else {
    664             *ncp++ = 0;
    665             *ncp++ = b;
    666             *ncp++ = g;
    667             *ncp++ = r;
    668         }
    669     }
    670     return rv;
    671 }
    672 
    673 static PyObject *
    674 imageop_rgb2grey(PyObject *self, PyObject *args)
    675 {
    676     int x, y, len, nlen;
    677     unsigned char *cp;
    678     unsigned char *ncp;
    679     PyObject *rv;
    680     int i, r, g, b;
    681     int nvalue;
    682     int backward_compatible = imageop_backward_compatible();
    683 
    684     if ( !PyArg_ParseTuple(args, "s#ii", &cp, &len, &x, &y) )
    685         return 0;
    686 
    687     if ( !check_multiply_size(len, x, "x", y, "y", 4) )
    688         return 0;
    689     nlen = x*y;
    690     if ( !check_multiply(nlen, x, y) )
    691         return 0;
    692 
    693     rv = PyString_FromStringAndSize(NULL, nlen);
    694     if ( rv == 0 )
    695         return 0;
    696     ncp = (unsigned char *)PyString_AsString(rv);
    697 
    698     for ( i=0; i < nlen; i++ ) {
    699         if (backward_compatible) {
    700             Py_UInt32 value = * (Py_UInt32 *) cp;
    701             cp += 4;
    702             r = (int) ((value & 0xff) / 255. * 7. + .5);
    703             g = (int) (((value >> 8) & 0xff) / 255. * 7. + .5);
    704             b = (int) (((value >> 16) & 0xff) / 255. * 3. + .5);
    705         } else {
    706             cp++;                       /* skip alpha channel */
    707             b = *cp++;
    708             g = *cp++;
    709             r = *cp++;
    710         }
    711         nvalue = (int)(0.30*r + 0.59*g + 0.11*b);
    712         if ( nvalue > 255 ) nvalue = 255;
    713         *ncp++ = (unsigned char)nvalue;
    714     }
    715     return rv;
    716 }
    717 
    718 static PyObject *
    719 imageop_grey2rgb(PyObject *self, PyObject *args)
    720 {
    721     int x, y, len, nlen;
    722     unsigned char *cp;
    723     unsigned char *ncp;
    724     PyObject *rv;
    725     int i;
    726     unsigned char value;
    727     int backward_compatible = imageop_backward_compatible();
    728 
    729     if ( !PyArg_ParseTuple(args, "s#ii", &cp, &len, &x, &y) )
    730         return 0;
    731 
    732     if ( !check_multiply(len, x, y) )
    733         return 0;
    734     nlen = x*y*4;
    735     if ( !check_multiply_size(nlen, x, "x", y, "y", 4) )
    736         return 0;
    737 
    738     rv = PyString_FromStringAndSize(NULL, nlen);
    739     if ( rv == 0 )
    740         return 0;
    741     ncp = (unsigned char *)PyString_AsString(rv);
    742 
    743     for ( i=0; i < len; i++ ) {
    744         value = *cp++;
    745         if (backward_compatible) {
    746             * (Py_UInt32 *) ncp = (Py_UInt32) value | ((Py_UInt32) value << 8 ) | ((Py_UInt32) value << 16);
    747             ncp += 4;
    748         } else {
    749             *ncp++ = 0;
    750             *ncp++ = value;
    751             *ncp++ = value;
    752             *ncp++ = value;
    753         }
    754     }
    755     return rv;
    756 }
    757 
    758 static PyMethodDef imageop_methods[] = {
    759     { "crop",                   imageop_crop, METH_VARARGS },
    760     { "scale",                  imageop_scale, METH_VARARGS },
    761     { "grey2mono",              imageop_grey2mono, METH_VARARGS },
    762     { "grey2grey2",             imageop_grey2grey2, METH_VARARGS },
    763     { "grey2grey4",             imageop_grey2grey4, METH_VARARGS },
    764     { "dither2mono",            imageop_dither2mono, METH_VARARGS },
    765     { "dither2grey2",           imageop_dither2grey2, METH_VARARGS },
    766     { "mono2grey",              imageop_mono2grey, METH_VARARGS },
    767     { "grey22grey",             imageop_grey22grey, METH_VARARGS },
    768     { "grey42grey",             imageop_grey42grey, METH_VARARGS },
    769     { "tovideo",                imageop_tovideo, METH_VARARGS },
    770     { "rgb2rgb8",               imageop_rgb2rgb8, METH_VARARGS },
    771     { "rgb82rgb",               imageop_rgb82rgb, METH_VARARGS },
    772     { "rgb2grey",               imageop_rgb2grey, METH_VARARGS },
    773     { "grey2rgb",               imageop_grey2rgb, METH_VARARGS },
    774     { 0,                    0 }
    775 };
    776 
    777 
    778 PyMODINIT_FUNC
    779 initimageop(void)
    780 {
    781     PyObject *m;
    782 
    783     if (PyErr_WarnPy3k("the imageop module has been removed in "
    784                        "Python 3.0", 2) < 0)
    785         return;
    786 
    787     m = Py_InitModule("imageop", imageop_methods);
    788     if (m == NULL)
    789         return;
    790     ImageopDict = PyModule_GetDict(m);
    791     ImageopError = PyErr_NewException("imageop.error", NULL, NULL);
    792     if (ImageopError != NULL)
    793         PyDict_SetItemString(ImageopDict, "error", ImageopError);
    794 }
    795