Fixed bug in time-to-midnight calculation.
[python.git] / Modules / imageop.c
blob5b87898bbbfd686e29fdf1e763f5769e84105e2e
2 /* imageopmodule - Various operations on pictures */
4 #ifdef sun
5 #define signed
6 #endif
8 #include "Python.h"
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
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
39 is as specified.)
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
43 int.
46 static int
47 imageop_backward_compatible(void)
49 static PyObject *bcos;
50 PyObject *bco;
51 long rc;
53 if (ImageopDict == NULL) /* "cannot happen" */
54 return 1;
55 if (bcos == NULL) {
56 /* cache string object for future use */
57 bcos = PyString_FromString("backward_compatible");
58 if (bcos == NULL)
59 return 1;
61 bco = PyDict_GetItem(ImageopDict, bcos);
62 if (bco == NULL)
63 return 1;
64 if (!PyInt_Check(bco))
65 return 1;
66 rc = PyInt_AsLong(bco);
67 if (PyErr_Occurred()) {
68 /* not an integer, or too large, or something */
69 PyErr_Clear();
70 rc = 1;
72 return rc != 0; /* convert to values 0, 1 */
75 static PyObject *
76 imageop_crop(PyObject *self, PyObject *args)
78 char *cp, *ncp;
79 short *nsp;
80 Py_Int32 *nlp;
81 int len, size, x, y, newx1, newx2, newy1, newy2;
82 int ix, iy, xstep, ystep;
83 PyObject *rv;
85 if ( !PyArg_ParseTuple(args, "s#iiiiiii", &cp, &len, &size, &x, &y,
86 &newx1, &newy1, &newx2, &newy2) )
87 return 0;
89 if ( size != 1 && size != 2 && size != 4 ) {
90 PyErr_SetString(ImageopError, "Size should be 1, 2 or 4");
91 return 0;
93 if ( len != size*x*y ) {
94 PyErr_SetString(ImageopError, "String has incorrect length");
95 return 0;
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);
102 if ( rv == 0 )
103 return 0;
104 ncp = (char *)PyString_AsString(rv);
105 nsp = (short *)ncp;
106 nlp = (Py_Int32 *)ncp;
107 newy2 += ystep;
108 newx2 += xstep;
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 ) {
112 if ( size == 1 )
113 *ncp++ = 0;
114 else
115 *nlp++ = 0;
116 } else {
117 if ( size == 1 )
118 *ncp++ = *CHARP(cp, x, ix, iy);
119 else if ( size == 2 )
120 *nsp++ = *SHORTP(cp, x, ix, iy);
121 else
122 *nlp++ = *LONGP(cp, x, ix, iy);
126 return rv;
129 static PyObject *
130 imageop_scale(PyObject *self, PyObject *args)
132 char *cp, *ncp;
133 short *nsp;
134 Py_Int32 *nlp;
135 int len, size, x, y, newx, newy;
136 int ix, iy;
137 int oix, oiy;
138 PyObject *rv;
140 if ( !PyArg_ParseTuple(args, "s#iiiii",
141 &cp, &len, &size, &x, &y, &newx, &newy) )
142 return 0;
144 if ( size != 1 && size != 2 && size != 4 ) {
145 PyErr_SetString(ImageopError, "Size should be 1, 2 or 4");
146 return 0;
148 if ( len != size*x*y ) {
149 PyErr_SetString(ImageopError, "String has incorrect length");
150 return 0;
153 rv = PyString_FromStringAndSize(NULL, newx*newy*size);
154 if ( rv == 0 )
155 return 0;
156 ncp = (char *)PyString_AsString(rv);
157 nsp = (short *)ncp;
158 nlp = (Py_Int32 *)ncp;
159 for( iy = 0; iy < newy; iy++ ) {
160 for ( ix = 0; ix < newx; ix++ ) {
161 oix = ix * x / newx;
162 oiy = iy * y / newy;
163 if ( size == 1 )
164 *ncp++ = *CHARP(cp, x, oix, oiy);
165 else if ( size == 2 )
166 *nsp++ = *SHORTP(cp, x, oix, oiy);
167 else
168 *nlp++ = *LONGP(cp, x, oix, oiy);
171 return rv;
174 /* Note: this routine can use a bit of optimizing */
176 static PyObject *
177 imageop_tovideo(PyObject *self, PyObject *args)
179 int maxx, maxy, x, y, len;
180 int i;
181 unsigned char *cp, *ncp;
182 int width;
183 PyObject *rv;
186 if ( !PyArg_ParseTuple(args, "s#iii", &cp, &len, &width, &maxx, &maxy) )
187 return 0;
189 if ( width != 1 && width != 4 ) {
190 PyErr_SetString(ImageopError, "Size should be 1 or 4");
191 return 0;
193 if ( maxx*maxy*width != len ) {
194 PyErr_SetString(ImageopError, "String has incorrect length");
195 return 0;
198 rv = PyString_FromStringAndSize(NULL, len);
199 if ( rv == 0 )
200 return 0;
201 ncp = (unsigned char *)PyString_AsString(rv);
203 if ( width == 1 ) {
204 memcpy(ncp, cp, maxx); /* Copy first line */
205 ncp += maxx;
206 for (y=1; y<maxy; y++) { /* Interpolate other lines */
207 for(x=0; x<maxx; x++) {
208 i = y*maxx + x;
209 *ncp++ = ((int)cp[i] + (int)cp[i-maxx]) >> 1;
212 } else {
213 memcpy(ncp, cp, maxx*4); /* Copy first line */
214 ncp += maxx*4;
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;
220 i++;
221 *ncp++ = ((int)cp[i] + (int)cp[i-4*maxx]) >> 1;
222 i++;
223 *ncp++ = ((int)cp[i] + (int)cp[i-4*maxx]) >> 1;
227 return rv;
230 static PyObject *
231 imageop_grey2mono(PyObject *self, PyObject *args)
233 int tres, x, y, len;
234 unsigned char *cp, *ncp;
235 unsigned char ovalue;
236 PyObject *rv;
237 int i, bit;
240 if ( !PyArg_ParseTuple(args, "s#iii", &cp, &len, &x, &y, &tres) )
241 return 0;
243 if ( x*y != len ) {
244 PyErr_SetString(ImageopError, "String has incorrect length");
245 return 0;
248 rv = PyString_FromStringAndSize(NULL, (len+7)/8);
249 if ( rv == 0 )
250 return 0;
251 ncp = (unsigned char *)PyString_AsString(rv);
253 bit = 0x80;
254 ovalue = 0;
255 for ( i=0; i < len; i++ ) {
256 if ( (int)cp[i] > tres )
257 ovalue |= bit;
258 bit >>= 1;
259 if ( bit == 0 ) {
260 *ncp++ = ovalue;
261 bit = 0x80;
262 ovalue = 0;
265 if ( bit != 0x80 )
266 *ncp++ = ovalue;
267 return rv;
270 static PyObject *
271 imageop_grey2grey4(PyObject *self, PyObject *args)
273 int x, y, len;
274 unsigned char *cp, *ncp;
275 unsigned char ovalue;
276 PyObject *rv;
277 int i;
278 int pos;
281 if ( !PyArg_ParseTuple(args, "s#ii", &cp, &len, &x, &y) )
282 return 0;
284 if ( x*y != len ) {
285 PyErr_SetString(ImageopError, "String has incorrect length");
286 return 0;
289 rv = PyString_FromStringAndSize(NULL, (len+1)/2);
290 if ( rv == 0 )
291 return 0;
292 ncp = (unsigned char *)PyString_AsString(rv);
293 pos = 0;
294 ovalue = 0;
295 for ( i=0; i < len; i++ ) {
296 ovalue |= ((int)cp[i] & 0xf0) >> pos;
297 pos += 4;
298 if ( pos == 8 ) {
299 *ncp++ = ovalue;
300 ovalue = 0;
301 pos = 0;
304 if ( pos != 0 )
305 *ncp++ = ovalue;
306 return rv;
309 static PyObject *
310 imageop_grey2grey2(PyObject *self, PyObject *args)
312 int x, y, len;
313 unsigned char *cp, *ncp;
314 unsigned char ovalue;
315 PyObject *rv;
316 int i;
317 int pos;
320 if ( !PyArg_ParseTuple(args, "s#ii", &cp, &len, &x, &y) )
321 return 0;
323 if ( x*y != len ) {
324 PyErr_SetString(ImageopError, "String has incorrect length");
325 return 0;
328 rv = PyString_FromStringAndSize(NULL, (len+3)/4);
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] & 0xc0) >> pos;
336 pos += 2;
337 if ( pos == 8 ) {
338 *ncp++ = ovalue;
339 ovalue = 0;
340 pos = 0;
343 if ( pos != 0 )
344 *ncp++ = ovalue;
345 return rv;
348 static PyObject *
349 imageop_dither2mono(PyObject *self, PyObject *args)
351 int sum, x, y, len;
352 unsigned char *cp, *ncp;
353 unsigned char ovalue;
354 PyObject *rv;
355 int i, bit;
358 if ( !PyArg_ParseTuple(args, "s#ii", &cp, &len, &x, &y) )
359 return 0;
361 if ( x*y != len ) {
362 PyErr_SetString(ImageopError, "String has incorrect length");
363 return 0;
366 rv = PyString_FromStringAndSize(NULL, (len+7)/8);
367 if ( rv == 0 )
368 return 0;
369 ncp = (unsigned char *)PyString_AsString(rv);
371 bit = 0x80;
372 ovalue = 0;
373 sum = 0;
374 for ( i=0; i < len; i++ ) {
375 sum += cp[i];
376 if ( sum >= 256 ) {
377 sum -= 256;
378 ovalue |= bit;
380 bit >>= 1;
381 if ( bit == 0 ) {
382 *ncp++ = ovalue;
383 bit = 0x80;
384 ovalue = 0;
387 if ( bit != 0x80 )
388 *ncp++ = ovalue;
389 return rv;
392 static PyObject *
393 imageop_dither2grey2(PyObject *self, PyObject *args)
395 int x, y, len;
396 unsigned char *cp, *ncp;
397 unsigned char ovalue;
398 PyObject *rv;
399 int i;
400 int pos;
401 int sum = 0, nvalue;
404 if ( !PyArg_ParseTuple(args, "s#ii", &cp, &len, &x, &y) )
405 return 0;
407 if ( x*y != len ) {
408 PyErr_SetString(ImageopError, "String has incorrect length");
409 return 0;
412 rv = PyString_FromStringAndSize(NULL, (len+3)/4);
413 if ( rv == 0 )
414 return 0;
415 ncp = (unsigned char *)PyString_AsString(rv);
416 pos = 1;
417 ovalue = 0;
418 for ( i=0; i < len; i++ ) {
419 sum += cp[i];
420 nvalue = sum & 0x180;
421 sum -= nvalue;
422 ovalue |= nvalue >> pos;
423 pos += 2;
424 if ( pos == 9 ) {
425 *ncp++ = ovalue;
426 ovalue = 0;
427 pos = 1;
430 if ( pos != 0 )
431 *ncp++ = ovalue;
432 return rv;
435 static PyObject *
436 imageop_mono2grey(PyObject *self, PyObject *args)
438 int v0, v1, x, y, len, nlen;
439 unsigned char *cp, *ncp;
440 PyObject *rv;
441 int i, bit;
443 if ( !PyArg_ParseTuple(args, "s#iiii", &cp, &len, &x, &y, &v0, &v1) )
444 return 0;
446 nlen = x*y;
447 if ( (nlen+7)/8 != len ) {
448 PyErr_SetString(ImageopError, "String has incorrect length");
449 return 0;
452 rv = PyString_FromStringAndSize(NULL, nlen);
453 if ( rv == 0 )
454 return 0;
455 ncp = (unsigned char *)PyString_AsString(rv);
457 bit = 0x80;
458 for ( i=0; i < nlen; i++ ) {
459 if ( *cp & bit )
460 *ncp++ = v1;
461 else
462 *ncp++ = v0;
463 bit >>= 1;
464 if ( bit == 0 ) {
465 bit = 0x80;
466 cp++;
469 return rv;
472 static PyObject *
473 imageop_grey22grey(PyObject *self, PyObject *args)
475 int x, y, len, nlen;
476 unsigned char *cp, *ncp;
477 PyObject *rv;
478 int i, pos, value = 0, nvalue;
480 if ( !PyArg_ParseTuple(args, "s#ii", &cp, &len, &x, &y) )
481 return 0;
483 nlen = x*y;
484 if ( (nlen+3)/4 != len ) {
485 PyErr_SetString(ImageopError, "String has incorrect length");
486 return 0;
489 rv = PyString_FromStringAndSize(NULL, nlen);
490 if ( rv == 0 )
491 return 0;
492 ncp = (unsigned char *)PyString_AsString(rv);
494 pos = 0;
495 for ( i=0; i < nlen; i++ ) {
496 if ( pos == 0 ) {
497 value = *cp++;
498 pos = 8;
500 pos -= 2;
501 nvalue = (value >> pos) & 0x03;
502 *ncp++ = nvalue | (nvalue << 2) |
503 (nvalue << 4) | (nvalue << 6);
505 return rv;
508 static PyObject *
509 imageop_grey42grey(PyObject *self, PyObject *args)
511 int x, y, len, nlen;
512 unsigned char *cp, *ncp;
513 PyObject *rv;
514 int i, pos, value = 0, nvalue;
516 if ( !PyArg_ParseTuple(args, "s#ii", &cp, &len, &x, &y) )
517 return 0;
519 nlen = x*y;
520 if ( (nlen+1)/2 != len ) {
521 PyErr_SetString(ImageopError, "String has incorrect length");
522 return 0;
525 rv = PyString_FromStringAndSize(NULL, nlen);
526 if ( rv == 0 )
527 return 0;
528 ncp = (unsigned char *)PyString_AsString(rv);
530 pos = 0;
531 for ( i=0; i < nlen; i++ ) {
532 if ( pos == 0 ) {
533 value = *cp++;
534 pos = 8;
536 pos -= 4;
537 nvalue = (value >> pos) & 0x0f;
538 *ncp++ = nvalue | (nvalue << 4);
540 return rv;
543 static PyObject *
544 imageop_rgb2rgb8(PyObject *self, PyObject *args)
546 int x, y, len, nlen;
547 unsigned char *cp;
548 unsigned char *ncp;
549 PyObject *rv;
550 int i, r, g, b;
551 int backward_compatible = imageop_backward_compatible();
553 if ( !PyArg_ParseTuple(args, "s#ii", &cp, &len, &x, &y) )
554 return 0;
556 nlen = x*y;
557 if ( nlen*4 != len ) {
558 PyErr_SetString(ImageopError, "String has incorrect length");
559 return 0;
562 rv = PyString_FromStringAndSize(NULL, nlen);
563 if ( rv == 0 )
564 return 0;
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;
571 cp += 4;
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);
575 } else {
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);
583 return rv;
586 static PyObject *
587 imageop_rgb82rgb(PyObject *self, PyObject *args)
589 int x, y, len, nlen;
590 unsigned char *cp;
591 unsigned char *ncp;
592 PyObject *rv;
593 int i, r, g, b;
594 unsigned char value;
595 int backward_compatible = imageop_backward_compatible();
597 if ( !PyArg_ParseTuple(args, "s#ii", &cp, &len, &x, &y) )
598 return 0;
600 nlen = x*y;
601 if ( nlen != len ) {
602 PyErr_SetString(ImageopError, "String has incorrect length");
603 return 0;
606 rv = PyString_FromStringAndSize(NULL, nlen*4);
607 if ( rv == 0 )
608 return 0;
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
615 value = *cp++;
616 r = (value >> 5) & 7;
617 g = (value ) & 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;
625 ncp += 4;
626 } else {
627 *ncp++ = 0;
628 *ncp++ = b;
629 *ncp++ = g;
630 *ncp++ = r;
633 return rv;
636 static PyObject *
637 imageop_rgb2grey(PyObject *self, PyObject *args)
639 int x, y, len, nlen;
640 unsigned char *cp;
641 unsigned char *ncp;
642 PyObject *rv;
643 int i, r, g, b;
644 int nvalue;
645 int backward_compatible = imageop_backward_compatible();
647 if ( !PyArg_ParseTuple(args, "s#ii", &cp, &len, &x, &y) )
648 return 0;
650 nlen = x*y;
651 if ( nlen*4 != len ) {
652 PyErr_SetString(ImageopError, "String has incorrect length");
653 return 0;
656 rv = PyString_FromStringAndSize(NULL, nlen);
657 if ( rv == 0 )
658 return 0;
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;
664 cp += 4;
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);
668 } else {
669 cp++; /* skip alpha channel */
670 b = *cp++;
671 g = *cp++;
672 r = *cp++;
674 nvalue = (int)(0.30*r + 0.59*g + 0.11*b);
675 if ( nvalue > 255 ) nvalue = 255;
676 *ncp++ = (unsigned char)nvalue;
678 return rv;
681 static PyObject *
682 imageop_grey2rgb(PyObject *self, PyObject *args)
684 int x, y, len, nlen;
685 unsigned char *cp;
686 unsigned char *ncp;
687 PyObject *rv;
688 int i;
689 unsigned char value;
690 int backward_compatible = imageop_backward_compatible();
692 if ( !PyArg_ParseTuple(args, "s#ii", &cp, &len, &x, &y) )
693 return 0;
695 nlen = x*y;
696 if ( nlen != len ) {
697 PyErr_SetString(ImageopError, "String has incorrect length");
698 return 0;
701 rv = PyString_FromStringAndSize(NULL, nlen*4);
702 if ( rv == 0 )
703 return 0;
704 ncp = (unsigned char *)PyString_AsString(rv);
706 for ( i=0; i < nlen; i++ ) {
707 value = *cp++;
708 if (backward_compatible) {
709 * (Py_UInt32 *) ncp = (Py_UInt32) value | ((Py_UInt32) value << 8 ) | ((Py_UInt32) value << 16);
710 ncp += 4;
711 } else {
712 *ncp++ = 0;
713 *ncp++ = value;
714 *ncp++ = value;
715 *ncp++ = value;
718 return rv;
722 static object *
723 imageop_mul(object *self, object *args)
725 char *cp, *ncp;
726 int len, size, x, y;
727 object *rv;
728 int i;
730 if ( !getargs(args, "(s#iii)", &cp, &len, &size, &x, &y) )
731 return 0;
733 if ( size != 1 && size != 4 ) {
734 err_setstr(ImageopError, "Size should be 1 or 4");
735 return 0;
737 if ( len != size*x*y ) {
738 err_setstr(ImageopError, "String has incorrect length");
739 return 0;
742 rv = newsizedstringobject(NULL, XXXX);
743 if ( rv == 0 )
744 return 0;
745 ncp = (char *)getstringvalue(rv);
748 for ( i=0; i < len; i += size ) {
750 return rv;
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 },
770 { 0, 0 }
774 PyMODINIT_FUNC
775 initimageop(void)
777 PyObject *m;
778 m = Py_InitModule("imageop", imageop_methods);
779 ImageopDict = PyModule_GetDict(m);
780 ImageopError = PyErr_NewException("imageop.error", NULL, NULL);
781 if (ImageopError != NULL)
782 PyDict_SetItemString(ImageopDict, "error", ImageopError);