blob: 4a983efb7c972c5e3f7f6e60b30f68d896a126fd [file] [log] [blame]
Sjoerd Mullenderc4f169c1993-12-21 17:06:12 +00001/*
2 * fastimg -
3 * Faster reading and writing of image files.
4 *
5 * This code should work on machines with any byte order.
6 *
7 * Could someone make this run real fast using multiple processors
8 * or how about using memory mapped files to speed it up?
9 *
10 * Paul Haeberli - 1991
11 *
12 * Changed to return sizes.
13 * Sjoerd Mullender - 1993
14 * Changed to incorporate into Python.
15 * Sjoerd Mullender - 1993
16 */
17#include "allobjects.h"
18#include "modsupport.h"
19#include <unistd.h>
Sjoerd Mullender92fa23f1993-12-24 10:05:51 +000020#include <string.h>
Sjoerd Mullenderc4f169c1993-12-21 17:06:12 +000021
22/*
23 * from image.h
24 *
25 */
26typedef 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;
38
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;
54
55#define IMAGIC 0732
56
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))
66/*
67 * end of image.h stuff
68 *
69 */
70
71#define RINTLUM (79)
72#define GINTLUM (156)
73#define BINTLUM (21)
74
75#define ILUM(r,g,b) ((int)(RINTLUM*(r)+GINTLUM*(g)+BINTLUM*(b))>>8)
76
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
81
82#define CHANOFFSET(z) (3-(z)) /* this is byte order dependent */
83
Sjoerd Mullender92fa23f1993-12-24 10:05:51 +000084static expandrow PROTO((unsigned char *, unsigned char *, int));
85static setalpha PROTO((unsigned char *, int));
86static copybw PROTO((long *, int));
87static interleaverow PROTO((unsigned char *, unsigned char *, int, int));
88static int compressrow PROTO((unsigned char *, unsigned char *, int, int));
89static lumrow PROTO((unsigned char *, unsigned char *, int));
Sjoerd Mullenderc4f169c1993-12-21 17:06:12 +000090
91#ifdef ADD_TAGS
92#define TAGLEN (5)
93#else
94#define TAGLEN (0)
95#endif
96
97static object *ImgfileError;
98
99#ifdef ADD_TAGS
100/*
101 * addlongimgtag -
102 * this is used to extract image data from core dumps.
103 *
104 */
105addlongimgtag(dptr,xsize,ysize)
106unsigned long *dptr;
107int xsize, ysize;
108{
109 dptr = dptr+(xsize*ysize);
110 dptr[0] = 0x12345678;
111 dptr[1] = 0x59493333;
112 dptr[2] = 0x69434222;
113 dptr[3] = xsize;
114 dptr[4] = ysize;
115}
116#endif
117
118/*
119 * byte order independent read/write of shorts and longs.
120 *
121 */
122static unsigned short getshort(inf)
123FILE *inf;
124{
125 unsigned char buf[2];
126
127 fread(buf,2,1,inf);
128 return (buf[0]<<8)+(buf[1]<<0);
129}
130
131static unsigned long getlong(inf)
132FILE *inf;
133{
134 unsigned char buf[4];
135
136 fread(buf,4,1,inf);
137 return (buf[0]<<24)+(buf[1]<<16)+(buf[2]<<8)+(buf[3]<<0);
138}
139
140static putshort(outf,val)
141FILE *outf;
142unsigned short val;
143{
144 unsigned char buf[2];
145
146 buf[0] = (val>>8);
147 buf[1] = (val>>0);
148 fwrite(buf,2,1,outf);
149}
150
151static int putlong(outf,val)
152FILE *outf;
153unsigned long val;
154{
155 unsigned char buf[4];
156
157 buf[0] = (val>>24);
158 buf[1] = (val>>16);
159 buf[2] = (val>>8);
160 buf[3] = (val>>0);
161 return fwrite(buf,4,1,outf);
162}
163
164static readheader(inf,image)
165FILE *inf;
166IMAGE *image;
167{
Sjoerd Mullender92fa23f1993-12-24 10:05:51 +0000168 memset(image,0,sizeof(IMAGE));
Sjoerd Mullenderc4f169c1993-12-21 17:06:12 +0000169 image->imagic = getshort(inf);
170 image->type = getshort(inf);
171 image->dim = getshort(inf);
172 image->xsize = getshort(inf);
173 image->ysize = getshort(inf);
174 image->zsize = getshort(inf);
175}
176
177static int writeheader(outf,image)
178FILE *outf;
179IMAGE *image;
180{
181 IMAGE t;
182
Sjoerd Mullender92fa23f1993-12-24 10:05:51 +0000183 memset(&t,0,sizeof(IMAGE));
Sjoerd Mullenderc4f169c1993-12-21 17:06:12 +0000184 fwrite(&t,sizeof(IMAGE),1,outf);
185 fseek(outf,0,SEEK_SET);
186 putshort(outf,image->imagic);
187 putshort(outf,image->type);
188 putshort(outf,image->dim);
189 putshort(outf,image->xsize);
190 putshort(outf,image->ysize);
191 putshort(outf,image->zsize);
192 putlong(outf,image->min);
193 putlong(outf,image->max);
194 putlong(outf,0);
195 return fwrite("no name",8,1,outf);
196}
197
198static int writetab(outf,tab,len)
199FILE *outf;
200unsigned long *tab;
201int len;
202{
203 int r;
204
205 while(len) {
206 r = putlong(outf,*tab++);
207 len -= 4;
208 }
209 return r;
210}
211
212static readtab(inf,tab,len)
213FILE *inf;
214unsigned long *tab;
215int len;
216{
217 while(len) {
218 *tab++ = getlong(inf);
219 len -= 4;
220 }
221}
222
223/*
224 * sizeofimage -
225 * return the xsize and ysize of an iris image file.
226 *
227 */
228static object *
229sizeofimage(self, args)
230 object *self, *args;
231{
232 char *name;
233 IMAGE image;
234 FILE *inf;
235
236 if (!getargs(args, "s", &name))
237 return NULL;
238
239 inf = fopen(name,"r");
240 if(!inf) {
241 err_setstr(ImgfileError, "can't open image file");
242 return NULL;
243 }
244 readheader(inf,&image);
245 fclose(inf);
246 if(image.imagic != IMAGIC) {
247 err_setstr(ImgfileError, "bad magic number in image file");
248 return NULL;
249 }
250 return mkvalue("(ii)", image.xsize, image.ysize);
251}
252
253/*
254 * longimagedata -
255 * read in a B/W RGB or RGBA iris image file and return a
256 * pointer to an array of longs.
257 *
258 */
259static object *
260longimagedata(self, args)
261 object *self, *args;
262{
263 char *name;
Sjoerd Mullender92fa23f1993-12-24 10:05:51 +0000264 unsigned char *base, *lptr;
Sjoerd Mullenderc4f169c1993-12-21 17:06:12 +0000265 unsigned char *rledat, *verdat;
266 long *starttab, *lengthtab;
267 FILE *inf;
268 IMAGE image;
269 int y, z, pos, len, tablen;
270 int xsize, ysize, zsize;
271 int bpp, rle, cur, badorder;
272 int rlebuflen;
273 object *rv;
274
275 if (!getargs(args, "s", &name))
276 return NULL;
277
278 inf = fopen(name,"r");
279 if(!inf) {
280 err_setstr(ImgfileError,"can't open image file");
281 return NULL;
282 }
283 readheader(inf,&image);
284 if(image.imagic != IMAGIC) {
285 err_setstr(ImgfileError,"bad magic number in image file");
286 fclose(inf);
287 return NULL;
288 }
289 rle = ISRLE(image.type);
290 bpp = BPP(image.type);
291 if(bpp != 1 ) {
292 err_setstr(ImgfileError,"image must have 1 byte per pix chan");
293 fclose(inf);
294 return NULL;
295 }
296 xsize = image.xsize;
297 ysize = image.ysize;
298 zsize = image.zsize;
299 if(rle) {
300 tablen = ysize*zsize*sizeof(long);
301 starttab = (long *)malloc(tablen);
302 lengthtab = (long *)malloc(tablen);
303 rlebuflen = 1.05*xsize+10;
304 rledat = (unsigned char *)malloc(rlebuflen);
305 fseek(inf,512,SEEK_SET);
306 readtab(inf,starttab,tablen);
307 readtab(inf,lengthtab,tablen);
308
309/* check data order */
310 cur = 0;
311 badorder = 0;
312 for(y=0; y<ysize; y++) {
313 for(z=0; z<zsize; z++) {
314 if(starttab[y+z*ysize]<cur) {
315 badorder = 1;
316 break;
317 }
318 cur = starttab[y+z*ysize];
319 }
320 if(badorder)
321 break;
322 }
323
324 fseek(inf,512+2*tablen,SEEK_SET);
325 cur = 512+2*tablen;
326 rv = newsizedstringobject((char *) 0,
327 (xsize*ysize+TAGLEN)*sizeof(long));
328 if (rv == NULL) {
329 fclose(inf);
330 free(lengthtab);
331 free(starttab);
332 free(rledat);
333 return NULL;
334 }
Sjoerd Mullender92fa23f1993-12-24 10:05:51 +0000335 base = (unsigned char *) getstringvalue(rv);
Sjoerd Mullenderc4f169c1993-12-21 17:06:12 +0000336#ifdef ADD_TAGS
337 addlongimgtag(base,xsize,ysize);
338#endif
339 if(badorder) {
340 for(z=0; z<zsize; z++) {
341 lptr = base;
342 for(y=0; y<ysize; y++) {
343 if(cur != starttab[y+z*ysize]) {
344 fseek(inf,starttab[y+z*ysize],SEEK_SET);
345 cur = starttab[y+z*ysize];
346 }
347 if(lengthtab[y+z*ysize]>rlebuflen) {
348 err_setstr(ImgfileError,"rlebuf is too small - bad poop");
349 fclose(inf);
350 DECREF(rv);
351 free(rledat);
352 free(starttab);
353 free(lengthtab);
354 return NULL;
355 }
356 fread(rledat,lengthtab[y+z*ysize],1,inf);
357 cur += lengthtab[y+z*ysize];
358 expandrow(lptr,rledat,3-z);
Sjoerd Mullender92fa23f1993-12-24 10:05:51 +0000359 lptr += xsize * sizeof(unsigned long);
Sjoerd Mullenderc4f169c1993-12-21 17:06:12 +0000360 }
361 }
362 } else {
363 lptr = base;
364 for(y=0; y<ysize; y++) {
365 for(z=0; z<zsize; z++) {
366 if(cur != starttab[y+z*ysize]) {
367 fseek(inf,starttab[y+z*ysize],SEEK_SET);
368 cur = starttab[y+z*ysize];
369 }
370 fread(rledat,lengthtab[y+z*ysize],1,inf);
371 cur += lengthtab[y+z*ysize];
372 expandrow(lptr,rledat,3-z);
373 }
Sjoerd Mullender92fa23f1993-12-24 10:05:51 +0000374 lptr += xsize * sizeof(unsigned long);
Sjoerd Mullenderc4f169c1993-12-21 17:06:12 +0000375 }
376 }
377 if(zsize == 3)
378 setalpha(base,xsize*ysize);
379 else if(zsize<3)
Sjoerd Mullender92fa23f1993-12-24 10:05:51 +0000380 copybw((long *) base,xsize*ysize);
Sjoerd Mullenderc4f169c1993-12-21 17:06:12 +0000381 fclose(inf);
382 free(starttab);
383 free(lengthtab);
384 free(rledat);
385 return rv;
386 } else {
387 rv = newsizedstringobject((char *) 0,
388 (xsize*ysize+TAGLEN)*sizeof(long));
389 if (rv == NULL) {
390 fclose(inf);
391 return NULL;
392 }
Sjoerd Mullender92fa23f1993-12-24 10:05:51 +0000393 base = (unsigned char *) getstringvalue(rv);
Sjoerd Mullenderc4f169c1993-12-21 17:06:12 +0000394#ifdef ADD_TAGS
395 addlongimgtag(base,xsize,ysize);
396#endif
397 verdat = (unsigned char *)malloc(xsize);
398 fseek(inf,512,SEEK_SET);
399 for(z=0; z<zsize; z++) {
400 lptr = base;
401 for(y=0; y<ysize; y++) {
402 fread(verdat,xsize,1,inf);
403 interleaverow(lptr,verdat,3-z,xsize);
Sjoerd Mullender92fa23f1993-12-24 10:05:51 +0000404 lptr += xsize * sizeof(unsigned long);
Sjoerd Mullenderc4f169c1993-12-21 17:06:12 +0000405 }
406 }
407 if(zsize == 3)
408 setalpha(base,xsize*ysize);
409 else if(zsize<3)
Sjoerd Mullender92fa23f1993-12-24 10:05:51 +0000410 copybw((long *) base,xsize*ysize);
Sjoerd Mullenderc4f169c1993-12-21 17:06:12 +0000411 fclose(inf);
412 free(verdat);
413 return rv;
414 }
415}
416
417/* static utility functions for longimagedata */
418
419static interleaverow(lptr,cptr,z,n)
420unsigned char *lptr, *cptr;
421int z, n;
422{
423 lptr += z;
424 while(n--) {
425 *lptr = *cptr++;
426 lptr += 4;
427 }
428}
429
430static copybw(lptr,n)
431long *lptr;
432int n;
433{
434 while(n>=8) {
435 lptr[0] = 0xff000000+(0x010101*(lptr[0]&0xff));
436 lptr[1] = 0xff000000+(0x010101*(lptr[1]&0xff));
437 lptr[2] = 0xff000000+(0x010101*(lptr[2]&0xff));
438 lptr[3] = 0xff000000+(0x010101*(lptr[3]&0xff));
439 lptr[4] = 0xff000000+(0x010101*(lptr[4]&0xff));
440 lptr[5] = 0xff000000+(0x010101*(lptr[5]&0xff));
441 lptr[6] = 0xff000000+(0x010101*(lptr[6]&0xff));
442 lptr[7] = 0xff000000+(0x010101*(lptr[7]&0xff));
443 lptr += 8;
444 n-=8;
445 }
446 while(n--) {
447 *lptr = 0xff000000+(0x010101*(*lptr&0xff));
448 lptr++;
449 }
450}
451
452static setalpha(lptr,n)
453unsigned char *lptr;
454{
455 while(n>=8) {
456 lptr[0*4] = 0xff;
457 lptr[1*4] = 0xff;
458 lptr[2*4] = 0xff;
459 lptr[3*4] = 0xff;
460 lptr[4*4] = 0xff;
461 lptr[5*4] = 0xff;
462 lptr[6*4] = 0xff;
463 lptr[7*4] = 0xff;
464 lptr += 4*8;
465 n -= 8;
466 }
467 while(n--) {
468 *lptr = 0xff;
469 lptr += 4;
470 }
471}
472
473static expandrow(optr,iptr,z)
474unsigned char *optr, *iptr;
475int z;
476{
477 unsigned char pixel, count;
478
479 optr += z;
480 while(1) {
481 pixel = *iptr++;
482 if ( !(count = (pixel & 0x7f)) )
483 return;
484 if(pixel & 0x80) {
485 while(count>=8) {
486 optr[0*4] = iptr[0];
487 optr[1*4] = iptr[1];
488 optr[2*4] = iptr[2];
489 optr[3*4] = iptr[3];
490 optr[4*4] = iptr[4];
491 optr[5*4] = iptr[5];
492 optr[6*4] = iptr[6];
493 optr[7*4] = iptr[7];
494 optr += 8*4;
495 iptr += 8;
496 count -= 8;
497 }
498 while(count--) {
499 *optr = *iptr++;
500 optr+=4;
501 }
502 } else {
503 pixel = *iptr++;
504 while(count>=8) {
505 optr[0*4] = pixel;
506 optr[1*4] = pixel;
507 optr[2*4] = pixel;
508 optr[3*4] = pixel;
509 optr[4*4] = pixel;
510 optr[5*4] = pixel;
511 optr[6*4] = pixel;
512 optr[7*4] = pixel;
513 optr += 8*4;
514 count -= 8;
515 }
516 while(count--) {
517 *optr = pixel;
518 optr+=4;
519 }
520 }
521 }
522}
523
524/*
525 * longstoimage -
526 * copy an array of longs to an iris image file. Each long
527 * represents one pixel. xsize and ysize specify the dimensions of
528 * the pixel array. zsize specifies what kind of image file to
529 * write out. if zsize is 1, the luminance of the pixels are
530 * calculated, and a sinlge channel black and white image is saved.
531 * If zsize is 3, an RGB image file is saved. If zsize is 4, an
532 * RGBA image file is saved.
533 *
534 */
535static object *
536longstoimage(self, args)
537 object *self, *args;
538{
Sjoerd Mullender92fa23f1993-12-24 10:05:51 +0000539 unsigned char *lptr;
Sjoerd Mullenderc4f169c1993-12-21 17:06:12 +0000540 char *name;
541 int xsize, ysize, zsize;
542 FILE *outf;
543 IMAGE image;
544 int tablen, y, z, pos, len;
545 long *starttab, *lengthtab;
546 unsigned char *rlebuf;
Sjoerd Mullender92fa23f1993-12-24 10:05:51 +0000547 unsigned char *lumbuf;
Sjoerd Mullenderc4f169c1993-12-21 17:06:12 +0000548 int rlebuflen, goodwrite;
549
550 if (!getargs(args, "(s#iiis)", &lptr, &len, &xsize, &ysize, &zsize, &name))
551 return NULL;
552
553 goodwrite = 1;
554 outf = fopen(name,"w");
555 if(!outf) {
556 err_setstr(ImgfileError,"can't open output file");
557 return NULL;
558 }
559 tablen = ysize*zsize*sizeof(long);
560
561 starttab = (long *)malloc(tablen);
562 lengthtab = (long *)malloc(tablen);
563 rlebuflen = 1.05*xsize+10;
564 rlebuf = (unsigned char *)malloc(rlebuflen);
Sjoerd Mullender92fa23f1993-12-24 10:05:51 +0000565 lumbuf = (unsigned char *)malloc(xsize*sizeof(long));
Sjoerd Mullenderc4f169c1993-12-21 17:06:12 +0000566
Sjoerd Mullender92fa23f1993-12-24 10:05:51 +0000567 memset(&image,0,sizeof(IMAGE));
Sjoerd Mullenderc4f169c1993-12-21 17:06:12 +0000568 image.imagic = IMAGIC;
569 image.type = RLE(1);
570 if(zsize>1)
571 image.dim = 3;
572 else
573 image.dim = 2;
574 image.xsize = xsize;
575 image.ysize = ysize;
576 image.zsize = zsize;
577 image.min = 0;
578 image.max = 255;
579 goodwrite *= writeheader(outf,&image);
580 fseek(outf,512+2*tablen,SEEK_SET);
581 pos = 512+2*tablen;
582 for(y=0; y<ysize; y++) {
583 for(z=0; z<zsize; z++) {
584 if(zsize == 1) {
585 lumrow(lptr,lumbuf,xsize);
586 len = compressrow(lumbuf,rlebuf,CHANOFFSET(z),xsize);
587 } else {
588 len = compressrow(lptr,rlebuf,CHANOFFSET(z),xsize);
589 }
590 if(len>rlebuflen) {
591 err_setstr(ImgfileError,"rlebuf is too small - bad poop");
592 free(starttab);
593 free(lengthtab);
594 free(rlebuf);
595 free(lumbuf);
596 fclose(outf);
597 return NULL;
598 }
599 goodwrite *= fwrite(rlebuf,len,1,outf);
600 starttab[y+z*ysize] = pos;
601 lengthtab[y+z*ysize] = len;
602 pos += len;
603 }
Sjoerd Mullender92fa23f1993-12-24 10:05:51 +0000604 lptr += xsize * sizeof(unsigned long);
Sjoerd Mullenderc4f169c1993-12-21 17:06:12 +0000605 }
606
607 fseek(outf,512,SEEK_SET);
608 goodwrite *= writetab(outf,starttab,tablen);
609 goodwrite *= writetab(outf,lengthtab,tablen);
610 free(starttab);
611 free(lengthtab);
612 free(rlebuf);
613 free(lumbuf);
614 fclose(outf);
615 if(goodwrite) {
616 INCREF(None);
617 return None;
618 } else {
619 err_setstr(ImgfileError,"not enough space for image!!");
620 return NULL;
621 }
622}
623
624/* static utility functions for longstoimage */
625
626static lumrow(rgbptr,lumptr,n)
627unsigned char *rgbptr, *lumptr;
628int n;
629{
630 lumptr += CHANOFFSET(0);
631 while(n--) {
632 *lumptr = ILUM(rgbptr[OFFSET_R],rgbptr[OFFSET_G],rgbptr[OFFSET_B]);
633 lumptr += 4;
634 rgbptr += 4;
635 }
636}
637
638static int compressrow(lbuf,rlebuf,z,cnt)
639unsigned char *lbuf, *rlebuf;
640int z, cnt;
641{
642 unsigned char *iptr, *ibufend, *sptr, *optr;
643 short todo, cc;
644 long count;
645
646 lbuf += z;
647 iptr = lbuf;
648 ibufend = iptr+cnt*4;
649 optr = rlebuf;
650
651 while(iptr<ibufend) {
652 sptr = iptr;
653 iptr += 8;
654 while((iptr<ibufend)&& ((iptr[-8]!=iptr[-4])||(iptr[-4]!=iptr[0])))
655 iptr+=4;
656 iptr -= 8;
657 count = (iptr-sptr)/4;
658 while(count) {
659 todo = count>126 ? 126:count;
660 count -= todo;
661 *optr++ = 0x80|todo;
662 while(todo>8) {
663 optr[0] = sptr[0*4];
664 optr[1] = sptr[1*4];
665 optr[2] = sptr[2*4];
666 optr[3] = sptr[3*4];
667 optr[4] = sptr[4*4];
668 optr[5] = sptr[5*4];
669 optr[6] = sptr[6*4];
670 optr[7] = sptr[7*4];
671 optr += 8;
672 sptr += 8*4;
673 todo -= 8;
674 }
675 while(todo--) {
676 *optr++ = *sptr;
677 sptr += 4;
678 }
679 }
680 sptr = iptr;
681 cc = *iptr;
682 iptr += 4;
683 while( (iptr<ibufend) && (*iptr == cc) )
684 iptr += 4;
685 count = (iptr-sptr)/4;
686 while(count) {
687 todo = count>126 ? 126:count;
688 count -= todo;
689 *optr++ = todo;
690 *optr++ = cc;
691 }
692 }
693 *optr++ = 0;
694 return optr - (unsigned char *)rlebuf;
695}
696
697static struct methodlist rgbimg_methods[] = {
698 {"sizeofimage", sizeofimage},
699 {"longimagedata", longimagedata},
700 {"longstoimage", longstoimage},
701 {NULL, NULL} /* sentinel */
702};
703
704void
705initrgbimg()
706{
707 object *m, *d;
708 m = initmodule("rgbimg", rgbimg_methods);
709 d = getmoduledict(m);
710 ImgfileError = newstringobject("rgbimg,error");
711 if (ImgfileError == NULL || dictinsert(d, "error", ImgfileError))
712 fatal("can't define rgbimg.error");
713}