2 /* imageopmodule - Various operations on pictures */
12 typedef unsigned int Py_UInt32
;
15 typedef long Py_Int32
;
16 typedef unsigned long Py_UInt32
;
18 #error "No 4-byte integral type"
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)))
26 static PyObject
*ImageopError
;
27 static PyObject
*ImageopDict
;
30 * Check a coordonnate, make sure that (0 < value).
34 check_coordonnate(int value
, const char* name
)
38 PyErr_Format(PyExc_ValueError
, "%s value is negative or nul", name
);
43 * Check integer overflow to make sure that product == x*y*size.
47 check_multiply_size(int product
, int x
, const char* xname
, int y
, const char* yname
, int size
)
49 if ( !check_coordonnate(x
, xname
) )
51 if ( !check_coordonnate(y
, yname
) )
53 if ( size
== (product
/ y
) / x
)
55 PyErr_SetString(ImageopError
, "String has incorrect length");
60 * Check integer overflow to make sure that product == x*y.
64 check_multiply(int product
, int x
, int y
)
66 return check_multiply_size(product
, x
, "x", y
, "y", 1);
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
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
87 imageop_backward_compatible(void)
89 static PyObject
*bcos
;
93 if (ImageopDict
== NULL
) /* "cannot happen" */
96 /* cache string object for future use */
97 bcos
= PyString_FromString("backward_compatible");
101 bco
= PyDict_GetItem(ImageopDict
, bcos
);
104 if (!PyInt_Check(bco
))
106 rc
= PyInt_AsLong(bco
);
107 if (PyErr_Occurred()) {
108 /* not an integer, or too large, or something */
112 return rc
!= 0; /* convert to values 0, 1 */
116 imageop_crop(PyObject
*self
, PyObject
*args
)
121 int len
, size
, x
, y
, newx1
, newx2
, newy1
, newy2
, nlen
;
122 int ix
, iy
, xstep
, ystep
;
125 if ( !PyArg_ParseTuple(args
, "s#iiiiiii", &cp
, &len
, &size
, &x
, &y
,
126 &newx1
, &newy1
, &newx2
, &newy2
) )
129 if ( size
!= 1 && size
!= 2 && size
!= 4 ) {
130 PyErr_SetString(ImageopError
, "Size should be 1, 2 or 4");
133 if ( !check_multiply_size(len
, x
, "x", y
, "y", size
) )
136 xstep
= (newx1
< newx2
)? 1 : -1;
137 ystep
= (newy1
< newy2
)? 1 : -1;
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
) )
142 rv
= PyString_FromStringAndSize(NULL
, nlen
);
145 ncp
= (char *)PyString_AsString(rv
);
147 nlp
= (Py_Int32
*)ncp
;
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
) {
159 *ncp
++ = *CHARP(cp
, x
, ix
, iy
);
160 else if ( size
== 2 )
161 *nsp
++ = *SHORTP(cp
, x
, ix
, iy
);
163 *nlp
++ = *LONGP(cp
, x
, ix
, iy
);
171 imageop_scale(PyObject
*self
, PyObject
*args
)
176 int len
, size
, x
, y
, newx
, newy
, nlen
;
181 if ( !PyArg_ParseTuple(args
, "s#iiiii",
182 &cp
, &len
, &size
, &x
, &y
, &newx
, &newy
) )
185 if ( size
!= 1 && size
!= 2 && size
!= 4 ) {
186 PyErr_SetString(ImageopError
, "Size should be 1, 2 or 4");
189 if ( !check_multiply_size(len
, x
, "x", y
, "y", size
) )
191 nlen
= newx
*newy
*size
;
192 if ( !check_multiply_size(nlen
, newx
, "newx", newy
, "newy", size
) )
195 rv
= PyString_FromStringAndSize(NULL
, nlen
);
198 ncp
= (char *)PyString_AsString(rv
);
200 nlp
= (Py_Int32
*)ncp
;
201 for( iy
= 0; iy
< newy
; iy
++ ) {
202 for ( ix
= 0; ix
< newx
; ix
++ ) {
206 *ncp
++ = *CHARP(cp
, x
, oix
, oiy
);
207 else if ( size
== 2 )
208 *nsp
++ = *SHORTP(cp
, x
, oix
, oiy
);
210 *nlp
++ = *LONGP(cp
, x
, oix
, oiy
);
216 /* Note: this routine can use a bit of optimizing */
219 imageop_tovideo(PyObject
*self
, PyObject
*args
)
221 int maxx
, maxy
, x
, y
, len
;
223 unsigned char *cp
, *ncp
;
228 if ( !PyArg_ParseTuple(args
, "s#iii", &cp
, &len
, &width
, &maxx
, &maxy
) )
231 if ( width
!= 1 && width
!= 4 ) {
232 PyErr_SetString(ImageopError
, "Size should be 1 or 4");
235 if ( !check_multiply_size(len
, maxx
, "max", maxy
, "maxy", width
) )
238 rv
= PyString_FromStringAndSize(NULL
, len
);
241 ncp
= (unsigned char *)PyString_AsString(rv
);
244 memcpy(ncp
, cp
, maxx
); /* Copy first line */
246 for (y
=1; y
<maxy
; y
++) { /* Interpolate other lines */
247 for(x
=0; x
<maxx
; x
++) {
249 *ncp
++ = ((int)cp
[i
] + (int)cp
[i
-maxx
]) >> 1;
253 memcpy(ncp
, cp
, maxx
*4); /* Copy first line */
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;
261 *ncp
++ = ((int)cp
[i
] + (int)cp
[i
-4*maxx
]) >> 1;
263 *ncp
++ = ((int)cp
[i
] + (int)cp
[i
-4*maxx
]) >> 1;
271 imageop_grey2mono(PyObject
*self
, PyObject
*args
)
274 unsigned char *cp
, *ncp
;
275 unsigned char ovalue
;
280 if ( !PyArg_ParseTuple(args
, "s#iii", &cp
, &len
, &x
, &y
, &tres
) )
283 if ( !check_multiply(len
, x
, y
) )
286 rv
= PyString_FromStringAndSize(NULL
, (len
+7)/8);
289 ncp
= (unsigned char *)PyString_AsString(rv
);
293 for ( i
=0; i
< len
; i
++ ) {
294 if ( (int)cp
[i
] > tres
)
309 imageop_grey2grey4(PyObject
*self
, PyObject
*args
)
312 unsigned char *cp
, *ncp
;
313 unsigned char ovalue
;
319 if ( !PyArg_ParseTuple(args
, "s#ii", &cp
, &len
, &x
, &y
) )
322 if ( !check_multiply(len
, x
, y
) )
325 rv
= PyString_FromStringAndSize(NULL
, (len
+1)/2);
328 ncp
= (unsigned char *)PyString_AsString(rv
);
331 for ( i
=0; i
< len
; i
++ ) {
332 ovalue
|= ((int)cp
[i
] & 0xf0) >> pos
;
346 imageop_grey2grey2(PyObject
*self
, PyObject
*args
)
349 unsigned char *cp
, *ncp
;
350 unsigned char ovalue
;
356 if ( !PyArg_ParseTuple(args
, "s#ii", &cp
, &len
, &x
, &y
) )
359 if ( !check_multiply(len
, x
, y
) )
362 rv
= PyString_FromStringAndSize(NULL
, (len
+3)/4);
365 ncp
= (unsigned char *)PyString_AsString(rv
);
368 for ( i
=0; i
< len
; i
++ ) {
369 ovalue
|= ((int)cp
[i
] & 0xc0) >> pos
;
383 imageop_dither2mono(PyObject
*self
, PyObject
*args
)
386 unsigned char *cp
, *ncp
;
387 unsigned char ovalue
;
392 if ( !PyArg_ParseTuple(args
, "s#ii", &cp
, &len
, &x
, &y
) )
395 if ( !check_multiply(len
, x
, y
) )
398 rv
= PyString_FromStringAndSize(NULL
, (len
+7)/8);
401 ncp
= (unsigned char *)PyString_AsString(rv
);
406 for ( i
=0; i
< len
; i
++ ) {
425 imageop_dither2grey2(PyObject
*self
, PyObject
*args
)
428 unsigned char *cp
, *ncp
;
429 unsigned char ovalue
;
436 if ( !PyArg_ParseTuple(args
, "s#ii", &cp
, &len
, &x
, &y
) )
439 if ( !check_multiply(len
, x
, y
) )
442 rv
= PyString_FromStringAndSize(NULL
, (len
+3)/4);
445 ncp
= (unsigned char *)PyString_AsString(rv
);
448 for ( i
=0; i
< len
; i
++ ) {
450 nvalue
= sum
& 0x180;
452 ovalue
|= nvalue
>> pos
;
466 imageop_mono2grey(PyObject
*self
, PyObject
*args
)
468 int v0
, v1
, x
, y
, len
, nlen
;
469 unsigned char *cp
, *ncp
;
473 if ( !PyArg_ParseTuple(args
, "s#iiii", &cp
, &len
, &x
, &y
, &v0
, &v1
) )
477 if ( !check_multiply(nlen
, x
, y
) )
479 if ( (nlen
+7)/8 != len
) {
480 PyErr_SetString(ImageopError
, "String has incorrect length");
484 rv
= PyString_FromStringAndSize(NULL
, nlen
);
487 ncp
= (unsigned char *)PyString_AsString(rv
);
490 for ( i
=0; i
< nlen
; i
++ ) {
505 imageop_grey22grey(PyObject
*self
, PyObject
*args
)
508 unsigned char *cp
, *ncp
;
510 int i
, pos
, value
= 0, nvalue
;
512 if ( !PyArg_ParseTuple(args
, "s#ii", &cp
, &len
, &x
, &y
) )
516 if ( !check_multiply(nlen
, x
, y
) ) {
519 if ( (nlen
+3)/4 != len
) {
520 PyErr_SetString(ImageopError
, "String has incorrect length");
524 rv
= PyString_FromStringAndSize(NULL
, nlen
);
527 ncp
= (unsigned char *)PyString_AsString(rv
);
530 for ( i
=0; i
< nlen
; i
++ ) {
536 nvalue
= (value
>> pos
) & 0x03;
537 *ncp
++ = nvalue
| (nvalue
<< 2) |
538 (nvalue
<< 4) | (nvalue
<< 6);
544 imageop_grey42grey(PyObject
*self
, PyObject
*args
)
547 unsigned char *cp
, *ncp
;
549 int i
, pos
, value
= 0, nvalue
;
551 if ( !PyArg_ParseTuple(args
, "s#ii", &cp
, &len
, &x
, &y
) )
555 if ( !check_multiply(nlen
, x
, y
) )
557 if ( (nlen
+1)/2 != len
) {
558 PyErr_SetString(ImageopError
, "String has incorrect length");
562 rv
= PyString_FromStringAndSize(NULL
, nlen
);
565 ncp
= (unsigned char *)PyString_AsString(rv
);
568 for ( i
=0; i
< nlen
; i
++ ) {
574 nvalue
= (value
>> pos
) & 0x0f;
575 *ncp
++ = nvalue
| (nvalue
<< 4);
581 imageop_rgb2rgb8(PyObject
*self
, PyObject
*args
)
588 int backward_compatible
= imageop_backward_compatible();
590 if ( !PyArg_ParseTuple(args
, "s#ii", &cp
, &len
, &x
, &y
) )
593 if ( !check_multiply_size(len
, x
, "x", y
, "y", 4) )
596 if ( !check_multiply(nlen
, x
, y
) )
599 rv
= PyString_FromStringAndSize(NULL
, nlen
);
602 ncp
= (unsigned char *)PyString_AsString(rv
);
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
;
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);
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);
618 *ncp
++ = (unsigned char)((r
<<5) | (b
<<3) | g
);
624 imageop_rgb82rgb(PyObject
*self
, PyObject
*args
)
632 int backward_compatible
= imageop_backward_compatible();
634 if ( !PyArg_ParseTuple(args
, "s#ii", &cp
, &len
, &x
, &y
) )
637 if ( !check_multiply(len
, x
, y
) )
640 if ( !check_multiply_size(nlen
, x
, "x", y
, "y", 4) )
643 rv
= PyString_FromStringAndSize(NULL
, nlen
);
646 ncp
= (unsigned char *)PyString_AsString(rv
);
648 for ( i
=0; i
< len
; i
++ ) {
649 /* Bits in source: RRRBBGGG
650 ** Red and Green are multiplied by 36.5, Blue by 85
653 r
= (value
>> 5) & 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
;
674 imageop_rgb2grey(PyObject
*self
, PyObject
*args
)
682 int backward_compatible
= imageop_backward_compatible();
684 if ( !PyArg_ParseTuple(args
, "s#ii", &cp
, &len
, &x
, &y
) )
687 if ( !check_multiply_size(len
, x
, "x", y
, "y", 4) )
690 if ( !check_multiply(nlen
, x
, y
) )
693 rv
= PyString_FromStringAndSize(NULL
, nlen
);
696 ncp
= (unsigned char *)PyString_AsString(rv
);
698 for ( i
=0; i
< nlen
; i
++ ) {
699 if (backward_compatible
) {
700 Py_UInt32 value
= * (Py_UInt32
*) cp
;
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);
706 cp
++; /* skip alpha channel */
711 nvalue
= (int)(0.30*r
+ 0.59*g
+ 0.11*b
);
712 if ( nvalue
> 255 ) nvalue
= 255;
713 *ncp
++ = (unsigned char)nvalue
;
719 imageop_grey2rgb(PyObject
*self
, PyObject
*args
)
727 int backward_compatible
= imageop_backward_compatible();
729 if ( !PyArg_ParseTuple(args
, "s#ii", &cp
, &len
, &x
, &y
) )
732 if ( !check_multiply(len
, x
, y
) )
735 if ( !check_multiply_size(nlen
, x
, "x", y
, "y", 4) )
738 rv
= PyString_FromStringAndSize(NULL
, nlen
);
741 ncp
= (unsigned char *)PyString_AsString(rv
);
743 for ( i
=0; i
< len
; i
++ ) {
745 if (backward_compatible
) {
746 * (Py_UInt32
*) ncp
= (Py_UInt32
) value
| ((Py_UInt32
) value
<< 8 ) | ((Py_UInt32
) value
<< 16);
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
},
783 if (PyErr_WarnPy3k("the imageop module has been removed in "
784 "Python 3.0", 2) < 0)
787 m
= Py_InitModule("imageop", imageop_methods
);
790 ImageopDict
= PyModule_GetDict(m
);
791 ImageopError
= PyErr_NewException("imageop.error", NULL
, NULL
);
792 if (ImageopError
!= NULL
)
793 PyDict_SetItemString(ImageopDict
, "error", ImageopError
);