This is xviris.c in view mode; [Download] [Up]
/*
* xviris.c - load routine for IRIS 'rgb' format pictures
*
* LoadIRIS()
* WriteIRIS()
*/
/* Copyright Notice
* ================
* Copyright 1989, 1990, 1991, 1992, 1993 by John Bradley
*
* Permission to use, copy, and distribute XV in its entirety, for
* non-commercial purposes, is hereby granted without fee, provided that
* this license information and copyright notice appear in all copies.
*
* Note that distributing XV 'bundled' in with ANY product is considered
* to be a 'commercial purpose'.
*
* Also note that any copies of XV that are distributed MUST be built
* and/or configured to be in their 'unregistered copy' mode, so that it
* is made obvious to the user that XV is shareware, and that they should
* consider donating, or at least reading this License Info.
*
* The software may be modified for your own purposes, but modified
* versions may NOT be distributed without prior consent of the author.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the author be held liable for any damages
* arising from the use of this software.
*
* If you would like to do something with XV that this copyright
* prohibits (such as distributing it with a commercial product,
* using portions of the source in some other program, etc.), please
* contact the author (preferably via email). Arrangements can
* probably be worked out.
*
* XV is shareware for PERSONAL USE only. You may use XV for your own
* amusement, and if you find it nifty, useful, generally cool, or of
* some value to you, your non-deductable donation would be greatly
* appreciated. $25 is the suggested donation, though, of course,
* larger donations are quite welcome. Folks who donate $25 or more
* can receive a Real Nice bound copy of the XV manual for no extra
* charge.
*
* Commercial, government, and institutional users MUST register their
* copies of XV, for the exceedingly REASONABLE price of just $25 per
* workstation/X terminal. Site licenses are available for those who
* wish to run XV on a large number of machines. Contact the author
* for more details.
*
* The author may be contacted via:
* US Mail: John Bradley
* 1053 Floyd Terrace
* Bryn Mawr, PA 19010
*
* Phone: (215) 898-8813
* EMail: bradley@cis.upenn.edu
*/
/* based on:
*
* 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
*/
#include "xv.h"
#define IMAGIC 0732
#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))
typedef struct {
u_short imagic; /* stuff saved on disk . . */
u_short type;
u_short dim;
u_short xsize;
u_short ysize;
u_short zsize;
u_long min;
u_long max;
u_long wastebytes;
char name[80];
u_long colormap;
long file; /* stuff used in core only */
u_short flags;
short dorev;
short x;
short y;
short z;
short cnt;
u_short *ptr;
u_short *base;
u_short *tmpbuf;
u_long offset;
u_long rleend; /* for rle images */
u_long *rowstart; /* for rle images */
long *rowsize; /* for rle images */
} IMAGE;
#define TAGLEN (5)
#define RINTLUM (79)
#define GINTLUM (156)
#define BINTLUM (21)
#define OFFSET_R 3 /* this is byte order dependent */
#define OFFSET_G 2
#define OFFSET_B 1
#define OFFSET_A 0
#define ILUM(r,g,b) ((int)(RINTLUM*(r)+GINTLUM*(g)+BINTLUM*(b))>>8)
#define CHANOFFSET(z) (3-(z)) /* this is byte order dependent */
#ifdef __STDC__
static int irisError (char *, char *);
static byte *getimagedata (FILE *, IMAGE *);
static void interleaverow(byte *, byte *, int, int);
static void expandrow (byte *, byte *, int);
static void readtab (FILE *, u_long *, int);
static void addimgtag (byte *, int, int);
static void lumrow (byte *, byte *, int);
static int compressrow (byte *, byte *, int, int);
static void writetab (FILE *, u_long *, int);
static u_short getshort (FILE *);
static u_long getlong (FILE *);
static void putshort (FILE *, int);
static void putlong (FILE *, u_long);
#else
static int irisError();
static byte *getimagedata();
static void interleaverow(), expandrow(), readtab(), addimgtag();
static void lumrow(), writetab();
static int compressrow();
static u_short getshort();
static u_long getlong ();
static void putshort(), putlong ();
#endif
static char *loaderr;
/*****************************************************/
int LoadIRIS(fname, pinfo)
char *fname;
PICINFO *pinfo;
/*****************************************************/
{
/* returns '1' on success, '0' on failure */
FILE *fp;
IMAGE img;
byte *rawdata, *rptr;
byte *pic824, *bptr;
int trunc, i, j;
long filesize;
char *bname;
trunc = 0;
xvbzero((char *) &img, sizeof(IMAGE));
bname = BaseName(fname);
/* open the file */
fp = fopen(fname, "r");
if (!fp) return(irisError(bname, "can't open file"));
/* figure out the file size */
fseek(fp, 0L, 2);
filesize = ftell(fp);
fseek(fp, 0L, 0);
/* read header information from file */
img.imagic = getshort(fp);
img.type = getshort(fp);
img.dim = getshort(fp);
img.xsize = getshort(fp);
img.ysize = getshort(fp);
img.zsize = getshort(fp);
if (ferror(fp)) {
fclose(fp);
return irisError(bname, "error in header info");
}
if (img.imagic != IMAGIC) {
fclose(fp);
return irisError(bname, "bad magic number");
}
rawdata = getimagedata(fp, &img);
if (!rawdata) {
fclose(fp);
if (loaderr) irisError(bname, loaderr);
return 0;
}
if (ferror(fp)) trunc = 1; /* probably truncated file */
fclose(fp);
/* got the raw image data. Convert to an XV image (1,3 bytes / pix) */
if (img.zsize < 3) { /* grayscale */
pic824 = (byte *) malloc(img.xsize * img.ysize);
if (!pic824) FatalError("couldn't malloc pic824 in LoadIRIS()");
/* copy plane 3 from rawdata into pic824, inverting pic vertically */
for (i=0, bptr=pic824; i<img.ysize; i++) {
rptr = rawdata + 3 + ((img.ysize - 1) - i) * (img.xsize * 4);
for (j=0; j<img.xsize; j++, bptr++, rptr+=4) *bptr = *rptr;
}
for (i=0; i<256; i++)
pinfo->r[i] = pinfo->g[i] = pinfo->b[i] = i;
pinfo->pic = pic824;
pinfo->type = PIC8;
pinfo->frmType = F_IRIS;
pinfo->colType = F_GREYSCALE;
sprintf(pinfo->fullInfo, "IRIS Greyscale format%s (%ld bytes)",
(ISRLE(img.type)) ? ", RLE compressed." : ".", filesize);
sprintf(pinfo->shrtInfo, "%dx%d IRIS Greyscale.", img.xsize, img.ysize);
}
else { /* truecolor */
pic824 = (byte *) malloc(img.xsize * img.ysize * 3);
if (!pic824) FatalError("couldn't malloc pic824 in LoadIRIS()");
/* copy plane 3 from rawdata into pic824, inverting pic vertically */
for (i=0, bptr=pic824; i<img.ysize; i++) {
rptr = rawdata + ((img.ysize - 1) - i) * (img.xsize * 4);
for (j=0; j<img.xsize; j++, rptr+=4) {
*bptr++ = rptr[3];
*bptr++ = rptr[2];
*bptr++ = rptr[1];
}
}
pinfo->pic = pic824;
pinfo->type = PIC24;
pinfo->frmType = F_IRIS;
pinfo->colType = F_FULLCOLOR;
sprintf(pinfo->fullInfo, "IRIS RGB format%s (%ld bytes)",
(ISRLE(img.type)) ? ", RLE compressed." : ".", filesize);
sprintf(pinfo->shrtInfo, "%dx%d IRIS RGB.", img.xsize, img.ysize);
}
free(rawdata);
if (trunc) irisError(bname, "File appears to be truncated.");
pinfo->w = img.xsize; pinfo->h = img.ysize;
pinfo->comment = (char *) NULL;
return 1;
}
/*******************************************/
static int irisError(name, st)
char *name, *st;
{
SetISTR(ISTR_WARNING,"%s: %s", name, st);
return 0;
}
/****************************************************/
static byte *getimagedata(fp, img)
FILE *fp;
IMAGE *img;
{
/* read in a B/W RGB or RGBA iris image file and return a
pointer to an array of 4-byte pixels, arranged ABGR, NULL on error */
byte *base, *lptr;
byte *verdat;
int y, z, pos, len, tablen;
int xsize, ysize, zsize;
int bpp, rle, cur, badorder;
int rlebuflen;
rle = ISRLE(img->type);
bpp = BPP(img->type);
loaderr = (char *) NULL;
if (bpp != 1) {
loaderr = "image must have 1 byte per pix chan";
return (byte *) NULL;
}
xsize = img->xsize;
ysize = img->ysize;
zsize = img->zsize;
if (rle) {
byte *rledat;
long *starttab, *lengthtab;
rlebuflen = 2 * xsize + 10;
tablen = ysize * zsize * sizeof(long);
starttab = (long *) malloc(tablen);
lengthtab = (long *) malloc(tablen);
rledat = (byte *) malloc(rlebuflen);
if (!starttab || !lengthtab || !rledat)
FatalError("out of memory in LoadIRIS()");
fseek(fp,512,0);
readtab(fp, starttab, tablen);
readtab(fp, lengthtab, tablen);
if (ferror(fp)) {
loaderr = "error reading scanline tables";
free(starttab); free(lengthtab); free(rledat);
return (byte *) NULL;
}
/* check data order */
cur = 0;
badorder = 0;
for (y=0; y<ysize && !badorder; y++) {
for (z=0; z<zsize && !badorder; z++) {
if (starttab[y+z*ysize] < cur) badorder = 1;
else cur = starttab[y+z*ysize];
}
}
fseek(fp, 512 + 2*tablen, 0);
cur = 512 + 2*tablen;
base = (byte *) malloc((xsize*ysize+TAGLEN) * 4);
if (!base) FatalError("out of memory in LoadIRIS()");
addimgtag(base,xsize,ysize);
if (badorder) {
for (z=0; z<zsize; z++) {
lptr = base;
for (y=0; y<ysize; y++) {
if (cur != starttab[y+z*ysize]) {
fseek(fp,starttab[y+z*ysize],0);
cur = starttab[y+z*ysize];
}
if (lengthtab[y+z*ysize]>rlebuflen) {
FatalError("LoadIRIS() - rlebuf too small");
}
fread(rledat,lengthtab[y+z*ysize],1,fp);
cur += lengthtab[y+z*ysize];
expandrow(lptr,rledat,3-z);
lptr += (xsize * 4);
}
}
}
else {
lptr = base;
for (y=0; y<ysize; y++) {
for (z=0; z<zsize; z++) {
if (cur != starttab[y+z*ysize]) {
fseek(fp,starttab[y+z*ysize],0);
cur = starttab[y+z*ysize];
}
fread(rledat,lengthtab[y+z*ysize],1,fp);
cur += lengthtab[y+z*ysize];
expandrow(lptr,rledat,3-z);
}
lptr += (xsize * 4);
}
}
free(starttab);
free(lengthtab);
free(rledat);
return base;
} /* end of RLE case */
else { /* not RLE */
verdat = (byte *) malloc(xsize);
base = (byte *) malloc((xsize*ysize+TAGLEN) * 4);
if (!base || !verdat) FatalError("out of memory in LoadIRIS()");
addimgtag(base,xsize,ysize);
fseek(fp,512,0);
for (z=0; z<zsize; z++) {
lptr = base;
for (y=0; y<ysize; y++) {
fread(verdat,xsize,1,fp);
interleaverow(lptr,verdat,3-z,xsize);
lptr += (xsize * 4);
}
}
free(verdat);
return base;
}
}
/******************************************/
static void interleaverow(lptr,cptr,z,n)
byte *lptr, *cptr;
int z, n;
{
lptr += z;
while(n--) {
*lptr = *cptr++;
lptr += 4;
}
}
/******************************************/
static void expandrow(optr,iptr,z)
byte *optr, *iptr;
int z;
{
byte 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;
}
}
}
}
/****************************************************/
static void readtab(fp, tab, len)
FILE *fp;
u_long *tab;
int len;
{
while(len) {
*tab++ = getlong(fp);
len -= 4;
}
}
/*****************************************************/
static void addimgtag(dptr,xsize,ysize)
byte *dptr;
int xsize, ysize;
{
/* this is used to extract image data from core dumps.
I doubt this is necessary... --jhb */
dptr = dptr + (xsize * ysize * 4);
dptr[0] = 0x12; dptr[1] = 0x34; dptr[2] = 0x56; dptr[3] = 0x78;
dptr += 4;
dptr[0] = 0x59; dptr[1] = 0x49; dptr[2] = 0x33; dptr[3] = 0x33;
dptr += 4;
dptr[0] = 0x69; dptr[1] = 0x43; dptr[2] = 0x42; dptr[3] = 0x22;
dptr += 4;
dptr[0] = (xsize>>24)&0xff;
dptr[1] = (xsize>>16)&0xff;
dptr[2] = (xsize>> 8)&0xff;
dptr[3] = (xsize )&0xff;
dptr += 4;
dptr[0] = (ysize>>24)&0xff;
dptr[1] = (ysize>>16)&0xff;
dptr[2] = (ysize>> 8)&0xff;
dptr[3] = (ysize )&0xff;
}
/*************************************************/
/* IRIS image-writing routines */
/*************************************************/
/*************************************************/
int WriteIRIS(fp, pic, ptype, w, h, rmap, gmap, bmap, numcols, colorstyle)
FILE *fp;
byte *pic, *rmap, *gmap, *bmap;
int ptype, w, h, numcols, colorstyle;
{
/* writes a greyscale or 24-bit RGB IRIS file to the already open
stream, rle compressed */
IMAGE img;
int i, j, pos, len, tablen, rlebuflen, zsize;
long *starttab, *lengthtab;
byte *rlebuf, *pptr;
byte *lumbuf, *lptr, *longpic;
xvbzero((char *) &img, sizeof(IMAGE));
/* write header information */
fwrite(&img, sizeof(IMAGE), 1, fp);
fseek(fp, 0L, 0);
/* load up header */
img.imagic = IMAGIC;
img.type = ITYPE_RLE | (1 & BPPMASK); /* RLE, 1 byteperpix */
img.dim = (colorstyle == F_FULLCOLOR) ? 3 : 2;
img.xsize = w;
img.ysize = h;
img.zsize = zsize = (colorstyle == F_FULLCOLOR) ? 3 : 1;
img.min = 0;
img.max = 255;
putshort(fp, img.imagic);
putshort(fp, img.type);
putshort(fp, img.dim);
putshort(fp, img.xsize);
putshort(fp, img.ysize);
putshort(fp, img.zsize);
putlong (fp, img.min);
putlong (fp, img.max);
putlong (fp, 0);
fwrite ("no name",8,1,fp);
if (ferror(fp)) { fclose(fp); return -1; }
/* allocate RLE compression tables & stuff */
rlebuflen = 2*w + 10;
tablen = h * zsize * sizeof(long);
starttab = (long *) malloc(tablen);
lengthtab = (long *) malloc(tablen);
rlebuf = (byte *) malloc(rlebuflen);
lumbuf = (byte *) malloc(w * 4);
if (!starttab || !lengthtab || !rlebuf || !lumbuf)
FatalError("out of memory in WriteIRIS()");
pos = 512 + 2 * tablen;
fseek(fp, pos, 0);
/* convert image into 4-byte per pix image that the compress routines want */
longpic = (byte *) malloc(w * h * 4);
if (!longpic) FatalError("couldn't malloc longpic in WriteIRIS()");
for (i=0, pptr=pic; i<h; i++) {
lptr = longpic + ((h-1) - i) * (w * 4); /* vertical flip */
if (ptype == PIC8) { /* colormapped */
for (j=0; j<w; j++, pptr++) {
*lptr++ = 0xff;
*lptr++ = bmap[*pptr];
*lptr++ = gmap[*pptr];
*lptr++ = rmap[*pptr];
}
}
else { /* PIC24 */
for (j=0; j<w; j++, pptr+=3) {
*lptr++ = 0xff;
*lptr++ = pptr[2];
*lptr++ = pptr[1];
*lptr++ = pptr[0];
}
}
}
/* compress and write the data */
lptr = longpic;
for (i=0; i<h; i++) {
for (j=0; j<zsize; j++) {
if (zsize == 1) {
lumrow(lptr, lumbuf, w);
len = compressrow(lumbuf, rlebuf, CHANOFFSET(j), w);
}
else {
len = compressrow(lptr, rlebuf, CHANOFFSET(j), w);
}
if (len > rlebuflen) {
FatalError("WriteIRIS: rlebuf is too small");
exit(1);
}
fwrite(rlebuf, len, 1, fp);
starttab [i + j*h] = pos;
lengthtab[i + j*h] = len;
pos += len;
}
lptr += (w*4);
}
/* write out line start and length tables */
fseek (fp, 512, 0);
writetab(fp, starttab, tablen);
writetab(fp, lengthtab,tablen);
free(starttab);
free(lengthtab);
free(rlebuf);
free(lumbuf);
free(longpic);
if (ferror(fp)) return -1;
return 0;
}
/*************************************/
static void lumrow(rgbptr, lumptr, n)
byte *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)
byte *lbuf, *rlebuf;
int z, cnt;
{
byte *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 - rlebuf);
}
/****************************************************/
static void writetab(outf,tab,len)
FILE *outf;
u_long *tab;
int len;
{
while(len) {
putlong(outf,*tab++);
len -= 4;
}
}
/* byte order independent read/write of shorts and longs. */
static u_short getshort(inf)
FILE *inf;
{
byte buf[2];
fread(buf,2,1,inf);
return (buf[0]<<8)+(buf[1]<<0);
}
static u_long getlong(inf)
FILE *inf;
{
byte buf[4];
fread(buf,4,1,inf);
return (((u_long) buf[0])<<24) + (((u_long) buf[1])<<16)
+ (((u_long) buf[2])<<8) + buf[3];
}
static void putshort(outf,val)
FILE *outf;
int val;
{
byte buf[2];
buf[0] = (val>>8);
buf[1] = (val>>0);
fwrite(buf,2,1,outf);
}
static void putlong(outf,val)
FILE *outf;
u_long val;
{
byte buf[4];
buf[0] = (val>>24);
buf[1] = (val>>16);
buf[2] = (val>>8);
buf[3] = (val>>0);
fwrite(buf,4,1,outf);
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.