ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/tonemap.c
(Generate patch)

Comparing ray/src/common/tonemap.c (file contents):
Revision 3.3 by greg, Wed Apr 16 20:28:03 1997 UTC vs.
Revision 3.9 by greg, Sat Feb 22 02:07:22 2003 UTC

# Line 1 | Line 1
1 /* Copyright (c) 1997 Regents of the University of California */
2
1   #ifndef lint
2 < static char SCCSid[] = "$SunId$ LBL";
2 > static const char       RCSid[] = "$Id$";
3   #endif
6
4   /*
5   * Tone mapping functions.
6   * See tonemap.h for detailed function descriptions.
7 + * Added von Kries white-balance calculations 10/01 (GW).
8 + *
9 + * Externals declared in tonemap.h
10   */
11  
12 + /* ====================================================================
13 + * The Radiance Software License, Version 1.0
14 + *
15 + * Copyright (c) 1990 - 2002 The Regents of the University of California,
16 + * through Lawrence Berkeley National Laboratory.   All rights reserved.
17 + *
18 + * Redistribution and use in source and binary forms, with or without
19 + * modification, are permitted provided that the following conditions
20 + * are met:
21 + *
22 + * 1. Redistributions of source code must retain the above copyright
23 + *         notice, this list of conditions and the following disclaimer.
24 + *
25 + * 2. Redistributions in binary form must reproduce the above copyright
26 + *       notice, this list of conditions and the following disclaimer in
27 + *       the documentation and/or other materials provided with the
28 + *       distribution.
29 + *
30 + * 3. The end-user documentation included with the redistribution,
31 + *           if any, must include the following acknowledgment:
32 + *             "This product includes Radiance software
33 + *                 (http://radsite.lbl.gov/)
34 + *                 developed by the Lawrence Berkeley National Laboratory
35 + *               (http://www.lbl.gov/)."
36 + *       Alternately, this acknowledgment may appear in the software itself,
37 + *       if and wherever such third-party acknowledgments normally appear.
38 + *
39 + * 4. The names "Radiance," "Lawrence Berkeley National Laboratory"
40 + *       and "The Regents of the University of California" must
41 + *       not be used to endorse or promote products derived from this
42 + *       software without prior written permission. For written
43 + *       permission, please contact [email protected].
44 + *
45 + * 5. Products derived from this software may not be called "Radiance",
46 + *       nor may "Radiance" appear in their name, without prior written
47 + *       permission of Lawrence Berkeley National Laboratory.
48 + *
49 + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
50 + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
51 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
52 + * DISCLAIMED.   IN NO EVENT SHALL Lawrence Berkeley National Laboratory OR
53 + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
54 + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
55 + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
56 + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
57 + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
58 + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
59 + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60 + * SUCH DAMAGE.
61 + * ====================================================================
62 + *
63 + * This software consists of voluntary contributions made by many
64 + * individuals on behalf of Lawrence Berkeley National Laboratory.   For more
65 + * information on Lawrence Berkeley National Laboratory, please see
66 + * <http://www.lbl.gov/>.
67 + */
68 +
69   #include        <stdio.h>
70   #include        <math.h>
71   #include        "tmprivat.h"
# Line 18 | Line 75 | static char SCCSid[] = "$SunId$ LBL";
75  
76   struct tmStruct *tmTop = NULL;          /* current tone mapping stack */
77  
78 +                                        /* our list of conversion packages */
79 + struct tmPackage        *tmPkg[TM_MAXPKG];
80 + int     tmNumPkgs = 0;                  /* number of registered packages */
81  
82 < int
83 < tmErrorReturn(func, err)                /* error return (with message) */
24 < char    *func;
25 < int     err;
26 < {
27 <        if (tmTop != NULL && tmTop->flags & TM_F_NOSTDERR)
28 <                return(err);
29 <        fputs(func, stderr);
30 <        fputs(": ", stderr);
31 <        fputs(tmErrorMessage[err], stderr);
32 <        fputs("!\n", stderr);
33 <        return(err);
34 < }
82 > int     tmLastError;                    /* last error incurred by library */
83 > char    *tmLastFunction;                /* error-generating function name */
84  
85  
86   struct tmStruct *
# Line 40 | Line 89 | int    flags;
89   RGBPRIMP        monpri;
90   double  gamval;
91   {
43        static char     funcName[] = "tmInit";
92          COLORMAT        cmat;
93          register struct tmStruct        *tmnew;
94          register int    i;
# Line 57 | Line 105 | double gamval;
105                  tmnew->clf[GRN] = rgb2xyzmat[1][1];
106                  tmnew->clf[BLU] = rgb2xyzmat[1][2];
107          } else {
108 <                comprgb2xyzmat(cmat, tmnew->monpri=monpri);
108 >                comprgb2xyzWBmat(cmat, tmnew->monpri=monpri);
109                  tmnew->clf[RED] = cmat[1][0];
110                  tmnew->clf[GRN] = cmat[1][1];
111                  tmnew->clf[BLU] = cmat[1][2];
112          }
65        tmnew->clfb[RED] = 256.*tmnew->clf[RED] + .5;
66        tmnew->clfb[GRN] = 256.*tmnew->clf[GRN] + .5;
67        tmnew->clfb[BLU] = 256.*tmnew->clf[BLU] + .5;
68        tmnew->clfb[EXP] = COLXS;
113                                                  /* set gamma value */
114          if (gamval < MINGAM)
115                  tmnew->mongam = DEFGAM;
116          else
117                  tmnew->mongam = gamval;
118 <        for (i = TM_GAMTSZ; i--; )
119 <                tmnew->gamb[i] = 256.*pow((i+.5)/TM_GAMTSZ, 1./tmnew->mongam);
118 >                                                /* set color divisors */
119 >        for (i = 0; i < 3; i++)
120 >                tmnew->cdiv[i] = 256.*pow(tmnew->clf[i], 1./tmnew->mongam);
121 >
122                                                  /* set input transform */
123          tmnew->inppri = tmnew->monpri;
124          tmnew->cmat[0][0] = tmnew->cmat[1][1] = tmnew->cmat[2][2] =
125                          tmnew->inpsf = WHTEFFICACY;
80        tmnew->inpsfb = TM_BRTSCALE*log(tmnew->inpsf) + .5;
126          tmnew->cmat[0][1] = tmnew->cmat[0][2] = tmnew->cmat[1][0] =
127          tmnew->cmat[1][2] = tmnew->cmat[2][0] = tmnew->cmat[2][1] = 0.;
128 <        tmnew->flags &= ~TM_F_NEEDMAT;
84 <        tmnew->brmin = tmnew->brmax = 0;
128 >        tmnew->hbrmin = 10; tmnew->hbrmax = -10;
129          tmnew->histo = NULL;
130 +        tmnew->mbrmin = 10; tmnew->mbrmax = -10;
131          tmnew->lumap = NULL;
132 <        tmnew->tmprev = NULL;
133 <
134 <        tmnew->flags |= TM_F_INITED;
135 <                                                /* make it current */
132 >                                                /* zero private data */
133 >        for (i = TM_MAXPKG; i--; )
134 >                tmnew->pd[i] = NULL;
135 >                                                /* make tmnew current */
136          tmnew->tmprev = tmTop;
137          return(tmTop = tmnew);
138   }
# Line 110 | Line 155 | double sf;
155                  returnOK;
156          tmTop->inppri = pri;                    /* let's set it */
157          tmTop->inpsf = sf;
113        tmTop->inpsfb = TM_BRTSCALE*log(sf) + (sf>=1. ? .5 : -.5);
158  
159          if (tmTop->flags & TM_F_BW) {           /* color doesn't matter */
160                  tmTop->monpri = tmTop->inppri;          /* eliminate xform */
161                  if (tmTop->inppri == TM_XYZPRIM) {
162                          tmTop->clf[CIEX] = tmTop->clf[CIEZ] = 0.;
163                          tmTop->clf[CIEY] = 1.;
120                        tmTop->clfb[CIEX] = tmTop->clfb[CIEZ] = 0;
121                        tmTop->clfb[CIEY] = 255;
164                  } else {
165 <                        comprgb2xyzmat(tmTop->cmat, tmTop->monpri);
165 >                        comprgb2xyzWBmat(tmTop->cmat, tmTop->monpri);
166                          tmTop->clf[RED] = tmTop->cmat[1][0];
167                          tmTop->clf[GRN] = tmTop->cmat[1][1];
168                          tmTop->clf[BLU] = tmTop->cmat[1][2];
# Line 131 | Line 173 | double sf;
173                  tmTop->cmat[1][2] = tmTop->cmat[2][0] = tmTop->cmat[2][1] = 0.;
174  
175          } else if (tmTop->inppri == TM_XYZPRIM) /* input is XYZ */
176 <                compxyz2rgbmat(tmTop->cmat, tmTop->monpri);
176 >                compxyz2rgbWBmat(tmTop->cmat, tmTop->monpri);
177  
178          else {                                  /* input is RGB */
179                  if (tmTop->inppri != tmTop->monpri &&
180                                  PRIMEQ(tmTop->inppri, tmTop->monpri))
181                          tmTop->inppri = tmTop->monpri;  /* no xform */
182 <                comprgb2rgbmat(tmTop->cmat, tmTop->inppri, tmTop->monpri);
182 >                comprgb2rgbWBmat(tmTop->cmat, tmTop->inppri, tmTop->monpri);
183          }
184          for (i = 0; i < 3; i++)
185                  for (j = 0; j < 3; j++)
186                          tmTop->cmat[i][j] *= tmTop->inpsf;
187 <        if (tmTop->inppri != tmTop->monpri)
188 <                tmTop->flags |= TM_F_NEEDMAT;
189 <        else
190 <                tmTop->flags &= ~TM_F_NEEDMAT;
187 >                                                /* set color divisors */
188 >        for (i = 0; i < 3; i++)
189 >                if (tmTop->clf[i] > .001)
190 >                        tmTop->cdiv[i] =
191 >                                256.*pow(tmTop->clf[i], 1./tmTop->mongam);
192 >                else
193 >                        tmTop->cdiv[i] = 1;
194 >                                                /* notify packages */
195 >        for (i = tmNumPkgs; i--; )
196 >                if (tmTop->pd[i] != NULL && tmPkg[i]->NewSpace != NULL)
197 >                        (*tmPkg[i]->NewSpace)(tmTop);
198          returnOK;
199   }
200  
# Line 155 | Line 204 | tmClearHisto()                 /* clear current histogram */
204   {
205          if (tmTop == NULL || tmTop->histo == NULL)
206                  return;
207 <        free((char *)tmTop->histo);
207 >        free((MEM_PTR)tmTop->histo);
208          tmTop->histo = NULL;
209   }
210  
# Line 168 | Line 217 | COLOR  *scan;
217   int     len;
218   {
219          static char     funcName[] = "tmCvColors";
220 +        static COLOR    csmall = {1e-6, 1e-6, 1e-6};
221          COLOR   cmon;
222          double  lum, slum;
223          register double d;
# Line 175 | Line 225 | int    len;
225  
226          if (tmTop == NULL)
227                  returnErr(TM_E_TMINVAL);
228 <        if (ls == NULL | scan == NULL | len <= 0)
228 >        if (ls == NULL | scan == NULL | len < 0)
229                  returnErr(TM_E_ILLEGAL);
230          for (i = len; i--; ) {
231 <                if (tmTop->flags & TM_F_NEEDMAT)        /* get monitor RGB */
231 >                if (tmNeedMatrix(tmTop))                /* get monitor RGB */
232                          colortrans(cmon, tmTop->cmat, scan[i]);
233                  else {
234                          cmon[RED] = tmTop->inpsf*scan[i][RED];
# Line 190 | Line 240 | int    len;
240                          tmTop->clf[GRN]*cmon[GRN] +
241                          tmTop->clf[BLU]*cmon[BLU] ;
242                                                          /* check range */
243 <                if (clipgamut(cmon, lum, CGAMUT_LOWER, cblack, cwhite))
243 >                if (clipgamut(cmon, lum, CGAMUT_LOWER, csmall, cwhite))
244                          lum =   tmTop->clf[RED]*cmon[RED] +
245                                  tmTop->clf[GRN]*cmon[GRN] +
246                                  tmTop->clf[BLU]*cmon[BLU] ;
# Line 223 | Line 273 | int    len;
273                          cmon[RED] = cmon[GRN] = cmon[BLU] = lum;
274                  }
275                  d = tmTop->clf[RED]*cmon[RED]/lum;
276 <                /* cs[3*i  ] = d>.999 ? 255 : 256.*pow(d, 1./tmTop->mongam); */
277 <                cs[3*i  ] = d>.999 ? 255 : tmTop->gamb[(int)(d*TM_GAMTSZ)];
276 >                cs[3*i  ] = d>=.999 ? 255 :
277 >                                (int)(256.*pow(d, 1./tmTop->mongam));
278                  d = tmTop->clf[GRN]*cmon[GRN]/lum;
279 <                /* cs[3*i+1] = d>.999 ? 255 : 256.*pow(d, 1./tmTop->mongam); */
280 <                cs[3*i+1] = d>.999 ? 255 : tmTop->gamb[(int)(d*TM_GAMTSZ)];
279 >                cs[3*i+1] = d>=.999 ? 255 :
280 >                                (int)(256.*pow(d, 1./tmTop->mongam));
281                  d = tmTop->clf[BLU]*cmon[BLU]/lum;
282 <                /* cs[3*i+2] = d>.999 ? 255 : 256.*pow(d, 1./tmTop->mongam); */
283 <                cs[3*i+2] = d>.999 ? 255 : tmTop->gamb[(int)(d*TM_GAMTSZ)];
282 >                cs[3*i+2] = d>=.999 ? 255 :
283 >                                (int)(256.*pow(d, 1./tmTop->mongam));
284          }
285          returnOK;
286   }
287  
288  
289   int
290 + tmCvGrays(ls, scan, len)                /* convert float gray values */
291 + TMbright        *ls;
292 + float   *scan;
293 + int     len;
294 + {
295 +        static char     funcName[] = "tmCvGrays";
296 +        register double d;
297 +        register int    i;
298 +
299 +        if (tmTop == NULL)
300 +                returnErr(TM_E_TMINVAL);
301 +        if (ls == NULL | scan == NULL | len < 0)
302 +                returnErr(TM_E_ILLEGAL);
303 +        for (i = len; i--; )
304 +                if (scan[i] <= TM_NOLUM) {
305 +                        ls[i] = TM_NOBRT;               /* bogus value */
306 +                } else {
307 +                        d = TM_BRTSCALE*log(scan[i]);   /* encode it */
308 +                        ls[i] = d>0. ? (int)(d+.5) : (int)(d-.5);
309 +                }
310 +        returnOK;
311 + }
312 +
313 +
314 + int
315   tmAddHisto(ls, len, wt)                 /* add values to histogram */
316   register TMbright       *ls;
317   int     len;
318   int     wt;
319   {
320          static char     funcName[] = "tmAddHisto";
321 <        int     sum, oldorig, oldlen, horig, hlen;
321 >        int     oldorig=0, oldlen, horig, hlen;
322          register int    i, j;
323  
249        if (len <= 0)
250                returnErr(TM_E_ILLEGAL);
324          if (tmTop == NULL)
325                  returnErr(TM_E_TMINVAL);
326 +        if (len < 0)
327 +                returnErr(TM_E_ILLEGAL);
328 +        if (len == 0)
329 +                returnOK;
330                                                  /* first, grow limits */
331          if (tmTop->histo == NULL) {
332                  for (i = len; i-- && ls[i] < MINBRT; )
333                          ;
334                  if (i < 0)
335                          returnOK;
336 <                tmTop->brmin = tmTop->brmax = ls[i];
336 >                tmTop->hbrmin = tmTop->hbrmax = ls[i];
337                  oldlen = 0;
338          } else {
339 <                oldorig = (tmTop->brmin-MINBRT)/HISTEP;
340 <                oldlen = (tmTop->brmax-MINBRT)/HISTEP + 1 - oldorig;
339 >                oldorig = (tmTop->hbrmin-MINBRT)/HISTEP;
340 >                oldlen = (tmTop->hbrmax-MINBRT)/HISTEP + 1 - oldorig;
341          }
342          for (i = len; i--; ) {
343                  if ((j = ls[i]) < MINBRT)
344                          continue;
345 <                if (j < tmTop->brmin)
346 <                        tmTop->brmin = j;
347 <                else if (j > tmTop->brmax)
348 <                        tmTop->brmax = j;
345 >                if (j < tmTop->hbrmin)
346 >                        tmTop->hbrmin = j;
347 >                else if (j > tmTop->hbrmax)
348 >                        tmTop->hbrmax = j;
349          }
350 <        horig = (tmTop->brmin-MINBRT)/HISTEP;
351 <        hlen = (tmTop->brmax-MINBRT)/HISTEP + 1 - horig;
350 >        horig = (tmTop->hbrmin-MINBRT)/HISTEP;
351 >        hlen = (tmTop->hbrmax-MINBRT)/HISTEP + 1 - horig;
352          if (hlen > oldlen) {                    /* (re)allocate histogram */
353                  register int    *newhist = (int *)calloc(hlen, sizeof(int));
354                  if (newhist == NULL)
# Line 279 | Line 356 | int    wt;
356                  if (oldlen) {                   /* copy and free old */
357                          for (i = oldlen, j = i+oldorig-horig; i; )
358                                  newhist[--j] = tmTop->histo[--i];
359 <                        free((char *)tmTop->histo);
359 >                        free((MEM_PTR)tmTop->histo);
360                  }
361                  tmTop->histo = newhist;
285                if (tmTop->lumap != NULL) {     /* invalid tone map */
286                        free((char *)tmTop->lumap);
287                        tmTop->lumap = NULL;
288                }
362          }
363          if (wt == 0)
364                  returnOK;
# Line 318 | Line 391 | double La;
391   }
392  
393  
394 + static int
395 + tmNewMap()
396 + {
397 +        if (tmTop->lumap != NULL && (tmTop->mbrmax - tmTop->mbrmin) !=
398 +                                        (tmTop->hbrmax - tmTop->hbrmin)) {
399 +                free((MEM_PTR)tmTop->lumap);
400 +                tmTop->lumap = NULL;
401 +        }
402 +        tmTop->mbrmin = tmTop->hbrmin;
403 +        tmTop->mbrmax = tmTop->hbrmax;
404 +        if (tmTop->mbrmin > tmTop->mbrmax)
405 +                return 0;
406 +        if (tmTop->lumap == NULL)
407 +                tmTop->lumap = (unsigned short *)malloc(sizeof(unsigned short)*
408 +                                        (tmTop->mbrmax-tmTop->mbrmin+1));
409 +        return(tmTop->lumap != NULL);
410 + }
411 +
412 +
413   int
414 + tmFixedMapping(expmult, gamval)
415 + double  expmult;
416 + double  gamval;
417 + {
418 +        static char     funcName[] = "tmFixedMapping";
419 +        double          d;
420 +        register int    i;
421 +        
422 +        if (!tmNewMap())
423 +                returnErr(TM_E_NOMEM);
424 +        if (expmult <= .0)
425 +                expmult = 1.;
426 +        if (gamval < MINGAM)
427 +                gamval = tmTop->mongam;
428 +        d = log(expmult/tmTop->inpsf);
429 +        for (i = tmTop->mbrmax-tmTop->mbrmin+1; i--; )
430 +                tmTop->lumap[i] = 256. * exp(
431 +                        ( d + (tmTop->mbrmin+i)*(1./TM_BRTSCALE) )
432 +                        / gamval );
433 +        returnOK;
434 + }
435 +
436 +
437 + int
438   tmComputeMapping(gamval, Lddyn, Ldmax)
439   double  gamval;
440   double  Lddyn;
# Line 327 | Line 443 | double Ldmax;
443          static char     funcName[] = "tmComputeMapping";
444          int     *histo;
445          float   *cumf;
446 <        int     brt0, histlen, histot, threshold, ceiling, trimmings;
446 >        int     brt0, histlen, threshold, ceiling, trimmings;
447          double  logLddyn, Ldmin, Ldavg, Lwavg, Tr, Lw, Ld;
448 <        int4    sum;
448 >        int4    histot;
449 >        double  sum;
450          register double d;
451          register int    i, j;
452  
# Line 343 | Line 460 | double Ldmax;
460          Ldmin = Ldmax/Lddyn;
461          logLddyn = log(Lddyn);
462          Ldavg = sqrt(Ldmax*Ldmin);
463 <        i = (tmTop->brmin-MINBRT)/HISTEP;
463 >        i = (tmTop->hbrmin-MINBRT)/HISTEP;
464          brt0 = MINBRT + HISTEP/2 + i*HISTEP;
465 <        histlen = (tmTop->brmax-MINBRT)/HISTEP + 1 - i;
465 >        histlen = (tmTop->hbrmax-MINBRT)/HISTEP + 1 - i;
466                                          /* histogram total and mean */
467          histot = 0; sum = 0;
468          j = brt0 + histlen*HISTEP;
# Line 357 | Line 474 | double Ldmax;
474          if (threshold < 4)
475                  returnErr(TM_E_TMFAIL);
476          Lwavg = tmLuminance( (double)sum / histot );
477 <        if (!(tmTop->flags & TM_F_LINEAR)) {    /* clamp histogram */
478 <                histo = (int *)malloc(histlen*sizeof(int));
479 <                cumf = (float *)malloc((histlen+1)*sizeof(float));
480 <                if (histo == NULL | cumf == NULL)
481 <                        returnErr(TM_E_NOMEM);
482 <                for (i = histlen; i--; )        /* make malleable copy */
483 <                        histo[i] = tmTop->histo[i];
484 <                do {                            /* iterate to solution */
485 <                        sum = 0;                /* cumulative probability */
486 <                        for (i = 0; i < histlen; i++) {
487 <                                cumf[i] = (double)sum/histot;
488 <                                sum += histo[i];
477 >                                        /* allocate space for mapping */
478 >        if (!tmNewMap())
479 >                returnErr(TM_E_NOMEM);
480 >                                        /* use linear tone mapping? */
481 >        if (tmTop->flags & TM_F_LINEAR)
482 >                goto linearmap;
483 >                                        /* clamp histogram */
484 >        histo = (int *)malloc(histlen*sizeof(int));
485 >        cumf = (float *)malloc((histlen+2)*sizeof(float));
486 >        if (histo == NULL | cumf == NULL)
487 >                returnErr(TM_E_NOMEM);
488 >        cumf[histlen+1] = 1.;           /* guard for assignment code */
489 >        for (i = histlen; i--; )        /* make malleable copy */
490 >                histo[i] = tmTop->histo[i];
491 >        do {                            /* iterate to solution */
492 >                sum = 0;                /* cumulative probability */
493 >                for (i = 0; i < histlen; i++) {
494 >                        cumf[i] = (double)sum/histot;
495 >                        sum += histo[i];
496 >                }
497 >                cumf[histlen] = 1.;
498 >                Tr = histot * (double)(tmTop->hbrmax - tmTop->hbrmin) /
499 >                        ((double)histlen*TM_BRTSCALE) / logLddyn;
500 >                ceiling = Tr + 1.;
501 >                trimmings = 0;          /* clip to envelope */
502 >                for (i = histlen; i--; ) {
503 >                        if (tmTop->flags & TM_F_HCONTR) {
504 >                                Lw = tmLuminance(brt0 + i*HISTEP);
505 >                                Ld = Ldmin * exp( logLddyn *
506 >                                        .5*(cumf[i]+cumf[i+1]) );
507 >                                ceiling = Tr * (htcontrs(Ld) * Lw) /
508 >                                        (htcontrs(Lw) * Ld) + 1.;
509                          }
510 <                        cumf[i] = 1.;
511 <                        Tr = histot * (double)(tmTop->brmax - tmTop->brmin) /
512 <                                ((double)histlen*TM_BRTSCALE) / logLddyn;
376 <                        ceiling = Tr + 1.;
377 <                        trimmings = 0;                  /* clip to envelope */
378 <                        for (i = histlen; i--; ) {
379 <                                if (tmTop->flags & TM_F_HCONTR) {
380 <                                        Lw = tmLuminance(brt0 + i*HISTEP);
381 <                                        Ld = Ldmin * exp( logLddyn *
382 <                                                .5*(cumf[i]+cumf[i+1]) );
383 <                                        ceiling = Tr * (htcontrs(Ld) * Lw) /
384 <                                                (htcontrs(Lw) * Ld) + 1.;
385 <                                }
386 <                                if (histo[i] > ceiling) {
387 <                                        trimmings += histo[i] - ceiling;
388 <                                        histo[i] = ceiling;
389 <                                }
510 >                        if (histo[i] > ceiling) {
511 >                                trimmings += histo[i] - ceiling;
512 >                                histo[i] = ceiling;
513                          }
391                } while ((histot -= trimmings) > threshold &&
392                                                trimmings > threshold);
393        }
394                                                /* allocate luminance map */
395        if (tmTop->lumap == NULL) {
396                tmTop->lumap = (unsigned short *)malloc(
397                        (tmTop->brmax-tmTop->brmin+1)*sizeof(unsigned short) );
398                if (tmTop->lumap == NULL)
399                        returnErr(TM_E_NOMEM);
400        }
401        if (tmTop->flags & TM_F_LINEAR || histot <= threshold) {
402                                                /* linear tone mapping */
403                if (tmTop->flags & TM_F_HCONTR)
404                        d = htcontrs(Ldavg) / htcontrs(Lwavg);
405                else
406                        d = Ldavg / Lwavg;
407                d = log(d/Ldmax);
408                for (i = tmTop->brmax-tmTop->brmin+1; i--; )
409                        tmTop->lumap[i] = 256. * exp(
410                                ( d + (tmTop->brmin+i)/(double)TM_BRTSCALE )
411                                / gamval );
412        } else {
413                                                /* histogram adjustment */
414                for (i = tmTop->brmax-tmTop->brmin+1; i--; ) {
415                        j = d = (double)i/(tmTop->brmax-tmTop->brmin)*histlen;
416                        d -= (double)j;
417                        Ld = Ldmin*exp(logLddyn*((1.-d)*cumf[j]+d*cumf[j+1]));
418                        d = (Ld - Ldmin)/(Ldmax - Ldmin);
419                        tmTop->lumap[i] = 256.*pow(d, 1./gamval);
514                  }
515 +                                        /* check if we're out of data */
516 +                if ((histot -= trimmings) <= threshold) {
517 +                        free((MEM_PTR)histo);
518 +                        free((MEM_PTR)cumf);
519 +                        goto linearmap;
520 +                }
521 +        } while (trimmings > threshold);
522 +                                        /* assign tone-mapping */
523 +        for (i = tmTop->mbrmax-tmTop->mbrmin+1; i--; ) {
524 +                j = d = (double)i/(tmTop->mbrmax-tmTop->mbrmin)*histlen;
525 +                d -= (double)j;
526 +                Ld = Ldmin*exp(logLddyn*((1.-d)*cumf[j]+d*cumf[j+1]));
527 +                d = (Ld - Ldmin)/(Ldmax - Ldmin);
528 +                tmTop->lumap[i] = 256.*pow(d, 1./gamval);
529          }
530 <        if (!(tmTop->flags & TM_F_LINEAR)) {
531 <                free((char *)histo);
424 <                free((char *)cumf);
425 <        }
530 >        free((MEM_PTR)histo);           /* clean up and return */
531 >        free((MEM_PTR)cumf);
532          returnOK;
533 + linearmap:                              /* linear tone-mapping */
534 +        if (tmTop->flags & TM_F_HCONTR)
535 +                d = htcontrs(Ldavg) / htcontrs(Lwavg);
536 +        else
537 +                d = Ldavg / Lwavg;
538 +        return(tmFixedMapping(tmTop->inpsf*d/Ldmax, gamval));
539   }
540  
541  
# Line 435 | Line 547 | register BYTE  *cs;
547   int     len;
548   {
549          static char     funcName[] = "tmMapPixels";
550 <        int     rdiv, gdiv, bdiv;
439 <        register int    li, pv;
550 >        register int4   li, pv;
551  
552          if (tmTop == NULL || tmTop->lumap == NULL)
553                  returnErr(TM_E_TMINVAL);
554 <        if (ps == NULL | ls == NULL | len <= 0)
554 >        if (ps == NULL | ls == NULL | len < 0)
555                  returnErr(TM_E_ILLEGAL);
445        rdiv = tmTop->gamb[((int4)TM_GAMTSZ*tmTop->clfb[RED])>>8];
446        gdiv = tmTop->gamb[((int4)TM_GAMTSZ*tmTop->clfb[GRN])>>8];
447        bdiv = tmTop->gamb[((int4)TM_GAMTSZ*tmTop->clfb[BLU])>>8];
556          while (len--) {
557 <                if ((li = *ls++) < tmTop->brmin)
558 <                        li = tmTop->brmin;
559 <                else if (li > tmTop->brmax)
560 <                        li = tmTop->brmax;
561 <                li = tmTop->lumap[li - tmTop->brmin];
557 >                if ((li = *ls++) < tmTop->mbrmin) {
558 >                        li = 0;
559 >                } else {
560 >                        if (li > tmTop->mbrmax)
561 >                                li = tmTop->mbrmax;
562 >                        li = tmTop->lumap[li - tmTop->mbrmin];
563 >                }
564                  if (cs == TM_NOCHROM)
565                          *ps++ = li>255 ? 255 : li;
566                  else {
567 <                        pv = *cs++ * li / rdiv;
567 >                        pv = *cs++ * li / tmTop->cdiv[RED];
568                          *ps++ = pv>255 ? 255 : pv;
569 <                        pv = *cs++ * li / gdiv;
569 >                        pv = *cs++ * li / tmTop->cdiv[GRN];
570                          *ps++ = pv>255 ? 255 : pv;
571 <                        pv = *cs++ * li / bdiv;
571 >                        pv = *cs++ * li / tmTop->cdiv[BLU];
572                          *ps++ = pv>255 ? 255 : pv;
573                  }
574          }
# Line 514 | Line 624 | tmDup()                                /* duplicate top tone mapping */
624                  return(NULL);
625          *tmnew = *tmTop;                /* copy everything */
626          if (tmnew->histo != NULL) {     /* duplicate histogram */
627 <                len = (tmnew->brmax-MINBRT)/HISTEP + 1 -
628 <                                (tmnew->brmin-MINBRT)/HISTEP;
627 >                len = (tmnew->hbrmax-MINBRT)/HISTEP + 1 -
628 >                                (tmnew->hbrmin-MINBRT)/HISTEP;
629                  tmnew->histo = (int *)malloc(len*sizeof(int));
630                  if (tmnew->histo != NULL)
631                          for (i = len; i--; )
632                                  tmnew->histo[i] = tmTop->histo[i];
633          }
634          if (tmnew->lumap != NULL) {     /* duplicate luminance mapping */
635 <                len = tmnew->brmax-tmnew->brmin+1;
635 >                len = tmnew->mbrmax-tmnew->mbrmin+1;
636                  tmnew->lumap = (unsigned short *)malloc(
637                                                  len*sizeof(unsigned short) );
638                  if (tmnew->lumap != NULL)
639                          for (i = len; i--; )
640                                  tmnew->lumap[i] = tmTop->lumap[i];
641          }
642 +                                        /* clear package data */
643 +        for (i = tmNumPkgs; i--; )
644 +                tmnew->pd[i] = NULL;
645          tmnew->tmprev = tmTop;          /* make copy current */
646          return(tmTop = tmnew);
647   }
# Line 540 | Line 653 | register struct tmStruct       *tms;
653   {
654          static char     funcName[] = "tmPush";
655                                          /* check validity */
656 <        if (tms == NULL || !(tms->flags & TM_F_INITED))
656 >        if (tms == NULL)
657                  returnErr(TM_E_ILLEGAL);
658          if (tms == tmTop)               /* check necessity */
659                  returnOK;
# Line 557 | Line 670 | void
670   tmDone(tms)                     /* done with tone mapping -- destroy it */
671   register struct tmStruct        *tms;
672   {
673 +        register int    i;
674                                          /* NULL arg. is equiv. to tmTop */
675          if (tms == NULL && (tms = tmTop) == NULL)
676                  return;
# Line 564 | Line 678 | register struct tmStruct       *tms;
678          (void)tmPull(tms);
679                                          /* free tables */
680          if (tms->histo != NULL)
681 <                free((char *)tms->histo);
681 >                free((MEM_PTR)tms->histo);
682          if (tms->lumap != NULL)
683 <                free((char *)tms->lumap);
684 <        tms->flags = 0;
685 <        free((char *)tms);              /* free basic structure */
683 >                free((MEM_PTR)tms->lumap);
684 >                                        /* free private data */
685 >        for (i = tmNumPkgs; i--; )
686 >                if (tms->pd[i] != NULL)
687 >                        (*tmPkg[i]->Free)(tms->pd[i]);
688 >        free((MEM_PTR)tms);             /* free basic structure */
689 > }
690 >
691 > /******************** Shared but Private library routines *********************/
692 >
693 > BYTE    tmMesofact[BMESUPPER-BMESLOWER];
694 >
695 > void
696 > tmMkMesofact()                          /* build mesopic lookup factor table */
697 > {
698 >        register int    i;
699 >
700 >        if (tmMesofact[BMESUPPER-BMESLOWER-1])
701 >                return;
702 >
703 >        for (i = BMESLOWER; i < BMESUPPER; i++)
704 >                tmMesofact[i-BMESLOWER] = 256. *
705 >                                (tmLuminance(i) - LMESLOWER) /
706 >                                (LMESUPPER - LMESLOWER);
707 > }
708 >
709 >
710 > int
711 > tmErrorReturn(func, err)                /* error return (with message) */
712 > char    *func;
713 > int     err;
714 > {
715 >        tmLastFunction = func;
716 >        tmLastError = err;
717 >        if (tmTop != NULL && tmTop->flags & TM_F_NOSTDERR)
718 >                return(err);
719 >        fputs(func, stderr);
720 >        fputs(": ", stderr);
721 >        fputs(tmErrorMessage[err], stderr);
722 >        fputs("!\n", stderr);
723 >        return(err);
724   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines