18 |
|
|
19 |
|
double gamcor = 2.2; /* gamma correction value */ |
20 |
|
|
21 |
< |
static void quiterr(const char *err); |
22 |
< |
static void tmap2bmp(char *fnin, char *fnout, char *expec, |
21 |
> |
char *info = ""; /* information header string */ |
22 |
> |
int infolen = 0; /* information header length */ |
23 |
> |
|
24 |
> |
extern void quiterr(const char *err); |
25 |
> |
extern void addBMPcspace(RGBPRIMP pp, double gamma); |
26 |
> |
extern void tmap2bmp(char *fnin, char *fnout, char *expec, |
27 |
|
RGBPRIMP monpri, double gamval); |
28 |
< |
static void rad2bmp(FILE *rfp, BMPWriter *bwr, int inv, RGBPRIMP monpri); |
29 |
< |
static void bmp2rad(BMPReader *brd, FILE *rfp, int inv); |
28 |
> |
extern void rad2bmp(FILE *rfp, BMPWriter *bwr, int inv, RGBPRIMP monpri); |
29 |
> |
extern void bmp2rad(BMPReader *brd, FILE *rfp, int inv); |
30 |
> |
extern void info2rad(char *infs, int len, FILE *fout); |
31 |
> |
extern char *growInfo(int n); |
32 |
> |
extern gethfunc headline; |
33 |
|
|
34 |
< |
static RGBPRIMP rgbinp = stdprims; /* RGB input primitives */ |
35 |
< |
static RGBPRIMS myinprims; /* custom primitives holder */ |
34 |
> |
#define add2info(s) strcpy(growInfo(strlen(s)), s) |
35 |
> |
#define clearInfo() growInfo(-infolen) |
36 |
|
|
37 |
< |
static gethfunc headline; |
37 |
> |
RGBPRIMP rgbinp = stdprims; /* RGB input primitives */ |
38 |
> |
RGBPRIMS myinprims; /* custom primitives holder */ |
39 |
|
|
40 |
|
|
41 |
|
int |
101 |
|
|
102 |
|
if (i == argc-2 && strcmp(argv[i+1], "-")) |
103 |
|
outfile = argv[i+1]; |
104 |
< |
/* check for tone-mapping */ |
105 |
< |
if (expec != NULL) { |
104 |
> |
|
105 |
> |
if (expec != NULL) { /* check for tone-mapping */ |
106 |
|
if (reverse) |
107 |
|
goto userr; |
108 |
|
tmap2bmp(inpfile, outfile, expec, rgbp, gamcor); |
109 |
|
return(0); |
110 |
|
} |
103 |
– |
|
104 |
– |
setcolrgam(gamcor); /* set up conversion */ |
105 |
– |
|
111 |
|
if (reverse) { |
112 |
|
BMPReader *rdr; |
113 |
|
/* open BMP file or stream */ |
129 |
|
} |
130 |
|
/* put Radiance header */ |
131 |
|
newheader("RADIANCE", stdout); |
132 |
+ |
info2rad(BMPinfo(rdr->hdr), rdr->hdr->infoSiz, stdout); |
133 |
|
printargs(i, argv, stdout); |
134 |
|
fputformat(COLRFMT, stdout); |
135 |
|
putchar('\n'); |
140 |
|
if (rdr->hdr->yIsDown || inpfile != NULL) |
141 |
|
rs.rt |= YDECR; |
142 |
|
fputsresolu(&rs, stdout); |
143 |
+ |
/* set up conversion */ |
144 |
+ |
setcolrgam(gamcor); |
145 |
|
/* convert file */ |
146 |
< |
bmp2rad(rdr, stdout, !rdr->hdr->yIsDown && inpfile!=NULL); |
146 |
> |
bmp2rad(rdr, stdout, !rdr->hdr->yIsDown & (inpfile!=NULL)); |
147 |
|
/* flush output */ |
148 |
|
BMPcloseInput(rdr); |
149 |
|
if (fflush(stdout) < 0) |
157 |
|
inpfile); |
158 |
|
exit(1); |
159 |
|
} |
160 |
< |
/* get header info. */ |
160 |
> |
/* get/save header info. */ |
161 |
|
if (getheader(stdin, headline, NULL) < 0 || |
162 |
< |
!fgetsresolu(&rs, stdin)) |
162 |
> |
!fgetsresolu(&rs, stdin)) |
163 |
|
quiterr("bad Radiance picture format"); |
164 |
< |
/* initialize BMP header */ |
164 |
> |
/* record color space */ |
165 |
> |
addBMPcspace(rgbp, gamcor); |
166 |
> |
/* open output/write BMP header */ |
167 |
|
if (rgbp == NULL) { |
168 |
|
hdr = BMPmappedHeader(scanlen(&rs), |
169 |
< |
numscans(&rs), 0, 256); |
169 |
> |
numscans(&rs), infolen+1, 256); |
170 |
|
/* |
171 |
|
if (outfile != NULL) |
172 |
|
hdr->compr = BI_RLE8; |
173 |
|
*/ |
174 |
|
} else |
175 |
|
hdr = BMPtruecolorHeader(scanlen(&rs), |
176 |
< |
numscans(&rs), 0); |
176 |
> |
numscans(&rs), infolen+1); |
177 |
|
if (hdr == NULL) |
178 |
< |
quiterr("cannot initialize BMP header"); |
178 |
> |
quiterr("cannot create BMP output"); |
179 |
> |
/* copy info to BMP header */ |
180 |
> |
strcpy(BMPinfo(hdr), info); |
181 |
> |
clearInfo(); |
182 |
|
/* set up output direction */ |
183 |
|
hdr->yIsDown = ((outfile == NULL) | (hdr->compr == BI_RLE8)); |
184 |
|
/* open BMP output */ |
188 |
|
wtr = BMPopenOutputStream(stdout, hdr); |
189 |
|
if (wtr == NULL) |
190 |
|
quiterr("cannot allocate writer structure"); |
191 |
+ |
/* set up conversion */ |
192 |
+ |
setcolrgam(gamcor); |
193 |
|
/* convert file */ |
194 |
|
rad2bmp(stdin, wtr, !hdr->yIsDown, rgbp); |
195 |
|
/* flush output */ |
209 |
|
} |
210 |
|
|
211 |
|
/* print message and exit */ |
212 |
< |
static void |
212 |
> |
void |
213 |
|
quiterr(const char *err) |
214 |
|
{ |
215 |
|
if (err != NULL) { |
219 |
|
exit(0); |
220 |
|
} |
221 |
|
|
222 |
+ |
/* grow (or shrink) saved info header string */ |
223 |
+ |
char * |
224 |
+ |
growInfo(int n) |
225 |
+ |
{ |
226 |
+ |
char *ns = NULL; |
227 |
+ |
|
228 |
+ |
if (infolen + n <= 0) { |
229 |
+ |
if (info) free(info); |
230 |
+ |
info = ""; |
231 |
+ |
infolen = 0; |
232 |
+ |
return(NULL); |
233 |
+ |
} |
234 |
+ |
if (infolen) |
235 |
+ |
info = (char *)realloc(info, infolen+n+1); |
236 |
+ |
else |
237 |
+ |
info = (char *)malloc(n+1); |
238 |
+ |
|
239 |
+ |
if (info == NULL) |
240 |
+ |
quiterr("out of memory in growInfo()"); |
241 |
+ |
|
242 |
+ |
if (n > 0) memset(ns = info+infolen, 0, n+1); |
243 |
+ |
|
244 |
+ |
infolen += n; |
245 |
+ |
return(ns); |
246 |
+ |
} |
247 |
+ |
|
248 |
|
/* process header line (don't echo) */ |
249 |
< |
static int |
249 |
> |
int |
250 |
|
headline(char *s, void *p) |
251 |
|
{ |
252 |
|
char fmt[MAXFMTLEN]; |
253 |
|
|
254 |
+ |
if (isheadid(s)) /* skip header magic ID */ |
255 |
+ |
return(0); |
256 |
|
if (formatval(fmt, s)) { /* check if format string */ |
257 |
|
if (!strcmp(fmt,COLRFMT)) |
258 |
|
return(0); |
269 |
|
rgbinp = myinprims; |
270 |
|
return(0); |
271 |
|
} |
272 |
+ |
if (isexpos(s)) |
273 |
+ |
return(0); /* ignore this on input */ |
274 |
+ |
if (!strncmp(s, "GAMMA=", 6)) |
275 |
+ |
return(0); /* should not be here! */ |
276 |
|
if (isncomp(s)) { |
277 |
|
NCSAMP = ncompval(s); |
278 |
|
return(0); |
281 |
|
wlsplitval(WLPART, s); |
282 |
|
return(0); |
283 |
|
} |
284 |
< |
/* should I grok colcorr also? */ |
285 |
< |
return(0); |
284 |
> |
add2info(s); /* else save info string */ |
285 |
> |
return(1); |
286 |
|
} |
287 |
|
|
288 |
+ |
/* add BMP output color space to info string */ |
289 |
+ |
void |
290 |
+ |
addBMPcspace(RGBPRIMP pp, double gamma) |
291 |
+ |
{ |
292 |
+ |
char ibuf[128]; |
293 |
|
|
294 |
+ |
if (pp != NULL) { |
295 |
+ |
sprintf(ibuf, |
296 |
+ |
"%s %.4f %.4f %.4f %.4f %.4f %.4f %.4f %.4f\n", |
297 |
+ |
PRIMARYSTR, |
298 |
+ |
pp[RED][CIEX],pp[RED][CIEY], |
299 |
+ |
pp[GRN][CIEX],pp[GRN][CIEY], |
300 |
+ |
pp[BLU][CIEX],pp[BLU][CIEY], |
301 |
+ |
pp[WHT][CIEX],pp[WHT][CIEY]); |
302 |
+ |
add2info(ibuf); |
303 |
+ |
} |
304 |
+ |
sprintf(ibuf, "GAMMA=%.2f\n", gamma); |
305 |
+ |
add2info(ibuf); |
306 |
+ |
} |
307 |
+ |
|
308 |
+ |
/* write out Radiance header from BMP info string */ |
309 |
+ |
void |
310 |
+ |
info2rad(char *infs, int len, FILE *fout) |
311 |
+ |
{ |
312 |
+ |
char *cp; |
313 |
+ |
/* must fit metadata profile */ |
314 |
+ |
if (len < 3 || infs[0] == '\n' || |
315 |
+ |
infs[--len] != '\0' || infs[len-1] != '\n') |
316 |
+ |
return; /* not what we expected */ |
317 |
+ |
if (strlen(infs) < len || strstr(infs, "\n\n") != NULL) |
318 |
+ |
return; /* also not cool */ |
319 |
+ |
/* check for gamma */ |
320 |
+ |
if ((cp = strstr(infs, "GAMMA=")) != NULL) { |
321 |
+ |
/* copy what came before */ |
322 |
+ |
fwrite(infs, cp-infs, 1, fout); |
323 |
+ |
cp += 6; |
324 |
+ |
gamcor = atof(cp); /* record setting */ |
325 |
+ |
while (*cp++ != '\n') |
326 |
+ |
; |
327 |
+ |
len -= cp - infs; |
328 |
+ |
infs = cp; /* & elide from output */ |
329 |
+ |
} |
330 |
+ |
fputs(infs, fout); /* copy the remainder */ |
331 |
+ |
} |
332 |
+ |
|
333 |
|
/* convert Radiance picture to BMP */ |
334 |
< |
static void |
334 |
> |
void |
335 |
|
rad2bmp(FILE *rfp, BMPWriter *bwr, int inv, RGBPRIMP monpri) |
336 |
|
{ |
337 |
|
int usexfm = 0; |
345 |
|
if (scanin == NULL) |
346 |
|
quiterr("out of memory in rad2bmp"); |
347 |
|
/* set up color conversion */ |
348 |
< |
usexfm = (monpri != NULL ? rgbinp != monpri : |
349 |
< |
rgbinp != TM_XYZPRIM && rgbinp != stdprims); |
348 |
> |
usexfm = (monpri != NULL) ? (rgbinp != monpri) : |
349 |
> |
((rgbinp != TM_XYZPRIM) & (rgbinp != stdprims)); |
350 |
|
if (usexfm) { |
351 |
|
RGBPRIMP destpri = monpri != NULL ? monpri : stdprims; |
352 |
|
double expcomp = pow(2.0, (double)bradj); |
398 |
|
if (x != BIR_OK) |
399 |
|
quiterr(BMPerrorMessage(x)); |
400 |
|
} |
401 |
< |
/* free scanline */ |
311 |
< |
free((void *)scanin); |
401 |
> |
free(scanin); /* free scanline */ |
402 |
|
} |
403 |
|
|
404 |
|
/* convert BMP file to Radiance */ |
405 |
< |
static void |
405 |
> |
void |
406 |
|
bmp2rad(BMPReader *brd, FILE *rfp, int inv) |
407 |
|
{ |
408 |
|
COLR *scanout; |
437 |
|
if (fwritecolrs(scanout, brd->hdr->width, rfp) < 0) |
438 |
|
quiterr("error writing Radiance picture"); |
439 |
|
} |
440 |
< |
/* clean up */ |
351 |
< |
free((void *)scanout); |
440 |
> |
free(scanout); /* clean up */ |
441 |
|
} |
442 |
|
|
443 |
|
/* Tone-map and convert Radiance picture */ |
444 |
< |
static void |
444 |
> |
void |
445 |
|
tmap2bmp(char *fnin, char *fnout, char *expec, RGBPRIMP monpri, double gamval) |
446 |
|
{ |
447 |
|
int tmflags; |
476 |
|
if (tmMapPicture(&pa, &xr, &yr, tmflags, monpri, gamval, |
477 |
|
0., 0., fnin, fp) != TM_E_OK) |
478 |
|
exit(1); |
479 |
+ |
/* try to retrieve info */ |
480 |
+ |
if (fseek(fp, 0L, SEEK_SET) == 0) |
481 |
+ |
getheader(fp, headline, NULL); |
482 |
+ |
/* add output color space */ |
483 |
+ |
addBMPcspace(monpri, gamval); |
484 |
|
/* initialize BMP header */ |
485 |
|
if (tmflags & TM_F_BW) { |
486 |
< |
hdr = BMPmappedHeader(xr, yr, 0, 256); |
486 |
> |
hdr = BMPmappedHeader(xr, yr, infolen+1, 256); |
487 |
|
if (fnout != NULL) |
488 |
|
hdr->compr = BI_RLE8; |
489 |
|
} else |
490 |
< |
hdr = BMPtruecolorHeader(xr, yr, 0); |
490 |
> |
hdr = BMPtruecolorHeader(xr, yr, infolen+1); |
491 |
|
if (hdr == NULL) |
492 |
|
quiterr("cannot initialize BMP header"); |
493 |
+ |
|
494 |
+ |
strcpy(BMPinfo(hdr), info); /* copy info if any */ |
495 |
+ |
clearInfo(); |
496 |
|
/* open BMP output */ |
497 |
|
if (fnout != NULL) |
498 |
|
wtr = BMPopenOutputFile(fnout, hdr); |
505 |
|
uby8 *scn = pa + xr*((tmflags & TM_F_BW) ? 1 : 3)* |
506 |
|
(yr-1 - wtr->yscan); |
507 |
|
if (tmflags & TM_F_BW) |
508 |
< |
memcpy((void *)wtr->scanline, (void *)scn, xr); |
508 |
> |
memcpy(wtr->scanline, scn, xr); |
509 |
|
else |
510 |
|
for (i = xr; i--; ) { |
511 |
|
wtr->scanline[3*i] = scn[3*i+BLU]; |
521 |
|
/* clean up */ |
522 |
|
if (fnin != NULL) |
523 |
|
fclose(fp); |
524 |
< |
free((void *)pa); |
524 |
> |
free(pa); |
525 |
|
BMPcloseOutput(wtr); |
526 |
|
} |