ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/tonemap.c
Revision: 3.9
Committed: Sat Feb 22 02:07:22 2003 UTC (21 years, 2 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 3.8: +238 -100 lines
Log Message:
Changes and check-in for 3.5 release
Includes new source files and modifications not recorded for many years
See ray/doc/notes/ReleaseNotes for notes between 3.1 and 3.5 release

File Contents

# User Rev Content
1 greg 3.1 #ifndef lint
2 greg 3.9 static const char RCSid[] = "$Id$";
3 greg 3.1 #endif
4     /*
5     * Tone mapping functions.
6     * See tonemap.h for detailed function descriptions.
7 greg 3.9 * 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 greg 3.1 */
68    
69     #include <stdio.h>
70     #include <math.h>
71     #include "tmprivat.h"
72     #include "tmerrmsg.h"
73    
74     #define exp10(x) exp(M_LN10*(x))
75    
76     struct tmStruct *tmTop = NULL; /* current tone mapping stack */
77    
78 greg 3.4 /* our list of conversion packages */
79     struct tmPackage *tmPkg[TM_MAXPKG];
80     int tmNumPkgs = 0; /* number of registered packages */
81 greg 3.1
82 gregl 3.5 int tmLastError; /* last error incurred by library */
83     char *tmLastFunction; /* error-generating function name */
84 greg 3.4
85 gregl 3.5
86 greg 3.1 struct tmStruct *
87     tmInit(flags, monpri, gamval) /* initialize new tone mapping */
88     int flags;
89     RGBPRIMP monpri;
90     double gamval;
91     {
92     COLORMAT cmat;
93     register struct tmStruct *tmnew;
94     register int i;
95     /* allocate structure */
96     tmnew = (struct tmStruct *)malloc(sizeof(struct tmStruct));
97     if (tmnew == NULL)
98     return(NULL);
99    
100     tmnew->flags = flags & ~TM_F_UNIMPL;
101     /* set monitor transform */
102     if (monpri == NULL || monpri == stdprims || tmnew->flags & TM_F_BW) {
103     tmnew->monpri = stdprims;
104     tmnew->clf[RED] = rgb2xyzmat[1][0];
105     tmnew->clf[GRN] = rgb2xyzmat[1][1];
106     tmnew->clf[BLU] = rgb2xyzmat[1][2];
107     } else {
108 greg 3.9 comprgb2xyzWBmat(cmat, tmnew->monpri=monpri);
109 greg 3.1 tmnew->clf[RED] = cmat[1][0];
110     tmnew->clf[GRN] = cmat[1][1];
111     tmnew->clf[BLU] = cmat[1][2];
112     }
113     /* set gamma value */
114     if (gamval < MINGAM)
115     tmnew->mongam = DEFGAM;
116     else
117     tmnew->mongam = gamval;
118 greg 3.4 /* set color divisors */
119     for (i = 0; i < 3; i++)
120     tmnew->cdiv[i] = 256.*pow(tmnew->clf[i], 1./tmnew->mongam);
121    
122 greg 3.1 /* 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;
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 greg 3.9 tmnew->hbrmin = 10; tmnew->hbrmax = -10;
129 greg 3.1 tmnew->histo = NULL;
130 greg 3.9 tmnew->mbrmin = 10; tmnew->mbrmax = -10;
131 greg 3.1 tmnew->lumap = NULL;
132 greg 3.4 /* zero private data */
133     for (i = TM_MAXPKG; i--; )
134     tmnew->pd[i] = NULL;
135     /* make tmnew current */
136 greg 3.1 tmnew->tmprev = tmTop;
137     return(tmTop = tmnew);
138     }
139    
140    
141     int
142     tmSetSpace(pri, sf) /* set input color space for conversions */
143     RGBPRIMP pri;
144     double sf;
145     {
146     static char funcName[] = "tmSetSpace";
147     register int i, j;
148     /* error check */
149     if (tmTop == NULL)
150     returnErr(TM_E_TMINVAL);
151     if (sf <= 1e-12)
152     returnErr(TM_E_ILLEGAL);
153     /* check if no change */
154     if (pri == tmTop->inppri && FEQ(sf, tmTop->inpsf))
155     returnOK;
156     tmTop->inppri = pri; /* let's set it */
157     tmTop->inpsf = sf;
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.;
164     } else {
165 greg 3.9 comprgb2xyzWBmat(tmTop->cmat, tmTop->monpri);
166 greg 3.1 tmTop->clf[RED] = tmTop->cmat[1][0];
167     tmTop->clf[GRN] = tmTop->cmat[1][1];
168     tmTop->clf[BLU] = tmTop->cmat[1][2];
169     }
170     tmTop->cmat[0][0] = tmTop->cmat[1][1] = tmTop->cmat[2][2] =
171     tmTop->inpsf;
172     tmTop->cmat[0][1] = tmTop->cmat[0][2] = tmTop->cmat[1][0] =
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 greg 3.9 compxyz2rgbWBmat(tmTop->cmat, tmTop->monpri);
177 greg 3.1
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 greg 3.9 comprgb2rgbWBmat(tmTop->cmat, tmTop->inppri, tmTop->monpri);
183 greg 3.1 }
184     for (i = 0; i < 3; i++)
185     for (j = 0; j < 3; j++)
186     tmTop->cmat[i][j] *= tmTop->inpsf;
187 greg 3.4 /* 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 greg 3.1 returnOK;
199     }
200    
201    
202     void
203     tmClearHisto() /* clear current histogram */
204     {
205     if (tmTop == NULL || tmTop->histo == NULL)
206     return;
207 greg 3.4 free((MEM_PTR)tmTop->histo);
208 greg 3.1 tmTop->histo = NULL;
209     }
210    
211    
212     int
213     tmCvColors(ls, cs, scan, len) /* convert float colors */
214     TMbright *ls;
215     BYTE *cs;
216     COLOR *scan;
217     int len;
218     {
219     static char funcName[] = "tmCvColors";
220 greg 3.4 static COLOR csmall = {1e-6, 1e-6, 1e-6};
221 greg 3.1 COLOR cmon;
222     double lum, slum;
223     register double d;
224     register int i;
225    
226     if (tmTop == NULL)
227     returnErr(TM_E_TMINVAL);
228 gwlarson 3.8 if (ls == NULL | scan == NULL | len < 0)
229 greg 3.1 returnErr(TM_E_ILLEGAL);
230     for (i = len; i--; ) {
231 greg 3.4 if (tmNeedMatrix(tmTop)) /* get monitor RGB */
232 greg 3.1 colortrans(cmon, tmTop->cmat, scan[i]);
233     else {
234     cmon[RED] = tmTop->inpsf*scan[i][RED];
235     cmon[GRN] = tmTop->inpsf*scan[i][GRN];
236     cmon[BLU] = tmTop->inpsf*scan[i][BLU];
237     }
238     /* world luminance */
239     lum = tmTop->clf[RED]*cmon[RED] +
240     tmTop->clf[GRN]*cmon[GRN] +
241     tmTop->clf[BLU]*cmon[BLU] ;
242     /* check range */
243 greg 3.4 if (clipgamut(cmon, lum, CGAMUT_LOWER, csmall, cwhite))
244 greg 3.1 lum = tmTop->clf[RED]*cmon[RED] +
245     tmTop->clf[GRN]*cmon[GRN] +
246     tmTop->clf[BLU]*cmon[BLU] ;
247     if (lum < MINLUM) {
248     ls[i] = MINBRT-1; /* bogus value */
249     lum = MINLUM;
250     } else {
251     d = TM_BRTSCALE*log(lum); /* encode it */
252     ls[i] = d>0. ? (int)(d+.5) : (int)(d-.5);
253     }
254     if (cs == TM_NOCHROM) /* no color? */
255     continue;
256     if (tmTop->flags & TM_F_MESOPIC && lum < LMESUPPER) {
257     slum = scotlum(cmon); /* mesopic adj. */
258     if (lum < LMESLOWER)
259     cmon[RED] = cmon[GRN] = cmon[BLU] = slum;
260     else {
261     d = (lum - LMESLOWER)/(LMESUPPER - LMESLOWER);
262     if (tmTop->flags & TM_F_BW)
263     cmon[RED] = cmon[GRN] =
264     cmon[BLU] = d*lum;
265     else
266     scalecolor(cmon, d);
267     d = (1.-d)*slum;
268     cmon[RED] += d;
269     cmon[GRN] += d;
270     cmon[BLU] += d;
271     }
272     } else if (tmTop->flags & TM_F_BW) {
273     cmon[RED] = cmon[GRN] = cmon[BLU] = lum;
274     }
275     d = tmTop->clf[RED]*cmon[RED]/lum;
276 greg 3.4 cs[3*i ] = d>=.999 ? 255 :
277     (int)(256.*pow(d, 1./tmTop->mongam));
278 greg 3.1 d = tmTop->clf[GRN]*cmon[GRN]/lum;
279 greg 3.4 cs[3*i+1] = d>=.999 ? 255 :
280     (int)(256.*pow(d, 1./tmTop->mongam));
281 greg 3.1 d = tmTop->clf[BLU]*cmon[BLU]/lum;
282 greg 3.4 cs[3*i+2] = d>=.999 ? 255 :
283     (int)(256.*pow(d, 1./tmTop->mongam));
284 greg 3.1 }
285     returnOK;
286     }
287    
288    
289     int
290 greg 3.9 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 greg 3.1 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 greg 3.9 int oldorig=0, oldlen, horig, hlen;
322 greg 3.1 register int i, j;
323    
324     if (tmTop == NULL)
325     returnErr(TM_E_TMINVAL);
326 gwlarson 3.8 if (len < 0)
327     returnErr(TM_E_ILLEGAL);
328     if (len == 0)
329     returnOK;
330 greg 3.1 /* first, grow limits */
331     if (tmTop->histo == NULL) {
332     for (i = len; i-- && ls[i] < MINBRT; )
333     ;
334     if (i < 0)
335     returnOK;
336 gregl 3.6 tmTop->hbrmin = tmTop->hbrmax = ls[i];
337 greg 3.1 oldlen = 0;
338     } else {
339 gregl 3.6 oldorig = (tmTop->hbrmin-MINBRT)/HISTEP;
340     oldlen = (tmTop->hbrmax-MINBRT)/HISTEP + 1 - oldorig;
341 greg 3.1 }
342     for (i = len; i--; ) {
343     if ((j = ls[i]) < MINBRT)
344     continue;
345 gregl 3.6 if (j < tmTop->hbrmin)
346     tmTop->hbrmin = j;
347     else if (j > tmTop->hbrmax)
348     tmTop->hbrmax = j;
349 greg 3.1 }
350 gregl 3.6 horig = (tmTop->hbrmin-MINBRT)/HISTEP;
351     hlen = (tmTop->hbrmax-MINBRT)/HISTEP + 1 - horig;
352 greg 3.1 if (hlen > oldlen) { /* (re)allocate histogram */
353     register int *newhist = (int *)calloc(hlen, sizeof(int));
354     if (newhist == NULL)
355     returnErr(TM_E_NOMEM);
356     if (oldlen) { /* copy and free old */
357 greg 3.2 for (i = oldlen, j = i+oldorig-horig; i; )
358     newhist[--j] = tmTop->histo[--i];
359 greg 3.4 free((MEM_PTR)tmTop->histo);
360 greg 3.1 }
361     tmTop->histo = newhist;
362     }
363     if (wt == 0)
364     returnOK;
365     for (i = len; i--; ) /* add in new counts */
366     if (ls[i] >= MINBRT)
367     tmTop->histo[ (ls[i]-MINBRT)/HISTEP - horig ] += wt;
368     returnOK;
369     }
370    
371    
372     static double
373     htcontrs(La) /* human threshold contrast sensitivity, dL(La) */
374     double La;
375     {
376     double l10La, l10dL;
377     /* formula taken from Ferwerda et al. [SG96] */
378     if (La < 1.148e-4)
379     return(1.38e-3);
380     l10La = log10(La);
381     if (l10La < -1.44) /* rod response regime */
382     l10dL = pow(.405*l10La + 1.6, 2.18) - 2.86;
383     else if (l10La < -.0184)
384     l10dL = l10La - .395;
385     else if (l10La < 1.9) /* cone response regime */
386     l10dL = pow(.249*l10La + .65, 2.7) - .72;
387     else
388     l10dL = l10La - 1.255;
389    
390     return(exp10(l10dL));
391     }
392    
393    
394 greg 3.9 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 greg 3.1 int
438     tmComputeMapping(gamval, Lddyn, Ldmax)
439     double gamval;
440     double Lddyn;
441     double Ldmax;
442     {
443     static char funcName[] = "tmComputeMapping";
444     int *histo;
445     float *cumf;
446 greg 3.9 int brt0, histlen, threshold, ceiling, trimmings;
447 greg 3.1 double logLddyn, Ldmin, Ldavg, Lwavg, Tr, Lw, Ld;
448 greg 3.9 int4 histot;
449     double sum;
450 greg 3.1 register double d;
451     register int i, j;
452    
453     if (tmTop == NULL || tmTop->histo == NULL)
454     returnErr(TM_E_TMINVAL);
455     /* check arguments */
456     if (Lddyn < MINLDDYN) Lddyn = DEFLDDYN;
457     if (Ldmax < MINLDMAX) Ldmax = DEFLDMAX;
458     if (gamval < MINGAM) gamval = tmTop->mongam;
459     /* compute handy values */
460     Ldmin = Ldmax/Lddyn;
461     logLddyn = log(Lddyn);
462     Ldavg = sqrt(Ldmax*Ldmin);
463 gregl 3.6 i = (tmTop->hbrmin-MINBRT)/HISTEP;
464 greg 3.1 brt0 = MINBRT + HISTEP/2 + i*HISTEP;
465 gregl 3.6 histlen = (tmTop->hbrmax-MINBRT)/HISTEP + 1 - i;
466 greg 3.1 /* histogram total and mean */
467     histot = 0; sum = 0;
468     j = brt0 + histlen*HISTEP;
469     for (i = histlen; i--; ) {
470 greg 3.2 histot += tmTop->histo[i];
471     sum += (j -= HISTEP) * tmTop->histo[i];
472 greg 3.1 }
473     threshold = histot*.025 + .5;
474     if (threshold < 4)
475     returnErr(TM_E_TMFAIL);
476     Lwavg = tmLuminance( (double)sum / histot );
477 greg 3.9 /* 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 greg 3.2 }
510 greg 3.9 if (histo[i] > ceiling) {
511     trimmings += histo[i] - ceiling;
512     histo[i] = ceiling;
513 greg 3.1 }
514     }
515 greg 3.9 /* 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 greg 3.1 }
530 greg 3.9 free((MEM_PTR)histo); /* clean up and return */
531     free((MEM_PTR)cumf);
532 greg 3.1 returnOK;
533 greg 3.9 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 greg 3.1 }
540    
541    
542     int
543     tmMapPixels(ps, ls, cs, len)
544     register BYTE *ps;
545     TMbright *ls;
546     register BYTE *cs;
547     int len;
548     {
549     static char funcName[] = "tmMapPixels";
550 greg 3.4 register int4 li, pv;
551 greg 3.1
552     if (tmTop == NULL || tmTop->lumap == NULL)
553     returnErr(TM_E_TMINVAL);
554 gwlarson 3.8 if (ps == NULL | ls == NULL | len < 0)
555 greg 3.1 returnErr(TM_E_ILLEGAL);
556     while (len--) {
557 greg 3.9 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 greg 3.1 if (cs == TM_NOCHROM)
565     *ps++ = li>255 ? 255 : li;
566     else {
567 greg 3.4 pv = *cs++ * li / tmTop->cdiv[RED];
568 greg 3.1 *ps++ = pv>255 ? 255 : pv;
569 greg 3.4 pv = *cs++ * li / tmTop->cdiv[GRN];
570 greg 3.1 *ps++ = pv>255 ? 255 : pv;
571 greg 3.4 pv = *cs++ * li / tmTop->cdiv[BLU];
572 greg 3.1 *ps++ = pv>255 ? 255 : pv;
573     }
574     }
575     returnOK;
576     }
577    
578    
579     struct tmStruct *
580     tmPop() /* pop top tone mapping off stack */
581     {
582     register struct tmStruct *tms;
583    
584     if ((tms = tmTop) != NULL)
585     tmTop = tms->tmprev;
586     return(tms);
587     }
588    
589    
590     int
591     tmPull(tms) /* pull a tone mapping from stack */
592     register struct tmStruct *tms;
593     {
594     register struct tmStruct *tms2;
595     /* special cases first */
596     if (tms == NULL | tmTop == NULL)
597     return(0);
598     if (tms == tmTop) {
599     tmTop = tms->tmprev;
600     tms->tmprev = NULL;
601     return(1);
602     }
603     for (tms2 = tmTop; tms2->tmprev != NULL; tms2 = tms2->tmprev)
604     if (tms == tms2->tmprev) { /* remove it */
605     tms2->tmprev = tms->tmprev;
606     tms->tmprev = NULL;
607     return(1);
608     }
609     return(0); /* not found on stack */
610     }
611    
612    
613 greg 3.3 struct tmStruct *
614     tmDup() /* duplicate top tone mapping */
615     {
616     int len;
617     register int i;
618     register struct tmStruct *tmnew;
619    
620     if (tmTop == NULL) /* anything to duplicate? */
621     return(NULL);
622     tmnew = (struct tmStruct *)malloc(sizeof(struct tmStruct));
623     if (tmnew == NULL)
624     return(NULL);
625     *tmnew = *tmTop; /* copy everything */
626     if (tmnew->histo != NULL) { /* duplicate histogram */
627 gregl 3.6 len = (tmnew->hbrmax-MINBRT)/HISTEP + 1 -
628     (tmnew->hbrmin-MINBRT)/HISTEP;
629 greg 3.3 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 gregl 3.6 len = tmnew->mbrmax-tmnew->mbrmin+1;
636 greg 3.3 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 greg 3.4 /* clear package data */
643     for (i = tmNumPkgs; i--; )
644     tmnew->pd[i] = NULL;
645 greg 3.3 tmnew->tmprev = tmTop; /* make copy current */
646     return(tmTop = tmnew);
647     }
648    
649    
650 greg 3.1 int
651     tmPush(tms) /* push tone mapping on top of stack */
652     register struct tmStruct *tms;
653     {
654     static char funcName[] = "tmPush";
655     /* check validity */
656 greg 3.4 if (tms == NULL)
657 greg 3.1 returnErr(TM_E_ILLEGAL);
658     if (tms == tmTop) /* check necessity */
659     returnOK;
660     /* pull if already in stack */
661     (void)tmPull(tms);
662     /* push it on top */
663     tms->tmprev = tmTop;
664     tmTop = tms;
665     returnOK;
666     }
667    
668    
669     void
670     tmDone(tms) /* done with tone mapping -- destroy it */
671     register struct tmStruct *tms;
672     {
673 greg 3.4 register int i;
674 greg 3.1 /* NULL arg. is equiv. to tmTop */
675     if (tms == NULL && (tms = tmTop) == NULL)
676     return;
677     /* take out of stack if present */
678     (void)tmPull(tms);
679     /* free tables */
680     if (tms->histo != NULL)
681 greg 3.4 free((MEM_PTR)tms->histo);
682 greg 3.1 if (tms->lumap != NULL)
683 greg 3.4 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 greg 3.9 }
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 greg 3.1 }