Updated for 2.1b2 distribution.
[python/dscho.git] / Modules / rgbimgmodule.c
blobc8c42c2ac05a5226447daf144d3193329cc38f53
1 /*
2 * fastimg -
3 * Faster reading and writing of image files.
5 * This code should work on machines with any byte order.
7 * Could someone make this run real fast using multiple processors
8 * or how about using memory mapped files to speed it up?
10 * Paul Haeberli - 1991
12 * Changed to return sizes.
13 * Sjoerd Mullender - 1993
14 * Changed to incorporate into Python.
15 * Sjoerd Mullender - 1993
17 #include "Python.h"
19 #if SIZEOF_INT == 4
20 typedef int Py_Int32;
21 typedef unsigned int Py_UInt32;
22 #else
23 #if SIZEOF_LONG == 4
24 typedef long Py_Int32;
25 typedef unsigned long Py_UInt32;
26 #else
27 #error "No 4-byte integral type"
28 #endif
29 #endif
31 #ifdef HAVE_UNISTD_H
32 #include <unistd.h>
33 #endif
34 #include <string.h>
37 * from image.h
40 typedef struct {
41 unsigned short imagic; /* stuff saved on disk . . */
42 unsigned short type;
43 unsigned short dim;
44 unsigned short xsize;
45 unsigned short ysize;
46 unsigned short zsize;
47 Py_UInt32 min;
48 Py_UInt32 max;
49 Py_UInt32 wastebytes;
50 char name[80];
51 Py_UInt32 colormap;
53 Py_Int32 file; /* stuff used in core only */
54 unsigned short flags;
55 short dorev;
56 short x;
57 short y;
58 short z;
59 short cnt;
60 unsigned short *ptr;
61 unsigned short *base;
62 unsigned short *tmpbuf;
63 Py_UInt32 offset;
64 Py_UInt32 rleend; /* for rle images */
65 Py_UInt32 *rowstart; /* for rle images */
66 Py_Int32 *rowsize; /* for rle images */
67 } IMAGE;
69 #define IMAGIC 0732
71 #define TYPEMASK 0xff00
72 #define BPPMASK 0x00ff
73 #define ITYPE_VERBATIM 0x0000
74 #define ITYPE_RLE 0x0100
75 #define ISRLE(type) (((type) & 0xff00) == ITYPE_RLE)
76 #define ISVERBATIM(type) (((type) & 0xff00) == ITYPE_VERBATIM)
77 #define BPP(type) ((type) & BPPMASK)
78 #define RLE(bpp) (ITYPE_RLE | (bpp))
79 #define VERBATIM(bpp) (ITYPE_VERBATIM | (bpp))
81 * end of image.h stuff
85 #define RINTLUM (79)
86 #define GINTLUM (156)
87 #define BINTLUM (21)
89 #define ILUM(r,g,b) ((int)(RINTLUM*(r)+GINTLUM*(g)+BINTLUM*(b))>>8)
91 #define OFFSET_R 3 /* this is byte order dependent */
92 #define OFFSET_G 2
93 #define OFFSET_B 1
94 #define OFFSET_A 0
96 #define CHANOFFSET(z) (3-(z)) /* this is byte order dependent */
98 static void expandrow(unsigned char *, unsigned char *, int);
99 static void setalpha(unsigned char *, int);
100 static void copybw(Py_Int32 *, int);
101 static void interleaverow(unsigned char*, unsigned char*, int, int);
102 static int compressrow(unsigned char *, unsigned char *, int, int);
103 static void lumrow(unsigned char *, unsigned char *, int);
105 #ifdef ADD_TAGS
106 #define TAGLEN (5)
107 #else
108 #define TAGLEN (0)
109 #endif
111 static PyObject *ImgfileError;
113 static int reverse_order;
115 #ifdef ADD_TAGS
117 * addlongimgtag -
118 * this is used to extract image data from core dumps.
121 static void
122 addlongimgtag(Py_UInt32 *dptr, int xsize, int ysize)
124 dptr = dptr + (xsize * ysize);
125 dptr[0] = 0x12345678;
126 dptr[1] = 0x59493333;
127 dptr[2] = 0x69434222;
128 dptr[3] = xsize;
129 dptr[4] = ysize;
131 #endif
134 * byte order independent read/write of shorts and longs.
137 static unsigned short
138 getshort(FILE *inf)
140 unsigned char buf[2];
142 fread(buf, 2, 1, inf);
143 return (buf[0] << 8) + (buf[1] << 0);
146 static Py_UInt32
147 getlong(FILE *inf)
149 unsigned char buf[4];
151 fread(buf, 4, 1, inf);
152 return (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + (buf[3] << 0);
155 static void
156 putshort(FILE *outf, unsigned short val)
158 unsigned char buf[2];
160 buf[0] = (val >> 8);
161 buf[1] = (val >> 0);
162 fwrite(buf, 2, 1, outf);
165 static int
166 putlong(FILE *outf, Py_UInt32 val)
168 unsigned char buf[4];
170 buf[0] = (unsigned char) (val >> 24);
171 buf[1] = (unsigned char) (val >> 16);
172 buf[2] = (unsigned char) (val >> 8);
173 buf[3] = (unsigned char) (val >> 0);
174 return fwrite(buf, 4, 1, outf);
177 static void
178 readheader(FILE *inf, IMAGE *image)
180 memset(image ,0, sizeof(IMAGE));
181 image->imagic = getshort(inf);
182 image->type = getshort(inf);
183 image->dim = getshort(inf);
184 image->xsize = getshort(inf);
185 image->ysize = getshort(inf);
186 image->zsize = getshort(inf);
189 static int
190 writeheader(FILE *outf, IMAGE *image)
192 IMAGE t;
194 memset(&t, 0, sizeof(IMAGE));
195 fwrite(&t, sizeof(IMAGE), 1, outf);
196 fseek(outf, 0, SEEK_SET);
197 putshort(outf, image->imagic);
198 putshort(outf, image->type);
199 putshort(outf, image->dim);
200 putshort(outf, image->xsize);
201 putshort(outf, image->ysize);
202 putshort(outf, image->zsize);
203 putlong(outf, image->min);
204 putlong(outf, image->max);
205 putlong(outf, 0);
206 return fwrite("no name", 8, 1, outf);
209 static int
210 writetab(FILE *outf, /*unsigned*/ Py_Int32 *tab, int len)
212 int r = 0;
214 while(len) {
215 r = putlong(outf, *tab++);
216 len--;
218 return r;
221 static void
222 readtab(FILE *inf, /*unsigned*/ Py_Int32 *tab, int len)
224 while(len) {
225 *tab++ = getlong(inf);
226 len--;
231 * sizeofimage -
232 * return the xsize and ysize of an iris image file.
235 static PyObject *
236 sizeofimage(PyObject *self, PyObject *args)
238 char *name;
239 IMAGE image;
240 FILE *inf;
242 if (!PyArg_Parse(args, "s", &name))
243 return NULL;
245 inf = fopen(name, "rb");
246 if (!inf) {
247 PyErr_SetString(ImgfileError, "can't open image file");
248 return NULL;
250 readheader(inf, &image);
251 fclose(inf);
252 if (image.imagic != IMAGIC) {
253 PyErr_SetString(ImgfileError,
254 "bad magic number in image file");
255 return NULL;
257 return Py_BuildValue("(ii)", image.xsize, image.ysize);
261 * longimagedata -
262 * read in a B/W RGB or RGBA iris image file and return a
263 * pointer to an array of longs.
266 static PyObject *
267 longimagedata(PyObject *self, PyObject *args)
269 char *name;
270 unsigned char *base, *lptr;
271 unsigned char *rledat = NULL, *verdat = NULL;
272 Py_Int32 *starttab = NULL, *lengthtab = NULL;
273 FILE *inf = NULL;
274 IMAGE image;
275 int y, z, tablen;
276 int xsize, ysize, zsize;
277 int bpp, rle, cur, badorder;
278 int rlebuflen;
279 PyObject *rv = NULL;
281 if (!PyArg_Parse(args, "s", &name))
282 return NULL;
284 inf = fopen(name,"rb");
285 if (!inf) {
286 PyErr_SetString(ImgfileError, "can't open image file");
287 return NULL;
289 readheader(inf,&image);
290 if (image.imagic != IMAGIC) {
291 PyErr_SetString(ImgfileError,
292 "bad magic number in image file");
293 goto finally;
295 rle = ISRLE(image.type);
296 bpp = BPP(image.type);
297 if (bpp != 1) {
298 PyErr_SetString(ImgfileError,
299 "image must have 1 byte per pix chan");
300 goto finally;
302 xsize = image.xsize;
303 ysize = image.ysize;
304 zsize = image.zsize;
305 if (rle) {
306 tablen = ysize * zsize * sizeof(Py_Int32);
307 starttab = (Py_Int32 *)malloc(tablen);
308 lengthtab = (Py_Int32 *)malloc(tablen);
309 rlebuflen = (int) (1.05 * xsize +10);
310 rledat = (unsigned char *)malloc(rlebuflen);
311 if (!starttab || !lengthtab || !rledat) {
312 PyErr_NoMemory();
313 goto finally;
316 fseek(inf, 512, SEEK_SET);
317 readtab(inf, starttab, ysize*zsize);
318 readtab(inf, lengthtab, ysize*zsize);
320 /* check data order */
321 cur = 0;
322 badorder = 0;
323 for(y = 0; y < ysize; y++) {
324 for(z = 0; z < zsize; z++) {
325 if (starttab[y + z * ysize] < cur) {
326 badorder = 1;
327 break;
329 cur = starttab[y +z * ysize];
331 if (badorder)
332 break;
335 fseek(inf, 512 + 2 * tablen, SEEK_SET);
336 cur = 512 + 2 * tablen;
337 rv = PyString_FromStringAndSize((char *)NULL,
338 (xsize * ysize + TAGLEN) * sizeof(Py_Int32));
339 if (rv == NULL)
340 goto finally;
342 base = (unsigned char *) PyString_AsString(rv);
343 #ifdef ADD_TAGS
344 addlongimgtag(base,xsize,ysize);
345 #endif
346 if (badorder) {
347 for (z = 0; z < zsize; z++) {
348 lptr = base;
349 if (reverse_order)
350 lptr += (ysize - 1) * xsize
351 * sizeof(Py_UInt32);
352 for (y = 0; y < ysize; y++) {
353 int idx = y + z * ysize;
354 if (cur != starttab[idx]) {
355 fseek(inf,starttab[idx],
356 SEEK_SET);
357 cur = starttab[idx];
359 if (lengthtab[idx] > rlebuflen) {
360 PyErr_SetString(ImgfileError,
361 "rlebuf is too small");
362 Py_DECREF(rv);
363 rv = NULL;
364 goto finally;
366 fread(rledat, lengthtab[idx], 1, inf);
367 cur += lengthtab[idx];
368 expandrow(lptr, rledat, 3-z);
369 if (reverse_order)
370 lptr -= xsize
371 * sizeof(Py_UInt32);
372 else
373 lptr += xsize
374 * sizeof(Py_UInt32);
377 } else {
378 lptr = base;
379 if (reverse_order)
380 lptr += (ysize - 1) * xsize
381 * sizeof(Py_UInt32);
382 for (y = 0; y < ysize; y++) {
383 for(z = 0; z < zsize; z++) {
384 int idx = y + z * ysize;
385 if (cur != starttab[idx]) {
386 fseek(inf, starttab[idx],
387 SEEK_SET);
388 cur = starttab[idx];
390 fread(rledat, lengthtab[idx], 1, inf);
391 cur += lengthtab[idx];
392 expandrow(lptr, rledat, 3-z);
394 if (reverse_order)
395 lptr -= xsize * sizeof(Py_UInt32);
396 else
397 lptr += xsize * sizeof(Py_UInt32);
400 if (zsize == 3)
401 setalpha(base, xsize * ysize);
402 else if (zsize < 3)
403 copybw((Py_Int32 *) base, xsize * ysize);
405 else {
406 rv = PyString_FromStringAndSize((char *) 0,
407 (xsize*ysize+TAGLEN)*sizeof(Py_Int32));
408 if (rv == NULL)
409 goto finally;
411 base = (unsigned char *) PyString_AsString(rv);
412 #ifdef ADD_TAGS
413 addlongimgtag(base, xsize, ysize);
414 #endif
415 verdat = (unsigned char *)malloc(xsize);
416 fseek(inf, 512, SEEK_SET);
417 for (z = 0; z < zsize; z++) {
418 lptr = base;
419 if (reverse_order)
420 lptr += (ysize - 1) * xsize
421 * sizeof(Py_UInt32);
422 for (y = 0; y < ysize; y++) {
423 fread(verdat, xsize, 1, inf);
424 interleaverow(lptr, verdat, 3-z, xsize);
425 if (reverse_order)
426 lptr -= xsize * sizeof(Py_UInt32);
427 else
428 lptr += xsize * sizeof(Py_UInt32);
431 if (zsize == 3)
432 setalpha(base, xsize * ysize);
433 else if (zsize < 3)
434 copybw((Py_Int32 *) base, xsize * ysize);
436 finally:
437 free(starttab);
438 free(lengthtab);
439 free(rledat);
440 free(verdat);
441 fclose(inf);
442 return rv;
445 /* static utility functions for longimagedata */
447 static void
448 interleaverow(unsigned char *lptr, unsigned char *cptr, int z, int n)
450 lptr += z;
451 while (n--) {
452 *lptr = *cptr++;
453 lptr += 4;
457 static void
458 copybw(Py_Int32 *lptr, int n)
460 while (n >= 8) {
461 lptr[0] = 0xff000000 + (0x010101 * (lptr[0] & 0xff));
462 lptr[1] = 0xff000000 + (0x010101 * (lptr[1] & 0xff));
463 lptr[2] = 0xff000000 + (0x010101 * (lptr[2] & 0xff));
464 lptr[3] = 0xff000000 + (0x010101 * (lptr[3] & 0xff));
465 lptr[4] = 0xff000000 + (0x010101 * (lptr[4] & 0xff));
466 lptr[5] = 0xff000000 + (0x010101 * (lptr[5] & 0xff));
467 lptr[6] = 0xff000000 + (0x010101 * (lptr[6] & 0xff));
468 lptr[7] = 0xff000000 + (0x010101 * (lptr[7] & 0xff));
469 lptr += 8;
470 n -= 8;
472 while (n--) {
473 *lptr = 0xff000000 + (0x010101 * (*lptr&0xff));
474 lptr++;
478 static void
479 setalpha(unsigned char *lptr, int n)
481 while (n >= 8) {
482 lptr[0 * 4] = 0xff;
483 lptr[1 * 4] = 0xff;
484 lptr[2 * 4] = 0xff;
485 lptr[3 * 4] = 0xff;
486 lptr[4 * 4] = 0xff;
487 lptr[5 * 4] = 0xff;
488 lptr[6 * 4] = 0xff;
489 lptr[7 * 4] = 0xff;
490 lptr += 4 * 8;
491 n -= 8;
493 while (n--) {
494 *lptr = 0xff;
495 lptr += 4;
499 static void
500 expandrow(unsigned char *optr, unsigned char *iptr, int z)
502 unsigned char pixel, count;
504 optr += z;
505 while (1) {
506 pixel = *iptr++;
507 if (!(count = (pixel & 0x7f)))
508 return;
509 if (pixel & 0x80) {
510 while (count >= 8) {
511 optr[0 * 4] = iptr[0];
512 optr[1 * 4] = iptr[1];
513 optr[2 * 4] = iptr[2];
514 optr[3 * 4] = iptr[3];
515 optr[4 * 4] = iptr[4];
516 optr[5 * 4] = iptr[5];
517 optr[6 * 4] = iptr[6];
518 optr[7 * 4] = iptr[7];
519 optr += 8 * 4;
520 iptr += 8;
521 count -= 8;
523 while (count--) {
524 *optr = *iptr++;
525 optr += 4;
528 else {
529 pixel = *iptr++;
530 while (count >= 8) {
531 optr[0 * 4] = pixel;
532 optr[1 * 4] = pixel;
533 optr[2 * 4] = pixel;
534 optr[3 * 4] = pixel;
535 optr[4 * 4] = pixel;
536 optr[5 * 4] = pixel;
537 optr[6 * 4] = pixel;
538 optr[7 * 4] = pixel;
539 optr += 8 * 4;
540 count -= 8;
542 while (count--) {
543 *optr = pixel;
544 optr += 4;
551 * longstoimage -
552 * copy an array of longs to an iris image file. Each long
553 * represents one pixel. xsize and ysize specify the dimensions of
554 * the pixel array. zsize specifies what kind of image file to
555 * write out. if zsize is 1, the luminance of the pixels are
556 * calculated, and a single channel black and white image is saved.
557 * If zsize is 3, an RGB image file is saved. If zsize is 4, an
558 * RGBA image file is saved.
561 static PyObject *
562 longstoimage(PyObject *self, PyObject *args)
564 unsigned char *lptr;
565 char *name;
566 int xsize, ysize, zsize;
567 FILE *outf = NULL;
568 IMAGE image;
569 int tablen, y, z, pos, len;
570 Py_Int32 *starttab = NULL, *lengthtab = NULL;
571 unsigned char *rlebuf = NULL;
572 unsigned char *lumbuf = NULL;
573 int rlebuflen, goodwrite;
574 PyObject *retval = NULL;
576 if (!PyArg_Parse(args, "(s#iiis)", &lptr, &len, &xsize, &ysize, &zsize,
577 &name))
578 return NULL;
580 goodwrite = 1;
581 outf = fopen(name, "wb");
582 if (!outf) {
583 PyErr_SetString(ImgfileError, "can't open output file");
584 return NULL;
586 tablen = ysize * zsize * sizeof(Py_Int32);
588 starttab = (Py_Int32 *)malloc(tablen);
589 lengthtab = (Py_Int32 *)malloc(tablen);
590 rlebuflen = (int) (1.05 * xsize + 10);
591 rlebuf = (unsigned char *)malloc(rlebuflen);
592 lumbuf = (unsigned char *)malloc(xsize * sizeof(Py_Int32));
593 if (!starttab || !lengthtab || !rlebuf || !lumbuf) {
594 PyErr_NoMemory();
595 goto finally;
598 memset(&image, 0, sizeof(IMAGE));
599 image.imagic = IMAGIC;
600 image.type = RLE(1);
601 if (zsize>1)
602 image.dim = 3;
603 else
604 image.dim = 2;
605 image.xsize = xsize;
606 image.ysize = ysize;
607 image.zsize = zsize;
608 image.min = 0;
609 image.max = 255;
610 goodwrite *= writeheader(outf, &image);
611 pos = 512 + 2 * tablen;
612 fseek(outf, pos, SEEK_SET);
613 if (reverse_order)
614 lptr += (ysize - 1) * xsize * sizeof(Py_UInt32);
615 for (y = 0; y < ysize; y++) {
616 for (z = 0; z < zsize; z++) {
617 if (zsize == 1) {
618 lumrow(lptr, lumbuf, xsize);
619 len = compressrow(lumbuf, rlebuf,
620 CHANOFFSET(z), xsize);
621 } else {
622 len = compressrow(lptr, rlebuf,
623 CHANOFFSET(z), xsize);
625 if(len > rlebuflen) {
626 PyErr_SetString(ImgfileError,
627 "rlebuf is too small");
628 goto finally;
630 goodwrite *= fwrite(rlebuf, len, 1, outf);
631 starttab[y + z * ysize] = pos;
632 lengthtab[y + z * ysize] = len;
633 pos += len;
635 if (reverse_order)
636 lptr -= xsize * sizeof(Py_UInt32);
637 else
638 lptr += xsize * sizeof(Py_UInt32);
641 fseek(outf, 512, SEEK_SET);
642 goodwrite *= writetab(outf, starttab, ysize*zsize);
643 goodwrite *= writetab(outf, lengthtab, ysize*zsize);
644 if (goodwrite) {
645 Py_INCREF(Py_None);
646 retval = Py_None;
647 } else
648 PyErr_SetString(ImgfileError, "not enough space for image");
650 finally:
651 fclose(outf);
652 free(starttab);
653 free(lengthtab);
654 free(rlebuf);
655 free(lumbuf);
656 return retval;
659 /* static utility functions for longstoimage */
661 static void
662 lumrow(unsigned char *rgbptr, unsigned char *lumptr, int n)
664 lumptr += CHANOFFSET(0);
665 while (n--) {
666 *lumptr = ILUM(rgbptr[OFFSET_R],
667 rgbptr[OFFSET_G],
668 rgbptr[OFFSET_B]);
669 lumptr += 4;
670 rgbptr += 4;
674 static int
675 compressrow(unsigned char *lbuf, unsigned char *rlebuf, int z, int cnt)
677 unsigned char *iptr, *ibufend, *sptr, *optr;
678 short todo, cc;
679 Py_Int32 count;
681 lbuf += z;
682 iptr = lbuf;
683 ibufend = iptr + cnt * 4;
684 optr = rlebuf;
686 while(iptr < ibufend) {
687 sptr = iptr;
688 iptr += 8;
689 while ((iptr<ibufend) &&
690 ((iptr[-8]!=iptr[-4]) ||(iptr[-4]!=iptr[0])))
692 iptr += 4;
694 iptr -= 8;
695 count = (iptr - sptr) / 4;
696 while (count) {
697 todo = count > 126 ? 126 : (short)count;
698 count -= todo;
699 *optr++ = 0x80 | todo;
700 while (todo > 8) {
701 optr[0] = sptr[0 * 4];
702 optr[1] = sptr[1 * 4];
703 optr[2] = sptr[2 * 4];
704 optr[3] = sptr[3 * 4];
705 optr[4] = sptr[4 * 4];
706 optr[5] = sptr[5 * 4];
707 optr[6] = sptr[6 * 4];
708 optr[7] = sptr[7 * 4];
709 optr += 8;
710 sptr += 8 * 4;
711 todo -= 8;
713 while (todo--) {
714 *optr++ = *sptr;
715 sptr += 4;
718 sptr = iptr;
719 cc = *iptr;
720 iptr += 4;
721 while ((iptr < ibufend) && (*iptr == cc))
722 iptr += 4;
723 count = (iptr - sptr) / 4;
724 while (count) {
725 todo = count > 126 ? 126 : (short)count;
726 count -= todo;
727 *optr++ = (unsigned char) todo;
728 *optr++ = (unsigned char) cc;
731 *optr++ = 0;
732 return optr - (unsigned char *)rlebuf;
735 static PyObject *
736 ttob(PyObject *self, PyObject *args)
738 int order, oldorder;
740 if (!PyArg_Parse(args, "i", &order))
741 return NULL;
742 oldorder = reverse_order;
743 reverse_order = order;
744 return PyInt_FromLong(oldorder);
747 static PyMethodDef
748 rgbimg_methods[] = {
749 {"sizeofimage", sizeofimage},
750 {"longimagedata", longimagedata},
751 {"longstoimage", longstoimage},
752 {"ttob", ttob},
753 {NULL, NULL} /* sentinel */
757 DL_EXPORT(void)
758 initrgbimg(void)
760 PyObject *m, *d;
761 m = Py_InitModule("rgbimg", rgbimg_methods);
762 d = PyModule_GetDict(m);
763 ImgfileError = PyErr_NewException("rgbimg.error", NULL, NULL);
764 if (ImgfileError != NULL)
765 PyDict_SetItemString(d, "error", ImgfileError);