Logo Search packages:      
Sourcecode: radiance version File versions  Download package

tonemap.c

#ifndef lint
static const char RCSid[] = "$Id: tonemap.c,v 3.30 2007/11/27 02:42:54 greg Exp $";
#endif
/*
 * Tone mapping functions.
 * See tonemap.h for detailed function descriptions.
 * Added von Kries white-balance calculations 10/01 (GW).
 *
 * Externals declared in tonemap.h
 */

#include "copyright.h"

#include    <stdio.h>
#include    <math.h>
#include    "tmprivat.h"
#include    "tmerrmsg.h"

#define     exp10(x)    exp(M_LN10*(x))

                              /* our list of conversion packages */
struct tmPackage  *tmPkg[TM_MAXPKG];
int   tmNumPkgs = 0;                /* number of registered packages */

                              /* luminance->brightness lookup */
static TMbright         *tmFloat2BrtLUT = NULL;

#define tmCvLumLUfp(pf) tmFloat2BrtLUT[*(int32 *)(pf) >> 15]


TMstruct *
tmInit(                             /* initialize new tone mapping */
int   flags,
RGBPRIMP    monpri,
double      gamval
)
{
      COLORMAT    cmat;
      TMstruct    *tmnew;
      int   i;
                                    /* allocate structure */
      tmnew = (TMstruct *)malloc(sizeof(TMstruct));
      if (tmnew == NULL)
            return(NULL);

      tmnew->flags = flags & ~TM_F_UNIMPL;
      if (tmnew->flags & TM_F_BW)
            tmnew->flags &= ~TM_F_MESOPIC;
                                    /* set monitor transform */
      if (monpri == NULL || monpri == stdprims || tmnew->flags & TM_F_BW) {
            tmnew->monpri = stdprims;
            tmnew->clf[RED] = rgb2xyzmat[1][0];
            tmnew->clf[GRN] = rgb2xyzmat[1][1];
            tmnew->clf[BLU] = rgb2xyzmat[1][2];
      } else {
            comprgb2xyzmat(cmat, tmnew->monpri=monpri);
            tmnew->clf[RED] = cmat[1][0];
            tmnew->clf[GRN] = cmat[1][1];
            tmnew->clf[BLU] = cmat[1][2];
      }
                                    /* set gamma value */
      if (gamval < MINGAM)
            tmnew->mongam = DEFGAM;
      else
            tmnew->mongam = gamval;
                                    /* set color divisors */
      for (i = 0; i < 3; i++)
            tmnew->cdiv[i] = 256.*pow(tmnew->clf[i], 1./tmnew->mongam);

                                    /* set input transform */
      tmnew->inppri = tmnew->monpri;
      tmnew->cmat[0][0] = tmnew->cmat[1][1] = tmnew->cmat[2][2] =
                  tmnew->inpsf = WHTEFFICACY;
      tmnew->cmat[0][1] = tmnew->cmat[0][2] = tmnew->cmat[1][0] =
      tmnew->cmat[1][2] = tmnew->cmat[2][0] = tmnew->cmat[2][1] = 0.;
      tmnew->inpdat = NULL;
      tmnew->hbrmin = 10; tmnew->hbrmax = -10;
      tmnew->histo = NULL;
      tmnew->mbrmin = 10; tmnew->mbrmax = -10;
      tmnew->lumap = NULL;
                                    /* zero private data */
      for (i = TM_MAXPKG; i--; )
            tmnew->pd[i] = NULL;
      tmnew->lastError = TM_E_OK;
      tmnew->lastFunc = "NoErr";
                                    /* return new TMstruct */
      return(tmnew);
}


int
tmSetSpace(             /* set input color space for conversions */
TMstruct    *tms,
RGBPRIMP    pri,
double      sf,
MEM_PTR     dat
)
{
      static const char funcName[] = "tmSetSpace";
      int   i, j;
                                    /* error check */
      if (tms == NULL)
            returnErr(TM_E_TMINVAL);
      if (sf <= 1e-12)
            returnErr(TM_E_ILLEGAL);
                                    /* check if no change */
      if (pri == tms->inppri && FEQ(sf, tms->inpsf) && dat == tms->inpdat)
            returnOK;
      tms->inppri = pri;                  /* let's set it */
      tms->inpsf = sf;
      tms->inpdat = dat;

      if (tms->flags & TM_F_BW) {         /* color doesn't matter */
            tms->monpri = tms->inppri;          /* eliminate xform */
            if (tms->inppri == TM_XYZPRIM) {
                  tms->clf[CIEX] = tms->clf[CIEZ] = 0.;
                  tms->clf[CIEY] = 1.;
            } else {
                  comprgb2xyzmat(tms->cmat, tms->monpri);
                  tms->clf[RED] = tms->cmat[1][0];
                  tms->clf[GRN] = tms->cmat[1][1];
                  tms->clf[BLU] = tms->cmat[1][2];
            }
            tms->cmat[0][0] = tms->cmat[1][1] = tms->cmat[2][2] =
                        tms->inpsf;
            tms->cmat[0][1] = tms->cmat[0][2] = tms->cmat[1][0] =
            tms->cmat[1][2] = tms->cmat[2][0] = tms->cmat[2][1] = 0.;

      } else if (tms->inppri == TM_XYZPRIM)     /* input is XYZ */
            compxyz2rgbWBmat(tms->cmat, tms->monpri);

      else {                              /* input is RGB */
            if (tms->inppri != tms->monpri &&
                        PRIMEQ(tms->inppri, tms->monpri))
                  tms->inppri = tms->monpri;    /* no xform */
            comprgb2rgbWBmat(tms->cmat, tms->inppri, tms->monpri);
      }
      for (i = 0; i < 3; i++)
            for (j = 0; j < 3; j++)
                  tms->cmat[i][j] *= tms->inpsf;
                                    /* set color divisors */
      for (i = 0; i < 3; i++)
            if (tms->clf[i] > .001)
                  tms->cdiv[i] =
                        256.*pow(tms->clf[i], 1./tms->mongam);
            else
                  tms->cdiv[i] = 1;
                                    /* notify packages */
      for (i = tmNumPkgs; i--; )
            if (tms->pd[i] != NULL && tmPkg[i]->NewSpace != NULL)
                  (*tmPkg[i]->NewSpace)(tms);
      returnOK;
}


void
tmClearHisto(                       /* clear current histogram */
TMstruct    *tms
)
{
      if (tms == NULL || tms->histo == NULL)
            return;
      free((MEM_PTR)tms->histo);
      tms->histo = NULL;
}


TMbright
tmCvLuminance(                      /* convert a single luminance */
double      lum
)
{
      double      d;

#ifdef isfinite
      if (!isfinite(lum) || lum <= TM_NOLUM)
#else
      if (lum <= TM_NOLUM)
#endif
            return(TM_NOBRT);
      d = TM_BRTSCALE*log(lum);
      if (d > 0.)
            return((TMbright)(d+.5));
      return((TMbright)(d-.5));
}


int
tmCvLums(                     /* convert luminances using lookup */
TMbright    *ls,
float       *scan,
int         len
)
{
      if (tmFloat2BrtLUT == NULL) { /* initialize lookup table */
            int32 i;
            tmFloat2BrtLUT = (TMbright *)malloc(sizeof(TMbright)*0x10000);
            if (tmFloat2BrtLUT == NULL)
                  return(TM_E_NOMEM);
            for (i = 0; i < 0x10000; i++) {
                  int32 l = (i<<1 | 1) << 14;
#ifndef isfinite
                  if ((l & 0x7f800000) == 0x7f800000)
                        tmFloat2BrtLUT[i] = TM_NOBRT;
                  else
#endif
                  tmFloat2BrtLUT[i] = tmCvLuminance(*(float *)&l);
            }
      }
      if (len <= 0)
            return(TM_E_OK);
      if ((ls == NULL) | (scan == NULL))
            return(TM_E_ILLEGAL);
      while (len--) {
            if (*scan <= TM_NOLUM) {
                  *ls++ = TM_NOBRT;
                  ++scan;
                  continue;
            }
            *ls++ = tmCvLumLUfp(scan++);
      }
      return(TM_E_OK);
}


int
tmCvGrays(                    /* convert float gray values */
TMstruct    *tms,
TMbright    *ls,
float       *scan,
int         len
)
{
      static const char funcName[] = "tmCvGrays";
      int   i;

      if (tms == NULL)
            returnErr(TM_E_TMINVAL);
      if ((ls == NULL) | (scan == NULL) | (len < 0))
            returnErr(TM_E_ILLEGAL);
      if (tmFloat2BrtLUT == NULL)               /* initialize */
            tmCvLums(NULL, NULL, 0);
      for (i = len; i--; ) {
            float lum = tms->inpsf * scan[i];
            if (lum <= TM_NOLUM)
                  ls[i] = TM_NOBRT;
            else
                  ls[i] = tmCvLumLUfp(&lum);
      }
      returnOK;
}


int
tmCvColors(                   /* convert float colors */
TMstruct    *tms,
TMbright    *ls,
BYTE  *cs,
COLOR *scan,
int   len
)
{
      static const char funcName[] = "tmCvColors";
      static BYTE gamtab[1024];
      static double     curgam = .0;
      COLOR cmon;
      float lum, slum, d;
      int   i;

      if (tms == NULL)
            returnErr(TM_E_TMINVAL);
      if ((ls == NULL) | (scan == NULL) | (len < 0))
            returnErr(TM_E_ILLEGAL);
      if (tmFloat2BrtLUT == NULL)               /* initialize */
            tmCvLums(NULL, NULL, 0);
      if (cs != TM_NOCHROM && fabs(tms->mongam - curgam) > .02) {
            curgam = tms->mongam;               /* (re)build table */
            for (i = 1024; i--; )
                  gamtab[i] = (int)(256.*pow((i+.5)/1024., 1./curgam));
      }
      for (i = len; i--; ) {
            if (tmNeedMatrix(tms)) {            /* get monitor RGB */
                  colortrans(cmon, tms->cmat, scan[i]);
            } else {
                  cmon[RED] = tms->inpsf*scan[i][RED];
                  cmon[GRN] = tms->inpsf*scan[i][GRN];
                  cmon[BLU] = tms->inpsf*scan[i][BLU];
            }
#ifdef isfinite
            if (!isfinite(cmon[RED]) || cmon[RED] < .0f) cmon[RED] = .0f;
            if (!isfinite(cmon[GRN]) || cmon[GRN] < .0f) cmon[GRN] = .0f;
            if (!isfinite(cmon[BLU]) || cmon[BLU] < .0f) cmon[BLU] = .0f;
#else
            if (cmon[RED] < .0f) cmon[RED] = .0f;
            if (cmon[GRN] < .0f) cmon[GRN] = .0f;
            if (cmon[BLU] < .0f) cmon[BLU] = .0f;
#endif
                                          /* world luminance */
            lum = tms->clf[RED]*cmon[RED] +
                  tms->clf[GRN]*cmon[GRN] +
                  tms->clf[BLU]*cmon[BLU] ;
            if (lum <= TM_NOLUM) {              /* convert brightness */
                  lum = cmon[RED] = cmon[GRN] = cmon[BLU] = TM_NOLUM;
                  ls[i] = TM_NOBRT;
            } else
                  ls[i] = tmCvLumLUfp(&lum);
            if (cs == TM_NOCHROM)               /* no color? */
                  continue;
            if (tms->flags & TM_F_MESOPIC && lum < LMESUPPER) {
                  slum = scotlum(cmon);         /* mesopic adj. */
                  if (lum < LMESLOWER) {
                        cmon[RED] = cmon[GRN] = cmon[BLU] = slum;
                  } else {
                        d = (lum - LMESLOWER)/(LMESUPPER - LMESLOWER);
                        if (tms->flags & TM_F_BW)
                              cmon[RED] = cmon[GRN] =
                                          cmon[BLU] = d*lum;
                        else
                              scalecolor(cmon, d);
                        d = (1.f-d)*slum;
                        cmon[RED] += d;
                        cmon[GRN] += d;
                        cmon[BLU] += d;
                  }
            } else if (tms->flags & TM_F_BW) {
                  cmon[RED] = cmon[GRN] = cmon[BLU] = lum;
            }
            d = tms->clf[RED]*cmon[RED]/lum;
            cs[3*i  ] = d>=.999f ? 255 : gamtab[(int)(1024.f*d)];
            d = tms->clf[GRN]*cmon[GRN]/lum;
            cs[3*i+1] = d>=.999f ? 255 : gamtab[(int)(1024.f*d)];
            d = tms->clf[BLU]*cmon[BLU]/lum;
            cs[3*i+2] = d>=.999f ? 255 : gamtab[(int)(1024.f*d)];
      }
      returnOK;
}


int
tmAddHisto(                   /* add values to histogram */
TMstruct    *tms,
TMbright    *ls,
int   len,
int   wt
)
{
      static const char funcName[] = "tmAddHisto";
      int   oldorig=0, oldlen, horig, hlen;
      int   i, j;

      if (tms == NULL)
            returnErr(TM_E_TMINVAL);
      if (len < 0)
            returnErr(TM_E_ILLEGAL);
      if (len == 0)
            returnOK;
                                    /* first, grow limits */
      if (tms->histo == NULL) {
            for (i = len; i-- && ls[i] < MINBRT; )
                  ;
            if (i < 0)
                  returnOK;
            tms->hbrmin = tms->hbrmax = ls[i];
            oldlen = 0;
      } else {
            oldorig = (tms->hbrmin-MINBRT)/HISTEP;
            oldlen = (tms->hbrmax-MINBRT)/HISTEP + 1 - oldorig;
      }
      for (i = len; i--; ) {
            if ((j = ls[i]) < MINBRT)
                  continue;
            if (j < tms->hbrmin)
                  tms->hbrmin = j;
            else if (j > tms->hbrmax)
                  tms->hbrmax = j;
      }
      horig = (tms->hbrmin-MINBRT)/HISTEP;
      hlen = (tms->hbrmax-MINBRT)/HISTEP + 1 - horig;
      if (hlen > oldlen) {                /* (re)allocate histogram */
            int   *newhist = (int *)calloc(hlen, sizeof(int));
            if (newhist == NULL)
                  returnErr(TM_E_NOMEM);
            if (oldlen) {                 /* copy and free old */
                  for (i = oldlen, j = i+oldorig-horig; i; )
                        newhist[--j] = tms->histo[--i];
                  free((MEM_PTR)tms->histo);
            }
            tms->histo = newhist;
      }
      if (wt == 0)
            returnOK;
      for (i = len; i--; )                /* add in new counts */
            if (ls[i] >= MINBRT)
                  tms->histo[ (ls[i]-MINBRT)/HISTEP - horig ] += wt;
      returnOK;
}


static double
htcontrs(         /* human threshold contrast sensitivity, dL(La) */
double      La
)
{
      double      l10La, l10dL;
                        /* formula taken from Ferwerda et al. [SG96] */
      if (La < 1.148e-4)
            return(1.38e-3);
      l10La = log10(La);
      if (l10La < -1.44)            /* rod response regime */
            l10dL = pow(.405*l10La + 1.6, 2.18) - 2.86;
      else if (l10La < -.0184)
            l10dL = l10La - .395;
      else if (l10La < 1.9)         /* cone response regime */
            l10dL = pow(.249*l10La + .65, 2.7) - .72;
      else
            l10dL = l10La - 1.255;

      return(exp10(l10dL));
}


static int
tmNewMap(               /* allocate new tone-mapping array */
TMstruct    *tms
)
{
      if (tms->lumap != NULL && (tms->mbrmax - tms->mbrmin) !=
                              (tms->hbrmax - tms->hbrmin)) {
            free((MEM_PTR)tms->lumap);
            tms->lumap = NULL;
      }
      tms->mbrmin = tms->hbrmin;
      tms->mbrmax = tms->hbrmax;
      if (tms->mbrmin > tms->mbrmax)
            return 0;
      if (tms->lumap == NULL)
            tms->lumap = (unsigned short *)malloc(sizeof(unsigned short)*
                              (tms->mbrmax-tms->mbrmin+1));
      return(tms->lumap != NULL);
}


int
tmFixedMapping(               /* compute fixed, linear tone-mapping */
TMstruct    *tms,
double      expmult,
double      gamval
)
{
      static const char funcName[] = "tmFixedMapping";
      double            d;
      int   i;
      
      if (!tmNewMap(tms))
            returnErr(TM_E_NOMEM);
      if (expmult <= .0)
            expmult = 1.;
      if (gamval < MINGAM)
            gamval = tms->mongam;
      d = log(expmult/tms->inpsf);
      for (i = tms->mbrmax-tms->mbrmin+1; i--; ) {
            double      val = 256. * exp(
                  ( d + (tms->mbrmin+i)*(1./TM_BRTSCALE) )
                  / gamval);
            tms->lumap[i] = val >= (double)0xffff ? 0xffff : (int)val;
      }
      returnOK;
}


int
tmComputeMapping(             /* compute histogram tone-mapping */
TMstruct    *tms,
double      gamval,
double      Lddyn,
double      Ldmax
)
{
      static const char funcName[] = "tmComputeMapping";
      int   *histo;
      float *cumf;
      int   brt0, histlen, threshold, ceiling, trimmings;
      double      logLddyn, Ldmin, Ldavg, Lwavg, Tr, Lw, Ld;
      int32 histot;
      double      sum;
      double      d;
      int   i, j;

      if (tms == NULL || tms->histo == NULL)
            returnErr(TM_E_TMINVAL);
                              /* check arguments */
      if (Lddyn < MINLDDYN) Lddyn = DEFLDDYN;
      if (Ldmax < MINLDMAX) Ldmax = DEFLDMAX;
      if (gamval < MINGAM) gamval = tms->mongam;
                              /* compute handy values */
      Ldmin = Ldmax/Lddyn;
      logLddyn = log(Lddyn);
      Ldavg = sqrt(Ldmax*Ldmin);
      i = (tms->hbrmin-MINBRT)/HISTEP;
      brt0 = MINBRT + HISTEP/2 + i*HISTEP;
      histlen = (tms->hbrmax-MINBRT)/HISTEP + 1 - i;
                              /* histogram total and mean */
      histot = 0; sum = 0;
      j = brt0 + histlen*HISTEP;
      for (i = histlen; i--; ) {
            histot += tms->histo[i];
            sum += (double)(j -= HISTEP) * tms->histo[i];
      }
      threshold = histot*0.005 + .5;
      if (!histot)
            returnErr(TM_E_TMFAIL);
      Lwavg = tmLuminance( (double)sum / histot );
                              /* use linear tone mapping? */
      if (tms->flags & TM_F_LINEAR || threshold < 4 ||
                  tms->hbrmax - tms->hbrmin < TM_BRTSCALE*logLddyn)
            goto linearmap;
                              /* clamp histogram */
      histo = (int *)malloc(histlen*sizeof(int));
      cumf = (float *)malloc((histlen+2)*sizeof(float));
      if ((histo == NULL) | (cumf == NULL))
            returnErr(TM_E_NOMEM);
      cumf[histlen+1] = 1.;         /* guard for assignment code */
      for (i = histlen; i--; )      /* make malleable copy */
            histo[i] = tms->histo[i];
      do {                    /* iterate to solution */
            sum = 0;          /* cumulative probability */
            for (i = 0; i < histlen; i++) {
                  cumf[i] = (double)sum/histot;
                  sum += histo[i];
            }
            cumf[histlen] = 1.;
            Tr = histot * (double)(tms->hbrmax - tms->hbrmin) /
                  ((double)histlen*TM_BRTSCALE) / logLddyn;
            ceiling = Tr + 1.;
            trimmings = 0;          /* clip to envelope */
            for (i = histlen; i--; ) {
                  if (tms->flags & TM_F_HCONTR) {
                        Lw = tmLuminance(brt0 + i*HISTEP);
                        Ld = Ldmin * exp( logLddyn *
                              .5*(cumf[i]+cumf[i+1]) );
                        ceiling = Tr * (htcontrs(Ld) * Lw) /
                              (htcontrs(Lw) * Ld) + 1.;
                  }
                  if (histo[i] > ceiling) {
                        trimmings += histo[i] - ceiling;
                        histo[i] = ceiling;
                  }
            }
                              /* check if we're out of data */
            if ((histot -= trimmings) <= threshold) {
                  free((MEM_PTR)histo);
                  free((MEM_PTR)cumf);
                  goto linearmap;
            }
      } while (trimmings > threshold);
                              /* allocate space for mapping */
      if (!tmNewMap(tms))
            returnErr(TM_E_NOMEM);
                              /* assign tone-mapping */
      for (i = tms->mbrmax-tms->mbrmin+1; i--; ) {
            j = d = (double)i/(tms->mbrmax-tms->mbrmin)*histlen;
            d -= (double)j;
            Ld = Ldmin*exp(logLddyn*((1.-d)*cumf[j]+d*cumf[j+1]));
            d = (Ld - Ldmin)/(Ldmax - Ldmin);
            tms->lumap[i] = 256.*pow(d, 1./gamval);
      }
      free((MEM_PTR)histo);         /* clean up and return */
      free((MEM_PTR)cumf);
      returnOK;
linearmap:                    /* linear tone-mapping */
      if (tms->flags & TM_F_HCONTR)
            d = htcontrs(Ldavg) / htcontrs(Lwavg);
      else
            d = Ldavg / Lwavg;
      return(tmFixedMapping(tms, tms->inpsf*d/Ldmax, gamval));
}


int
tmMapPixels(                  /* apply tone-mapping to pixel(s) */
TMstruct    *tms,
BYTE  *ps,
TMbright    *ls,
BYTE  *cs,
int   len
)
{
      static const char funcName[] = "tmMapPixels";
      int32 li, pv;

      if (tms == NULL || tms->lumap == NULL)
            returnErr(TM_E_TMINVAL);
      if ((ps == NULL) | (ls == NULL) | (len < 0))
            returnErr(TM_E_ILLEGAL);
      while (len--) {
            if ((li = *ls++) < tms->mbrmin) {
                  li = 0;
            } else {
                  if (li > tms->mbrmax)
                        li = tms->mbrmax;
                  li = tms->lumap[li - tms->mbrmin];
            }
            if (cs == TM_NOCHROM)
                  *ps++ = li>255 ? 255 : li;
            else {
                  pv = *cs++ * li / tms->cdiv[RED];
                  *ps++ = pv>255 ? 255 : pv;
                  pv = *cs++ * li / tms->cdiv[GRN];
                  *ps++ = pv>255 ? 255 : pv;
                  pv = *cs++ * li / tms->cdiv[BLU];
                  *ps++ = pv>255 ? 255 : pv;
            }
      }
      returnOK;
}




TMstruct *
tmDup(                        /* duplicate top tone mapping */
TMstruct    *tms
)
{
      int   len;
      int   i;
      TMstruct    *tmnew;

      if (tms == NULL)        /* anything to duplicate? */
            return(NULL);
      tmnew = (TMstruct *)malloc(sizeof(TMstruct));
      if (tmnew == NULL)
            return(NULL);
      *tmnew = *tms;          /* copy everything */
      if (tmnew->histo != NULL) {   /* duplicate histogram */
            len = (tmnew->hbrmax-MINBRT)/HISTEP + 1 -
                        (tmnew->hbrmin-MINBRT)/HISTEP;
            tmnew->histo = (int *)malloc(len*sizeof(int));
            if (tmnew->histo != NULL)
                  for (i = len; i--; )
                        tmnew->histo[i] = tms->histo[i];
      }
      if (tmnew->lumap != NULL) {   /* duplicate luminance mapping */
            len = tmnew->mbrmax-tmnew->mbrmin+1;
            tmnew->lumap = (unsigned short *)malloc(
                                    len*sizeof(unsigned short) );
            if (tmnew->lumap != NULL)
                  for (i = len; i--; )
                        tmnew->lumap[i] = tms->lumap[i];
      }
                              /* clear package data */
      for (i = tmNumPkgs; i--; )
            tmnew->pd[i] = NULL;
                              /* return copy */
      return(tmnew);
}


void
tmDone(tms)             /* done with tone mapping -- destroy it */
TMstruct    *tms;
{
      int   i;
                              /* NULL arg. is equiv. to tms */
      if (tms == NULL)
            return;
                              /* free tables */
      if (tms->histo != NULL)
            free((MEM_PTR)tms->histo);
      if (tms->lumap != NULL)
            free((MEM_PTR)tms->lumap);
                              /* free private data */
      for (i = tmNumPkgs; i--; )
            if (tms->pd[i] != NULL)
                  (*tmPkg[i]->Free)(tms->pd[i]);
      free((MEM_PTR)tms);           /* free basic structure */
}

/******************** Shared but Private library routines *********************/

BYTE  tmMesofact[BMESUPPER-BMESLOWER];

void
tmMkMesofact()                      /* build mesopic lookup factor table */
{
      int   i;

      if (tmMesofact[BMESUPPER-BMESLOWER-1])
            return;

      for (i = BMESLOWER; i < BMESUPPER; i++)
            tmMesofact[i-BMESLOWER] = 256. *
                        (tmLuminance(i) - LMESLOWER) /
                        (LMESUPPER - LMESLOWER);
}


int
tmErrorReturn(                      /* error return (with message) */
const char  *func,
TMstruct    *tms,
int   err
)
{
      if (tms != NULL) {
            tms->lastFunc = func;
            tms->lastError = err;
            if (tms->flags & TM_F_NOSTDERR)
                  return(err);
      }
      fputs(func, stderr);
      fputs(": ", stderr);
      fputs(tmErrorMessage[err], stderr);
      fputs("!\n", stderr);
      return(err);
}

Generated by  Doxygen 1.6.0   Back to index