Back to index

radiance  4R0+20100331
color.c
Go to the documentation of this file.
00001 #ifndef lint
00002 static const char    RCSid[] = "$Id: color.c,v 2.16 2005/02/09 00:00:17 greg Exp $";
00003 #endif
00004 /*
00005  *  color.c - routines for color calculations.
00006  *
00007  *  Externals declared in color.h
00008  */
00009 
00010 #include "copyright.h"
00011 
00012 #include  <stdio.h>
00013 
00014 #include  <stdlib.h>
00015 
00016 #include  <math.h>
00017 
00018 #include  "color.h"
00019 
00020 #ifdef getc_unlocked        /* avoid horrendous overhead of flockfile */
00021 #undef getc
00022 #undef putc
00023 #define getc    getc_unlocked
00024 #define putc    putc_unlocked
00025 #endif
00026 
00027 #define  MINELEN     8      /* minimum scanline length for encoding */
00028 #define  MAXELEN     0x7fff /* maximum scanline length for encoding */
00029 #define  MINRUN             4      /* minimum run length */
00030 
00031 
00032 char *
00033 tempbuffer(len)                    /* get a temporary buffer */
00034 unsigned int  len;
00035 {
00036        static char  *tempbuf = NULL;
00037        static unsigned  tempbuflen = 0;
00038 
00039        if (len > tempbuflen) {
00040               if (tempbuflen > 0)
00041                      tempbuf = (char *)realloc((void *)tempbuf, len);
00042               else
00043                      tempbuf = (char *)malloc(len);
00044               tempbuflen = tempbuf==NULL ? 0 : len;
00045        }
00046        return(tempbuf);
00047 }
00048 
00049 
00050 int
00051 fwritecolrs(scanline, len, fp)            /* write out a colr scanline */
00052 register COLR  *scanline;
00053 int  len;
00054 register FILE  *fp;
00055 {
00056        register int  i, j, beg, cnt = 1;
00057        int  c2;
00058        
00059        if ((len < MINELEN) | (len > MAXELEN))    /* OOBs, write out flat */
00060               return(fwrite((char *)scanline,sizeof(COLR),len,fp) - len);
00061                                    /* put magic header */
00062        putc(2, fp);
00063        putc(2, fp);
00064        putc(len>>8, fp);
00065        putc(len&255, fp);
00066                                    /* put components seperately */
00067        for (i = 0; i < 4; i++) {
00068            for (j = 0; j < len; j += cnt) {      /* find next run */
00069               for (beg = j; beg < len; beg += cnt) {
00070                   for (cnt = 1; cnt < 127 && beg+cnt < len &&
00071                          scanline[beg+cnt][i] == scanline[beg][i]; cnt++)
00072                      ;
00073                   if (cnt >= MINRUN)
00074                      break;               /* long enough */
00075               }
00076               if (beg-j > 1 && beg-j < MINRUN) {
00077                   c2 = j+1;
00078                   while (scanline[c2++][i] == scanline[j][i])
00079                      if (c2 == beg) {     /* short run */
00080                          putc(128+beg-j, fp);
00081                          putc(scanline[j][i], fp);
00082                          j = beg;
00083                          break;
00084                      }
00085               }
00086               while (j < beg) {           /* write out non-run */
00087                   if ((c2 = beg-j) > 128) c2 = 128;
00088                   putc(c2, fp);
00089                   while (c2--)
00090                      putc(scanline[j++][i], fp);
00091               }
00092               if (cnt >= MINRUN) {        /* write out run */
00093                   putc(128+cnt, fp);
00094                   putc(scanline[beg][i], fp);
00095               } else
00096                   cnt = 0;
00097            }
00098        }
00099        return(ferror(fp) ? -1 : 0);
00100 }
00101 
00102 
00103 static int
00104 oldreadcolrs(scanline, len, fp)           /* read in an old colr scanline */
00105 register COLR  *scanline;
00106 int  len;
00107 register FILE  *fp;
00108 {
00109        int  rshift;
00110        register int  i;
00111        
00112        rshift = 0;
00113        
00114        while (len > 0) {
00115               scanline[0][RED] = getc(fp);
00116               scanline[0][GRN] = getc(fp);
00117               scanline[0][BLU] = getc(fp);
00118               scanline[0][EXP] = getc(fp);
00119               if (feof(fp) || ferror(fp))
00120                      return(-1);
00121               if (scanline[0][RED] == 1 &&
00122                             scanline[0][GRN] == 1 &&
00123                             scanline[0][BLU] == 1) {
00124                      for (i = scanline[0][EXP] << rshift; i > 0; i--) {
00125                             copycolr(scanline[0], scanline[-1]);
00126                             scanline++;
00127                             len--;
00128                      }
00129                      rshift += 8;
00130               } else {
00131                      scanline++;
00132                      len--;
00133                      rshift = 0;
00134               }
00135        }
00136        return(0);
00137 }
00138 
00139 
00140 int
00141 freadcolrs(scanline, len, fp)             /* read in an encoded colr scanline */
00142 register COLR  *scanline;
00143 int  len;
00144 register FILE  *fp;
00145 {
00146        register int  i, j;
00147        int  code, val;
00148                                    /* determine scanline type */
00149        if ((len < MINELEN) | (len > MAXELEN))
00150               return(oldreadcolrs(scanline, len, fp));
00151        if ((i = getc(fp)) == EOF)
00152               return(-1);
00153        if (i != 2) {
00154               ungetc(i, fp);
00155               return(oldreadcolrs(scanline, len, fp));
00156        }
00157        scanline[0][GRN] = getc(fp);
00158        scanline[0][BLU] = getc(fp);
00159        if ((i = getc(fp)) == EOF)
00160               return(-1);
00161        if (scanline[0][GRN] != 2 || scanline[0][BLU] & 128) {
00162               scanline[0][RED] = 2;
00163               scanline[0][EXP] = i;
00164               return(oldreadcolrs(scanline+1, len-1, fp));
00165        }
00166        if ((scanline[0][BLU]<<8 | i) != len)
00167               return(-1);          /* length mismatch! */
00168                                    /* read each component */
00169        for (i = 0; i < 4; i++)
00170            for (j = 0; j < len; ) {
00171               if ((code = getc(fp)) == EOF)
00172                   return(-1);
00173               if (code > 128) {    /* run */
00174                   code &= 127;
00175                   if ((val = getc(fp)) == EOF)
00176                      return -1;
00177                   if (j + code > len)
00178                      return -1;    /* overrun */
00179                   while (code--)
00180                      scanline[j++][i] = val;
00181               } else {             /* non-run */
00182                   if (j + code > len)
00183                      return -1;    /* overrun */
00184                   while (code--) {
00185                      if ((val = getc(fp)) == EOF)
00186                          return -1;
00187                      scanline[j++][i] = val;
00188                   }
00189               }
00190            }
00191        return(0);
00192 }
00193 
00194 
00195 int
00196 fwritescan(scanline, len, fp)             /* write out a scanline */
00197 register COLOR  *scanline;
00198 int  len;
00199 FILE  *fp;
00200 {
00201        COLR  *clrscan;
00202        int  n;
00203        register COLR  *sp;
00204                                    /* get scanline buffer */
00205        if ((sp = (COLR *)tempbuffer(len*sizeof(COLR))) == NULL)
00206               return(-1);
00207        clrscan = sp;
00208                                    /* convert scanline */
00209        n = len;
00210        while (n-- > 0) {
00211               setcolr(sp[0], scanline[0][RED],
00212                               scanline[0][GRN],
00213                               scanline[0][BLU]);
00214               scanline++;
00215               sp++;
00216        }
00217        return(fwritecolrs(clrscan, len, fp));
00218 }
00219 
00220 
00221 int
00222 freadscan(scanline, len, fp)              /* read in a scanline */
00223 register COLOR  *scanline;
00224 int  len;
00225 FILE  *fp;
00226 {
00227        register COLR  *clrscan;
00228 
00229        if ((clrscan = (COLR *)tempbuffer(len*sizeof(COLR))) == NULL)
00230               return(-1);
00231        if (freadcolrs(clrscan, len, fp) < 0)
00232               return(-1);
00233                                    /* convert scanline */
00234        colr_color(scanline[0], clrscan[0]);
00235        while (--len > 0) {
00236               scanline++; clrscan++;
00237               if (clrscan[0][RED] == clrscan[-1][RED] &&
00238                          clrscan[0][GRN] == clrscan[-1][GRN] &&
00239                          clrscan[0][BLU] == clrscan[-1][BLU] &&
00240                          clrscan[0][EXP] == clrscan[-1][EXP])
00241                      copycolor(scanline[0], scanline[-1]);
00242               else
00243                      colr_color(scanline[0], clrscan[0]);
00244        }
00245        return(0);
00246 }
00247 
00248 
00249 void
00250 setcolr(clr, r, g, b)              /* assign a short color value */
00251 register COLR  clr;
00252 double  r, g, b;
00253 {
00254        double  d;
00255        int  e;
00256        
00257        d = r > g ? r : g;
00258        if (b > d) d = b;
00259 
00260        if (d <= 1e-32) {
00261               clr[RED] = clr[GRN] = clr[BLU] = 0;
00262               clr[EXP] = 0;
00263               return;
00264        }
00265 
00266        d = frexp(d, &e) * 255.9999 / d;
00267 
00268        if (r > 0.0)
00269               clr[RED] = r * d;
00270        else
00271               clr[RED] = 0;
00272        if (g > 0.0)
00273               clr[GRN] = g * d;
00274        else
00275               clr[GRN] = 0;
00276        if (b > 0.0)
00277               clr[BLU] = b * d;
00278        else
00279               clr[BLU] = 0;
00280 
00281        clr[EXP] = e + COLXS;
00282 }
00283 
00284 
00285 void
00286 colr_color(col, clr)        /* convert short to float color */
00287 register COLOR  col;
00288 register COLR  clr;
00289 {
00290        double  f;
00291        
00292        if (clr[EXP] == 0)
00293               col[RED] = col[GRN] = col[BLU] = 0.0;
00294        else {
00295               f = ldexp(1.0, (int)clr[EXP]-(COLXS+8));
00296               col[RED] = (clr[RED] + 0.5)*f;
00297               col[GRN] = (clr[GRN] + 0.5)*f;
00298               col[BLU] = (clr[BLU] + 0.5)*f;
00299        }
00300 }
00301 
00302 
00303 int
00304 bigdiff(c1, c2, md)                /* c1 delta c2 > md? */
00305 register COLOR  c1, c2;
00306 double  md;
00307 {
00308        register int  i;
00309 
00310        for (i = 0; i < 3; i++)
00311               if (colval(c1,i)-colval(c2,i) > md*colval(c2,i) ||
00312                      colval(c2,i)-colval(c1,i) > md*colval(c1,i))
00313                      return(1);
00314        return(0);
00315 }