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