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
21 typedef unsigned int Py_UInt32
;
24 typedef long Py_Int32
;
25 typedef unsigned long Py_UInt32
;
27 #error "No 4-byte integral type"
38 unsigned short imagic
; /* stuff saved on disk . . */
50 Py_Int32 file
; /* stuff used in core only */
59 unsigned short *tmpbuf
;
61 Py_UInt32 rleend
; /* for rle images */
62 Py_UInt32
*rowstart
; /* for rle images */
63 Py_Int32
*rowsize
; /* for rle images */
68 #define TYPEMASK 0xff00
69 #define BPPMASK 0x00ff
70 #define ITYPE_VERBATIM 0x0000
71 #define ITYPE_RLE 0x0100
72 #define ISRLE(type) (((type) & 0xff00) == ITYPE_RLE)
73 #define ISVERBATIM(type) (((type) & 0xff00) == ITYPE_VERBATIM)
74 #define BPP(type) ((type) & BPPMASK)
75 #define RLE(bpp) (ITYPE_RLE | (bpp))
76 #define VERBATIM(bpp) (ITYPE_VERBATIM | (bpp))
78 * end of image.h stuff
86 #define ILUM(r,g,b) ((int)(RINTLUM*(r)+GINTLUM*(g)+BINTLUM*(b))>>8)
88 #define OFFSET_R 3 /* this is byte order dependent */
93 #define CHANOFFSET(z) (3-(z)) /* this is byte order dependent */
95 static void expandrow(unsigned char *, unsigned char *, int);
96 static void setalpha(unsigned char *, int);
97 static void copybw(Py_Int32
*, int);
98 static void interleaverow(unsigned char*, unsigned char*, int, int);
99 static int compressrow(unsigned char *, unsigned char *, int, int);
100 static void lumrow(unsigned char *, unsigned char *, int);
108 static PyObject
*ImgfileError
;
110 static int reverse_order
;
115 * this is used to extract image data from core dumps.
119 addlongimgtag(Py_UInt32
*dptr
, int xsize
, int ysize
)
121 dptr
= dptr
+ (xsize
* ysize
);
122 dptr
[0] = 0x12345678;
123 dptr
[1] = 0x59493333;
124 dptr
[2] = 0x69434222;
131 * byte order independent read/write of shorts and longs.
134 static unsigned short
137 unsigned char buf
[2];
139 fread(buf
, 2, 1, inf
);
140 return (buf
[0] << 8) + (buf
[1] << 0);
146 unsigned char buf
[4];
148 fread(buf
, 4, 1, inf
);
149 return (buf
[0] << 24) + (buf
[1] << 16) + (buf
[2] << 8) + (buf
[3] << 0);
153 putshort(FILE *outf
, unsigned short val
)
155 unsigned char buf
[2];
159 fwrite(buf
, 2, 1, outf
);
163 putlong(FILE *outf
, Py_UInt32 val
)
165 unsigned char buf
[4];
167 buf
[0] = (unsigned char) (val
>> 24);
168 buf
[1] = (unsigned char) (val
>> 16);
169 buf
[2] = (unsigned char) (val
>> 8);
170 buf
[3] = (unsigned char) (val
>> 0);
171 return fwrite(buf
, 4, 1, outf
);
175 readheader(FILE *inf
, IMAGE
*image
)
177 memset(image
,0, sizeof(IMAGE
));
178 image
->imagic
= getshort(inf
);
179 image
->type
= getshort(inf
);
180 image
->dim
= getshort(inf
);
181 image
->xsize
= getshort(inf
);
182 image
->ysize
= getshort(inf
);
183 image
->zsize
= getshort(inf
);
187 writeheader(FILE *outf
, IMAGE
*image
)
191 memset(&t
, 0, sizeof(IMAGE
));
192 fwrite(&t
, sizeof(IMAGE
), 1, outf
);
193 fseek(outf
, 0, SEEK_SET
);
194 putshort(outf
, image
->imagic
);
195 putshort(outf
, image
->type
);
196 putshort(outf
, image
->dim
);
197 putshort(outf
, image
->xsize
);
198 putshort(outf
, image
->ysize
);
199 putshort(outf
, image
->zsize
);
200 putlong(outf
, image
->min
);
201 putlong(outf
, image
->max
);
203 return fwrite("no name", 8, 1, outf
);
207 writetab(FILE *outf
, /*unsigned*/ Py_Int32
*tab
, int len
)
212 r
= putlong(outf
, *tab
++);
219 readtab(FILE *inf
, /*unsigned*/ Py_Int32
*tab
, int len
)
222 *tab
++ = getlong(inf
);
229 * return the xsize and ysize of an iris image file.
233 sizeofimage(PyObject
*self
, PyObject
*args
)
239 if (!PyArg_ParseTuple(args
, "s:sizeofimage", &name
))
242 inf
= fopen(name
, "rb");
244 PyErr_SetString(ImgfileError
, "can't open image file");
247 readheader(inf
, &image
);
249 if (image
.imagic
!= IMAGIC
) {
250 PyErr_SetString(ImgfileError
,
251 "bad magic number in image file");
254 return Py_BuildValue("(ii)", image
.xsize
, image
.ysize
);
259 * read in a B/W RGB or RGBA iris image file and return a
260 * pointer to an array of longs.
264 longimagedata(PyObject
*self
, PyObject
*args
)
267 unsigned char *base
, *lptr
;
268 unsigned char *rledat
= NULL
, *verdat
= NULL
;
269 Py_Int32
*starttab
= NULL
, *lengthtab
= NULL
;
273 int xsize
, ysize
, zsize
;
274 int bpp
, rle
, cur
, badorder
;
278 if (!PyArg_ParseTuple(args
, "s:longimagedata", &name
))
281 inf
= fopen(name
,"rb");
283 PyErr_SetString(ImgfileError
, "can't open image file");
286 readheader(inf
,&image
);
287 if (image
.imagic
!= IMAGIC
) {
288 PyErr_SetString(ImgfileError
,
289 "bad magic number in image file");
292 rle
= ISRLE(image
.type
);
293 bpp
= BPP(image
.type
);
295 PyErr_SetString(ImgfileError
,
296 "image must have 1 byte per pix chan");
303 tablen
= ysize
* zsize
* sizeof(Py_Int32
);
304 starttab
= (Py_Int32
*)malloc(tablen
);
305 lengthtab
= (Py_Int32
*)malloc(tablen
);
306 rlebuflen
= (int) (1.05 * xsize
+10);
307 rledat
= (unsigned char *)malloc(rlebuflen
);
308 if (!starttab
|| !lengthtab
|| !rledat
) {
313 fseek(inf
, 512, SEEK_SET
);
314 readtab(inf
, starttab
, ysize
*zsize
);
315 readtab(inf
, lengthtab
, ysize
*zsize
);
317 /* check data order */
320 for(y
= 0; y
< ysize
; y
++) {
321 for(z
= 0; z
< zsize
; z
++) {
322 if (starttab
[y
+ z
* ysize
] < cur
) {
326 cur
= starttab
[y
+z
* ysize
];
332 fseek(inf
, 512 + 2 * tablen
, SEEK_SET
);
333 cur
= 512 + 2 * tablen
;
334 rv
= PyString_FromStringAndSize((char *)NULL
,
335 (xsize
* ysize
+ TAGLEN
) * sizeof(Py_Int32
));
339 base
= (unsigned char *) PyString_AsString(rv
);
341 addlongimgtag(base
,xsize
,ysize
);
344 for (z
= 0; z
< zsize
; z
++) {
347 lptr
+= (ysize
- 1) * xsize
349 for (y
= 0; y
< ysize
; y
++) {
350 int idx
= y
+ z
* ysize
;
351 if (cur
!= starttab
[idx
]) {
352 fseek(inf
,starttab
[idx
],
356 if (lengthtab
[idx
] > rlebuflen
) {
357 PyErr_SetString(ImgfileError
,
358 "rlebuf is too small");
363 fread(rledat
, lengthtab
[idx
], 1, inf
);
364 cur
+= lengthtab
[idx
];
365 expandrow(lptr
, rledat
, 3-z
);
377 lptr
+= (ysize
- 1) * xsize
379 for (y
= 0; y
< ysize
; y
++) {
380 for(z
= 0; z
< zsize
; z
++) {
381 int idx
= y
+ z
* ysize
;
382 if (cur
!= starttab
[idx
]) {
383 fseek(inf
, starttab
[idx
],
387 fread(rledat
, lengthtab
[idx
], 1, inf
);
388 cur
+= lengthtab
[idx
];
389 expandrow(lptr
, rledat
, 3-z
);
392 lptr
-= xsize
* sizeof(Py_UInt32
);
394 lptr
+= xsize
* sizeof(Py_UInt32
);
398 setalpha(base
, xsize
* ysize
);
400 copybw((Py_Int32
*) base
, xsize
* ysize
);
403 rv
= PyString_FromStringAndSize((char *) 0,
404 (xsize
*ysize
+TAGLEN
)*sizeof(Py_Int32
));
408 base
= (unsigned char *) PyString_AsString(rv
);
410 addlongimgtag(base
, xsize
, ysize
);
412 verdat
= (unsigned char *)malloc(xsize
);
413 fseek(inf
, 512, SEEK_SET
);
414 for (z
= 0; z
< zsize
; z
++) {
417 lptr
+= (ysize
- 1) * xsize
419 for (y
= 0; y
< ysize
; y
++) {
420 fread(verdat
, xsize
, 1, inf
);
421 interleaverow(lptr
, verdat
, 3-z
, xsize
);
423 lptr
-= xsize
* sizeof(Py_UInt32
);
425 lptr
+= xsize
* sizeof(Py_UInt32
);
429 setalpha(base
, xsize
* ysize
);
431 copybw((Py_Int32
*) base
, xsize
* ysize
);
442 /* static utility functions for longimagedata */
445 interleaverow(unsigned char *lptr
, unsigned char *cptr
, int z
, int n
)
455 copybw(Py_Int32
*lptr
, int n
)
458 lptr
[0] = 0xff000000 + (0x010101 * (lptr
[0] & 0xff));
459 lptr
[1] = 0xff000000 + (0x010101 * (lptr
[1] & 0xff));
460 lptr
[2] = 0xff000000 + (0x010101 * (lptr
[2] & 0xff));
461 lptr
[3] = 0xff000000 + (0x010101 * (lptr
[3] & 0xff));
462 lptr
[4] = 0xff000000 + (0x010101 * (lptr
[4] & 0xff));
463 lptr
[5] = 0xff000000 + (0x010101 * (lptr
[5] & 0xff));
464 lptr
[6] = 0xff000000 + (0x010101 * (lptr
[6] & 0xff));
465 lptr
[7] = 0xff000000 + (0x010101 * (lptr
[7] & 0xff));
470 *lptr
= 0xff000000 + (0x010101 * (*lptr
&0xff));
476 setalpha(unsigned char *lptr
, int n
)
497 expandrow(unsigned char *optr
, unsigned char *iptr
, int z
)
499 unsigned char pixel
, count
;
504 if (!(count
= (pixel
& 0x7f)))
508 optr
[0 * 4] = iptr
[0];
509 optr
[1 * 4] = iptr
[1];
510 optr
[2 * 4] = iptr
[2];
511 optr
[3 * 4] = iptr
[3];
512 optr
[4 * 4] = iptr
[4];
513 optr
[5 * 4] = iptr
[5];
514 optr
[6 * 4] = iptr
[6];
515 optr
[7 * 4] = iptr
[7];
549 * copy an array of longs to an iris image file. Each long
550 * represents one pixel. xsize and ysize specify the dimensions of
551 * the pixel array. zsize specifies what kind of image file to
552 * write out. if zsize is 1, the luminance of the pixels are
553 * calculated, and a single channel black and white image is saved.
554 * If zsize is 3, an RGB image file is saved. If zsize is 4, an
555 * RGBA image file is saved.
559 longstoimage(PyObject
*self
, PyObject
*args
)
563 int xsize
, ysize
, zsize
;
566 int tablen
, y
, z
, pos
, len
;
567 Py_Int32
*starttab
= NULL
, *lengthtab
= NULL
;
568 unsigned char *rlebuf
= NULL
;
569 unsigned char *lumbuf
= NULL
;
570 int rlebuflen
, goodwrite
;
571 PyObject
*retval
= NULL
;
573 if (!PyArg_ParseTuple(args
, "s#iiis:longstoimage", &lptr
, &len
,
574 &xsize
, &ysize
, &zsize
, &name
))
578 outf
= fopen(name
, "wb");
580 PyErr_SetString(ImgfileError
, "can't open output file");
583 tablen
= ysize
* zsize
* sizeof(Py_Int32
);
585 starttab
= (Py_Int32
*)malloc(tablen
);
586 lengthtab
= (Py_Int32
*)malloc(tablen
);
587 rlebuflen
= (int) (1.05 * xsize
+ 10);
588 rlebuf
= (unsigned char *)malloc(rlebuflen
);
589 lumbuf
= (unsigned char *)malloc(xsize
* sizeof(Py_Int32
));
590 if (!starttab
|| !lengthtab
|| !rlebuf
|| !lumbuf
) {
595 memset(&image
, 0, sizeof(IMAGE
));
596 image
.imagic
= IMAGIC
;
607 goodwrite
*= writeheader(outf
, &image
);
608 pos
= 512 + 2 * tablen
;
609 fseek(outf
, pos
, SEEK_SET
);
611 lptr
+= (ysize
- 1) * xsize
* sizeof(Py_UInt32
);
612 for (y
= 0; y
< ysize
; y
++) {
613 for (z
= 0; z
< zsize
; z
++) {
615 lumrow(lptr
, lumbuf
, xsize
);
616 len
= compressrow(lumbuf
, rlebuf
,
617 CHANOFFSET(z
), xsize
);
619 len
= compressrow(lptr
, rlebuf
,
620 CHANOFFSET(z
), xsize
);
622 if(len
> rlebuflen
) {
623 PyErr_SetString(ImgfileError
,
624 "rlebuf is too small");
627 goodwrite
*= fwrite(rlebuf
, len
, 1, outf
);
628 starttab
[y
+ z
* ysize
] = pos
;
629 lengthtab
[y
+ z
* ysize
] = len
;
633 lptr
-= xsize
* sizeof(Py_UInt32
);
635 lptr
+= xsize
* sizeof(Py_UInt32
);
638 fseek(outf
, 512, SEEK_SET
);
639 goodwrite
*= writetab(outf
, starttab
, ysize
*zsize
);
640 goodwrite
*= writetab(outf
, lengthtab
, ysize
*zsize
);
645 PyErr_SetString(ImgfileError
, "not enough space for image");
656 /* static utility functions for longstoimage */
659 lumrow(unsigned char *rgbptr
, unsigned char *lumptr
, int n
)
661 lumptr
+= CHANOFFSET(0);
663 *lumptr
= ILUM(rgbptr
[OFFSET_R
],
672 compressrow(unsigned char *lbuf
, unsigned char *rlebuf
, int z
, int cnt
)
674 unsigned char *iptr
, *ibufend
, *sptr
, *optr
;
680 ibufend
= iptr
+ cnt
* 4;
683 while(iptr
< ibufend
) {
686 while ((iptr
<ibufend
) &&
687 ((iptr
[-8]!=iptr
[-4]) ||(iptr
[-4]!=iptr
[0])))
692 count
= (iptr
- sptr
) / 4;
694 todo
= count
> 126 ? 126 : (short)count
;
696 *optr
++ = 0x80 | todo
;
698 optr
[0] = sptr
[0 * 4];
699 optr
[1] = sptr
[1 * 4];
700 optr
[2] = sptr
[2 * 4];
701 optr
[3] = sptr
[3 * 4];
702 optr
[4] = sptr
[4 * 4];
703 optr
[5] = sptr
[5 * 4];
704 optr
[6] = sptr
[6 * 4];
705 optr
[7] = sptr
[7 * 4];
718 while ((iptr
< ibufend
) && (*iptr
== cc
))
720 count
= (iptr
- sptr
) / 4;
722 todo
= count
> 126 ? 126 : (short)count
;
724 *optr
++ = (unsigned char) todo
;
725 *optr
++ = (unsigned char) cc
;
729 return optr
- (unsigned char *)rlebuf
;
733 ttob(PyObject
*self
, PyObject
*args
)
737 if (!PyArg_ParseTuple(args
, "i:ttob", &order
))
739 oldorder
= reverse_order
;
740 reverse_order
= order
;
741 return PyInt_FromLong(oldorder
);
746 {"sizeofimage", sizeofimage
, METH_VARARGS
},
747 {"longimagedata", longimagedata
, METH_VARARGS
},
748 {"longstoimage", longstoimage
, METH_VARARGS
},
749 {"ttob", ttob
, METH_VARARGS
},
750 {NULL
, NULL
} /* sentinel */
758 m
= Py_InitModule("rgbimg", rgbimg_methods
);
759 d
= PyModule_GetDict(m
);
760 ImgfileError
= PyErr_NewException("rgbimg.error", NULL
, NULL
);
761 if (ImgfileError
!= NULL
)
762 PyDict_SetItemString(d
, "error", ImgfileError
);