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
11typedef int Py_Int32;
12typedef unsigned int Py_UInt32;
13#else
14#if SIZEOF_LONG == 4
15typedef long Py_Int32;
16typedef 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
26static PyObject *ImageopError;
27static PyObject *ImageopDict;
28
29/**
30 * Check a coordonnate, make sure that (0 < value).
31 * Return 0 on error.
32 */
33static int
34check_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 */
46static int
47check_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 */
66static int
67check_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
89static int
90imageop_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
118static PyObject *
119imageop_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
173static PyObject *
174imageop_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
221static PyObject *
222imageop_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
273static PyObject *
274imageop_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
311static PyObject *
312imageop_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
348static PyObject *
349imageop_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
385static PyObject *
386imageop_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
427static PyObject *
428imageop_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
468static PyObject *
469imageop_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
507static PyObject *
508imageop_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
546static PyObject *
547imageop_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
583static PyObject *
584imageop_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
626static PyObject *
627imageop_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
676static PyObject *
677imageop_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
721static PyObject *
722imageop_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
761static 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
781PyMODINIT_FUNC
782initimageop(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