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