Added function ttob.
[python/dscho.git] / Modules / rgbimgmodule.c
blob86ee71c8fb6370f4ab1ce12e4f3a439d0c2a37dc
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 "allobjects.h"
18 #include "modsupport.h"
19 #include <unistd.h>
20 #include <string.h>
23 * from image.h
26 typedef struct {
27 unsigned short imagic; /* stuff saved on disk . . */
28 unsigned short type;
29 unsigned short dim;
30 unsigned short xsize;
31 unsigned short ysize;
32 unsigned short zsize;
33 unsigned long min;
34 unsigned long max;
35 unsigned long wastebytes;
36 char name[80];
37 unsigned long colormap;
39 long file; /* stuff used in core only */
40 unsigned short flags;
41 short dorev;
42 short x;
43 short y;
44 short z;
45 short cnt;
46 unsigned short *ptr;
47 unsigned short *base;
48 unsigned short *tmpbuf;
49 unsigned long offset;
50 unsigned long rleend; /* for rle images */
51 unsigned long *rowstart; /* for rle images */
52 long *rowsize; /* for rle images */
53 } IMAGE;
55 #define IMAGIC 0732
57 #define TYPEMASK 0xff00
58 #define BPPMASK 0x00ff
59 #define ITYPE_VERBATIM 0x0000
60 #define ITYPE_RLE 0x0100
61 #define ISRLE(type) (((type) & 0xff00) == ITYPE_RLE)
62 #define ISVERBATIM(type) (((type) & 0xff00) == ITYPE_VERBATIM)
63 #define BPP(type) ((type) & BPPMASK)
64 #define RLE(bpp) (ITYPE_RLE | (bpp))
65 #define VERBATIM(bpp) (ITYPE_VERBATIM | (bpp))
67 * end of image.h stuff
71 #define RINTLUM (79)
72 #define GINTLUM (156)
73 #define BINTLUM (21)
75 #define ILUM(r,g,b) ((int)(RINTLUM*(r)+GINTLUM*(g)+BINTLUM*(b))>>8)
77 #define OFFSET_R 3 /* this is byte order dependent */
78 #define OFFSET_G 2
79 #define OFFSET_B 1
80 #define OFFSET_A 0
82 #define CHANOFFSET(z) (3-(z)) /* this is byte order dependent */
84 static expandrow PROTO((unsigned char *, unsigned char *, int));
85 static setalpha PROTO((unsigned char *, int));
86 static copybw PROTO((long *, int));
87 static interleaverow PROTO((unsigned char *, unsigned char *, int, int));
88 static int compressrow PROTO((unsigned char *, unsigned char *, int, int));
89 static lumrow PROTO((unsigned char *, unsigned char *, int));
91 #ifdef ADD_TAGS
92 #define TAGLEN (5)
93 #else
94 #define TAGLEN (0)
95 #endif
97 static object *ImgfileError;
99 static int reverse_order;
101 #ifdef ADD_TAGS
103 * addlongimgtag -
104 * this is used to extract image data from core dumps.
107 addlongimgtag(dptr,xsize,ysize)
108 unsigned long *dptr;
109 int xsize, ysize;
111 dptr = dptr+(xsize*ysize);
112 dptr[0] = 0x12345678;
113 dptr[1] = 0x59493333;
114 dptr[2] = 0x69434222;
115 dptr[3] = xsize;
116 dptr[4] = ysize;
118 #endif
121 * byte order independent read/write of shorts and longs.
124 static unsigned short getshort(inf)
125 FILE *inf;
127 unsigned char buf[2];
129 fread(buf,2,1,inf);
130 return (buf[0]<<8)+(buf[1]<<0);
133 static unsigned long getlong(inf)
134 FILE *inf;
136 unsigned char buf[4];
138 fread(buf,4,1,inf);
139 return (buf[0]<<24)+(buf[1]<<16)+(buf[2]<<8)+(buf[3]<<0);
142 static putshort(outf,val)
143 FILE *outf;
144 unsigned short val;
146 unsigned char buf[2];
148 buf[0] = (val>>8);
149 buf[1] = (val>>0);
150 fwrite(buf,2,1,outf);
153 static int putlong(outf,val)
154 FILE *outf;
155 unsigned long val;
157 unsigned char buf[4];
159 buf[0] = (val>>24);
160 buf[1] = (val>>16);
161 buf[2] = (val>>8);
162 buf[3] = (val>>0);
163 return fwrite(buf,4,1,outf);
166 static readheader(inf,image)
167 FILE *inf;
168 IMAGE *image;
170 memset(image,0,sizeof(IMAGE));
171 image->imagic = getshort(inf);
172 image->type = getshort(inf);
173 image->dim = getshort(inf);
174 image->xsize = getshort(inf);
175 image->ysize = getshort(inf);
176 image->zsize = getshort(inf);
179 static int writeheader(outf,image)
180 FILE *outf;
181 IMAGE *image;
183 IMAGE t;
185 memset(&t,0,sizeof(IMAGE));
186 fwrite(&t,sizeof(IMAGE),1,outf);
187 fseek(outf,0,SEEK_SET);
188 putshort(outf,image->imagic);
189 putshort(outf,image->type);
190 putshort(outf,image->dim);
191 putshort(outf,image->xsize);
192 putshort(outf,image->ysize);
193 putshort(outf,image->zsize);
194 putlong(outf,image->min);
195 putlong(outf,image->max);
196 putlong(outf,0);
197 return fwrite("no name",8,1,outf);
200 static int writetab(outf,tab,len)
201 FILE *outf;
202 unsigned long *tab;
203 int len;
205 int r;
207 while(len) {
208 r = putlong(outf,*tab++);
209 len -= 4;
211 return r;
214 static readtab(inf,tab,len)
215 FILE *inf;
216 unsigned long *tab;
217 int len;
219 while(len) {
220 *tab++ = getlong(inf);
221 len -= 4;
226 * sizeofimage -
227 * return the xsize and ysize of an iris image file.
230 static object *
231 sizeofimage(self, args)
232 object *self, *args;
234 char *name;
235 IMAGE image;
236 FILE *inf;
238 if (!getargs(args, "s", &name))
239 return NULL;
241 inf = fopen(name,"r");
242 if(!inf) {
243 err_setstr(ImgfileError, "can't open image file");
244 return NULL;
246 readheader(inf,&image);
247 fclose(inf);
248 if(image.imagic != IMAGIC) {
249 err_setstr(ImgfileError, "bad magic number in image file");
250 return NULL;
252 return mkvalue("(ii)", image.xsize, image.ysize);
256 * longimagedata -
257 * read in a B/W RGB or RGBA iris image file and return a
258 * pointer to an array of longs.
261 static object *
262 longimagedata(self, args)
263 object *self, *args;
265 char *name;
266 unsigned char *base, *lptr;
267 unsigned char *rledat, *verdat;
268 long *starttab, *lengthtab;
269 FILE *inf;
270 IMAGE image;
271 int y, z, pos, len, tablen;
272 int xsize, ysize, zsize;
273 int bpp, rle, cur, badorder;
274 int rlebuflen;
275 object *rv;
277 if (!getargs(args, "s", &name))
278 return NULL;
280 inf = fopen(name,"r");
281 if(!inf) {
282 err_setstr(ImgfileError,"can't open image file");
283 return NULL;
285 readheader(inf,&image);
286 if(image.imagic != IMAGIC) {
287 err_setstr(ImgfileError,"bad magic number in image file");
288 fclose(inf);
289 return NULL;
291 rle = ISRLE(image.type);
292 bpp = BPP(image.type);
293 if(bpp != 1 ) {
294 err_setstr(ImgfileError,"image must have 1 byte per pix chan");
295 fclose(inf);
296 return NULL;
298 xsize = image.xsize;
299 ysize = image.ysize;
300 zsize = image.zsize;
301 if(rle) {
302 tablen = ysize*zsize*sizeof(long);
303 starttab = (long *)malloc(tablen);
304 lengthtab = (long *)malloc(tablen);
305 rlebuflen = 1.05*xsize+10;
306 rledat = (unsigned char *)malloc(rlebuflen);
307 fseek(inf,512,SEEK_SET);
308 readtab(inf,starttab,tablen);
309 readtab(inf,lengthtab,tablen);
311 /* check data order */
312 cur = 0;
313 badorder = 0;
314 for(y=0; y<ysize; y++) {
315 for(z=0; z<zsize; z++) {
316 if(starttab[y+z*ysize]<cur) {
317 badorder = 1;
318 break;
320 cur = starttab[y+z*ysize];
322 if(badorder)
323 break;
326 fseek(inf,512+2*tablen,SEEK_SET);
327 cur = 512+2*tablen;
328 rv = newsizedstringobject((char *) 0,
329 (xsize*ysize+TAGLEN)*sizeof(long));
330 if (rv == NULL) {
331 fclose(inf);
332 free(lengthtab);
333 free(starttab);
334 free(rledat);
335 return NULL;
337 base = (unsigned char *) getstringvalue(rv);
338 #ifdef ADD_TAGS
339 addlongimgtag(base,xsize,ysize);
340 #endif
341 if(badorder) {
342 for(z=0; z<zsize; z++) {
343 lptr = base;
344 if (reverse_order)
345 lptr += (ysize - 1) * xsize * sizeof(unsigned long);
346 for(y=0; y<ysize; y++) {
347 if(cur != starttab[y+z*ysize]) {
348 fseek(inf,starttab[y+z*ysize],SEEK_SET);
349 cur = starttab[y+z*ysize];
351 if(lengthtab[y+z*ysize]>rlebuflen) {
352 err_setstr(ImgfileError,"rlebuf is too small - bad poop");
353 fclose(inf);
354 DECREF(rv);
355 free(rledat);
356 free(starttab);
357 free(lengthtab);
358 return NULL;
360 fread(rledat,lengthtab[y+z*ysize],1,inf);
361 cur += lengthtab[y+z*ysize];
362 expandrow(lptr,rledat,3-z);
363 if (reverse_order)
364 lptr -= xsize * sizeof(unsigned long);
365 else
366 lptr += xsize * sizeof(unsigned long);
369 } else {
370 lptr = base;
371 if (reverse_order)
372 lptr += (ysize - 1) * xsize * sizeof(unsigned long);
373 for(y=0; y<ysize; y++) {
374 for(z=0; z<zsize; z++) {
375 if(cur != starttab[y+z*ysize]) {
376 fseek(inf,starttab[y+z*ysize],SEEK_SET);
377 cur = starttab[y+z*ysize];
379 fread(rledat,lengthtab[y+z*ysize],1,inf);
380 cur += lengthtab[y+z*ysize];
381 expandrow(lptr,rledat,3-z);
383 if (reverse_order)
384 lptr -= xsize * sizeof(unsigned long);
385 else
386 lptr += xsize * sizeof(unsigned long);
389 if(zsize == 3)
390 setalpha(base,xsize*ysize);
391 else if(zsize<3)
392 copybw((long *) base,xsize*ysize);
393 fclose(inf);
394 free(starttab);
395 free(lengthtab);
396 free(rledat);
397 return rv;
398 } else {
399 rv = newsizedstringobject((char *) 0,
400 (xsize*ysize+TAGLEN)*sizeof(long));
401 if (rv == NULL) {
402 fclose(inf);
403 return NULL;
405 base = (unsigned char *) getstringvalue(rv);
406 #ifdef ADD_TAGS
407 addlongimgtag(base,xsize,ysize);
408 #endif
409 verdat = (unsigned char *)malloc(xsize);
410 fseek(inf,512,SEEK_SET);
411 for(z=0; z<zsize; z++) {
412 lptr = base;
413 if (reverse_order)
414 lptr += (ysize - 1) * xsize * sizeof(unsigned long);
415 for(y=0; y<ysize; y++) {
416 fread(verdat,xsize,1,inf);
417 interleaverow(lptr,verdat,3-z,xsize);
418 if (reverse_order)
419 lptr -= xsize * sizeof(unsigned long);
420 else
421 lptr += xsize * sizeof(unsigned long);
424 if(zsize == 3)
425 setalpha(base,xsize*ysize);
426 else if(zsize<3)
427 copybw((long *) base,xsize*ysize);
428 fclose(inf);
429 free(verdat);
430 return rv;
434 /* static utility functions for longimagedata */
436 static interleaverow(lptr,cptr,z,n)
437 unsigned char *lptr, *cptr;
438 int z, n;
440 lptr += z;
441 while(n--) {
442 *lptr = *cptr++;
443 lptr += 4;
447 static copybw(lptr,n)
448 long *lptr;
449 int n;
451 while(n>=8) {
452 lptr[0] = 0xff000000+(0x010101*(lptr[0]&0xff));
453 lptr[1] = 0xff000000+(0x010101*(lptr[1]&0xff));
454 lptr[2] = 0xff000000+(0x010101*(lptr[2]&0xff));
455 lptr[3] = 0xff000000+(0x010101*(lptr[3]&0xff));
456 lptr[4] = 0xff000000+(0x010101*(lptr[4]&0xff));
457 lptr[5] = 0xff000000+(0x010101*(lptr[5]&0xff));
458 lptr[6] = 0xff000000+(0x010101*(lptr[6]&0xff));
459 lptr[7] = 0xff000000+(0x010101*(lptr[7]&0xff));
460 lptr += 8;
461 n-=8;
463 while(n--) {
464 *lptr = 0xff000000+(0x010101*(*lptr&0xff));
465 lptr++;
469 static setalpha(lptr,n)
470 unsigned char *lptr;
472 while(n>=8) {
473 lptr[0*4] = 0xff;
474 lptr[1*4] = 0xff;
475 lptr[2*4] = 0xff;
476 lptr[3*4] = 0xff;
477 lptr[4*4] = 0xff;
478 lptr[5*4] = 0xff;
479 lptr[6*4] = 0xff;
480 lptr[7*4] = 0xff;
481 lptr += 4*8;
482 n -= 8;
484 while(n--) {
485 *lptr = 0xff;
486 lptr += 4;
490 static expandrow(optr,iptr,z)
491 unsigned char *optr, *iptr;
492 int z;
494 unsigned char pixel, count;
496 optr += z;
497 while(1) {
498 pixel = *iptr++;
499 if ( !(count = (pixel & 0x7f)) )
500 return;
501 if(pixel & 0x80) {
502 while(count>=8) {
503 optr[0*4] = iptr[0];
504 optr[1*4] = iptr[1];
505 optr[2*4] = iptr[2];
506 optr[3*4] = iptr[3];
507 optr[4*4] = iptr[4];
508 optr[5*4] = iptr[5];
509 optr[6*4] = iptr[6];
510 optr[7*4] = iptr[7];
511 optr += 8*4;
512 iptr += 8;
513 count -= 8;
515 while(count--) {
516 *optr = *iptr++;
517 optr+=4;
519 } else {
520 pixel = *iptr++;
521 while(count>=8) {
522 optr[0*4] = pixel;
523 optr[1*4] = pixel;
524 optr[2*4] = pixel;
525 optr[3*4] = pixel;
526 optr[4*4] = pixel;
527 optr[5*4] = pixel;
528 optr[6*4] = pixel;
529 optr[7*4] = pixel;
530 optr += 8*4;
531 count -= 8;
533 while(count--) {
534 *optr = pixel;
535 optr+=4;
542 * longstoimage -
543 * copy an array of longs to an iris image file. Each long
544 * represents one pixel. xsize and ysize specify the dimensions of
545 * the pixel array. zsize specifies what kind of image file to
546 * write out. if zsize is 1, the luminance of the pixels are
547 * calculated, and a sinlge channel black and white image is saved.
548 * If zsize is 3, an RGB image file is saved. If zsize is 4, an
549 * RGBA image file is saved.
552 static object *
553 longstoimage(self, args)
554 object *self, *args;
556 unsigned char *lptr;
557 char *name;
558 int xsize, ysize, zsize;
559 FILE *outf;
560 IMAGE image;
561 int tablen, y, z, pos, len;
562 long *starttab, *lengthtab;
563 unsigned char *rlebuf;
564 unsigned char *lumbuf;
565 int rlebuflen, goodwrite;
567 if (!getargs(args, "(s#iiis)", &lptr, &len, &xsize, &ysize, &zsize, &name))
568 return NULL;
570 goodwrite = 1;
571 outf = fopen(name,"w");
572 if(!outf) {
573 err_setstr(ImgfileError,"can't open output file");
574 return NULL;
576 tablen = ysize*zsize*sizeof(long);
578 starttab = (long *)malloc(tablen);
579 lengthtab = (long *)malloc(tablen);
580 rlebuflen = 1.05*xsize+10;
581 rlebuf = (unsigned char *)malloc(rlebuflen);
582 lumbuf = (unsigned char *)malloc(xsize*sizeof(long));
584 memset(&image,0,sizeof(IMAGE));
585 image.imagic = IMAGIC;
586 image.type = RLE(1);
587 if(zsize>1)
588 image.dim = 3;
589 else
590 image.dim = 2;
591 image.xsize = xsize;
592 image.ysize = ysize;
593 image.zsize = zsize;
594 image.min = 0;
595 image.max = 255;
596 goodwrite *= writeheader(outf,&image);
597 fseek(outf,512+2*tablen,SEEK_SET);
598 pos = 512+2*tablen;
599 if (reverse_order)
600 lptr += (ysize - 1) * xsize * sizeof(unsigned long);
601 for(y=0; y<ysize; y++) {
602 for(z=0; z<zsize; z++) {
603 if(zsize == 1) {
604 lumrow(lptr,lumbuf,xsize);
605 len = compressrow(lumbuf,rlebuf,CHANOFFSET(z),xsize);
606 } else {
607 len = compressrow(lptr,rlebuf,CHANOFFSET(z),xsize);
609 if(len>rlebuflen) {
610 err_setstr(ImgfileError,"rlebuf is too small - bad poop");
611 free(starttab);
612 free(lengthtab);
613 free(rlebuf);
614 free(lumbuf);
615 fclose(outf);
616 return NULL;
618 goodwrite *= fwrite(rlebuf,len,1,outf);
619 starttab[y+z*ysize] = pos;
620 lengthtab[y+z*ysize] = len;
621 pos += len;
623 if (reverse_order)
624 lptr -= xsize * sizeof(unsigned long);
625 else
626 lptr += xsize * sizeof(unsigned long);
629 fseek(outf,512,SEEK_SET);
630 goodwrite *= writetab(outf,starttab,tablen);
631 goodwrite *= writetab(outf,lengthtab,tablen);
632 free(starttab);
633 free(lengthtab);
634 free(rlebuf);
635 free(lumbuf);
636 fclose(outf);
637 if(goodwrite) {
638 INCREF(None);
639 return None;
640 } else {
641 err_setstr(ImgfileError,"not enough space for image!!");
642 return NULL;
646 /* static utility functions for longstoimage */
648 static lumrow(rgbptr,lumptr,n)
649 unsigned char *rgbptr, *lumptr;
650 int n;
652 lumptr += CHANOFFSET(0);
653 while(n--) {
654 *lumptr = ILUM(rgbptr[OFFSET_R],rgbptr[OFFSET_G],rgbptr[OFFSET_B]);
655 lumptr += 4;
656 rgbptr += 4;
660 static int compressrow(lbuf,rlebuf,z,cnt)
661 unsigned char *lbuf, *rlebuf;
662 int z, cnt;
664 unsigned char *iptr, *ibufend, *sptr, *optr;
665 short todo, cc;
666 long count;
668 lbuf += z;
669 iptr = lbuf;
670 ibufend = iptr+cnt*4;
671 optr = rlebuf;
673 while(iptr<ibufend) {
674 sptr = iptr;
675 iptr += 8;
676 while((iptr<ibufend)&& ((iptr[-8]!=iptr[-4])||(iptr[-4]!=iptr[0])))
677 iptr+=4;
678 iptr -= 8;
679 count = (iptr-sptr)/4;
680 while(count) {
681 todo = count>126 ? 126:count;
682 count -= todo;
683 *optr++ = 0x80|todo;
684 while(todo>8) {
685 optr[0] = sptr[0*4];
686 optr[1] = sptr[1*4];
687 optr[2] = sptr[2*4];
688 optr[3] = sptr[3*4];
689 optr[4] = sptr[4*4];
690 optr[5] = sptr[5*4];
691 optr[6] = sptr[6*4];
692 optr[7] = sptr[7*4];
693 optr += 8;
694 sptr += 8*4;
695 todo -= 8;
697 while(todo--) {
698 *optr++ = *sptr;
699 sptr += 4;
702 sptr = iptr;
703 cc = *iptr;
704 iptr += 4;
705 while( (iptr<ibufend) && (*iptr == cc) )
706 iptr += 4;
707 count = (iptr-sptr)/4;
708 while(count) {
709 todo = count>126 ? 126:count;
710 count -= todo;
711 *optr++ = todo;
712 *optr++ = cc;
715 *optr++ = 0;
716 return optr - (unsigned char *)rlebuf;
719 static object *
720 ttob(self, args)
721 object *self;
722 object *args;
724 int order, oldorder;
726 if (!getargs(args, "d", &order))
727 return NULL;
728 oldorder = reverse_order;
729 reverse_order = order;
730 return newintobject(oldorder);
733 static struct methodlist rgbimg_methods[] = {
734 {"sizeofimage", sizeofimage},
735 {"longimagedata", longimagedata},
736 {"longstoimage", longstoimage},
737 {"ttob", ttob},
738 {NULL, NULL} /* sentinel */
741 void
742 initrgbimg()
744 object *m, *d;
745 m = initmodule("rgbimg", rgbimg_methods);
746 d = getmoduledict(m);
747 ImgfileError = newstringobject("rgbimg,error");
748 if (ImgfileError == NULL || dictinsert(d, "error", ImgfileError))
749 fatal("can't define rgbimg.error");