The RADIANCE Picture File Format Radiance is a lighting simulation and rendering system available by anonymous ftp from hobbes.lbl.gov (128.3.12.38). The picture file format used by the program uses a floating point representation that provides greater fidelity and numerical accuracy over a 24-bit image, without taking much extra space. At the end of this message I have put a shar file of the routines you need to read and write Radiance pictures. The format has been enhanced slightly for the next release (in an upward compatible way), so you should definitely use these newer routines. The file format, like most binary files used by Radiance, contains an ASCII information header that is terminated by an empty line. This header typically begins with the line "#?RADIANCE", followd by the commands used to generate the file, along with variables indicating exposure, view parameters, and so on. Next there is a single line that indicates the resolution and pixel scanning order of the image. For Radiance pictures, the pixels are order as English text, left to right and top to bottom. This is indicated with a line of the form: -Y M +X N Where M and N are the y and x resolutions, respectively. The x and y image coordinates are always the same, starting with (0,0) at the lower left corner, (N,0) at the lower right, and (0,M) at the upper left. The y resolution appears first in our specification because it is the major sort, and is preceded by a minus sign because it is decreasing in the file. Finally, the floating point scanlines follow. Each pixel is represented by at most 4 bytes. The first three bytes are the red, green and blue mantissas (in that order), and the fourth byte is a common exponent. The floating point color (R,G,B)=(1.,.5,.25) would be represented by the bytes (128,64,32,129). The conversion back to floating point is possible using the ldexp() library routine, or it's better to use the colr_color() routine included in color.c. The scanlines are usually run-length encoded. My previous scheme (release 1.4 and earlier) used a simple count for repeated pixels. My new scheme is more complicated and encodes the four components separately. I don't recommend writing your own routine to decode it -- use what's in color.c. A skeletal program to read a Radiance picture file and convert to 24-bit gamma-corrected color looks like this: /* Copyright (c) 1992 Regents of the University of California */ #ifndef lint static char SCCSid[] = "@(#)ra_skel.c 2.9 2/27/94 LBL"; #endif /* * Skeletal 24-bit image conversion program. Replace "skel" * in this file with a more appropriate image type identifier. * * The Rmakefile entry should look something like this: * ra_skel: ra_skel.o * cc $(CFLAGS) -o ra_skel ra_skel.o -lrt -lm * ra_skel.o: ../common/color.h ../common/resolu.h * * If you like to do things the hard way, you can link directly * to the object files "color.o colrops.o resolu.o header.o" in * the common subdirectory instead of using the -lrt library. */ #include #include #ifdef MSDOS #include #endif #include "color.h" #include "resolu.h" extern char *malloc(); double gamcor = 2.2; /* gamma correction */ int bradj = 0; /* brightness adjustment */ char *progname; int xmax, ymax; main(argc, argv) int argc; char *argv[]; { int reverse = 0; int i; progname = argv[0]; for (i = 1; i < argc; i++) if (argv[i][0] == '-') switch (argv[i][1]) { case 'g': /* gamma correction */ gamcor = atof(argv[++i]); break; case 'e': /* exposure adjustment */ if (argv[i+1][0] != '+' && argv[i+1][0] != '-') goto userr; bradj = atoi(argv[++i]); break; case 'r': /* reverse conversion */ reverse = 1; break; default: goto userr; } else break; if (i < argc-2) goto userr; if (i <= argc-1 && freopen(argv[i], "r", stdin) == NULL) { fprintf(stderr, "%s: can't open input \"%s\"\n", progname, argv[i]); exit(1); } if (i == argc-2 && freopen(argv[i+1], "w", stdout) == NULL) { fprintf(stderr, "%s: can't open output \"%s\"\n", progname, argv[i+1]); exit(1); } #ifdef MSDOS setmode(fileno(stdin), O_BINARY); setmode(fileno(stdout), O_BINARY); #endif setcolrgam(gamcor); /* set up gamma correction */ if (reverse) { /* get their image resolution */ read_skel_head(&xmax, &ymax); /* put our header */ newheader("RADIANCE", stdout); printargs(i, argv, stdout); fputformat(COLRFMT, stdout); putchar('\n'); fprtresolu(xmax, ymax, stdout); /* convert file */ skel2ra(); } else { /* get our header */ if (checkheader(stdin, COLRFMT, NULL) < 0 || fgetresolu(&xmax, &ymax, stdin) < 0) quiterr("bad picture format"); /* write their header */ write_skel_head(xmax, ymax); /* convert file */ ra2skel(); } exit(0); userr: fprintf(stderr, "Usage: %s [-r][-g gamma][-e +/-stops] [input [output]]\n", progname); exit(1); } quiterr(err) /* print message and exit */ char *err; { if (err != NULL) { fprintf(stderr, "%s: %s\n", progname, err); exit(1); } exit(0); } skel2ra() /* convert 24-bit scanlines to Radiance picture */ { COLR *scanout; register int x; int y; /* allocate scanline */ scanout = (COLR *)malloc(xmax*sizeof(COLR)); if (scanout == NULL) quiterr("out of memory in skel2ra"); /* convert image */ for (y = ymax-1; y >= 0; y--) { for (x = 0; x < xmax; x++) { scanout[x][RED] = getc(stdin); scanout[x][GRN] = getc(stdin); scanout[x][BLU] = getc(stdin); } if (feof(stdin) | ferror(stdin)) quiterr("error reading skel image"); /* undo gamma */ gambs_colrs(scanout, xmax); if (bradj) /* adjust exposure */ shiftcolrs(scanout, xmax, bradj); if (fwritecolrs(scanout, xmax, stdout) < 0) quiterr("error writing Radiance picture"); } /* free scanline */ free((char *)scanout); } ra2skel() /* convert Radiance scanlines to 24-bit */ { COLR *scanin; register int x; int y; /* allocate scanline */ scanin = (COLR *)malloc(xmax*sizeof(COLR)); if (scanin == NULL) quiterr("out of memory in ra2skel"); /* convert image */ for (y = ymax-1; y >= 0; y--) { if (freadcolrs(scanin, xmax, stdin) < 0) quiterr("error reading Radiance picture"); if (bradj) /* adjust exposure */ shiftcolrs(scanin, xmax, bradj); colrs_gambs(scanin, xmax); /* gamma correction */ for (x = 0; x < xmax; x++) { putc(scanin[x][RED], stdout); putc(scanin[x][GRN], stdout); putc(scanin[x][BLU], stdout); } if (ferror(stdout)) quiterr("error writing skel file"); } /* free scanline */ free((char *)scanin); } -------------------------------------------------------------- You will find all the routines you need in ray/src/common. The checkheader() routine is in the module header.c, fgetresolu is in resolu.c, freadcolrs() is in color.c, and setcolrgam() and colrs_gambs() are in the module colrops.c. If you want to convert the file to 8-bit color, the process is quite a bit more complicated. I suggest you take a look at the ra_t8.c program in the ray/src/px directory to get a better idea of what is involved. ------------------------------ #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create: # color.h # resolu.h # resolu.c # header.c # color.c # colrops.c # This archive created: Tue Apr 5 14:07:02 1994 export PATH; PATH=/bin:/usr/bin:$PATH if test -f 'color.h' then echo shar: "will not over-write existing file 'color.h'" else sed 's/^X//' << \SHAR_EOF > 'color.h' X/* Copyright (c) 1991 Regents of the University of California */ X X/* SCCSid "@(#)color.h 2.6 8/2/93 LBL" */ X X/* X * color.h - header for routines using pixel color values. X * X * 12/31/85 X * X * Two color representations are used, one for calculation and X * another for storage. Calculation is done with three floats X * for speed. Stored color values use 4 bytes which contain X * three single byte mantissas and a common exponent. X */ X X#define RED 0 X#define GRN 1 X#define BLU 2 X#define EXP 3 X#define COLXS 128 /* excess used for exponent */ X Xtypedef unsigned char BYTE; /* 8-bit unsigned integer */ X Xtypedef BYTE COLR[4]; /* red, green, blue, exponent */ X X#define copycolr(c1,c2) (c1[0]=c2[0],c1[1]=c2[1], \ X c1[2]=c2[2],c1[3]=c2[3]) X Xtypedef float COLOR[3]; /* red, green, blue */ X X#define colval(col,pri) ((col)[pri]) X X#define setcolor(col,r,g,b) ((col)[RED]=(r),(col)[GRN]=(g),(col)[BLU]=(b)) X X#define copycolor(c1,c2) ((c1)[0]=(c2)[0],(c1)[1]=(c2)[1],(c1)[2]=(c2)[2]) X X#define scalecolor(col,sf) ((col)[0]*=(sf),(col)[1]*=(sf),(col)[2]*=(sf)) X X#define addcolor(c1,c2) ((c1)[0]+=(c2)[0],(c1)[1]+=(c2)[1],(c1)[2]+=(c2)[2]) X X#define multcolor(c1,c2) ((c1)[0]*=(c2)[0],(c1)[1]*=(c2)[1],(c1)[2]*=(c2)[2]) X X#ifdef NTSC X#define bright(col) (.295*(col)[RED]+.636*(col)[GRN]+.070*(col)[BLU]) X#define normbright(c) (int)((74L*(c)[RED]+164L*(c)[GRN]+18L*(c)[BLU])>>8) X#else X#define bright(col) (.263*(col)[RED]+.655*(col)[GRN]+.082*(col)[BLU]) X#define normbright(c) (int)((67L*(c)[RED]+168L*(c)[GRN]+21L*(c)[BLU])>>8) X#endif X X /* luminous efficacies over visible spectrum */ X#define MAXEFFICACY 683. /* defined maximum at 550 nm */ X#define WHTEFFICACY 179. /* uniform white light */ X#define D65EFFICACY 203. /* standard illuminant D65 */ X#define INCEFFICACY 160. /* illuminant A (incand.) */ X#define SUNEFFICACY 208. /* illuminant B (solar dir.) */ X#define SKYEFFICACY D65EFFICACY /* skylight */ X#define DAYEFFICACY D65EFFICACY /* combined sky and solar */ X X#define luminance(col) (WHTEFFICACY * bright(col)) X X#define intens(col) ( (col)[0] > (col)[1] \ X ? (col)[0] > (col)[2] ? (col)[0] : (col)[2] \ X : (col)[1] > (col)[2] ? (col)[1] : (col)[2] ) X X#define colrval(c,p) ( (c)[EXP] ? \ X ldexp((c)[p]+.5,(int)(c)[EXP]-(COLXS+8)) : \ X 0. ) X X#define WHTCOLOR {1.0,1.0,1.0} X#define BLKCOLOR {0.0,0.0,0.0} X#define WHTCOLR {128,128,128,COLXS+1} X#define BLKCOLR {0,0,0,0} X X /* picture format identifier */ X#define COLRFMT "32-bit_rle_rgbe" X X /* macros for exposures */ X#define EXPOSSTR "EXPOSURE=" X#define LEXPOSSTR 9 X#define isexpos(hl) (!strncmp(hl,EXPOSSTR,LEXPOSSTR)) X#define exposval(hl) atof((hl)+LEXPOSSTR) X#define fputexpos(ex,fp) fprintf(fp,"%s%e\n",EXPOSSTR,ex) X X /* macros for pixel aspect ratios */ X#define ASPECTSTR "PIXASPECT=" X#define LASPECTSTR 10 X#define isaspect(hl) (!strncmp(hl,ASPECTSTR,LASPECTSTR)) X#define aspectval(hl) atof((hl)+LASPECTSTR) X#define fputaspect(pa,fp) fprintf(fp,"%s%f\n",ASPECTSTR,pa) X X /* macros for color correction */ X#define COLCORSTR "COLORCORR=" X#define LCOLCORSTR 10 X#define iscolcor(hl) (!strncmp(hl,COLCORSTR,LCOLCORSTR)) X#define colcorval(cc,hl) sscanf(hl+LCOLCORSTR,"%f %f %f", \ X &(cc)[RED],&(cc)[GRN],&(cc)[BLU]) X#define fputcolcor(cc,fp) fprintf(fp,"%s %f %f %f\n",COLCORSTR, \ X (cc)[RED],(cc)[GRN],(cc)[BLU]) X X#ifdef DCL_ATOF Xextern double atof(), ldexp(), frexp(); X#endif SHAR_EOF fi if test -f 'resolu.h' then echo shar: "will not over-write existing file 'resolu.h'" else sed 's/^X//' << \SHAR_EOF > 'resolu.h' X/* Copyright (c) 1991 Regents of the University of California */ X X/* SCCSid "@(#)resolu.h 2.2 6/4/93 LBL" */ X X/* X * Definitions for resolution line in image file. X * X * True image orientation is defined by an xy coordinate system X * whose origin is at the lower left corner of the image, with X * x increasing to the right and y increasing in the upward direction. X * This true orientation is independent of how the pixels are actually X * ordered in the file, which is indicated by the resolution line. X * This line is of the form "{+-}{XY} xyres {+-}{YX} yxres\n". X * A typical line for a 1024x600 image might be "-Y 600 +X 1024\n", X * indicating that the scanlines are in English text order (PIXSTANDARD). X */ X X /* flags for scanline ordering */ X#define XDECR 1 X#define YDECR 2 X#define YMAJOR 4 X X /* standard scanline ordering */ X#define PIXSTANDARD (YMAJOR|YDECR) X#define PIXSTDFMT "-Y %d +X %d\n" X X /* structure for image dimensions */ Xtypedef struct { X int or; /* orientation (from flags above) */ X int xr, yr; /* x and y resolution */ X} RESOLU; X X /* macros to get scanline length and number */ X#define scanlen(rs) ((rs)->or & YMAJOR ? (rs)->xr : (rs)->yr) X#define numscans(rs) ((rs)->or & YMAJOR ? (rs)->yr : (rs)->xr) X X /* resolution string buffer and its size */ X#define RESOLU_BUFLEN 32 Xextern char resolu_buf[RESOLU_BUFLEN]; X X /* macros for reading/writing resolution struct */ X#define fputsresolu(rs,fp) fputs(resolu2str(resolu_buf,rs),fp) X#define fgetsresolu(rs,fp) str2resolu(rs, \ X fgets(resolu_buf,RESOLU_BUFLEN,fp)) X X /* reading/writing of standard ordering */ X#define fprtresolu(sl,ns,fp) fprintf(fp,PIXSTDFMT,ns,sl) X#define fscnresolu(sl,ns,fp) (fscanf(fp,PIXSTDFMT,ns,sl)==2) X Xextern char *resolu2str(); SHAR_EOF fi if test -f 'resolu.c' then echo shar: "will not over-write existing file 'resolu.c'" else sed 's/^X//' << \SHAR_EOF > 'resolu.c' X/* Copyright (c) 1991 Regents of the University of California */ X X#ifndef lint Xstatic char SCCSid[] = "@(#)resolu.c 2.2 11/28/91 LBL"; X#endif X X/* X * Read and write image resolutions. X */ X X#include X X#include "resolu.h" X X Xchar resolu_buf[RESOLU_BUFLEN]; /* resolution line buffer */ X X Xfputresolu(ord, sl, ns, fp) /* put out picture dimensions */ Xint ord; /* scanline ordering */ Xint sl, ns; /* scanline length and number */ XFILE *fp; X{ X RESOLU rs; X X if ((rs.or = ord) & YMAJOR) { X rs.xr = sl; X rs.yr = ns; X } else { X rs.xr = ns; X rs.yr = sl; X } X fputsresolu(&rs, fp); X} X X Xint Xfgetresolu(sl, ns, fp) /* get picture dimensions */ Xint *sl, *ns; /* scanline length and number */ XFILE *fp; X{ X RESOLU rs; X X if (!fgetsresolu(&rs, fp)) X return(-1); X if (rs.or & YMAJOR) { X *sl = rs.xr; X *ns = rs.yr; X } else { X *sl = rs.yr; X *ns = rs.xr; X } X return(rs.or); X} X X Xchar * Xresolu2str(buf, rp) /* convert resolution struct to line */ Xchar *buf; Xregister RESOLU *rp; X{ X if (rp->or&YMAJOR) X sprintf(buf, "%cY %d %cX %d\n", X rp->or&YDECR ? '-' : '+', rp->yr, X rp->or&XDECR ? '-' : '+', rp->xr); X else X sprintf(buf, "%cX %d %cY %d\n", X rp->or&XDECR ? '-' : '+', rp->xr, X rp->or&YDECR ? '-' : '+', rp->yr); X return(buf); X} X X Xstr2resolu(rp, buf) /* convert resolution line to struct */ Xregister RESOLU *rp; Xchar *buf; X{ X register char *xndx, *yndx; X register char *cp; X X if (buf == NULL) X return(0); X xndx = yndx = NULL; X for (cp = buf; *cp; cp++) X if (*cp == 'X') X xndx = cp; X else if (*cp == 'Y') X yndx = cp; X if (xndx == NULL || yndx == NULL) X return(0); X rp->or = 0; X if (xndx > yndx) rp->or |= YMAJOR; X if (xndx[-1] == '-') rp->or |= XDECR; X if (yndx[-1] == '-') rp->or |= YDECR; X if ((rp->xr = atoi(xndx+1)) <= 0) X return(0); X if ((rp->yr = atoi(yndx+1)) <= 0) X return(0); X return(1); X} SHAR_EOF fi if test -f 'header.c' then echo shar: "will not over-write existing file 'header.c'" else sed 's/^X//' << \SHAR_EOF > 'header.c' X/* Copyright (c) 1994 Regents of the University of California */ X X#ifndef lint Xstatic char SCCSid[] = "@(#)header.c 2.4 2/27/94 LBL"; X#endif X X/* X * header.c - routines for reading and writing information headers. X * X * 8/19/88 X * X * newheader(t,fp) start new information header identified by string t X * isheadid(s) returns true if s is a header id line X * headidval(r,s) copy header identifier value in s to r X * printargs(ac,av,fp) print an argument list to fp, followed by '\n' X * isformat(s) returns true if s is of the form "FORMAT=*" X * formatval(r,s) copy the format value in s to r X * fputformat(s,fp) write "FORMAT=%s" to fp X * getheader(fp,f,p) read header from fp, calling f(s,p) on each line X * checkheader(i,p,o) check header format from i against p and copy to o X * X * To copy header from input to output, use getheader(fin, fputs, fout) X */ X X#include X#include X X#define MAXLINE 512 X X#ifndef BSD X#define index strchr X#endif X Xextern char *index(); X Xchar HDRSTR[] = "#?"; /* information header magic number */ X Xchar FMTSTR[] = "FORMAT="; /* format identifier */ X X Xnewheader(s, fp) /* identifying line of information header */ Xchar *s; Xregister FILE *fp; X{ X fputs(HDRSTR, fp); X fputs(s, fp); X putc('\n', fp); X} X X Xheadidval(r,s) /* get header id (return true if is id) */ Xregister char *r, *s; X{ X register char *cp = HDRSTR; X X while (*cp) if (*cp++ != *s++) return(0); X if (r == NULL) return(1); X while (*s) *r++ = *s++; X *r = '\0'; X return(1); X} X X Xisheadid(s) /* check to see if line is header id */ Xchar *s; X{ X return(headidval(NULL, s)); X} X X Xprintargs(ac, av, fp) /* print arguments to a file */ Xint ac; Xchar **av; Xregister FILE *fp; X{ X int quote; X X while (ac-- > 0) { X if (index(*av, ' ') != NULL) { /* quote it */ X if (index(*av, '\'') != NULL) X quote = '"'; X else X quote = '\''; X putc(quote, fp); X fputs(*av++, fp); X putc(quote, fp); X } else X fputs(*av++, fp); X putc(' ', fp); X } X putc('\n', fp); X} X X Xformatval(r, s) /* get format value (return true if format) */ Xregister char *r; Xregister char *s; X{ X register char *cp = FMTSTR; X X while (*cp) if (*cp++ != *s++) return(0); X while (isspace(*s)) s++; X if (!*s) return(0); X if (r == NULL) return(1); X while(*s) *r++ = *s++; X while (isspace(r[-1])) r--; X *r = '\0'; X return(1); X} X X Xisformat(s) /* is line a format line? */ Xchar *s; X{ X return(formatval(NULL, s)); X} X X Xfputformat(s, fp) /* put out a format value */ Xchar *s; XFILE *fp; X{ X fputs(FMTSTR, fp); X fputs(s, fp); X putc('\n', fp); X} X X Xgetheader(fp, f, p) /* get header from file */ XFILE *fp; Xint (*f)(); Xchar *p; X{ X char buf[MAXLINE]; X X for ( ; ; ) { X buf[MAXLINE-2] = '\n'; X if (fgets(buf, MAXLINE, fp) == NULL) X return(-1); X if (buf[0] == '\n') X return(0); X#ifdef MSDOS X if (buf[0] == '\r' && buf[1] == '\n') X return(0); X#endif X if (buf[MAXLINE-2] != '\n') { X ungetc(buf[MAXLINE-2], fp); /* prevent false end */ X buf[MAXLINE-2] = '\0'; X } X if (f != NULL) X (*f)(buf, p); X } X} X X Xstruct check { X FILE *fp; X char fs[64]; X}; X X Xstatic Xmycheck(s, cp) /* check a header line for format info. */ Xchar *s; Xregister struct check *cp; X{ X if (!formatval(cp->fs, s) && cp->fp != NULL) X fputs(s, cp->fp); X} X X X/* X * Copymatch(pat,str) checks pat for wildcards, and X * copies str into pat if there is a match (returning true). X */ X X#ifdef COPYMATCH Xcopymatch(pat, str) Xchar *pat, *str; X{ X int docopy = 0; X register char *p = pat, *s = str; X X do { X switch (*p) { X case '?': /* match any character */ X if (!*s++) X return(0); X docopy++; X break; X case '*': /* match any string */ X while (p[1] == '*') p++; X do X if ( (p[1]=='?' || p[1]==*s) X && copymatch(p+1,s) ) { X strcpy(pat, str); X return(1); X } X while (*s++); X return(0); X case '\\': /* literal next */ X p++; X /* fall through */ X default: /* normal character */ X if (*p != *s) X return(0); X s++; X break; X } X } while (*p++); X if (docopy) X strcpy(pat, str); X return(1); X} X#else X#define copymatch(pat, s) (!strcmp(pat, s)) X#endif X X X/* X * Checkheader(fin,fmt,fout) returns a value of 1 if the input format X * matches the specification in fmt, 0 if no input format was found, X * and -1 if the input format does not match or there is an X * error reading the header. If fmt is empty, then -1 is returned X * if any input format is found (or there is an error), and 0 otherwise. X * If fmt contains any '*' or '?' characters, then checkheader X * does wildcard expansion and copies a matching result into fmt. X * Be sure that fmt is big enough to hold the match in such cases! X * The input header (minus any format lines) is copied to fout X * if fout is not NULL. X */ X Xcheckheader(fin, fmt, fout) XFILE *fin; Xchar *fmt; XFILE *fout; X{ X struct check cdat; X X cdat.fp = fout; X cdat.fs[0] = '\0'; X if (getheader(fin, mycheck, &cdat) < 0) X return(-1); X if (cdat.fs[0] != '\0') X return(copymatch(fmt, cdat.fs) ? 1 : -1); X return(0); X} SHAR_EOF fi if test -f 'color.c' then echo shar: "will not over-write existing file 'color.c'" else sed 's/^X//' << \SHAR_EOF > 'color.c' X/* Copyright (c) 1991 Regents of the University of California */ X X#ifndef lint Xstatic char SCCSid[] = "@(#)color.c 2.8 3/26/94 LBL"; X#endif X X/* X * color.c - routines for color calculations. X * X * 10/10/85 X */ X X#include X X#include X X#include "color.h" X X#define MINELEN 8 /* minimum scanline length for encoding */ X#define MAXELEN 0x7fff /* maximum scanline length for encoding */ X#define MINRUN 4 /* minimum run length */ X X Xchar * Xtempbuffer(len) /* get a temporary buffer */ Xunsigned len; X{ X extern char *malloc(), *realloc(); X static char *tempbuf = NULL; X static unsigned tempbuflen = 0; X X if (len > tempbuflen) { X if (tempbuflen > 0) X tempbuf = realloc(tempbuf, len); X else X tempbuf = malloc(len); X tempbuflen = tempbuf==NULL ? 0 : len; X } X return(tempbuf); X} X X Xfwritecolrs(scanline, len, fp) /* write out a colr scanline */ Xregister COLR *scanline; Xunsigned len; Xregister FILE *fp; X{ X register int i, j, beg, cnt; X int c2; X X if (len < MINELEN | len > MAXELEN) /* OOBs, write out flat */ X return(fwrite((char *)scanline,sizeof(COLR),len,fp) - len); X /* put magic header */ X putc(2, fp); X putc(2, fp); X putc(len>>8, fp); X putc(len&255, fp); X /* put components seperately */ X for (i = 0; i < 4; i++) { X for (j = 0; j < len; j += cnt) { /* find next run */ X for (beg = j; beg < len; beg += cnt) { X for (cnt = 1; cnt < 127 && beg+cnt < len && X scanline[beg+cnt][i] == scanline[beg][i]; cnt++) X ; X if (cnt >= MINRUN) X break; /* long enough */ X } X if (beg-j > 1 && beg-j < MINRUN) { X c2 = j+1; X while (scanline[c2++][i] == scanline[j][i]) X if (c2 == beg) { /* short run */ X putc(128+beg-j, fp); X putc(scanline[j][i], fp); X j = beg; X break; X } X } X while (j < beg) { /* write out non-run */ X if ((c2 = beg-j) > 128) c2 = 128; X putc(c2, fp); X while (c2--) X putc(scanline[j++][i], fp); X } X if (cnt >= MINRUN) { /* write out run */ X putc(128+cnt, fp); X putc(scanline[beg][i], fp); X } else X cnt = 0; X } X } X return(ferror(fp) ? -1 : 0); X} X X Xfreadcolrs(scanline, len, fp) /* read in an encoded colr scanline */ Xregister COLR *scanline; Xint len; Xregister FILE *fp; X{ X register int i, j; X int code, val; X /* determine scanline type */ X if (len < MINELEN | len > MAXELEN) X return(oldreadcolrs(scanline, len, fp)); X if ((i = getc(fp)) == EOF) X return(-1); X if (i != 2) { X ungetc(i, fp); X return(oldreadcolrs(scanline, len, fp)); X } X scanline[0][GRN] = getc(fp); X scanline[0][BLU] = getc(fp); X if ((i = getc(fp)) == EOF) X return(-1); X if (scanline[0][GRN] != 2 || scanline[0][BLU] & 128) { X scanline[0][RED] = 2; X scanline[0][EXP] = i; X return(oldreadcolrs(scanline+1, len-1, fp)); X } X if ((scanline[0][BLU]<<8 | i) != len) X return(-1); /* length mismatch! */ X /* read each component */ X for (i = 0; i < 4; i++) X for (j = 0; j < len; ) { X if ((code = getc(fp)) == EOF) X return(-1); X if (code > 128) { /* run */ X code &= 127; X val = getc(fp); X while (code--) X scanline[j++][i] = val; X } else /* non-run */ X while (code--) X scanline[j++][i] = getc(fp); X } X return(feof(fp) ? -1 : 0); X} X X Xoldreadcolrs(scanline, len, fp) /* read in an old colr scanline */ Xregister COLR *scanline; Xint len; Xregister FILE *fp; X{ X int rshift; X register int i; X X rshift = 0; X X while (len > 0) { X scanline[0][RED] = getc(fp); X scanline[0][GRN] = getc(fp); X scanline[0][BLU] = getc(fp); X scanline[0][EXP] = getc(fp); X if (feof(fp) || ferror(fp)) X return(-1); X if (scanline[0][RED] == 1 && X scanline[0][GRN] == 1 && X scanline[0][BLU] == 1) { X for (i = scanline[0][EXP] << rshift; i > 0; i--) { X copycolr(scanline[0], scanline[-1]); X scanline++; X len--; X } X rshift += 8; X } else { X scanline++; X len--; X rshift = 0; X } X } X return(0); X} X X Xfwritescan(scanline, len, fp) /* write out a scanline */ Xregister COLOR *scanline; Xint len; XFILE *fp; X{ X COLR *clrscan; X int n; X register COLR *sp; X /* get scanline buffer */ X if ((sp = (COLR *)tempbuffer(len*sizeof(COLR))) == NULL) X return(-1); X clrscan = sp; X /* convert scanline */ X n = len; X while (n-- > 0) { X setcolr(sp[0], scanline[0][RED], X scanline[0][GRN], X scanline[0][BLU]); X scanline++; X sp++; X } X return(fwritecolrs(clrscan, len, fp)); X} X X Xfreadscan(scanline, len, fp) /* read in a scanline */ Xregister COLOR *scanline; Xint len; XFILE *fp; X{ X register COLR *clrscan; X X if ((clrscan = (COLR *)tempbuffer(len*sizeof(COLR))) == NULL) X return(-1); X if (freadcolrs(clrscan, len, fp) < 0) X return(-1); X /* convert scanline */ X colr_color(scanline[0], clrscan[0]); X while (--len > 0) { X scanline++; clrscan++; X if (clrscan[0][RED] == clrscan[-1][RED] && X clrscan[0][GRN] == clrscan[-1][GRN] && X clrscan[0][BLU] == clrscan[-1][BLU] && X clrscan[0][EXP] == clrscan[-1][EXP]) X copycolor(scanline[0], scanline[-1]); X else X colr_color(scanline[0], clrscan[0]); X } X return(0); X} X X Xsetcolr(clr, r, g, b) /* assign a short color value */ Xregister COLR clr; Xdouble r, g, b; X{ X double d; X int e; X X d = r > g ? r : g; X if (b > d) d = b; X X if (d <= 1e-32) { X clr[RED] = clr[GRN] = clr[BLU] = 0; X clr[EXP] = 0; X return; X } X X d = frexp(d, &e) * 255.9999 / d; X X clr[RED] = r * d; X clr[GRN] = g * d; X clr[BLU] = b * d; X clr[EXP] = e + COLXS; X} X X Xcolr_color(col, clr) /* convert short to float color */ Xregister COLOR col; Xregister COLR clr; X{ X double f; X X if (clr[EXP] == 0) X col[RED] = col[GRN] = col[BLU] = 0.0; X else { X f = ldexp(1.0, (int)clr[EXP]-(COLXS+8)); X col[RED] = (clr[RED] + 0.5)*f; X col[GRN] = (clr[GRN] + 0.5)*f; X col[BLU] = (clr[BLU] + 0.5)*f; X } X} X X Xbigdiff(c1, c2, md) /* c1 delta c2 > md? */ Xregister COLOR c1, c2; Xdouble md; X{ X register int i; X X for (i = 0; i < 3; i++) X if (colval(c1,i)-colval(c2,i) > md*colval(c2,i) || X colval(c2,i)-colval(c1,i) > md*colval(c1,i)) X return(1); X return(0); X} SHAR_EOF fi if test -f 'colrops.c' then echo shar: "will not over-write existing file 'colrops.c'" else sed 's/^X//' << \SHAR_EOF > 'colrops.c' X/* Copyright (c) 1992 Regents of the University of California */ X X#ifndef lint Xstatic char SCCSid[] = "@(#)colrops.c 2.4 10/2/92 LBL"; X#endif X X/* X * Integer operations on COLR scanlines X */ X X#include "color.h" X X#define NULL 0 X Xextern char *bmalloc(); X X#define MAXGSHIFT 31 /* maximum shift for gamma table */ X Xstatic BYTE *g_mant = NULL, *g_nexp = NULL; X Xstatic BYTE (*g_bval)[256] = NULL; X X#ifndef pow Xextern double pow(); X#endif X X Xsetcolrcor(f, a2) /* set brightness correction */ Xdouble (*f)(); Xdouble a2; X{ X double mult; X register int i, j; X /* allocate tables */ X if (g_bval == NULL && (g_bval = X (BYTE (*)[256])bmalloc((MAXGSHIFT+1)*256)) == NULL) X return(-1); X /* compute colr -> gamb mapping */ X mult = 1.0/256.0; X for (i = 0; i <= MAXGSHIFT; i++) { X for (j = 0; j < 256; j++) X g_bval[i][j] = 256.0 * (*f)((j+.5)*mult, a2); X mult *= 0.5; X } X return(0); X} X X Xsetcolrinv(f, a2) /* set inverse brightness correction */ Xdouble (*f)(); Xdouble a2; X{ X double mult; X register int i, j; X /* allocate tables */ X if (g_mant == NULL && (g_mant = (BYTE *)bmalloc(256)) == NULL) X return(-1); X if (g_nexp == NULL && (g_nexp = (BYTE *)bmalloc(256)) == NULL) X return(-1); X /* compute gamb -> colr mapping */ X i = 0; X mult = 256.0; X for (j = 255; j > 0; j--) { X while ((g_mant[j] = mult * (*f)(j/256.0, a2)) < 128) { X i++; X mult *= 2.0; X } X g_nexp[j] = i; X } X g_mant[0] = 0; X g_nexp[0] = COLXS; X return(0); X} X X Xsetcolrgam(g) /* set gamma conversion */ Xdouble g; X{ X if (setcolrcor(pow, 1.0/g) < 0) X return(-1); X return(setcolrinv(pow, g)); X} X X Xcolrs_gambs(scan, len) /* convert scanline of colrs to gamma bytes */ Xregister COLR *scan; Xint len; X{ X register int i, expo; X X if (g_bval == NULL) X return(-1); X while (len-- > 0) { X expo = scan[0][EXP] - COLXS; X if (expo < -MAXGSHIFT) { X if (expo < -MAXGSHIFT-8) { X scan[0][RED] = X scan[0][GRN] = X scan[0][BLU] = 0; X } else { X i = (-MAXGSHIFT-1) - expo; X scan[0][RED] = X g_bval[MAXGSHIFT][((scan[0][RED]>>i)+1)>>1]; X scan[0][GRN] = X g_bval[MAXGSHIFT][((scan[0][GRN]>>i)+1)>>1]; X scan[0][BLU] = X g_bval[MAXGSHIFT][((scan[0][BLU]>>i)+1)>>1]; X } X } else if (expo > 0) { X if (expo > 8) { X scan[0][RED] = X scan[0][GRN] = X scan[0][BLU] = 255; X } else { X i = (scan[0][RED]<<1 | 1) << (expo-1); X scan[0][RED] = i > 255 ? 255 : g_bval[0][i]; X i = (scan[0][GRN]<<1 | 1) << (expo-1); X scan[0][GRN] = i > 255 ? 255 : g_bval[0][i]; X i = (scan[0][BLU]<<1 | 1) << (expo-1); X scan[0][BLU] = i > 255 ? 255 : g_bval[0][i]; X } X } else { X scan[0][RED] = g_bval[-expo][scan[0][RED]]; X scan[0][GRN] = g_bval[-expo][scan[0][GRN]]; X scan[0][BLU] = g_bval[-expo][scan[0][BLU]]; X } X scan[0][EXP] = COLXS; X scan++; X } X return(0); X} X X Xgambs_colrs(scan, len) /* convert gamma bytes to colr scanline */ Xregister COLR *scan; Xint len; X{ X register int nexpo; X X if (g_mant == NULL | g_nexp == NULL) X return(-1); X while (len-- > 0) { X nexpo = g_nexp[scan[0][RED]]; X if (g_nexp[scan[0][GRN]] < nexpo) X nexpo = g_nexp[scan[0][GRN]]; X if (g_nexp[scan[0][BLU]] < nexpo) X nexpo = g_nexp[scan[0][BLU]]; X if (nexpo < g_nexp[scan[0][RED]]) X scan[0][RED] = g_mant[scan[0][RED]] X >> (g_nexp[scan[0][RED]]-nexpo); X else X scan[0][RED] = g_mant[scan[0][RED]]; X if (nexpo < g_nexp[scan[0][GRN]]) X scan[0][GRN] = g_mant[scan[0][GRN]] X >> (g_nexp[scan[0][GRN]]-nexpo); X else X scan[0][GRN] = g_mant[scan[0][GRN]]; X if (nexpo < g_nexp[scan[0][BLU]]) X scan[0][BLU] = g_mant[scan[0][BLU]] X >> (g_nexp[scan[0][BLU]]-nexpo); X else X scan[0][BLU] = g_mant[scan[0][BLU]]; X scan[0][EXP] = COLXS - nexpo; X scan++; X } X return(0); X} X X Xshiftcolrs(scan, len, adjust) /* shift a scanline of colors by 2^adjust */ Xregister COLR *scan; Xregister int len; Xregister int adjust; X{ X int minexp; X X if (adjust == 0) X return; X minexp = adjust < 0 ? -adjust : 0; X while (len-- > 0) { X if (scan[0][EXP] <= minexp) X scan[0][RED] = scan[0][GRN] = scan[0][BLU] = X scan[0][EXP] = 0; X else X scan[0][EXP] += adjust; X scan++; X } X} X X Xnormcolrs(scan, len, adjust) /* normalize a scanline of colrs */ Xregister COLR *scan; Xint len; Xint adjust; X{ X register int c; X register int shift; X X while (len-- > 0) { X shift = scan[0][EXP] + adjust - COLXS; X if (shift > 0) { X if (shift > 8) { X scan[0][RED] = X scan[0][GRN] = X scan[0][BLU] = 255; X } else { X shift--; X c = (scan[0][RED]<<1 | 1) << shift; X scan[0][RED] = c > 255 ? 255 : c; X c = (scan[0][GRN]<<1 | 1) << shift; X scan[0][GRN] = c > 255 ? 255 : c; X c = (scan[0][BLU]<<1 | 1) << shift; X scan[0][BLU] = c > 255 ? 255 : c; X } X } else if (shift < 0) { X if (shift < -8) { X scan[0][RED] = X scan[0][GRN] = X scan[0][BLU] = 0; X } else { X shift = -1-shift; X scan[0][RED] = ((scan[0][RED]>>shift)+1)>>1; X scan[0][GRN] = ((scan[0][GRN]>>shift)+1)>>1; X scan[0][BLU] = ((scan[0][BLU]>>shift)+1)>>1; X } X } X scan[0][EXP] = COLXS - adjust; X scan++; X } X} SHAR_EOF fi exit 0 # End of shell archive