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

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id$";
3 #endif
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"
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 /* our list of conversion packages */
79 struct tmPackage *tmPkg[TM_MAXPKG];
80 int tmNumPkgs = 0; /* number of registered packages */
81
82 int tmLastError; /* last error incurred by library */
83 char *tmLastFunction; /* error-generating function name */
84
85
86 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 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 }
113 /* set gamma value */
114 if (gamval < MINGAM)
115 tmnew->mongam = DEFGAM;
116 else
117 tmnew->mongam = gamval;
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;
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->hbrmin = 10; tmnew->hbrmax = -10;
129 tmnew->histo = NULL;
130 tmnew->mbrmin = 10; tmnew->mbrmax = -10;
131 tmnew->lumap = NULL;
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 }
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 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];
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 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 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 /* 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
201
202 void
203 tmClearHisto() /* clear current histogram */
204 {
205 if (tmTop == NULL || tmTop->histo == NULL)
206 return;
207 free((MEM_PTR)tmTop->histo);
208 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 static COLOR csmall = {1e-6, 1e-6, 1e-6};
221 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 if (ls == NULL | scan == NULL | len < 0)
229 returnErr(TM_E_ILLEGAL);
230 for (i = len; i--; ) {
231 if (tmNeedMatrix(tmTop)) /* get monitor RGB */
232 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 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] ;
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 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 :
280 (int)(256.*pow(d, 1./tmTop->mongam));
281 d = tmTop->clf[BLU]*cmon[BLU]/lum;
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 oldorig=0, oldlen, horig, hlen;
322 register int i, j;
323
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->hbrmin = tmTop->hbrmax = ls[i];
337 oldlen = 0;
338 } else {
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->hbrmin)
346 tmTop->hbrmin = j;
347 else if (j > tmTop->hbrmax)
348 tmTop->hbrmax = j;
349 }
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)
355 returnErr(TM_E_NOMEM);
356 if (oldlen) { /* copy and free old */
357 for (i = oldlen, j = i+oldorig-horig; i; )
358 newhist[--j] = tmTop->histo[--i];
359 free((MEM_PTR)tmTop->histo);
360 }
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 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;
441 double Ldmax;
442 {
443 static char funcName[] = "tmComputeMapping";
444 int *histo;
445 float *cumf;
446 int brt0, histlen, threshold, ceiling, trimmings;
447 double logLddyn, Ldmin, Ldavg, Lwavg, Tr, Lw, Ld;
448 int4 histot;
449 double sum;
450 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 i = (tmTop->hbrmin-MINBRT)/HISTEP;
464 brt0 = MINBRT + HISTEP/2 + i*HISTEP;
465 histlen = (tmTop->hbrmax-MINBRT)/HISTEP + 1 - i;
466 /* histogram total and mean */
467 histot = 0; sum = 0;
468 j = brt0 + histlen*HISTEP;
469 for (i = histlen; i--; ) {
470 histot += tmTop->histo[i];
471 sum += (j -= HISTEP) * tmTop->histo[i];
472 }
473 threshold = histot*.025 + .5;
474 if (threshold < 4)
475 returnErr(TM_E_TMFAIL);
476 Lwavg = tmLuminance( (double)sum / histot );
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 if (histo[i] > ceiling) {
511 trimmings += histo[i] - ceiling;
512 histo[i] = ceiling;
513 }
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 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
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 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)
555 returnErr(TM_E_ILLEGAL);
556 while (len--) {
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 / tmTop->cdiv[RED];
568 *ps++ = pv>255 ? 255 : pv;
569 pv = *cs++ * li / tmTop->cdiv[GRN];
570 *ps++ = pv>255 ? 255 : pv;
571 pv = *cs++ * li / tmTop->cdiv[BLU];
572 *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 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 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->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 }
648
649
650 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 if (tms == NULL)
657 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 register int i;
674 /* 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 free((MEM_PTR)tms->histo);
682 if (tms->lumap != NULL)
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 }