--- ray/src/common/color.c 1989/05/11 22:15:57 1.4 +++ ray/src/common/color.c 2003/07/27 22:12:01 2.13 @@ -1,160 +1,100 @@ -/* Copyright (c) 1986 Regents of the University of California */ - #ifndef lint -static char SCCSid[] = "$SunId$ LBL"; +static const char RCSid[] = "$Id: color.c,v 2.13 2003/07/27 22:12:01 schorsch Exp $"; #endif - /* * color.c - routines for color calculations. * - * 10/10/85 + * Externals declared in color.h */ +#include "copyright.h" + #include -#include "color.h" +#include -#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. - */ +#include -#define STARTWL 380 /* starting wavelength (nanometers) */ -#define INCWL 10 /* wavelength increment */ -#define NINC 40 /* # of values */ +#include "color.h" -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 - } -}; +#define MINELEN 8 /* minimum scanline length for encoding */ +#define MAXELEN 0x7fff /* maximum scanline length for encoding */ +#define MINRUN 4 /* minimum run length */ -spec_rgb(col, s, e) /* comput RGB color from spectral range */ -COLOR col; -int s, e; +char * +tempbuffer(len) /* get a temporary buffer */ +unsigned int len; { - COLOR ciecolor; + static char *tempbuf = NULL; + static unsigned tempbuflen = 0; - spec_cie(ciecolor, s, e); - cie_rgb(col, ciecolor); -} - - -spec_cie(col, s, e) /* compute a color from a spectral range */ -COLOR col; /* returned color */ -int s, e; /* starting and ending wavelengths */ -{ - register int i, d, r; - - 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 > tempbuflen) { + if (tempbuflen > 0) + tempbuf = (char *)realloc((void *)tempbuf, len); + else + tempbuf = (char *)malloc(len); + tempbuflen = tempbuf==NULL ? 0 : len; } + return(tempbuf); } -#endif +int fwritecolrs(scanline, len, fp) /* write out a colr scanline */ register COLR *scanline; int len; register FILE *fp; { - COLR lastcolr; - int rept; + register int i, j, beg, cnt = 1; + int c2; - 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; + 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; } - 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--; + 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; + } } - 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); } -freadcolrs(scanline, len, fp) /* read in a colr scanline */ +static int +oldreadcolrs(scanline, len, fp) /* read in an old colr scanline */ register COLR *scanline; int len; register FILE *fp; @@ -190,99 +130,115 @@ register FILE *fp; } +int +freadcolrs(scanline, len, fp) /* read in an encoded colr scanline */ +register COLR *scanline; +int len; +register FILE *fp; +{ + register int i, j; + int code, val; + /* 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)); + } + 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)); + } + 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 */ + code &= 127; + if ((val = getc(fp)) == EOF) + return -1; + while (code--) + scanline[j++][i] = val; + } else /* non-run */ + while (code--) { + if ((val = getc(fp)) == EOF) + return -1; + scanline[j++][i] = val; + } + } + return(0); +} + + +int 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)); } +int 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); } +void setcolr(clr, r, g, b) /* assign a short color value */ register COLR clr; double r, g, b; { - double frexp(); double d; int e; @@ -295,20 +251,31 @@ double r, g, b; return; } - d = frexp(d, &e) * 256.0 / d; + d = frexp(d, &e) * 255.9999 / d; - clr[RED] = r * d; - clr[GRN] = g * d; - clr[BLU] = b * d; + if (r > 0.0) + clr[RED] = r * d; + else + clr[RED] = 0; + if (g > 0.0) + clr[GRN] = g * d; + else + clr[GRN] = 0; + if (b > 0.0) + clr[BLU] = b * d; + else + clr[BLU] = 0; + clr[EXP] = e + COLXS; } +void colr_color(col, clr) /* convert short to float color */ register COLOR col; register COLR clr; { - double ldexp(), f; + double f; if (clr[EXP] == 0) col[RED] = col[GRN] = col[BLU] = 0.0; @@ -318,4 +285,19 @@ register COLR clr; col[GRN] = (clr[GRN] + 0.5)*f; col[BLU] = (clr[BLU] + 0.5)*f; } +} + + +int +bigdiff(c1, c2, md) /* c1 delta c2 > md? */ +register COLOR c1, c2; +double md; +{ + register int i; + + for (i = 0; i < 3; i++) + if (colval(c1,i)-colval(c2,i) > md*colval(c2,i) || + colval(c2,i)-colval(c1,i) > md*colval(c1,i)) + return(1); + return(0); }