ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/tmapcolrs.c
Revision: 3.10
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.9: +83 -21 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 * Routines for tone mapping on Radiance RGBE and XYZE pictures.
6 *
7 * Externals declared in tonemap.h
8 */
9
10 /* ====================================================================
11 * The Radiance Software License, Version 1.0
12 *
13 * Copyright (c) 1990 - 2002 The Regents of the University of California,
14 * through Lawrence Berkeley National Laboratory. All rights reserved.
15 *
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
18 * are met:
19 *
20 * 1. Redistributions of source code must retain the above copyright
21 * notice, this list of conditions and the following disclaimer.
22 *
23 * 2. Redistributions in binary form must reproduce the above copyright
24 * notice, this list of conditions and the following disclaimer in
25 * the documentation and/or other materials provided with the
26 * distribution.
27 *
28 * 3. The end-user documentation included with the redistribution,
29 * if any, must include the following acknowledgment:
30 * "This product includes Radiance software
31 * (http://radsite.lbl.gov/)
32 * developed by the Lawrence Berkeley National Laboratory
33 * (http://www.lbl.gov/)."
34 * Alternately, this acknowledgment may appear in the software itself,
35 * if and wherever such third-party acknowledgments normally appear.
36 *
37 * 4. The names "Radiance," "Lawrence Berkeley National Laboratory"
38 * and "The Regents of the University of California" must
39 * not be used to endorse or promote products derived from this
40 * software without prior written permission. For written
41 * permission, please contact [email protected].
42 *
43 * 5. Products derived from this software may not be called "Radiance",
44 * nor may "Radiance" appear in their name, without prior written
45 * permission of Lawrence Berkeley National Laboratory.
46 *
47 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
48 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
49 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
50 * DISCLAIMED. IN NO EVENT SHALL Lawrence Berkeley National Laboratory OR
51 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
52 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
53 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
54 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
55 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
56 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
57 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * SUCH DAMAGE.
59 * ====================================================================
60 *
61 * This software consists of voluntary contributions made by many
62 * individuals on behalf of Lawrence Berkeley National Laboratory. For more
63 * information on Lawrence Berkeley National Laboratory, please see
64 * <http://www.lbl.gov/>.
65 */
66
67 #include <stdio.h>
68 #include <string.h>
69 #include <math.h>
70 #include <time.h>
71 #include "tmprivat.h"
72 #include "resolu.h"
73
74 #ifndef TM_PIC_CTRANS
75 #define TM_PIC_CTRANS 1 /* transform colors? (expensive) */
76 #endif
77
78 #define GAMTSZ 1024
79
80 typedef struct {
81 BYTE gamb[GAMTSZ]; /* gamma lookup table */
82 COLR clfb; /* encoded tm->clf */
83 TMbright inpsfb; /* encoded tm->inpsf */
84 } COLRDATA;
85
86 #ifdef NOPROTO
87 static MEM_PTR colrInit();
88 static void colrNewSpace();
89 #else
90 static MEM_PTR colrInit(struct tmStruct *);
91 static void colrNewSpace(struct tmStruct *);
92 #endif
93 static struct tmPackage colrPkg = { /* our package functions */
94 colrInit, colrNewSpace, free
95 };
96 static int colrReg = -1; /* our package registration number */
97
98 #define LOGISZ 260
99 static TMbright logi[LOGISZ];
100
101
102 int
103 tmCvColrs(ls, cs, scan, len) /* convert RGBE/XYZE colors */
104 TMbright *ls;
105 BYTE *cs;
106 COLR *scan;
107 int len;
108 {
109 static char funcName[] = "tmCvColrs";
110 COLR cmon;
111 register COLRDATA *cd;
112 register int i, bi, li;
113
114 if (tmTop == NULL)
115 returnErr(TM_E_TMINVAL);
116 if (ls == NULL | scan == NULL | len < 0)
117 returnErr(TM_E_ILLEGAL);
118 #if TM_PIC_CTRANS
119 if (tmNeedMatrix(tmTop)) { /* need floating point */
120 #else
121 if (tmTop->inppri == TM_XYZPRIM) { /* no way around this */
122 #endif
123 register COLOR *newscan;
124 newscan = (COLOR *)tempbuffer(len*sizeof(COLOR));
125 if (newscan == NULL)
126 returnErr(TM_E_NOMEM);
127 for (i = len; i--; )
128 colr_color(newscan[i], scan[i]);
129 return(tmCvColors(ls, cs, newscan, len));
130 }
131 if (colrReg < 0) { /* build tables if necessary */
132 colrReg = tmRegPkg(&colrPkg);
133 if (colrReg < 0)
134 returnErr(TM_E_CODERR1);
135 for (i = 256; i--; )
136 logi[i] = TM_BRTSCALE*log((i+.5)/256.) - .5;
137 for (i = 256; i < LOGISZ; i++)
138 logi[i] = 0;
139 tmMkMesofact();
140 }
141 if ((cd = (COLRDATA *)tmPkgData(tmTop,colrReg)) == NULL)
142 returnErr(TM_E_NOMEM);
143 for (i = len; i--; ) {
144 copycolr(cmon, scan[i]);
145 /* world luminance */
146 li = ( cd->clfb[RED]*cmon[RED] +
147 cd->clfb[GRN]*cmon[GRN] +
148 cd->clfb[BLU]*cmon[BLU] ) >> 8;
149 bi = BRT2SCALE(cmon[EXP]-COLXS) +
150 logi[li] + cd->inpsfb;
151 if (li <= 0) {
152 bi = TM_NOBRT; /* bogus value */
153 li = 1; /* avoid li==0 */
154 }
155 ls[i] = bi;
156 if (cs == TM_NOCHROM) /* no color? */
157 continue;
158 /* mesopic adj. */
159 if (tmTop->flags & TM_F_MESOPIC && bi < BMESUPPER) {
160 register int pf, sli = normscot(cmon);
161 if (bi < BMESLOWER)
162 cmon[RED] = cmon[GRN] = cmon[BLU] = sli;
163 else {
164 if (tmTop->flags & TM_F_BW)
165 cmon[RED] = cmon[GRN] = cmon[BLU] = li;
166 pf = tmMesofact[bi-BMESLOWER];
167 sli *= 256 - pf;
168 cmon[RED] = ( sli + pf*cmon[RED] ) >> 8;
169 cmon[GRN] = ( sli + pf*cmon[GRN] ) >> 8;
170 cmon[BLU] = ( sli + pf*cmon[BLU] ) >> 8;
171 }
172 } else if (tmTop->flags & TM_F_BW) {
173 cmon[RED] = cmon[GRN] = cmon[BLU] = li;
174 }
175 bi = ( (int4)GAMTSZ*cd->clfb[RED]*cmon[RED]/li ) >> 8;
176 cs[3*i ] = bi>=GAMTSZ ? 255 : cd->gamb[bi];
177 bi = ( (int4)GAMTSZ*cd->clfb[GRN]*cmon[GRN]/li ) >> 8;
178 cs[3*i+1] = bi>=GAMTSZ ? 255 : cd->gamb[bi];
179 bi = ( (int4)GAMTSZ*cd->clfb[BLU]*cmon[BLU]/li ) >> 8;
180 cs[3*i+2] = bi>=GAMTSZ ? 255 : cd->gamb[bi];
181 }
182 returnOK;
183 }
184
185
186 #define FMTRGB 1 /* Input is RGBE */
187 #define FMTCIE 2 /* Input is CIE XYZE */
188 #define FMTUNK 3 /* Input format is unspecified */
189 #define FMTBAD 4 /* Input is not a recognized format */
190
191 static struct radhead {
192 int format; /* FMTRGB, FMTCIE, FMTUNK, FMTBAD */
193 double expos; /* input exposure value */
194 RGBPRIMP primp; /* input primaries */
195 RGBPRIMS mypri; /* custom primaries */
196 } rhdefault = {FMTUNK, 1., stdprims, STDPRIMS};
197
198
199 static int
200 headline(s, rh) /* grok a header line */
201 register char *s;
202 register struct radhead *rh;
203 {
204 char fmt[32];
205
206 if (formatval(fmt, s)) {
207 if (!strcmp(fmt, COLRFMT))
208 rh->format = FMTRGB;
209 else if (!strcmp(fmt, CIEFMT))
210 rh->format = FMTCIE;
211 else
212 rh->format = FMTBAD;
213 return(0);
214 }
215 if (isexpos(s)) {
216 rh->expos *= exposval(s);
217 return(0);
218 }
219 if (isprims(s)) {
220 primsval(rh->mypri, s);
221 rh->primp = rh->mypri;
222 return(0);
223 }
224 return(0);
225 }
226
227
228 int
229 tmLoadPicture(lpp, cpp, xp, yp, fname, fp) /* convert Radiance picture */
230 TMbright **lpp;
231 BYTE **cpp;
232 int *xp, *yp;
233 char *fname;
234 FILE *fp;
235 {
236 char *funcName = fname==NULL ? "tmLoadPicture" : fname;
237 FILE *inpf;
238 struct radhead info;
239 int err;
240 COLR *scanin = NULL;
241 int i;
242 /* check arguments */
243 if (tmTop == NULL)
244 returnErr(TM_E_TMINVAL);
245 if (lpp == NULL | xp == NULL | yp == NULL |
246 (fname == NULL & fp == TM_GETFILE))
247 returnErr(TM_E_ILLEGAL);
248 *xp = *yp = 0; /* error precaution */
249 if ((inpf = fp) == TM_GETFILE && (inpf = fopen(fname, "r")) == NULL)
250 returnErr(TM_E_BADFILE);
251 *lpp = NULL;
252 if (cpp != TM_NOCHROMP) *cpp = NULL;
253 info = rhdefault; /* get our header */
254 getheader(inpf, headline, (char *)&info);
255 if (info.format == FMTBAD | info.expos <= 0. ||
256 fgetresolu(xp, yp, inpf) < 0) {
257 err = TM_E_BADFILE; goto done;
258 }
259 if (info.format == FMTUNK) /* assume RGBE format */
260 info.format = FMTRGB;
261 if (info.format == FMTRGB)
262 info.expos /= WHTEFFICACY;
263 else if (info.format == FMTCIE)
264 info.primp = TM_XYZPRIM;
265 /* prepare library */
266 if ((err = tmSetSpace(info.primp, 1./info.expos)) != TM_E_OK)
267 goto done;
268 err = TM_E_NOMEM; /* allocate arrays */
269 *lpp = (TMbright *)malloc(sizeof(TMbright) * *xp * *yp);
270 if (*lpp == NULL)
271 goto done;
272 if (cpp != TM_NOCHROMP) {
273 *cpp = (BYTE *)malloc(3*sizeof(BYTE) * *xp * *yp);
274 if (*cpp == NULL)
275 goto done;
276 }
277 scanin = (COLR *)malloc(sizeof(COLR) * *xp);
278 if (scanin == NULL)
279 goto done;
280 err = TM_E_BADFILE; /* read & convert scanlines */
281 for (i = 0; i < *yp; i++) {
282 if (freadcolrs(scanin, *xp, inpf) < 0) {
283 err = TM_E_BADFILE; break;
284 }
285 err = tmCvColrs(*lpp + (i * *xp),
286 cpp==TM_NOCHROMP ? TM_NOCHROM : *cpp + (i * 3 * *xp),
287 scanin, *xp);
288 if (err != TM_E_OK)
289 break;
290 }
291 done: /* clean up */
292 if (fp == NULL)
293 fclose(inpf);
294 if (scanin != NULL)
295 free((MEM_PTR)scanin);
296 if (err != TM_E_OK) {
297 if (*lpp != NULL)
298 free((MEM_PTR)*lpp);
299 if (cpp != TM_NOCHROMP && *cpp != NULL)
300 free((MEM_PTR)*cpp);
301 returnErr(err);
302 }
303 returnOK;
304 }
305
306
307 #ifdef PCOND
308 int /* run pcond to map picture */
309 dopcond(psp, xp, yp, flags, monpri, gamval, Lddyn, Ldmax, fname)
310 BYTE **psp;
311 int *xp, *yp;
312 int flags;
313 RGBPRIMP monpri;
314 double gamval, Lddyn, Ldmax;
315 char *fname;
316 {
317 char *funcName = fname;
318 char cmdbuf[1024];
319 FILE *infp;
320 register COLR *scan;
321 register BYTE *rp;
322 int y;
323 register int x;
324 /* set up gamma correction */
325 if (setcolrcor(pow, 1./gamval) < 0)
326 returnErr(TM_E_NOMEM);
327 /* create command */
328 strcpy(cmdbuf, PCOND);
329 if (flags & TM_F_HCONTR)
330 strcat(cmdbuf, " -s");
331 if (flags & TM_F_MESOPIC)
332 strcat(cmdbuf, " -c");
333 if (flags & TM_F_LINEAR)
334 strcat(cmdbuf, " -l");
335 if (flags & TM_F_ACUITY)
336 strcat(cmdbuf, " -a");
337 if (flags & TM_F_VEIL)
338 strcat(cmdbuf, " -v");
339 if (flags & TM_F_CWEIGHT)
340 strcat(cmdbuf, " -w");
341 if (monpri != stdprims)
342 sprintf(cmdbuf+strlen(cmdbuf), " -p %f %f %f %f %f %f %f %f",
343 monpri[RED][CIEX], monpri[RED][CIEY],
344 monpri[GRN][CIEX], monpri[GRN][CIEY],
345 monpri[BLU][CIEX], monpri[BLU][CIEY],
346 monpri[WHT][CIEX], monpri[WHT][CIEY]);
347 sprintf(cmdbuf+strlen(cmdbuf), " -d %f -u %f %s", Lddyn, Ldmax, fname);
348 /* start pcond */
349 if ((infp = popen(cmdbuf, "r")) == NULL)
350 returnErr(TM_E_BADFILE);
351 /* check picture format and size */
352 if (checkheader(infp, COLRFMT, NULL) < 0 ||
353 fgetresolu(xp, yp, infp) < 0) {
354 pclose(infp);
355 returnErr(TM_E_BADFILE);
356 }
357 /* allocate arrays */
358 scan = (COLR *)malloc(sizeof(COLR) * *xp);
359 if (flags & TM_F_BW)
360 rp = (BYTE *)malloc(sizeof(BYTE) * *xp * *yp);
361 else
362 rp = (BYTE *)malloc(3*sizeof(BYTE) * *xp * *yp);
363 if ((*psp = rp) == NULL | scan == NULL) {
364 pclose(infp);
365 returnErr(TM_E_NOMEM);
366 }
367 /* read and gamma map file */
368 for (y = 0; y < *yp; y++) {
369 if (freadcolrs(scan, *xp, infp) < 0) {
370 pclose(infp);
371 free((MEM_PTR)scan);
372 free((MEM_PTR)*psp);
373 *psp = NULL;
374 returnErr(TM_E_BADFILE);
375 }
376 colrs_gambs(scan, *xp);
377 if (flags & TM_F_BW)
378 for (x = 0; x < *xp; x++)
379 *rp++ = normbright(scan[x]);
380 else
381 for (x = 0; x < *xp; x++) {
382 *rp++ = scan[x][RED];
383 *rp++ = scan[x][GRN];
384 *rp++ = scan[x][BLU];
385 }
386 }
387 free((MEM_PTR)scan);
388 pclose(infp);
389 returnOK;
390 }
391 #endif
392
393
394 int /* map a Radiance picture */
395 tmMapPicture(psp, xp, yp, flags, monpri, gamval, Lddyn, Ldmax, fname, fp)
396 BYTE **psp;
397 int *xp, *yp;
398 int flags;
399 RGBPRIMP monpri;
400 double gamval, Lddyn, Ldmax;
401 char *fname;
402 FILE *fp;
403 {
404 char *funcName = fname==NULL ? "tmMapPicture" : fname;
405 BYTE *cp;
406 TMbright *lp;
407 int err;
408 /* check arguments */
409 if (psp == NULL | xp == NULL | yp == NULL | monpri == NULL |
410 (fname == NULL & fp == TM_GETFILE))
411 returnErr(TM_E_ILLEGAL);
412 /* set defaults */
413 if (gamval < MINGAM) gamval = DEFGAM;
414 if (Lddyn < MINLDDYN) Lddyn = DEFLDDYN;
415 if (Ldmax < MINLDMAX) Ldmax = DEFLDMAX;
416 if (flags & TM_F_BW) monpri = stdprims;
417 #ifdef PCOND
418 /* check for pcond run */
419 if (fp == TM_GETFILE && flags & TM_F_UNIMPL)
420 return( dopcond(psp, xp, yp, flags,
421 monpri, gamval, Lddyn, Ldmax, fname) );
422 #endif
423 /* initialize tone mapping */
424 if (tmInit(flags, monpri, gamval) == NULL)
425 returnErr(TM_E_NOMEM);
426 /* load & convert picture */
427 err = tmLoadPicture(&lp, (flags&TM_F_BW) ? TM_NOCHROMP : &cp,
428 xp, yp, fname, fp);
429 if (err != TM_E_OK) {
430 tmDone(NULL);
431 return(err);
432 }
433 /* allocate space for result */
434 if (flags & TM_F_BW) {
435 *psp = (BYTE *)malloc(sizeof(BYTE) * *xp * *yp);
436 if (*psp == NULL) {
437 free((MEM_PTR)lp);
438 tmDone(NULL);
439 returnErr(TM_E_NOMEM);
440 }
441 cp = TM_NOCHROM;
442 } else
443 *psp = cp;
444 /* compute color mapping */
445 err = tmAddHisto(lp, *xp * *yp, 1);
446 if (err != TM_E_OK)
447 goto done;
448 err = tmComputeMapping(gamval, Lddyn, Ldmax);
449 if (err != TM_E_OK)
450 goto done;
451 /* map colors */
452 err = tmMapPixels(*psp, lp, cp, *xp * *yp);
453
454 done: /* clean up */
455 free((MEM_PTR)lp);
456 tmDone(NULL);
457 if (err != TM_E_OK) { /* free memory on error */
458 free((MEM_PTR)*psp);
459 *psp = NULL;
460 returnErr(err);
461 }
462 returnOK;
463 }
464
465
466 static void
467 colrNewSpace(tms) /* color space changed for tone mapping */
468 register struct tmStruct *tms;
469 {
470 register COLRDATA *cd;
471 double d;
472
473 cd = (COLRDATA *)tms->pd[colrReg];
474 cd->clfb[RED] = 256.*tms->clf[RED] + .5;
475 cd->clfb[GRN] = 256.*tms->clf[GRN] + .5;
476 cd->clfb[BLU] = 256.*tms->clf[BLU] + .5;
477 cd->clfb[EXP] = COLXS;
478 d = TM_BRTSCALE*log(tms->inpsf);
479 cd->inpsfb = d<0. ? d-.5 : d+.5;
480 }
481
482
483 static MEM_PTR
484 colrInit(tms) /* initialize private data for tone mapping */
485 register struct tmStruct *tms;
486 {
487 register COLRDATA *cd;
488 register int i;
489 /* allocate our data */
490 cd = (COLRDATA *)malloc(sizeof(COLRDATA));
491 if (cd == NULL)
492 return(NULL);
493 tms->pd[colrReg] = (MEM_PTR)cd;
494 /* compute gamma table */
495 for (i = GAMTSZ; i--; )
496 cd->gamb[i] = 256.*pow((i+.5)/GAMTSZ, 1./tms->mongam);
497 /* compute color and scale factors */
498 colrNewSpace(tms);
499 return((MEM_PTR)cd);
500 }