--- ray/src/common/color.c 1989/10/20 16:53:01 1.7 +++ ray/src/common/color.c 1993/02/26 10:08:50 2.5 @@ -1,4 +1,4 @@ -/* Copyright (c) 1986 Regents of the University of California */ +/* Copyright (c) 1991 Regents of the University of California */ #ifndef lint static char SCCSid[] = "$SunId$ LBL"; @@ -14,193 +14,131 @@ static char SCCSid[] = "$SunId$ LBL"; #include "color.h" -#ifdef SPEC_RGB -/* - * The following table contains the CIE tristimulus integrals - * for X, Y, and Z. The table is cumulative, so that - * each color coordinate integrates to 1. - */ +#define MINELEN 8 /* minimum scanline length for encoding */ +#define MAXELEN 0x7ffe /* maximum scanline length for encoding */ +#define MINRUN 4 /* minimum run length */ -#define STARTWL 380 /* starting wavelength (nanometers) */ -#define INCWL 10 /* wavelength increment */ -#define NINC 40 /* # of values */ +#ifndef frexp +extern double frexp(); +#endif -static BYTE chroma[3][NINC] = { - { /* X */ - 0, 0, 0, 2, 6, 13, 22, 30, 36, 41, - 42, 43, 43, 44, 46, 52, 60, 71, 87, 106, - 128, 153, 178, 200, 219, 233, 243, 249, 252, 254, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 - }, { /* Y */ - 0, 0, 0, 0, 0, 1, 2, 4, 7, 11, - 17, 24, 34, 48, 64, 84, 105, 127, 148, 169, - 188, 205, 220, 232, 240, 246, 250, 253, 254, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 - }, { /* Z */ - 0, 0, 2, 10, 32, 66, 118, 153, 191, 220, - 237, 246, 251, 253, 254, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 - } -}; - -spec_rgb(col, s, e) /* comput RGB color from spectral range */ -COLOR col; -int s, e; +char * +tempbuffer(len) /* get a temporary buffer */ +unsigned len; { - COLOR ciecolor; + extern char *malloc(), *realloc(); + static char *tempbuf = NULL; + static unsigned tempbuflen = 0; - spec_cie(ciecolor, s, e); - cie_rgb(col, ciecolor); + if (len > tempbuflen) { + if (tempbuflen > 0) + tempbuf = realloc(tempbuf, len); + else + tempbuf = malloc(len); + tempbuflen = tempbuf==NULL ? 0 : len; + } + return(tempbuf); } -spec_cie(col, s, e) /* compute a color from a spectral range */ -COLOR col; /* returned color */ -int s, e; /* starting and ending wavelengths */ +fwritecolrs(scanline, len, fp) /* write out a colr scanline */ +register COLR *scanline; +unsigned len; +register FILE *fp; { - register int i, d, r; + register int i, j, beg, cnt; + int c2; - s -= STARTWL; - if (s < 0) - s = 0; - - e -= STARTWL; - if (e >= INCWL*(NINC - 1)) - e = INCWL*(NINC - 1) - 1; - - d = e / INCWL; /* interpolate values */ - r = e % INCWL; - for (i = 0; i < 3; i++) - col[i] = chroma[i][d]*(INCWL - r) + chroma[i][d + 1]*r; - - d = s / INCWL; - r = s % INCWL; - for (i = 0; i < 3; i++) - col[i] -= chroma[i][d]*(INCWL - r) - chroma[i][d + 1]*r; - - col[RED] = (col[RED] + 0.5) / (256*INCWL); - col[GRN] = (col[GRN] + 0.5) / (256*INCWL); - col[BLU] = (col[BLU] + 0.5) / (256*INCWL); -} - - -cie_rgb(rgbcolor, ciecolor) /* convert CIE to RGB (NTSC) */ -register COLOR rgbcolor, ciecolor; -{ - static float cmat[3][3] = { - 1.73, -.48, -.26, - -.81, 1.65, -.02, - .08, -.17, 1.28, - }; - register int i; - - for (i = 0; i < 3; i++) { - rgbcolor[i] = cmat[i][0]*ciecolor[0] + - cmat[i][1]*ciecolor[1] + - cmat[i][2]*ciecolor[2] ; - if (rgbcolor[i] < 0.0) - rgbcolor[i] = 0.0; + if (len < MINELEN | len > MAXELEN) /* OOBs, write out flat */ + return(fwrite((char *)scanline,sizeof(COLR),len,fp) - len); + /* put magic header */ + putc(2, fp); + putc(2, fp); + putc(len>>8, fp); + putc(len&255, fp); + /* put components seperately */ + for (i = 0; i < 4; i++) { + for (j = 0; j < len; j += cnt) { /* find next run */ + for (beg = j; beg < len; beg += cnt) { + for (cnt = 1; cnt < 127 && beg+cnt < len && + scanline[beg+cnt][i] == scanline[beg][i]; cnt++) + ; + if (cnt >= MINRUN) + break; /* long enough */ + } + if (beg-j > 1 && beg-j < MINRUN) { + c2 = j+1; + while (scanline[c2++][i] == scanline[j][i]) + if (c2 == beg) { /* short run */ + putc(128+beg-j, fp); + putc(scanline[j][i], fp); + j = beg; + break; + } + } + while (j < beg) { /* write out non-run */ + if ((c2 = beg-j) > 128) c2 = 128; + putc(c2, fp); + while (c2--) + putc(scanline[j++][i], fp); + } + if (cnt >= MINRUN) { /* write out run */ + putc(128+cnt, fp); + putc(scanline[beg][i], fp); + } else + cnt = 0; + } } + return(ferror(fp) ? -1 : 0); } -#endif -fputresolu(ord, xres, yres, fp) /* put x and y resolution */ -register int ord; -int xres, yres; -FILE *fp; -{ - if (ord&YMAJOR) - fprintf(fp, "%cY %d %cX %d\n", - ord&YDECR ? '-' : '+', yres, - ord&XDECR ? '-' : '+', xres); - else - fprintf(fp, "%cX %d %cY %d\n", - ord&XDECR ? '-' : '+', xres, - ord&YDECR ? '-' : '+', yres); -} - - -fgetresolu(xrp, yrp, fp) /* get x and y resolution */ -int *xrp, *yrp; -FILE *fp; -{ - char buf[64], *xndx, *yndx; - register char *cp; - register int ord; - - if (fgets(buf, sizeof(buf), fp) == NULL) - return(-1); - xndx = yndx = NULL; - for (cp = buf+1; *cp; cp++) - if (*cp == 'X') - xndx = cp; - else if (*cp == 'Y') - yndx = cp; - if (xndx == NULL || yndx == NULL) - return(-1); - ord = 0; - if (xndx > yndx) ord |= YMAJOR; - if (xndx[-1] == '-') ord |= XDECR; - if (yndx[-1] == '-') ord |= YDECR; - if ((*xrp = atoi(xndx+1)) <= 0) - return(-1); - if ((*yrp = atoi(yndx+1)) <= 0) - return(-1); - return(ord); -} - - -fwritecolrs(scanline, len, fp) /* write out a colr scanline */ +freadcolrs(scanline, len, fp) /* read in an encoded colr scanline */ register COLR *scanline; int len; register FILE *fp; { - COLR lastcolr; - int rept; - - lastcolr[RED] = lastcolr[GRN] = lastcolr[BLU] = 1; - lastcolr[EXP] = 0; - rept = 0; - - while (len > 0) { - if (scanline[0][EXP] == lastcolr[EXP] && - scanline[0][RED] == lastcolr[RED] && - scanline[0][GRN] == lastcolr[GRN] && - scanline[0][BLU] == lastcolr[BLU]) - rept++; - else { - while (rept) { /* write out count */ - putc(1, fp); - putc(1, fp); - putc(1, fp); - putc(rept & 255, fp); - rept >>= 8; - } - putc(scanline[0][RED], fp); /* new color */ - putc(scanline[0][GRN], fp); - putc(scanline[0][BLU], fp); - putc(scanline[0][EXP], fp); - copycolr(lastcolr, scanline[0]); - rept = 0; - } - scanline++; - len--; + register int i, j; + int code; + /* determine scanline type */ + if (len < MINELEN | len > MAXELEN) + return(oldreadcolrs(scanline, len, fp)); + if ((i = getc(fp)) == EOF) + return(-1); + if (i != 2) { + ungetc(i, fp); + return(oldreadcolrs(scanline, len, fp)); } - while (rept) { /* write out count */ - putc(1, fp); - putc(1, fp); - putc(1, fp); - putc(rept & 255, fp); - rept >>= 8; + scanline[0][GRN] = getc(fp); + scanline[0][BLU] = getc(fp); + if ((i = getc(fp)) == EOF) + return(-1); + if (scanline[0][GRN] != 2 || scanline[0][BLU] & 128) { + scanline[0][RED] = 2; + scanline[0][EXP] = i; + return(oldreadcolrs(scanline+1, len-1, fp)); } - return(ferror(fp) ? -1 : 0); + if ((scanline[0][BLU]<<8 | i) != len) + return(-1); /* length mismatch! */ + /* read each component */ + for (i = 0; i < 4; i++) + for (j = 0; j < len; ) { + if ((code = getc(fp)) == EOF) + return(-1); + if (code > 128) { /* run */ + scanline[j++][i] = getc(fp); + for (code &= 127; --code; j++) + scanline[j][i] = scanline[j-1][i]; + } else /* non-run */ + while (code--) + scanline[j++][i] = getc(fp); + } + return(feof(fp) ? -1 : 0); } -freadcolrs(scanline, len, fp) /* read in a colr scanline */ +oldreadcolrs(scanline, len, fp) /* read in an old colr scanline */ register COLR *scanline; int len; register FILE *fp; @@ -239,86 +177,50 @@ register FILE *fp; fwritescan(scanline, len, fp) /* write out a scanline */ register COLOR *scanline; int len; -register FILE *fp; +FILE *fp; { - COLR lastcolr, thiscolr; - int rept; - - lastcolr[RED] = lastcolr[GRN] = lastcolr[BLU] = 1; - lastcolr[EXP] = 0; - rept = 0; - - while (len > 0) { - setcolr(thiscolr, scanline[0][RED], + COLR *clrscan; + int n; + register COLR *sp; + /* get scanline buffer */ + if ((sp = (COLR *)tempbuffer(len*sizeof(COLR))) == NULL) + return(-1); + clrscan = sp; + /* convert scanline */ + n = len; + while (n-- > 0) { + setcolr(sp[0], scanline[0][RED], scanline[0][GRN], scanline[0][BLU]); - if (thiscolr[EXP] == lastcolr[EXP] && - thiscolr[RED] == lastcolr[RED] && - thiscolr[GRN] == lastcolr[GRN] && - thiscolr[BLU] == lastcolr[BLU]) - rept++; - else { - while (rept) { /* write out count */ - putc(1, fp); - putc(1, fp); - putc(1, fp); - putc(rept & 255, fp); - rept >>= 8; - } - putc(thiscolr[RED], fp); /* new color */ - putc(thiscolr[GRN], fp); - putc(thiscolr[BLU], fp); - putc(thiscolr[EXP], fp); - copycolr(lastcolr, thiscolr); - rept = 0; - } scanline++; - len--; + sp++; } - while (rept) { /* write out count */ - putc(1, fp); - putc(1, fp); - putc(1, fp); - putc(rept & 255, fp); - rept >>= 8; - } - return(ferror(fp) ? -1 : 0); + return(fwritecolrs(clrscan, len, fp)); } freadscan(scanline, len, fp) /* read in a scanline */ register COLOR *scanline; int len; -register FILE *fp; +FILE *fp; { - COLR thiscolr; - int rshift; - register int i; - - rshift = 0; - - while (len > 0) { - thiscolr[RED] = getc(fp); - thiscolr[GRN] = getc(fp); - thiscolr[BLU] = getc(fp); - thiscolr[EXP] = getc(fp); - if (feof(fp) || ferror(fp)) - return(-1); - if (thiscolr[RED] == 1 && - thiscolr[GRN] == 1 && - thiscolr[BLU] == 1) { - for (i = thiscolr[EXP] << rshift; i > 0; i--) { - copycolor(scanline[0], scanline[-1]); - scanline++; - len--; - } - rshift += 8; - } else { - colr_color(scanline[0], thiscolr); - scanline++; - len--; - rshift = 0; - } + register COLR *clrscan; + + if ((clrscan = (COLR *)tempbuffer(len*sizeof(COLR))) == NULL) + return(-1); + if (freadcolrs(clrscan, len, fp) < 0) + return(-1); + /* convert scanline */ + colr_color(scanline[0], clrscan[0]); + while (--len > 0) { + scanline++; clrscan++; + if (clrscan[0][RED] == clrscan[-1][RED] && + clrscan[0][GRN] == clrscan[-1][GRN] && + clrscan[0][BLU] == clrscan[-1][BLU] && + clrscan[0][EXP] == clrscan[-1][EXP]) + copycolor(scanline[0], scanline[-1]); + else + colr_color(scanline[0], clrscan[0]); } return(0); } @@ -328,7 +230,6 @@ setcolr(clr, r, g, b) /* assign a short color value * register COLR clr; double r, g, b; { - double frexp(); double d; int e; @@ -364,42 +265,6 @@ register COLR clr; col[GRN] = (clr[GRN] + 0.5)*f; col[BLU] = (clr[BLU] + 0.5)*f; } -} - - -int -colr_norm(clr, nclr) /* normalize a short color, return shift */ -COLR clr, nclr; -{ - register int c; - register int shift = clr[EXP]-COLXS; - - if (shift > 0) { - if (shift >= 8) { - nclr[RED] = nclr[GRN] = nclr[BLU] = 255; - } else { - c = clr[RED] << shift; - nclr[RED] = c > 255 ? 255 : c; - c = clr[GRN] << shift; - nclr[GRN] = c > 255 ? 255 : c; - c = clr[BLU] << shift; - nclr[BLU] = c > 255 ? 255 : c; - } - } else if (shift < 0) { - if (shift <= -8) { - nclr[RED] = nclr[GRN] = nclr[BLU] = 0; - } else { - nclr[RED] = clr[RED] >> -shift; - nclr[GRN] = clr[GRN] >> -shift; - nclr[BLU] = clr[BLU] >> -shift; - } - } else { - nclr[RED] = clr[RED]; - nclr[GRN] = clr[GRN]; - nclr[BLU] = clr[BLU]; - } - nclr[EXP] = COLXS; - return(shift); }