Python-2.7.3/Modules/imageop.c

No issues found

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