0
0
mirror of https://github.com/python/cpython.git synced 2024-12-01 11:15:56 +01:00
cpython/Modules/rgbimgmodule.c
Guido van Rossum 3bbc62e9c2 Another bulky set of minor changes.
Note addition of gethostbyaddr() and improved repr() for sockets,
renaming of md5.md5() to md5.new(), and fixing of leaks in threads.
1995-01-02 19:30:30 +00:00

753 lines
16 KiB
C

/*
* fastimg -
* Faster reading and writing of image files.
*
* This code should work on machines with any byte order.
*
* Could someone make this run real fast using multiple processors
* or how about using memory mapped files to speed it up?
*
* Paul Haeberli - 1991
*
* Changed to return sizes.
* Sjoerd Mullender - 1993
* Changed to incorporate into Python.
* Sjoerd Mullender - 1993
*/
#include "allobjects.h"
#include "modsupport.h"
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <string.h>
/*
* from image.h
*
*/
typedef struct {
unsigned short imagic; /* stuff saved on disk . . */
unsigned short type;
unsigned short dim;
unsigned short xsize;
unsigned short ysize;
unsigned short zsize;
unsigned long min;
unsigned long max;
unsigned long wastebytes;
char name[80];
unsigned long colormap;
long file; /* stuff used in core only */
unsigned short flags;
short dorev;
short x;
short y;
short z;
short cnt;
unsigned short *ptr;
unsigned short *base;
unsigned short *tmpbuf;
unsigned long offset;
unsigned long rleend; /* for rle images */
unsigned long *rowstart; /* for rle images */
long *rowsize; /* for rle images */
} IMAGE;
#define IMAGIC 0732
#define TYPEMASK 0xff00
#define BPPMASK 0x00ff
#define ITYPE_VERBATIM 0x0000
#define ITYPE_RLE 0x0100
#define ISRLE(type) (((type) & 0xff00) == ITYPE_RLE)
#define ISVERBATIM(type) (((type) & 0xff00) == ITYPE_VERBATIM)
#define BPP(type) ((type) & BPPMASK)
#define RLE(bpp) (ITYPE_RLE | (bpp))
#define VERBATIM(bpp) (ITYPE_VERBATIM | (bpp))
/*
* end of image.h stuff
*
*/
#define RINTLUM (79)
#define GINTLUM (156)
#define BINTLUM (21)
#define ILUM(r,g,b) ((int)(RINTLUM*(r)+GINTLUM*(g)+BINTLUM*(b))>>8)
#define OFFSET_R 3 /* this is byte order dependent */
#define OFFSET_G 2
#define OFFSET_B 1
#define OFFSET_A 0
#define CHANOFFSET(z) (3-(z)) /* this is byte order dependent */
static expandrow PROTO((unsigned char *, unsigned char *, int));
static setalpha PROTO((unsigned char *, int));
static copybw PROTO((long *, int));
static interleaverow PROTO((unsigned char *, unsigned char *, int, int));
static int compressrow PROTO((unsigned char *, unsigned char *, int, int));
static lumrow PROTO((unsigned char *, unsigned char *, int));
#ifdef ADD_TAGS
#define TAGLEN (5)
#else
#define TAGLEN (0)
#endif
static object *ImgfileError;
static int reverse_order;
#ifdef ADD_TAGS
/*
* addlongimgtag -
* this is used to extract image data from core dumps.
*
*/
addlongimgtag(dptr,xsize,ysize)
unsigned long *dptr;
int xsize, ysize;
{
dptr = dptr+(xsize*ysize);
dptr[0] = 0x12345678;
dptr[1] = 0x59493333;
dptr[2] = 0x69434222;
dptr[3] = xsize;
dptr[4] = ysize;
}
#endif
/*
* byte order independent read/write of shorts and longs.
*
*/
static unsigned short getshort(inf)
FILE *inf;
{
unsigned char buf[2];
fread(buf,2,1,inf);
return (buf[0]<<8)+(buf[1]<<0);
}
static unsigned long getlong(inf)
FILE *inf;
{
unsigned char buf[4];
fread(buf,4,1,inf);
return (buf[0]<<24)+(buf[1]<<16)+(buf[2]<<8)+(buf[3]<<0);
}
static putshort(outf,val)
FILE *outf;
unsigned short val;
{
unsigned char buf[2];
buf[0] = (val>>8);
buf[1] = (val>>0);
fwrite(buf,2,1,outf);
}
static int putlong(outf,val)
FILE *outf;
unsigned long val;
{
unsigned char buf[4];
buf[0] = (val>>24);
buf[1] = (val>>16);
buf[2] = (val>>8);
buf[3] = (val>>0);
return fwrite(buf,4,1,outf);
}
static readheader(inf,image)
FILE *inf;
IMAGE *image;
{
memset(image,0,sizeof(IMAGE));
image->imagic = getshort(inf);
image->type = getshort(inf);
image->dim = getshort(inf);
image->xsize = getshort(inf);
image->ysize = getshort(inf);
image->zsize = getshort(inf);
}
static int writeheader(outf,image)
FILE *outf;
IMAGE *image;
{
IMAGE t;
memset(&t,0,sizeof(IMAGE));
fwrite(&t,sizeof(IMAGE),1,outf);
fseek(outf,0,SEEK_SET);
putshort(outf,image->imagic);
putshort(outf,image->type);
putshort(outf,image->dim);
putshort(outf,image->xsize);
putshort(outf,image->ysize);
putshort(outf,image->zsize);
putlong(outf,image->min);
putlong(outf,image->max);
putlong(outf,0);
return fwrite("no name",8,1,outf);
}
static int writetab(outf,tab,len)
FILE *outf;
/*unsigned*/ long *tab;
int len;
{
int r;
while(len) {
r = putlong(outf,*tab++);
len -= 4;
}
return r;
}
static readtab(inf,tab,len)
FILE *inf;
/*unsigned*/ long *tab;
int len;
{
while(len) {
*tab++ = getlong(inf);
len -= 4;
}
}
/*
* sizeofimage -
* return the xsize and ysize of an iris image file.
*
*/
static object *
sizeofimage(self, args)
object *self, *args;
{
char *name;
IMAGE image;
FILE *inf;
if (!getargs(args, "s", &name))
return NULL;
inf = fopen(name,"r");
if(!inf) {
err_setstr(ImgfileError, "can't open image file");
return NULL;
}
readheader(inf,&image);
fclose(inf);
if(image.imagic != IMAGIC) {
err_setstr(ImgfileError, "bad magic number in image file");
return NULL;
}
return mkvalue("(ii)", image.xsize, image.ysize);
}
/*
* longimagedata -
* read in a B/W RGB or RGBA iris image file and return a
* pointer to an array of longs.
*
*/
static object *
longimagedata(self, args)
object *self, *args;
{
char *name;
unsigned char *base, *lptr;
unsigned char *rledat, *verdat;
long *starttab, *lengthtab;
FILE *inf;
IMAGE image;
int y, z, tablen;
int xsize, ysize, zsize;
int bpp, rle, cur, badorder;
int rlebuflen;
object *rv;
if (!getargs(args, "s", &name))
return NULL;
inf = fopen(name,"r");
if(!inf) {
err_setstr(ImgfileError,"can't open image file");
return NULL;
}
readheader(inf,&image);
if(image.imagic != IMAGIC) {
err_setstr(ImgfileError,"bad magic number in image file");
fclose(inf);
return NULL;
}
rle = ISRLE(image.type);
bpp = BPP(image.type);
if(bpp != 1 ) {
err_setstr(ImgfileError,"image must have 1 byte per pix chan");
fclose(inf);
return NULL;
}
xsize = image.xsize;
ysize = image.ysize;
zsize = image.zsize;
if(rle) {
tablen = ysize*zsize*sizeof(long);
starttab = (long *)malloc(tablen);
lengthtab = (long *)malloc(tablen);
rlebuflen = 1.05*xsize+10;
rledat = (unsigned char *)malloc(rlebuflen);
fseek(inf,512,SEEK_SET);
readtab(inf,starttab,tablen);
readtab(inf,lengthtab,tablen);
/* check data order */
cur = 0;
badorder = 0;
for(y=0; y<ysize; y++) {
for(z=0; z<zsize; z++) {
if(starttab[y+z*ysize]<cur) {
badorder = 1;
break;
}
cur = starttab[y+z*ysize];
}
if(badorder)
break;
}
fseek(inf,512+2*tablen,SEEK_SET);
cur = 512+2*tablen;
rv = newsizedstringobject((char *) 0,
(xsize*ysize+TAGLEN)*sizeof(long));
if (rv == NULL) {
fclose(inf);
free(lengthtab);
free(starttab);
free(rledat);
return NULL;
}
base = (unsigned char *) getstringvalue(rv);
#ifdef ADD_TAGS
addlongimgtag(base,xsize,ysize);
#endif
if(badorder) {
for(z=0; z<zsize; z++) {
lptr = base;
if (reverse_order)
lptr += (ysize - 1) * xsize * sizeof(unsigned long);
for(y=0; y<ysize; y++) {
if(cur != starttab[y+z*ysize]) {
fseek(inf,starttab[y+z*ysize],SEEK_SET);
cur = starttab[y+z*ysize];
}
if(lengthtab[y+z*ysize]>rlebuflen) {
err_setstr(ImgfileError,"rlebuf is too small - bad poop");
fclose(inf);
DECREF(rv);
free(rledat);
free(starttab);
free(lengthtab);
return NULL;
}
fread(rledat,lengthtab[y+z*ysize],1,inf);
cur += lengthtab[y+z*ysize];
expandrow(lptr,rledat,3-z);
if (reverse_order)
lptr -= xsize * sizeof(unsigned long);
else
lptr += xsize * sizeof(unsigned long);
}
}
} else {
lptr = base;
if (reverse_order)
lptr += (ysize - 1) * xsize * sizeof(unsigned long);
for(y=0; y<ysize; y++) {
for(z=0; z<zsize; z++) {
if(cur != starttab[y+z*ysize]) {
fseek(inf,starttab[y+z*ysize],SEEK_SET);
cur = starttab[y+z*ysize];
}
fread(rledat,lengthtab[y+z*ysize],1,inf);
cur += lengthtab[y+z*ysize];
expandrow(lptr,rledat,3-z);
}
if (reverse_order)
lptr -= xsize * sizeof(unsigned long);
else
lptr += xsize * sizeof(unsigned long);
}
}
if(zsize == 3)
setalpha(base,xsize*ysize);
else if(zsize<3)
copybw((long *) base,xsize*ysize);
fclose(inf);
free(starttab);
free(lengthtab);
free(rledat);
return rv;
} else {
rv = newsizedstringobject((char *) 0,
(xsize*ysize+TAGLEN)*sizeof(long));
if (rv == NULL) {
fclose(inf);
return NULL;
}
base = (unsigned char *) getstringvalue(rv);
#ifdef ADD_TAGS
addlongimgtag(base,xsize,ysize);
#endif
verdat = (unsigned char *)malloc(xsize);
fseek(inf,512,SEEK_SET);
for(z=0; z<zsize; z++) {
lptr = base;
if (reverse_order)
lptr += (ysize - 1) * xsize * sizeof(unsigned long);
for(y=0; y<ysize; y++) {
fread(verdat,xsize,1,inf);
interleaverow(lptr,verdat,3-z,xsize);
if (reverse_order)
lptr -= xsize * sizeof(unsigned long);
else
lptr += xsize * sizeof(unsigned long);
}
}
if(zsize == 3)
setalpha(base,xsize*ysize);
else if(zsize<3)
copybw((long *) base,xsize*ysize);
fclose(inf);
free(verdat);
return rv;
}
}
/* static utility functions for longimagedata */
static interleaverow(lptr,cptr,z,n)
unsigned char *lptr, *cptr;
int z, n;
{
lptr += z;
while(n--) {
*lptr = *cptr++;
lptr += 4;
}
}
static copybw(lptr,n)
long *lptr;
int n;
{
while(n>=8) {
lptr[0] = 0xff000000+(0x010101*(lptr[0]&0xff));
lptr[1] = 0xff000000+(0x010101*(lptr[1]&0xff));
lptr[2] = 0xff000000+(0x010101*(lptr[2]&0xff));
lptr[3] = 0xff000000+(0x010101*(lptr[3]&0xff));
lptr[4] = 0xff000000+(0x010101*(lptr[4]&0xff));
lptr[5] = 0xff000000+(0x010101*(lptr[5]&0xff));
lptr[6] = 0xff000000+(0x010101*(lptr[6]&0xff));
lptr[7] = 0xff000000+(0x010101*(lptr[7]&0xff));
lptr += 8;
n-=8;
}
while(n--) {
*lptr = 0xff000000+(0x010101*(*lptr&0xff));
lptr++;
}
}
static setalpha(lptr,n)
unsigned char *lptr;
{
while(n>=8) {
lptr[0*4] = 0xff;
lptr[1*4] = 0xff;
lptr[2*4] = 0xff;
lptr[3*4] = 0xff;
lptr[4*4] = 0xff;
lptr[5*4] = 0xff;
lptr[6*4] = 0xff;
lptr[7*4] = 0xff;
lptr += 4*8;
n -= 8;
}
while(n--) {
*lptr = 0xff;
lptr += 4;
}
}
static expandrow(optr,iptr,z)
unsigned char *optr, *iptr;
int z;
{
unsigned char pixel, count;
optr += z;
while(1) {
pixel = *iptr++;
if ( !(count = (pixel & 0x7f)) )
return;
if(pixel & 0x80) {
while(count>=8) {
optr[0*4] = iptr[0];
optr[1*4] = iptr[1];
optr[2*4] = iptr[2];
optr[3*4] = iptr[3];
optr[4*4] = iptr[4];
optr[5*4] = iptr[5];
optr[6*4] = iptr[6];
optr[7*4] = iptr[7];
optr += 8*4;
iptr += 8;
count -= 8;
}
while(count--) {
*optr = *iptr++;
optr+=4;
}
} else {
pixel = *iptr++;
while(count>=8) {
optr[0*4] = pixel;
optr[1*4] = pixel;
optr[2*4] = pixel;
optr[3*4] = pixel;
optr[4*4] = pixel;
optr[5*4] = pixel;
optr[6*4] = pixel;
optr[7*4] = pixel;
optr += 8*4;
count -= 8;
}
while(count--) {
*optr = pixel;
optr+=4;
}
}
}
}
/*
* longstoimage -
* copy an array of longs to an iris image file. Each long
* represents one pixel. xsize and ysize specify the dimensions of
* the pixel array. zsize specifies what kind of image file to
* write out. if zsize is 1, the luminance of the pixels are
* calculated, and a sinlge channel black and white image is saved.
* If zsize is 3, an RGB image file is saved. If zsize is 4, an
* RGBA image file is saved.
*
*/
static object *
longstoimage(self, args)
object *self, *args;
{
unsigned char *lptr;
char *name;
int xsize, ysize, zsize;
FILE *outf;
IMAGE image;
int tablen, y, z, pos, len;
long *starttab, *lengthtab;
unsigned char *rlebuf;
unsigned char *lumbuf;
int rlebuflen, goodwrite;
if (!getargs(args, "(s#iiis)", &lptr, &len, &xsize, &ysize, &zsize, &name))
return NULL;
goodwrite = 1;
outf = fopen(name,"w");
if(!outf) {
err_setstr(ImgfileError,"can't open output file");
return NULL;
}
tablen = ysize*zsize*sizeof(long);
starttab = (long *)malloc(tablen);
lengthtab = (long *)malloc(tablen);
rlebuflen = 1.05*xsize+10;
rlebuf = (unsigned char *)malloc(rlebuflen);
lumbuf = (unsigned char *)malloc(xsize*sizeof(long));
memset(&image,0,sizeof(IMAGE));
image.imagic = IMAGIC;
image.type = RLE(1);
if(zsize>1)
image.dim = 3;
else
image.dim = 2;
image.xsize = xsize;
image.ysize = ysize;
image.zsize = zsize;
image.min = 0;
image.max = 255;
goodwrite *= writeheader(outf,&image);
fseek(outf,512+2*tablen,SEEK_SET);
pos = 512+2*tablen;
if (reverse_order)
lptr += (ysize - 1) * xsize * sizeof(unsigned long);
for(y=0; y<ysize; y++) {
for(z=0; z<zsize; z++) {
if(zsize == 1) {
lumrow(lptr,lumbuf,xsize);
len = compressrow(lumbuf,rlebuf,CHANOFFSET(z),xsize);
} else {
len = compressrow(lptr,rlebuf,CHANOFFSET(z),xsize);
}
if(len>rlebuflen) {
err_setstr(ImgfileError,"rlebuf is too small - bad poop");
free(starttab);
free(lengthtab);
free(rlebuf);
free(lumbuf);
fclose(outf);
return NULL;
}
goodwrite *= fwrite(rlebuf,len,1,outf);
starttab[y+z*ysize] = pos;
lengthtab[y+z*ysize] = len;
pos += len;
}
if (reverse_order)
lptr -= xsize * sizeof(unsigned long);
else
lptr += xsize * sizeof(unsigned long);
}
fseek(outf,512,SEEK_SET);
goodwrite *= writetab(outf,starttab,tablen);
goodwrite *= writetab(outf,lengthtab,tablen);
free(starttab);
free(lengthtab);
free(rlebuf);
free(lumbuf);
fclose(outf);
if(goodwrite) {
INCREF(None);
return None;
} else {
err_setstr(ImgfileError,"not enough space for image!!");
return NULL;
}
}
/* static utility functions for longstoimage */
static lumrow(rgbptr,lumptr,n)
unsigned char *rgbptr, *lumptr;
int n;
{
lumptr += CHANOFFSET(0);
while(n--) {
*lumptr = ILUM(rgbptr[OFFSET_R],rgbptr[OFFSET_G],rgbptr[OFFSET_B]);
lumptr += 4;
rgbptr += 4;
}
}
static int compressrow(lbuf,rlebuf,z,cnt)
unsigned char *lbuf, *rlebuf;
int z, cnt;
{
unsigned char *iptr, *ibufend, *sptr, *optr;
short todo, cc;
long count;
lbuf += z;
iptr = lbuf;
ibufend = iptr+cnt*4;
optr = rlebuf;
while(iptr<ibufend) {
sptr = iptr;
iptr += 8;
while((iptr<ibufend)&& ((iptr[-8]!=iptr[-4])||(iptr[-4]!=iptr[0])))
iptr+=4;
iptr -= 8;
count = (iptr-sptr)/4;
while(count) {
todo = count>126 ? 126:count;
count -= todo;
*optr++ = 0x80|todo;
while(todo>8) {
optr[0] = sptr[0*4];
optr[1] = sptr[1*4];
optr[2] = sptr[2*4];
optr[3] = sptr[3*4];
optr[4] = sptr[4*4];
optr[5] = sptr[5*4];
optr[6] = sptr[6*4];
optr[7] = sptr[7*4];
optr += 8;
sptr += 8*4;
todo -= 8;
}
while(todo--) {
*optr++ = *sptr;
sptr += 4;
}
}
sptr = iptr;
cc = *iptr;
iptr += 4;
while( (iptr<ibufend) && (*iptr == cc) )
iptr += 4;
count = (iptr-sptr)/4;
while(count) {
todo = count>126 ? 126:count;
count -= todo;
*optr++ = todo;
*optr++ = cc;
}
}
*optr++ = 0;
return optr - (unsigned char *)rlebuf;
}
static object *
ttob(self, args)
object *self;
object *args;
{
int order, oldorder;
if (!getargs(args, "i", &order))
return NULL;
oldorder = reverse_order;
reverse_order = order;
return newintobject(oldorder);
}
static struct methodlist rgbimg_methods[] = {
{"sizeofimage", sizeofimage},
{"longimagedata", longimagedata},
{"longstoimage", longstoimage},
{"ttob", ttob},
{NULL, NULL} /* sentinel */
};
void
initrgbimg()
{
object *m, *d;
m = initmodule("rgbimg", rgbimg_methods);
d = getmoduledict(m);
ImgfileError = newstringobject("rgbimg.error");
if (ImgfileError == NULL || dictinsert(d, "error", ImgfileError))
fatal("can't define rgbimg.error");
}