Back to index

radiance  4R0+20100331
tonemap.c
Go to the documentation of this file.
00001 #ifndef lint
00002 static const char    RCSid[] = "$Id: tonemap.c,v 3.34 2009/02/09 20:48:08 greg Exp $";
00003 #endif
00004 /*
00005  * Tone mapping functions.
00006  * See tonemap.h for detailed function descriptions.
00007  * Added von Kries white-balance calculations 10/01 (GW).
00008  *
00009  * Externals declared in tonemap.h
00010  */
00011 
00012 #include "copyright.h"
00013 
00014 #include      <stdio.h>
00015 #include      <stdlib.h>
00016 #include      <math.h>
00017 #include      "tmprivat.h"
00018 #include      "tmerrmsg.h"
00019 
00020 #define       exp10(x)      exp(M_LN10*(x))
00021 
00022                                    /* our list of conversion packages */
00023 struct tmPackage     *tmPkg[TM_MAXPKG];
00024 int    tmNumPkgs = 0;                     /* number of registered packages */
00025 
00026                                    /* luminance->brightness lookup */
00027 static TMbright             *tmFloat2BrtLUT = NULL;
00028 
00029 #define tmCvLumLUfp(pf)     tmFloat2BrtLUT[*(int32 *)(pf) >> 15]
00030 
00031 
00032 TMstruct *
00033 tmInit(                                   /* initialize new tone mapping */
00034 int    flags,
00035 RGBPRIMP      monpri,
00036 double gamval
00037 )
00038 {
00039        COLORMAT      cmat;
00040        TMstruct      *tmnew;
00041        int    i;
00042                                           /* allocate structure */
00043        tmnew = (TMstruct *)malloc(sizeof(TMstruct));
00044        if (tmnew == NULL)
00045               return(NULL);
00046 
00047        tmnew->flags = flags & ~TM_F_UNIMPL;
00048        if (tmnew->flags & TM_F_BW)
00049               tmnew->flags &= ~TM_F_MESOPIC;
00050                                           /* set monitor transform */
00051        if (monpri == NULL || monpri == stdprims || tmnew->flags & TM_F_BW) {
00052               tmnew->monpri = stdprims;
00053               tmnew->clf[RED] = rgb2xyzmat[1][0];
00054               tmnew->clf[GRN] = rgb2xyzmat[1][1];
00055               tmnew->clf[BLU] = rgb2xyzmat[1][2];
00056        } else {
00057               comprgb2xyzmat(cmat, tmnew->monpri=monpri);
00058               tmnew->clf[RED] = cmat[1][0];
00059               tmnew->clf[GRN] = cmat[1][1];
00060               tmnew->clf[BLU] = cmat[1][2];
00061        }
00062                                           /* set gamma value */
00063        if (gamval < MINGAM)
00064               tmnew->mongam = DEFGAM;
00065        else
00066               tmnew->mongam = gamval;
00067                                           /* set color divisors */
00068        for (i = 0; i < 3; i++)
00069               tmnew->cdiv[i] = 256.*pow(tmnew->clf[i], 1./tmnew->mongam);
00070 
00071                                           /* set input transform */
00072        tmnew->inppri = tmnew->monpri;
00073        tmnew->cmat[0][0] = tmnew->cmat[1][1] = tmnew->cmat[2][2] =
00074                      tmnew->inpsf = WHTEFFICACY;
00075        tmnew->cmat[0][1] = tmnew->cmat[0][2] = tmnew->cmat[1][0] =
00076        tmnew->cmat[1][2] = tmnew->cmat[2][0] = tmnew->cmat[2][1] = 0.;
00077        tmnew->inpdat = NULL;
00078        tmnew->hbrmin = 10; tmnew->hbrmax = -10;
00079        tmnew->histo = NULL;
00080        tmnew->mbrmin = 10; tmnew->mbrmax = -10;
00081        tmnew->lumap = NULL;
00082                                           /* zero private data */
00083        for (i = TM_MAXPKG; i--; )
00084               tmnew->pd[i] = NULL;
00085        tmnew->lastError = TM_E_OK;
00086        tmnew->lastFunc = "NoErr";
00087                                           /* return new TMstruct */
00088        return(tmnew);
00089 }
00090 
00091 
00092 int
00093 tmSetSpace(                 /* set input color space for conversions */
00094 TMstruct      *tms,
00095 RGBPRIMP      pri,
00096 double sf,
00097 MEM_PTR       dat
00098 )
00099 {
00100        static const char funcName[] = "tmSetSpace";
00101        int    i, j;
00102                                           /* error check */
00103        if (tms == NULL)
00104               returnErr(TM_E_TMINVAL);
00105        if (sf <= 1e-12)
00106               returnErr(TM_E_ILLEGAL);
00107                                           /* check if no change */
00108        if (pri == tms->inppri && FEQ(sf, tms->inpsf) && dat == tms->inpdat)
00109               returnOK;
00110        tms->inppri = pri;                 /* let's set it */
00111        tms->inpsf = sf;
00112        tms->inpdat = dat;
00113 
00114        if (tms->flags & TM_F_BW) {        /* color doesn't matter */
00115               tms->monpri = tms->inppri;         /* eliminate xform */
00116               if (tms->inppri == TM_XYZPRIM) {
00117                      tms->clf[CIEX] = tms->clf[CIEZ] = 0.;
00118                      tms->clf[CIEY] = 1.;
00119               } else {
00120                      comprgb2xyzmat(tms->cmat, tms->monpri);
00121                      tms->clf[RED] = tms->cmat[1][0];
00122                      tms->clf[GRN] = tms->cmat[1][1];
00123                      tms->clf[BLU] = tms->cmat[1][2];
00124               }
00125               tms->cmat[0][0] = tms->cmat[1][1] = tms->cmat[2][2] =
00126                             tms->inpsf;
00127               tms->cmat[0][1] = tms->cmat[0][2] = tms->cmat[1][0] =
00128               tms->cmat[1][2] = tms->cmat[2][0] = tms->cmat[2][1] = 0.;
00129 
00130        } else if (tms->inppri == TM_XYZPRIM)     /* input is XYZ */
00131               compxyz2rgbWBmat(tms->cmat, tms->monpri);
00132 
00133        else {                             /* input is RGB */
00134               if (tms->inppri != tms->monpri &&
00135                             PRIMEQ(tms->inppri, tms->monpri))
00136                      tms->inppri = tms->monpri;  /* no xform */
00137               comprgb2rgbWBmat(tms->cmat, tms->inppri, tms->monpri);
00138        }
00139        for (i = 0; i < 3; i++)
00140               for (j = 0; j < 3; j++)
00141                      tms->cmat[i][j] *= tms->inpsf;
00142                                           /* set color divisors */
00143        for (i = 0; i < 3; i++)
00144               if (tms->clf[i] > .001)
00145                      tms->cdiv[i] =
00146                             256.*pow(tms->clf[i], 1./tms->mongam);
00147               else
00148                      tms->cdiv[i] = 1;
00149                                           /* notify packages */
00150        for (i = tmNumPkgs; i--; )
00151               if (tms->pd[i] != NULL && tmPkg[i]->NewSpace != NULL)
00152                      (*tmPkg[i]->NewSpace)(tms);
00153        returnOK;
00154 }
00155 
00156 
00157 void
00158 tmClearHisto(                      /* clear current histogram */
00159 TMstruct      *tms
00160 )
00161 {
00162        if (tms == NULL || tms->histo == NULL)
00163               return;
00164        free((MEM_PTR)tms->histo);
00165        tms->histo = NULL;
00166 }
00167 
00168 
00169 TMbright
00170 tmCvLuminance(                            /* convert a single luminance */
00171 double lum
00172 )
00173 {
00174        double d;
00175 
00176 #ifdef isfinite
00177        if (!isfinite(lum) || lum <= TM_NOLUM)
00178 #else
00179        if (lum <= TM_NOLUM)
00180 #endif
00181               return(TM_NOBRT);
00182        d = TM_BRTSCALE*log(lum);
00183        if (d > 0.)
00184               return((TMbright)(d+.5));
00185        return((TMbright)(d-.5));
00186 }
00187 
00188 
00189 int
00190 tmCvLums(                          /* convert luminances using lookup */
00191 TMbright      *ls,
00192 float         *scan,
00193 int           len
00194 )
00195 {
00196        if (tmFloat2BrtLUT == NULL) {      /* initialize lookup table */
00197               int32  i;
00198               tmFloat2BrtLUT = (TMbright *)malloc(sizeof(TMbright)*0x10000);
00199               if (tmFloat2BrtLUT == NULL)
00200                      return(TM_E_NOMEM);
00201               for (i = 0; i < 0x10000; i++) {
00202                      int32  l = (i<<1 | 1) << 14;
00203 #ifndef isfinite
00204                      if ((l & 0x7f800000) == 0x7f800000)
00205                             tmFloat2BrtLUT[i] = TM_NOBRT;
00206                      else
00207 #endif
00208                      tmFloat2BrtLUT[i] = tmCvLuminance(*(float *)&l);
00209               }
00210        }
00211        if (len <= 0)
00212               return(TM_E_OK);
00213        if ((ls == NULL) | (scan == NULL))
00214               return(TM_E_ILLEGAL);
00215        while (len--) {
00216               if (*scan <= TM_NOLUM) {
00217                      *ls++ = TM_NOBRT;
00218                      ++scan;
00219                      continue;
00220               }
00221               *ls++ = tmCvLumLUfp(scan++);
00222        }
00223        return(TM_E_OK);
00224 }
00225 
00226 
00227 int
00228 tmCvGrays(                         /* convert float gray values */
00229 TMstruct      *tms,
00230 TMbright      *ls,
00231 float         *scan,
00232 int           len
00233 )
00234 {
00235        static const char funcName[] = "tmCvGrays";
00236        int    i;
00237 
00238        if (tms == NULL)
00239               returnErr(TM_E_TMINVAL);
00240        if ((ls == NULL) | (scan == NULL) | (len < 0))
00241               returnErr(TM_E_ILLEGAL);
00242        if (tmFloat2BrtLUT == NULL)               /* initialize */
00243               tmCvLums(NULL, NULL, 0);
00244        for (i = len; i--; ) {
00245               float  lum = tms->inpsf * scan[i];
00246               if (lum <= TM_NOLUM)
00247                      ls[i] = TM_NOBRT;
00248               else
00249                      ls[i] = tmCvLumLUfp(&lum);
00250        }
00251        returnOK;
00252 }
00253 
00254 
00255 int
00256 tmCvColors(                        /* convert float colors */
00257 TMstruct      *tms,
00258 TMbright      *ls,
00259 BYTE   *cs,
00260 COLOR  *scan,
00261 int    len
00262 )
00263 {
00264        static const char funcName[] = "tmCvColors";
00265        static BYTE   gamtab[1024];
00266        static double curgam = .0;
00267        COLOR  cmon;
00268        float  lum, slum, d;
00269        int    i;
00270 
00271        if (tms == NULL)
00272               returnErr(TM_E_TMINVAL);
00273        if ((ls == NULL) | (scan == NULL) | (len < 0))
00274               returnErr(TM_E_ILLEGAL);
00275        if (tmFloat2BrtLUT == NULL)               /* initialize */
00276               tmCvLums(NULL, NULL, 0);
00277        if (cs != TM_NOCHROM && fabs(tms->mongam - curgam) > .02) {
00278               curgam = tms->mongam;                     /* (re)build table */
00279               for (i = 1024; i--; )
00280                      gamtab[i] = (int)(256.*pow((i+.5)/1024., 1./curgam));
00281        }
00282        for (i = len; i--; ) {
00283               if (tmNeedMatrix(tms)) {           /* get monitor RGB */
00284                      colortrans(cmon, tms->cmat, scan[i]);
00285               } else {
00286                      cmon[RED] = tms->inpsf*scan[i][RED];
00287                      cmon[GRN] = tms->inpsf*scan[i][GRN];
00288                      cmon[BLU] = tms->inpsf*scan[i][BLU];
00289               }
00290 #ifdef isfinite
00291               if (!isfinite(cmon[RED]) || cmon[RED] < .0f) cmon[RED] = .0f;
00292               if (!isfinite(cmon[GRN]) || cmon[GRN] < .0f) cmon[GRN] = .0f;
00293               if (!isfinite(cmon[BLU]) || cmon[BLU] < .0f) cmon[BLU] = .0f;
00294 #else
00295               if (cmon[RED] < .0f) cmon[RED] = .0f;
00296               if (cmon[GRN] < .0f) cmon[GRN] = .0f;
00297               if (cmon[BLU] < .0f) cmon[BLU] = .0f;
00298 #endif
00299                                                  /* world luminance */
00300               lum =  tms->clf[RED]*cmon[RED] +
00301                      tms->clf[GRN]*cmon[GRN] +
00302                      tms->clf[BLU]*cmon[BLU] ;
00303               if (lum <= TM_NOLUM) {                    /* convert brightness */
00304                      lum = cmon[RED] = cmon[GRN] = cmon[BLU] = TM_NOLUM;
00305                      ls[i] = TM_NOBRT;
00306               } else
00307                      ls[i] = tmCvLumLUfp(&lum);
00308               if (cs == TM_NOCHROM)                     /* no color? */
00309                      continue;
00310               if (tms->flags & TM_F_MESOPIC && lum < LMESUPPER) {
00311                      slum = scotlum(cmon);              /* mesopic adj. */
00312                      if (lum < LMESLOWER) {
00313                             cmon[RED] = cmon[GRN] = cmon[BLU] = slum;
00314                      } else {
00315                             d = (lum - LMESLOWER)/(LMESUPPER - LMESLOWER);
00316                             if (tms->flags & TM_F_BW)
00317                                    cmon[RED] = cmon[GRN] =
00318                                                  cmon[BLU] = d*lum;
00319                             else
00320                                    scalecolor(cmon, d);
00321                             d = (1.f-d)*slum;
00322                             cmon[RED] += d;
00323                             cmon[GRN] += d;
00324                             cmon[BLU] += d;
00325                      }
00326               } else if (tms->flags & TM_F_BW) {
00327                      cmon[RED] = cmon[GRN] = cmon[BLU] = lum;
00328               }
00329               d = tms->clf[RED]*cmon[RED]/lum;
00330               cs[3*i  ] = d>=.999f ? 255 : gamtab[(int)(1024.f*d)];
00331               d = tms->clf[GRN]*cmon[GRN]/lum;
00332               cs[3*i+1] = d>=.999f ? 255 : gamtab[(int)(1024.f*d)];
00333               d = tms->clf[BLU]*cmon[BLU]/lum;
00334               cs[3*i+2] = d>=.999f ? 255 : gamtab[(int)(1024.f*d)];
00335        }
00336        returnOK;
00337 }
00338 
00339 
00340 int
00341 tmAddHisto(                        /* add values to histogram */
00342 TMstruct      *tms,
00343 TMbright      *ls,
00344 int    len,
00345 int    wt
00346 )
00347 {
00348        static const char funcName[] = "tmAddHisto";
00349        int    oldorig=0, oldlen, horig, hlen;
00350        int    i, j;
00351 
00352        if (tms == NULL)
00353               returnErr(TM_E_TMINVAL);
00354        if (len < 0)
00355               returnErr(TM_E_ILLEGAL);
00356        if (len == 0)
00357               returnOK;
00358                                           /* first, grow limits */
00359        if (tms->histo == NULL) {
00360               for (i = len; i-- && ls[i] < MINBRT; )
00361                      ;
00362               if (i < 0)
00363                      returnOK;
00364               tms->hbrmin = tms->hbrmax = ls[i];
00365               oldlen = 0;
00366        } else {
00367               oldorig = HISTI(tms->hbrmin);
00368               oldlen = HISTI(tms->hbrmax) + 1 - oldorig;
00369        }
00370        for (i = len; i--; ) {
00371               if ((j = ls[i]) < MINBRT)
00372                      continue;
00373               if (j < tms->hbrmin)
00374                      tms->hbrmin = j;
00375               else if (j > tms->hbrmax)
00376                      tms->hbrmax = j;
00377        }
00378        horig = HISTI(tms->hbrmin);
00379        hlen = HISTI(tms->hbrmax) + 1 - horig;
00380        if (hlen > oldlen) {               /* (re)allocate histogram */
00381               int    *newhist = (int *)calloc(hlen, sizeof(int));
00382               if (newhist == NULL)
00383                      returnErr(TM_E_NOMEM);
00384               if (oldlen) {               /* copy and free old */
00385                      for (i = oldlen, j = i+oldorig-horig; i; )
00386                             newhist[--j] = tms->histo[--i];
00387                      free((MEM_PTR)tms->histo);
00388               }
00389               tms->histo = newhist;
00390        }
00391        if (wt == 0)
00392               returnOK;
00393        for (i = len; i--; )               /* add in new counts */
00394               if (ls[i] >= MINBRT)
00395                      tms->histo[ HISTI(ls[i]) - horig ] += wt;
00396        returnOK;
00397 }
00398 
00399 
00400 static double
00401 htcontrs(            /* human threshold contrast sensitivity, dL(La) */
00402 double La
00403 )
00404 {
00405        double l10La, l10dL;
00406                             /* formula taken from Ferwerda et al. [SG96] */
00407        if (La < 1.148e-4)
00408               return(1.38e-3);
00409        l10La = log10(La);
00410        if (l10La < -1.44)          /* rod response regime */
00411               l10dL = pow(.405*l10La + 1.6, 2.18) - 2.86;
00412        else if (l10La < -.0184)
00413               l10dL = l10La - .395;
00414        else if (l10La < 1.9)              /* cone response regime */
00415               l10dL = pow(.249*l10La + .65, 2.7) - .72;
00416        else
00417               l10dL = l10La - 1.255;
00418 
00419        return(exp10(l10dL));
00420 }
00421 
00422 
00423 int
00424 tmFixedMapping(                    /* compute fixed, linear tone-mapping */
00425 TMstruct      *tms,
00426 double expmult,
00427 double gamval
00428 )
00429 {
00430        static const char funcName[] = "tmFixedMapping";
00431        double        d;
00432        int    i;
00433        
00434        if (!tmNewMap(tms))
00435               returnErr(TM_E_NOMEM);
00436        if (expmult <= .0)
00437               expmult = 1.;
00438        if (gamval < MINGAM)
00439               gamval = tms->mongam;
00440        d = log(expmult/tms->inpsf);
00441        for (i = tms->mbrmax-tms->mbrmin+1; i--; ) {
00442               double val = 256. * exp(
00443                      ( d + (tms->mbrmin+i)*(1./TM_BRTSCALE) )
00444                      / gamval);
00445               tms->lumap[i] = val >= (double)0xffff ? 0xffff : (int)val;
00446        }
00447        returnOK;
00448 }
00449 
00450 
00451 int
00452 tmComputeMapping(                  /* compute histogram tone-mapping */
00453 TMstruct      *tms,
00454 double gamval,
00455 double Lddyn,
00456 double Ldmax
00457 )
00458 {
00459        static const char funcName[] = "tmComputeMapping";
00460        int    *histo;
00461        float  *cumf;
00462        int    brt0, histlen, threshold, ceiling, trimmings;
00463        double logLddyn, Ldmin, Ldavg, Lwavg, Tr, Lw, Ld;
00464        int32  histot;
00465        double sum;
00466        double d;
00467        int    i, j;
00468 
00469        if (tms == NULL || tms->histo == NULL)
00470               returnErr(TM_E_TMINVAL);
00471                                    /* check arguments */
00472        if (Lddyn < MINLDDYN) Lddyn = DEFLDDYN;
00473        if (Ldmax < MINLDMAX) Ldmax = DEFLDMAX;
00474        if (gamval < MINGAM) gamval = tms->mongam;
00475                                    /* compute handy values */
00476        Ldmin = Ldmax/Lddyn;
00477        logLddyn = log(Lddyn);
00478        Ldavg = sqrt(Ldmax*Ldmin);
00479        i = HISTI(tms->hbrmin);
00480        brt0 = HISTV(i);
00481        histlen = HISTI(tms->hbrmax) + 1 - i;
00482                                    /* histogram total and mean */
00483        histot = 0; sum = 0;
00484        j = brt0 + histlen*HISTEP;
00485        for (i = histlen; i--; ) {
00486               histot += tms->histo[i];
00487               sum += (double)(j -= HISTEP) * tms->histo[i];
00488        }
00489        threshold = histot*0.005 + .5;
00490        if (!histot)
00491               returnErr(TM_E_TMFAIL);
00492        Lwavg = tmLuminance( (double)sum / histot );
00493                                    /* use linear tone mapping? */
00494        if (tms->flags & TM_F_LINEAR || threshold < 4 ||
00495                      tms->hbrmax - tms->hbrmin < TM_BRTSCALE*logLddyn)
00496               goto linearmap;
00497                                    /* clamp histogram */
00498        histo = (int *)malloc(histlen*sizeof(int));
00499        cumf = (float *)malloc((histlen+2)*sizeof(float));
00500        if ((histo == NULL) | (cumf == NULL))
00501               returnErr(TM_E_NOMEM);
00502        cumf[histlen+1] = 1.;              /* guard for assignment code */
00503        for (i = histlen; i--; )    /* make malleable copy */
00504               histo[i] = tms->histo[i];
00505        do {                        /* iterate to solution */
00506               sum = 0;             /* cumulative probability */
00507               for (i = 0; i < histlen; i++) {
00508                      cumf[i] = (double)sum/histot;
00509                      sum += histo[i];
00510               }
00511               cumf[histlen] = 1.;
00512               Tr = histot * (double)(tms->hbrmax - tms->hbrmin) /
00513                      ((double)histlen*TM_BRTSCALE) / logLddyn;
00514               ceiling = Tr + 1.;
00515               trimmings = 0;              /* clip to envelope */
00516               for (i = histlen; i--; ) {
00517                      if (tms->flags & TM_F_HCONTR) {
00518                             Lw = tmLuminance(brt0 + i*HISTEP);
00519                             Ld = Ldmin * exp( logLddyn *
00520                                    .5*(cumf[i]+cumf[i+1]) );
00521                             ceiling = Tr * (htcontrs(Ld) * Lw) /
00522                                    (htcontrs(Lw) * Ld) + 1.;
00523                      }
00524                      if (histo[i] > ceiling) {
00525                             trimmings += histo[i] - ceiling;
00526                             histo[i] = ceiling;
00527                      }
00528               }
00529                                    /* check if we're out of data */
00530               if ((histot -= trimmings) <= threshold) {
00531                      free((MEM_PTR)histo);
00532                      free((MEM_PTR)cumf);
00533                      goto linearmap;
00534               }
00535        } while (trimmings > threshold);
00536                                    /* allocate space for mapping */
00537        if (!tmNewMap(tms))
00538               returnErr(TM_E_NOMEM);
00539                                    /* assign tone-mapping */
00540        for (i = tms->mbrmax-tms->mbrmin+1; i--; ) {
00541               j = d = (double)i/(tms->mbrmax-tms->mbrmin)*histlen;
00542               d -= (double)j;
00543               Ld = Ldmin*exp(logLddyn*((1.-d)*cumf[j]+d*cumf[j+1]));
00544               d = (Ld - Ldmin)/(Ldmax - Ldmin);
00545               tms->lumap[i] = 256.*pow(d, 1./gamval);
00546        }
00547        free((MEM_PTR)histo);              /* clean up and return */
00548        free((MEM_PTR)cumf);
00549        returnOK;
00550 linearmap:                         /* linear tone-mapping */
00551        if (tms->flags & TM_F_HCONTR)
00552               d = htcontrs(Ldavg) / htcontrs(Lwavg);
00553        else
00554               d = Ldavg / Lwavg;
00555        return(tmFixedMapping(tms, tms->inpsf*d/Ldmax, gamval));
00556 }
00557 
00558 
00559 int
00560 tmMapPixels(                /* apply tone-mapping to pixel(s) */
00561 TMstruct      *tms,
00562 BYTE   *ps,
00563 TMbright      *ls,
00564 BYTE   *cs,
00565 int    len
00566 )
00567 {
00568        static const char funcName[] = "tmMapPixels";
00569        int32  li, pv;
00570 
00571        if (tms == NULL || tms->lumap == NULL)
00572               returnErr(TM_E_TMINVAL);
00573        if ((ps == NULL) | (ls == NULL) | (len < 0))
00574               returnErr(TM_E_ILLEGAL);
00575        while (len--) {
00576               if ((li = *ls++) < tms->mbrmin) {
00577                      li = 0;
00578               } else {
00579                      if (li > tms->mbrmax)
00580                             li = tms->mbrmax;
00581                      li = tms->lumap[li - tms->mbrmin];
00582               }
00583               if (cs == TM_NOCHROM)
00584                      *ps++ = li>255 ? 255 : li;
00585               else {
00586                      pv = *cs++ * li / tms->cdiv[RED];
00587                      *ps++ = pv>255 ? 255 : pv;
00588                      pv = *cs++ * li / tms->cdiv[GRN];
00589                      *ps++ = pv>255 ? 255 : pv;
00590                      pv = *cs++ * li / tms->cdiv[BLU];
00591                      *ps++ = pv>255 ? 255 : pv;
00592               }
00593        }
00594        returnOK;
00595 }
00596 
00597 
00598 TMstruct *
00599 tmDup(                      /* duplicate top tone mapping */
00600 TMstruct      *tms
00601 )
00602 {
00603        int    len;
00604        int    i;
00605        TMstruct      *tmnew;
00606 
00607        if (tms == NULL)            /* anything to duplicate? */
00608               return(NULL);
00609        tmnew = (TMstruct *)malloc(sizeof(TMstruct));
00610        if (tmnew == NULL)
00611               return(NULL);
00612        *tmnew = *tms;              /* copy everything */
00613        if (tmnew->histo != NULL) { /* duplicate histogram */
00614               len = HISTI(tmnew->hbrmax) + 1 - HISTI(tmnew->hbrmin);
00615               tmnew->histo = (int *)malloc(len*sizeof(int));
00616               if (tmnew->histo != NULL)
00617                      for (i = len; i--; )
00618                             tmnew->histo[i] = tms->histo[i];
00619        }
00620        if (tmnew->lumap != NULL) { /* duplicate luminance mapping */
00621               len = tmnew->mbrmax-tmnew->mbrmin+1;
00622               tmnew->lumap = (unsigned short *)malloc(
00623                                           len*sizeof(unsigned short) );
00624               if (tmnew->lumap != NULL)
00625                      for (i = len; i--; )
00626                             tmnew->lumap[i] = tms->lumap[i];
00627        }
00628                                    /* clear package data */
00629        for (i = tmNumPkgs; i--; )
00630               tmnew->pd[i] = NULL;
00631                                    /* return copy */
00632        return(tmnew);
00633 }
00634 
00635 
00636 void
00637 tmDone(tms)                 /* done with tone mapping -- destroy it */
00638 TMstruct      *tms;
00639 {
00640        int    i;
00641                                    /* NULL arg. is equiv. to tms */
00642        if (tms == NULL)
00643               return;
00644                                    /* free tables */
00645        if (tms->histo != NULL)
00646               free((MEM_PTR)tms->histo);
00647        if (tms->lumap != NULL)
00648               free((MEM_PTR)tms->lumap);
00649                                    /* free private data */
00650        for (i = tmNumPkgs; i--; )
00651               if (tms->pd[i] != NULL)
00652                      (*tmPkg[i]->Free)(tms->pd[i]);
00653        free((MEM_PTR)tms);         /* free basic structure */
00654 }
00655 
00656 /******************** Shared but Private library routines *********************/
00657 
00658 BYTE   tmMesofact[BMESUPPER-BMESLOWER];
00659 
00660 void
00661 tmMkMesofact()                            /* build mesopic lookup factor table */
00662 {
00663        int    i;
00664 
00665        if (tmMesofact[BMESUPPER-BMESLOWER-1])
00666               return;
00667 
00668        for (i = BMESLOWER; i < BMESUPPER; i++)
00669               tmMesofact[i-BMESLOWER] = 256. *
00670                             (tmLuminance(i) - LMESLOWER) /
00671                             (LMESUPPER - LMESLOWER);
00672 }
00673 
00674 
00675 int
00676 tmNewMap(                   /* allocate new tone-mapping array */
00677 TMstruct      *tms
00678 )
00679 {
00680        if (tms->lumap != NULL && (tms->mbrmax - tms->mbrmin) !=
00681                                    (tms->hbrmax - tms->hbrmin)) {
00682               free((MEM_PTR)tms->lumap);
00683               tms->lumap = NULL;
00684        }
00685        tms->mbrmin = tms->hbrmin;
00686        tms->mbrmax = tms->hbrmax;
00687        if (tms->mbrmin > tms->mbrmax)
00688               return 0;
00689        if (tms->lumap == NULL)
00690               tms->lumap = (unsigned short *)malloc(sizeof(unsigned short)*
00691                                    (tms->mbrmax-tms->mbrmin+1));
00692        return(tms->lumap != NULL);
00693 }
00694 
00695 
00696 int
00697 tmErrorReturn(                            /* error return (with message) */
00698 const char    *func,
00699 TMstruct      *tms,
00700 int    err
00701 )
00702 {
00703        if (tms != NULL) {
00704               tms->lastFunc = func;
00705               tms->lastError = err;
00706               if (tms->flags & TM_F_NOSTDERR)
00707                      return(err);
00708        }
00709        fputs(func, stderr);
00710        fputs(": ", stderr);
00711        fputs(tmErrorMessage[err], stderr);
00712        fputs("!\n", stderr);
00713        return(err);
00714 }