Back to index

radiance  4R0+20100331
tmap16bit.c
Go to the documentation of this file.
00001 #ifndef lint
00002 static const char RCSid[] = "$Id: tmap16bit.c,v 1.8 2008/05/15 22:15:16 greg Exp $";
00003 #endif
00004 /*
00005  * Routines for tone-mapping 16-bit/primary pixels
00006  *
00007  * Externals declared in tonemap.h
00008  */
00009 
00010 #include "copyright.h"
00011 
00012 #include <stdio.h>
00013 #include <math.h>
00014 #include "tmprivat.h"
00015 
00016 #define LOGTABBITS   11     /* log table is 1<<LOGTABBITS long */
00017 #define GAMTABBITS   9      /* gamma table is 1<<GAMTABBITS long */
00018 #define MONGAMTSZ    1024   /* monitor gamma table length */
00019 
00020 static float  logtab[1<<LOGTABBITS];
00021 static float  gamtab[1<<GAMTABBITS];
00022 static float  gammul[16];
00023 static double cur_gam = 0.;
00024 static BYTE   mongamtab[MONGAMTSZ];
00025 static double cur_mongam = 0.;
00026 
00027 #define imultpow2(i,s)      ((s)>=0 ? (i)<<(s) : (i)>>-(s))
00028 
00029 
00030 /* Fill our log table */
00031 static void
00032 mkLogTable()
00033 {      
00034        int    i;
00035 
00036        if (logtab[0] != 0.f)
00037               return;
00038        for (i = 1<<LOGTABBITS; i--; )
00039               logtab[i] = log(imultpow2(i,15-LOGTABBITS)*(1./(1L<<16))
00040                                    + .5);
00041 }
00042 
00043 
00044 /* Fill our input gamma table */
00045 static void
00046 mkGamTable(double gv)
00047 {
00048        int    i;
00049 
00050        if (gv == cur_gam)
00051               return;
00052        for (i = 1<<GAMTABBITS; i--; )
00053               gamtab[i] = pow((i+.5)*(1./(1<<GAMTABBITS)), gv);
00054        for (i = 16; i--; )
00055               gammul[i] = pow((double)(1L<<i), -gv);
00056        cur_gam = gv;
00057 }
00058 
00059 
00060 /* Fill our monitor gamma table */
00061 static void
00062 mkMonGamTable(TMstruct *tms)
00063 {
00064        int    i;
00065        
00066        if (tms->mongam == cur_mongam)
00067               return;
00068        for (i = MONGAMTSZ; i--; )
00069               mongamtab[i] = 256.*pow((i+.5)*(1./MONGAMTSZ), 1./tms->mongam);
00070        cur_mongam = tms->mongam;
00071 }
00072 
00073 
00074 /* Find normalizing shift value for a 2-byte unsigned integer */
00075 static int
00076 normShift16(int i)
00077 {
00078        int    s = 0;
00079        
00080        if (!i)
00081               return(-1);
00082        while (!(i & 0x8000)) {
00083               i <<= 1;
00084               ++s;
00085        }
00086        return(s);
00087 }
00088 
00089 
00090 /* Find common normalizing shift for 3 2-byte unsigned integers */
00091 static int
00092 normShift48(uint16 clr48[3])
00093 {
00094        int    imax = (clr48[1] > clr48[0] ? clr48[1] : clr48[0]);
00095        if (clr48[2] > imax)
00096               imax = clr48[2];
00097        return(normShift16(imax));
00098 }
00099 
00100 
00101 /* convert at 48-bit tristimulus value to a COLOR */
00102 static void
00103 rgb48_color(COLOR col, uint16 clr48[3], double gv)
00104 {
00105        int    nshft;
00106 
00107        if (gv == 1.) {                           /* linear case */
00108               col[0] = clr48[0]*(1./(1L<<16));
00109               col[1] = clr48[1]*(1./(1L<<16));
00110               col[2] = clr48[2]*(1./(1L<<16));
00111               return;
00112        }
00113                                           /* non-linear case */
00114        /* XXX Uncomment if this routine is made public
00115        if (gv != cur_gam)
00116               mkGamTable(gv);
00117        */
00118        nshft = normShift48(clr48);
00119        if (nshft < 0) {
00120               col[0] = col[1] = col[2] = .0f;
00121               return;
00122        }
00123        col[0] = gamtab[imultpow2(clr48[0],GAMTABBITS-16+nshft)] * 
00124                      gammul[nshft];
00125        col[1] = gamtab[imultpow2(clr48[1],GAMTABBITS-16+nshft)] *
00126                      gammul[nshft];
00127        col[2] = gamtab[imultpow2(clr48[2],GAMTABBITS-16+nshft)] *
00128                      gammul[nshft];
00129 }
00130 
00131 
00132 /* Convert 16-bit gray scanline to encoded luminance */
00133 int
00134 tmCvGray16(TMstruct *tms, TMbright *ls, uint16 *scan, int len, double gv)
00135 {
00136        static const char    funcName[] = "tmCvGray16";
00137        static double cur_inpsf = 1.;
00138        static double log_inpsf = 0.;
00139        int           nshft;
00140        double        d;
00141 
00142        if (tms == NULL)
00143               returnErr(TM_E_TMINVAL);
00144        if ((ls == NULL) | (scan == NULL) | (len < 0))
00145               returnErr(TM_E_ILLEGAL);
00146        if (gv <= 0.)
00147               gv = DEFGAM;
00148                                           /* initialize log table */
00149        if (logtab[0] == 0.f)
00150               mkLogTable();
00151        if (cur_inpsf != tms->inpsf)
00152               log_inpsf = log(cur_inpsf = tms->inpsf);
00153                                           /* convert 16-bit grays */
00154        while (len--) {
00155               nshft = normShift16(*scan);
00156               if (nshft < 0) {            /* bogus value */
00157                      *ls++ = TM_NOBRT;
00158                      scan++;
00159                      continue;
00160               }
00161               d = logtab[ imultpow2(*scan,LOGTABBITS-15+nshft) &
00162                                    ((1L<<LOGTABBITS)-1) ];
00163               d -= M_LN2*nshft;
00164               d = (double)TM_BRTSCALE * (gv*d + log_inpsf);
00165               *ls++ = (d>0. ? d+.5 : d-.5);
00166               scan++;
00167        }
00168        returnOK;
00169 }
00170 
00171 /* Convert a 48-bit RGB scanline to encoded luminance/chrominance */
00172 int
00173 tmCvRGB48(TMstruct *tms, TMbright *ls, BYTE *cs,
00174               uint16 (*scan)[3], int len, double gv)
00175 {
00176        static const char    funcName[] = "tmCvRGB48";
00177        static double cur_inpsf = 1.;
00178        static double log_inpsf = 0.;
00179        int           i;
00180 
00181        if (tms == NULL)
00182               returnErr(TM_E_TMINVAL);
00183        if ((ls == NULL) | (scan == NULL) | (len < 0))
00184               returnErr(TM_E_ILLEGAL);
00185        if (gv <= 0.)
00186               gv = DEFGAM;
00187                                           /* sync input gamma table */
00188        if (gv != cur_gam)
00189               mkGamTable(gv);
00190        if (tmNeedMatrix(tms)) {           /* need floating point */
00191               COLOR  *newscan;
00192               newscan = (COLOR *)tempbuffer(len*sizeof(COLOR));
00193               if (newscan == NULL)
00194                      returnErr(TM_E_NOMEM);
00195               for (i = len; i--; )
00196                      rgb48_color(newscan[i], scan[i], gv);
00197               return(tmCvColors(tms, ls, cs, newscan, len));
00198        }
00199                                           /* sync monitor gamma table */
00200        if (cs != TM_NOCHROM && tms->mongam != cur_mongam)
00201               mkMonGamTable(tms);
00202                                           /* initialize log table */
00203        if (logtab[0] == 0.f)
00204               mkLogTable();
00205        if (cur_inpsf != tms->inpsf)
00206               log_inpsf = log(cur_inpsf = tms->inpsf);
00207        if (tms->flags & TM_F_MESOPIC)
00208               tmMkMesofact();
00209                                           /* convert scanline */
00210        for (i = len; i--; ) {
00211               int    nshft = normShift48(scan[i]);
00212               COLOR  cmon;
00213               double lum;
00214               int    bi;
00215               
00216               if (nshft < 0) {
00217                      bi = TM_NOBRT;                     /* bogus value */
00218                      lum = 1.;
00219                      setcolor(cmon, 1., 1., 1.);
00220               } else {
00221                      int    j = GAMTABBITS-16+nshft;
00222                      int    nshft2;
00223                      double d;
00224                                                  /* normalized linear */
00225                      setcolor(cmon,       gamtab[imultpow2(scan[i][0],j)],
00226                                    gamtab[imultpow2(scan[i][1],j)],
00227                                    gamtab[imultpow2(scan[i][2],j)] );
00228                      lum =  tms->clf[RED]*cmon[RED];
00229                      lum += tms->clf[GRN]*cmon[GRN];
00230                      lum += tms->clf[BLU]*cmon[BLU];
00231                                                  /* convert to log Y */
00232                      j = lum * (double)(1L<<16);
00233                      nshft2 = normShift16(j);
00234                      d = logtab[ imultpow2(j,LOGTABBITS-15+nshft2) &
00235                                           ((1L<<LOGTABBITS)-1) ];
00236                      d -= M_LN2*(gv*nshft + nshft2);
00237                      d = (double)TM_BRTSCALE*(d + log_inpsf);
00238                      bi = (int)(d>0. ? d+.5 : d-.5);
00239               }
00240                                                  /* world luminance */
00241               ls[i] = bi;
00242               if (cs == TM_NOCHROM)                     /* no color? */
00243                      continue;
00244                                                  /* mesopic adj. */
00245               if (tms->flags & TM_F_MESOPIC && bi < BMESUPPER) {
00246                      double slum = scotlum(cmon);
00247                      if (bi < BMESLOWER)
00248                             setcolor(cmon, slum, slum, slum);
00249                      else {
00250                             double pf;
00251                             pf = (1./256.)*tmMesofact[bi-BMESLOWER];
00252                             if (tms->flags & TM_F_BW)
00253                                    cmon[RED] = cmon[GRN] = cmon[BLU] = lum;
00254                             slum *= 1. - pf;
00255                             cmon[RED] = slum + pf*cmon[RED];
00256                             cmon[GRN] = slum + pf*cmon[GRN];
00257                             cmon[BLU] = slum + pf*cmon[BLU];
00258                      }
00259               } else if (tms->flags & TM_F_BW) {
00260                      cmon[RED] = cmon[GRN] = cmon[BLU] = lum;
00261               }
00262               bi = (double)MONGAMTSZ*tms->clf[RED]*cmon[RED]/lum;
00263               cs[3*i  ] = bi>=MONGAMTSZ ? 255 : mongamtab[bi];
00264               bi = (double)MONGAMTSZ*tms->clf[GRN]*cmon[GRN]/lum;
00265               cs[3*i+1] = bi>=MONGAMTSZ ? 255 : mongamtab[bi];
00266               bi = (double)MONGAMTSZ*tms->clf[BLU]*cmon[BLU]/lum;
00267               cs[3*i+2] = bi>=MONGAMTSZ ? 255 : mongamtab[bi];
00268        }
00269        returnOK;
00270 }