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
;
29 /* If this function returns true (the default if anything goes wrong), we're
30 behaving in a backward-compatible way with respect to how multi-byte pixels
31 are stored in the strings. The code in this module was originally written
32 for an SGI which is a big-endian system, and so the old code assumed that
33 4-byte integers hold the R, G, and B values in a particular order.
34 However, on little-endian systems the order is reversed, and so not
35 actually compatible with what gl.lrectwrite and imgfile expect.
36 (gl.lrectwrite and imgfile are also SGI-specific, however, it is
37 conceivable that the data handled here comes from or goes to an SGI or that
38 it is otherwise used in the expectation that the byte order in the strings
41 The function returns the value of the module variable
42 "backward_compatible", or 1 if the variable does not exist or is not an
47 imageop_backward_compatible(void)
49 static PyObject
*bcos
;
53 if (ImageopDict
== NULL
) /* "cannot happen" */
56 /* cache string object for future use */
57 bcos
= PyString_FromString("backward_compatible");
61 bco
= PyDict_GetItem(ImageopDict
, bcos
);
64 if (!PyInt_Check(bco
))
66 rc
= PyInt_AsLong(bco
);
67 if (PyErr_Occurred()) {
68 /* not an integer, or too large, or something */
72 return rc
!= 0; /* convert to values 0, 1 */
76 imageop_crop(PyObject
*self
, PyObject
*args
)
81 int len
, size
, x
, y
, newx1
, newx2
, newy1
, newy2
;
82 int ix
, iy
, xstep
, ystep
;
85 if ( !PyArg_ParseTuple(args
, "s#iiiiiii", &cp
, &len
, &size
, &x
, &y
,
86 &newx1
, &newy1
, &newx2
, &newy2
) )
89 if ( size
!= 1 && size
!= 2 && size
!= 4 ) {
90 PyErr_SetString(ImageopError
, "Size should be 1, 2 or 4");
93 if ( len
!= size
*x
*y
) {
94 PyErr_SetString(ImageopError
, "String has incorrect length");
97 xstep
= (newx1
< newx2
)? 1 : -1;
98 ystep
= (newy1
< newy2
)? 1 : -1;
100 rv
= PyString_FromStringAndSize(NULL
,
101 (abs(newx2
-newx1
)+1)*(abs(newy2
-newy1
)+1)*size
);
104 ncp
= (char *)PyString_AsString(rv
);
106 nlp
= (Py_Int32
*)ncp
;
109 for( iy
= newy1
; iy
!= newy2
; iy
+=ystep
) {
110 for ( ix
= newx1
; ix
!= newx2
; ix
+=xstep
) {
111 if ( iy
< 0 || iy
>= y
|| ix
< 0 || ix
>= x
) {
118 *ncp
++ = *CHARP(cp
, x
, ix
, iy
);
119 else if ( size
== 2 )
120 *nsp
++ = *SHORTP(cp
, x
, ix
, iy
);
122 *nlp
++ = *LONGP(cp
, x
, ix
, iy
);
130 imageop_scale(PyObject
*self
, PyObject
*args
)
135 int len
, size
, x
, y
, newx
, newy
;
140 if ( !PyArg_ParseTuple(args
, "s#iiiii",
141 &cp
, &len
, &size
, &x
, &y
, &newx
, &newy
) )
144 if ( size
!= 1 && size
!= 2 && size
!= 4 ) {
145 PyErr_SetString(ImageopError
, "Size should be 1, 2 or 4");
148 if ( len
!= size
*x
*y
) {
149 PyErr_SetString(ImageopError
, "String has incorrect length");
153 rv
= PyString_FromStringAndSize(NULL
, newx
*newy
*size
);
156 ncp
= (char *)PyString_AsString(rv
);
158 nlp
= (Py_Int32
*)ncp
;
159 for( iy
= 0; iy
< newy
; iy
++ ) {
160 for ( ix
= 0; ix
< newx
; ix
++ ) {
164 *ncp
++ = *CHARP(cp
, x
, oix
, oiy
);
165 else if ( size
== 2 )
166 *nsp
++ = *SHORTP(cp
, x
, oix
, oiy
);
168 *nlp
++ = *LONGP(cp
, x
, oix
, oiy
);
174 /* Note: this routine can use a bit of optimizing */
177 imageop_tovideo(PyObject
*self
, PyObject
*args
)
179 int maxx
, maxy
, x
, y
, len
;
181 unsigned char *cp
, *ncp
;
186 if ( !PyArg_ParseTuple(args
, "s#iii", &cp
, &len
, &width
, &maxx
, &maxy
) )
189 if ( width
!= 1 && width
!= 4 ) {
190 PyErr_SetString(ImageopError
, "Size should be 1 or 4");
193 if ( maxx
*maxy
*width
!= len
) {
194 PyErr_SetString(ImageopError
, "String has incorrect length");
198 rv
= PyString_FromStringAndSize(NULL
, len
);
201 ncp
= (unsigned char *)PyString_AsString(rv
);
204 memcpy(ncp
, cp
, maxx
); /* Copy first line */
206 for (y
=1; y
<maxy
; y
++) { /* Interpolate other lines */
207 for(x
=0; x
<maxx
; x
++) {
209 *ncp
++ = ((int)cp
[i
] + (int)cp
[i
-maxx
]) >> 1;
213 memcpy(ncp
, cp
, maxx
*4); /* Copy first line */
215 for (y
=1; y
<maxy
; y
++) { /* Interpolate other lines */
216 for(x
=0; x
<maxx
; x
++) {
217 i
= (y
*maxx
+ x
)*4 + 1;
218 *ncp
++ = 0; /* Skip alfa comp */
219 *ncp
++ = ((int)cp
[i
] + (int)cp
[i
-4*maxx
]) >> 1;
221 *ncp
++ = ((int)cp
[i
] + (int)cp
[i
-4*maxx
]) >> 1;
223 *ncp
++ = ((int)cp
[i
] + (int)cp
[i
-4*maxx
]) >> 1;
231 imageop_grey2mono(PyObject
*self
, PyObject
*args
)
234 unsigned char *cp
, *ncp
;
235 unsigned char ovalue
;
240 if ( !PyArg_ParseTuple(args
, "s#iii", &cp
, &len
, &x
, &y
, &tres
) )
244 PyErr_SetString(ImageopError
, "String has incorrect length");
248 rv
= PyString_FromStringAndSize(NULL
, (len
+7)/8);
251 ncp
= (unsigned char *)PyString_AsString(rv
);
255 for ( i
=0; i
< len
; i
++ ) {
256 if ( (int)cp
[i
] > tres
)
271 imageop_grey2grey4(PyObject
*self
, PyObject
*args
)
274 unsigned char *cp
, *ncp
;
275 unsigned char ovalue
;
281 if ( !PyArg_ParseTuple(args
, "s#ii", &cp
, &len
, &x
, &y
) )
285 PyErr_SetString(ImageopError
, "String has incorrect length");
289 rv
= PyString_FromStringAndSize(NULL
, (len
+1)/2);
292 ncp
= (unsigned char *)PyString_AsString(rv
);
295 for ( i
=0; i
< len
; i
++ ) {
296 ovalue
|= ((int)cp
[i
] & 0xf0) >> pos
;
310 imageop_grey2grey2(PyObject
*self
, PyObject
*args
)
313 unsigned char *cp
, *ncp
;
314 unsigned char ovalue
;
320 if ( !PyArg_ParseTuple(args
, "s#ii", &cp
, &len
, &x
, &y
) )
324 PyErr_SetString(ImageopError
, "String has incorrect length");
328 rv
= PyString_FromStringAndSize(NULL
, (len
+3)/4);
331 ncp
= (unsigned char *)PyString_AsString(rv
);
334 for ( i
=0; i
< len
; i
++ ) {
335 ovalue
|= ((int)cp
[i
] & 0xc0) >> pos
;
349 imageop_dither2mono(PyObject
*self
, PyObject
*args
)
352 unsigned char *cp
, *ncp
;
353 unsigned char ovalue
;
358 if ( !PyArg_ParseTuple(args
, "s#ii", &cp
, &len
, &x
, &y
) )
362 PyErr_SetString(ImageopError
, "String has incorrect length");
366 rv
= PyString_FromStringAndSize(NULL
, (len
+7)/8);
369 ncp
= (unsigned char *)PyString_AsString(rv
);
374 for ( i
=0; i
< len
; i
++ ) {
393 imageop_dither2grey2(PyObject
*self
, PyObject
*args
)
396 unsigned char *cp
, *ncp
;
397 unsigned char ovalue
;
404 if ( !PyArg_ParseTuple(args
, "s#ii", &cp
, &len
, &x
, &y
) )
408 PyErr_SetString(ImageopError
, "String has incorrect length");
412 rv
= PyString_FromStringAndSize(NULL
, (len
+3)/4);
415 ncp
= (unsigned char *)PyString_AsString(rv
);
418 for ( i
=0; i
< len
; i
++ ) {
420 nvalue
= sum
& 0x180;
422 ovalue
|= nvalue
>> pos
;
436 imageop_mono2grey(PyObject
*self
, PyObject
*args
)
438 int v0
, v1
, x
, y
, len
, nlen
;
439 unsigned char *cp
, *ncp
;
443 if ( !PyArg_ParseTuple(args
, "s#iiii", &cp
, &len
, &x
, &y
, &v0
, &v1
) )
447 if ( (nlen
+7)/8 != len
) {
448 PyErr_SetString(ImageopError
, "String has incorrect length");
452 rv
= PyString_FromStringAndSize(NULL
, nlen
);
455 ncp
= (unsigned char *)PyString_AsString(rv
);
458 for ( i
=0; i
< nlen
; i
++ ) {
473 imageop_grey22grey(PyObject
*self
, PyObject
*args
)
476 unsigned char *cp
, *ncp
;
478 int i
, pos
, value
= 0, nvalue
;
480 if ( !PyArg_ParseTuple(args
, "s#ii", &cp
, &len
, &x
, &y
) )
484 if ( (nlen
+3)/4 != len
) {
485 PyErr_SetString(ImageopError
, "String has incorrect length");
489 rv
= PyString_FromStringAndSize(NULL
, nlen
);
492 ncp
= (unsigned char *)PyString_AsString(rv
);
495 for ( i
=0; i
< nlen
; i
++ ) {
501 nvalue
= (value
>> pos
) & 0x03;
502 *ncp
++ = nvalue
| (nvalue
<< 2) |
503 (nvalue
<< 4) | (nvalue
<< 6);
509 imageop_grey42grey(PyObject
*self
, PyObject
*args
)
512 unsigned char *cp
, *ncp
;
514 int i
, pos
, value
= 0, nvalue
;
516 if ( !PyArg_ParseTuple(args
, "s#ii", &cp
, &len
, &x
, &y
) )
520 if ( (nlen
+1)/2 != len
) {
521 PyErr_SetString(ImageopError
, "String has incorrect length");
525 rv
= PyString_FromStringAndSize(NULL
, nlen
);
528 ncp
= (unsigned char *)PyString_AsString(rv
);
531 for ( i
=0; i
< nlen
; i
++ ) {
537 nvalue
= (value
>> pos
) & 0x0f;
538 *ncp
++ = nvalue
| (nvalue
<< 4);
544 imageop_rgb2rgb8(PyObject
*self
, PyObject
*args
)
551 int backward_compatible
= imageop_backward_compatible();
553 if ( !PyArg_ParseTuple(args
, "s#ii", &cp
, &len
, &x
, &y
) )
557 if ( nlen
*4 != len
) {
558 PyErr_SetString(ImageopError
, "String has incorrect length");
562 rv
= PyString_FromStringAndSize(NULL
, nlen
);
565 ncp
= (unsigned char *)PyString_AsString(rv
);
567 for ( i
=0; i
< nlen
; i
++ ) {
568 /* Bits in source: aaaaaaaa BBbbbbbb GGGggggg RRRrrrrr */
569 if (backward_compatible
) {
570 Py_UInt32 value
= * (Py_UInt32
*) cp
;
572 r
= (int) ((value
& 0xff) / 255. * 7. + .5);
573 g
= (int) (((value
>> 8) & 0xff) / 255. * 7. + .5);
574 b
= (int) (((value
>> 16) & 0xff) / 255. * 3. + .5);
576 cp
++; /* skip alpha channel */
577 b
= (int) (*cp
++ / 255. * 3. + .5);
578 g
= (int) (*cp
++ / 255. * 7. + .5);
579 r
= (int) (*cp
++ / 255. * 7. + .5);
581 *ncp
++ = (unsigned char)((r
<<5) | (b
<<3) | g
);
587 imageop_rgb82rgb(PyObject
*self
, PyObject
*args
)
595 int backward_compatible
= imageop_backward_compatible();
597 if ( !PyArg_ParseTuple(args
, "s#ii", &cp
, &len
, &x
, &y
) )
602 PyErr_SetString(ImageopError
, "String has incorrect length");
606 rv
= PyString_FromStringAndSize(NULL
, nlen
*4);
609 ncp
= (unsigned char *)PyString_AsString(rv
);
611 for ( i
=0; i
< nlen
; i
++ ) {
612 /* Bits in source: RRRBBGGG
613 ** Red and Green are multiplied by 36.5, Blue by 85
616 r
= (value
>> 5) & 7;
618 b
= (value
>> 3) & 3;
619 r
= (r
<<5) | (r
<<3) | (r
>>1);
620 g
= (g
<<5) | (g
<<3) | (g
>>1);
621 b
= (b
<<6) | (b
<<4) | (b
<<2) | b
;
622 if (backward_compatible
) {
623 Py_UInt32 nvalue
= r
| (g
<<8) | (b
<<16);
624 * (Py_UInt32
*) ncp
= nvalue
;
637 imageop_rgb2grey(PyObject
*self
, PyObject
*args
)
645 int backward_compatible
= imageop_backward_compatible();
647 if ( !PyArg_ParseTuple(args
, "s#ii", &cp
, &len
, &x
, &y
) )
651 if ( nlen
*4 != len
) {
652 PyErr_SetString(ImageopError
, "String has incorrect length");
656 rv
= PyString_FromStringAndSize(NULL
, nlen
);
659 ncp
= (unsigned char *)PyString_AsString(rv
);
661 for ( i
=0; i
< nlen
; i
++ ) {
662 if (backward_compatible
) {
663 Py_UInt32 value
= * (Py_UInt32
*) cp
;
665 r
= (int) ((value
& 0xff) / 255. * 7. + .5);
666 g
= (int) (((value
>> 8) & 0xff) / 255. * 7. + .5);
667 b
= (int) (((value
>> 16) & 0xff) / 255. * 3. + .5);
669 cp
++; /* skip alpha channel */
674 nvalue
= (int)(0.30*r
+ 0.59*g
+ 0.11*b
);
675 if ( nvalue
> 255 ) nvalue
= 255;
676 *ncp
++ = (unsigned char)nvalue
;
682 imageop_grey2rgb(PyObject
*self
, PyObject
*args
)
690 int backward_compatible
= imageop_backward_compatible();
692 if ( !PyArg_ParseTuple(args
, "s#ii", &cp
, &len
, &x
, &y
) )
697 PyErr_SetString(ImageopError
, "String has incorrect length");
701 rv
= PyString_FromStringAndSize(NULL
, nlen
*4);
704 ncp
= (unsigned char *)PyString_AsString(rv
);
706 for ( i
=0; i
< nlen
; i
++ ) {
708 if (backward_compatible
) {
709 * (Py_UInt32
*) ncp
= (Py_UInt32
) value
| ((Py_UInt32
) value
<< 8 ) | ((Py_UInt32
) value
<< 16);
723 imageop_mul(object *self, object *args)
730 if ( !getargs(args, "(s#iii)", &cp, &len, &size, &x, &y) )
733 if ( size != 1 && size != 4 ) {
734 err_setstr(ImageopError, "Size should be 1 or 4");
737 if ( len != size*x*y ) {
738 err_setstr(ImageopError, "String has incorrect length");
742 rv = newsizedstringobject(NULL, XXXX);
745 ncp = (char *)getstringvalue(rv);
748 for ( i=0; i < len; i += size ) {
754 static PyMethodDef imageop_methods
[] = {
755 { "crop", imageop_crop
, METH_VARARGS
},
756 { "scale", imageop_scale
, METH_VARARGS
},
757 { "grey2mono", imageop_grey2mono
, METH_VARARGS
},
758 { "grey2grey2", imageop_grey2grey2
, METH_VARARGS
},
759 { "grey2grey4", imageop_grey2grey4
, METH_VARARGS
},
760 { "dither2mono", imageop_dither2mono
, METH_VARARGS
},
761 { "dither2grey2", imageop_dither2grey2
, METH_VARARGS
},
762 { "mono2grey", imageop_mono2grey
, METH_VARARGS
},
763 { "grey22grey", imageop_grey22grey
, METH_VARARGS
},
764 { "grey42grey", imageop_grey42grey
, METH_VARARGS
},
765 { "tovideo", imageop_tovideo
, METH_VARARGS
},
766 { "rgb2rgb8", imageop_rgb2rgb8
, METH_VARARGS
},
767 { "rgb82rgb", imageop_rgb82rgb
, METH_VARARGS
},
768 { "rgb2grey", imageop_rgb2grey
, METH_VARARGS
},
769 { "grey2rgb", imageop_grey2rgb
, METH_VARARGS
},
778 m
= Py_InitModule("imageop", imageop_methods
);
781 ImageopDict
= PyModule_GetDict(m
);
782 ImageopError
= PyErr_NewException("imageop.error", NULL
, NULL
);
783 if (ImageopError
!= NULL
)
784 PyDict_SetItemString(ImageopDict
, "error", ImageopError
);