ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/px/ra_bmp.c
Revision: 2.9
Committed: Thu Sep 23 18:00:54 2004 UTC (19 years, 7 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.8: +68 -12 lines
Log Message:
Enabled -p option (display primaries) and XYZE reading to ra_bmp

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: ra_bmp.c,v 2.8 2004/07/20 03:08:42 greg Exp $";
3 #endif
4 /*
5 * program to convert between RADIANCE and Windows BMP file
6 */
7
8 #include <stdio.h>
9 #include <math.h>
10 #include <string.h>
11
12 #include "platform.h"
13 #include "color.h"
14 #include "tonemap.h"
15 #include "resolu.h"
16 #include "bmpfile.h"
17
18 int bradj = 0; /* brightness adjustment */
19
20 double gamcor = 2.2; /* gamma correction value */
21
22 char *progname;
23
24 static void quiterr(const char *err);
25 static void tmap2bmp(char *fnin, char *fnout, char *expec,
26 RGBPRIMP monpri, double gamval);
27 static void rad2bmp(FILE *rfp, BMPWriter *bwr, int inv, RGBPRIMP monpri);
28 static void bmp2rad(BMPReader *brd, FILE *rfp, int inv);
29
30 static RGBPRIMP rgbinp = stdprims; /* RGB input primitives */
31 static RGBPRIMS myinprims; /* custom primitives holder */
32
33 static gethfunc headline;
34
35
36 int
37 main(int argc, char *argv[])
38 {
39 char *inpfile=NULL, *outfile=NULL;
40 char *expec = NULL;
41 int reverse = 0;
42 RGBPRIMP rgbp = stdprims;
43 RGBPRIMS myprims;
44 RESOLU rs;
45 int i;
46
47 progname = argv[0];
48
49 for (i = 1; i < argc; i++)
50 if (argv[i][0] == '-' && argv[i][1])
51 switch (argv[i][1]) {
52 case 'b':
53 rgbp = NULL;
54 break;
55 case 'g':
56 gamcor = atof(argv[++i]);
57 break;
58 case 'e':
59 if (argv[i+1][0] != '+' && argv[i+1][0] != '-')
60 expec = argv[++i];
61 else
62 bradj = atoi(argv[++i]);
63 break;
64 case 'p':
65 if (argc-i < 9)
66 goto userr;
67 myprims[RED][CIEX] = atof(argv[++i]);
68 myprims[RED][CIEY] = atof(argv[++i]);
69 myprims[GRN][CIEX] = atof(argv[++i]);
70 myprims[GRN][CIEY] = atof(argv[++i]);
71 myprims[BLU][CIEX] = atof(argv[++i]);
72 myprims[BLU][CIEY] = atof(argv[++i]);
73 myprims[WHT][CIEX] = atof(argv[++i]);
74 myprims[WHT][CIEY] = atof(argv[++i]);
75 if (rgbp == stdprims)
76 rgbp = myprims;
77 break;
78 case 'r':
79 reverse = !reverse;
80 break;
81 default:
82 goto userr;
83 }
84 else
85 break;
86
87 if (i < argc-2)
88 goto userr;
89
90 SET_FILE_BINARY(stdin);
91 SET_FILE_BINARY(stdout);
92 SET_DEFAULT_BINARY();
93
94 if (i <= argc-1 && strcmp(argv[i], "-"))
95 inpfile = argv[i];
96
97 if (i == argc-2 && strcmp(argv[i+1], "-"))
98 outfile = argv[i+1];
99 /* check for tone-mapping */
100 if (expec != NULL) {
101 if (reverse)
102 goto userr;
103 tmap2bmp(inpfile, outfile, expec, rgbp, gamcor);
104 return(0);
105 }
106
107 setcolrgam(gamcor); /* set up conversion */
108
109 if (reverse) {
110 BMPReader *rdr;
111 /* open BMP file or stream */
112 if (inpfile != NULL)
113 rdr = BMPopenInputFile(inpfile);
114 else
115 rdr = BMPopenInputStream(stdin);
116
117 if (rdr == NULL) {
118 fprintf(stderr, "%s: cannot open or recognize BMP\n",
119 inpfile != NULL ? inpfile : "<stdin>");
120 exit(1);
121 }
122 /* open Radiance output */
123 if (outfile != NULL && freopen(outfile, "w", stdout) == NULL) {
124 fprintf(stderr, "%s: cannot open for output\n",
125 outfile);
126 exit(1);
127 }
128 /* put Radiance header */
129 newheader("RADIANCE", stdout);
130 printargs(i, argv, stdout);
131 fputformat(COLRFMT, stdout);
132 putchar('\n');
133 rs.xr = rdr->hdr->width;
134 rs.yr = rdr->hdr->height;
135 rs.rt = YMAJOR;
136 /* write scans downward if we can */
137 if (rdr->hdr->yIsDown || inpfile != NULL)
138 rs.rt |= YDECR;
139 fputsresolu(&rs, stdout);
140 /* convert file */
141 bmp2rad(rdr, stdout, !rdr->hdr->yIsDown && inpfile!=NULL);
142 /* flush output */
143 BMPcloseInput(rdr);
144 if (fflush(stdout) < 0)
145 quiterr("error writing Radiance output");
146 } else {
147 BMPHeader *hdr;
148 BMPWriter *wtr;
149 /* open Radiance input */
150 if (inpfile != NULL && freopen(inpfile, "r", stdin) == NULL) {
151 fprintf(stderr, "%s: cannot open input file\n",
152 inpfile);
153 exit(1);
154 }
155 /* get header info. */
156 if (getheader(stdin, headline, NULL) < 0 ||
157 !fgetsresolu(&rs, stdin))
158 quiterr("bad Radiance picture format");
159 /* initialize BMP header */
160 if (rgbp == NULL) {
161 hdr = BMPmappedHeader(scanlen(&rs),
162 numscans(&rs), 0, 256);
163 if (outfile != NULL)
164 hdr->compr = BI_RLE8;
165 } else
166 hdr = BMPtruecolorHeader(scanlen(&rs),
167 numscans(&rs), 0);
168 if (hdr == NULL)
169 quiterr("cannot initialize BMP header");
170 /* set up output direction */
171 hdr->yIsDown = ((outfile == NULL) | (hdr->compr == BI_RLE8));
172 /* open BMP output */
173 if (outfile != NULL)
174 wtr = BMPopenOutputFile(outfile, hdr);
175 else
176 wtr = BMPopenOutputStream(stdout, hdr);
177 if (wtr == NULL)
178 quiterr("cannot allocate writer structure");
179 /* convert file */
180 rad2bmp(stdin, wtr, !hdr->yIsDown, rgbp);
181 /* flush output */
182 if (fflush((FILE *)wtr->c_data) < 0)
183 quiterr("error writing BMP output");
184 BMPcloseOutput(wtr);
185 }
186 return(0); /* success */
187 userr:
188 fprintf(stderr,
189 "Usage: %s [-b][-g gamma][-e spec][-p xr yr xg yg xb yb xw yw] [input|- [output]]\n",
190 progname);
191 fprintf(stderr,
192 " or: %s -r [-g gamma][-e +/-stops] [input|- [output]]\n",
193 progname);
194 return(1);
195 }
196
197 /* print message and exit */
198 static void
199 quiterr(const char *err)
200 {
201 if (err != NULL) {
202 fprintf(stderr, "%s: %s\n", progname, err);
203 exit(1);
204 }
205 exit(0);
206 }
207
208 /* process header line (don't echo) */
209 static int
210 headline(char *s, void *p)
211 {
212 char fmt[32];
213
214 if (formatval(fmt, s)) { /* check if format string */
215 if (!strcmp(fmt,COLRFMT))
216 return(0);
217 if (!strcmp(fmt,CIEFMT)) {
218 rgbinp = TM_XYZPRIM;
219 return(0);
220 }
221 return(-1);
222 }
223 if (isprims(s)) { /* get input primaries */
224 primsval(myinprims, s);
225 rgbinp = myinprims;
226 return(0);
227 }
228 /* should I grok colcorr also? */
229 return(0);
230 }
231
232
233 /* convert Radiance picture to BMP */
234 static void
235 rad2bmp(FILE *rfp, BMPWriter *bwr, int inv, RGBPRIMP monpri)
236 {
237 int usexfm = 0;
238 COLORMAT xfm;
239 COLR *scanin;
240 COLOR cval;
241 int y, yend, ystp;
242 int x;
243 /* allocate scanline */
244 scanin = (COLR *)malloc(bwr->hdr->width*sizeof(COLR));
245 if (scanin == NULL)
246 quiterr("out of memory in rad2bmp");
247 /* set up color conversion */
248 usexfm = (monpri != NULL ? rgbinp != monpri :
249 rgbinp != TM_XYZPRIM && rgbinp != stdprims);
250 if (usexfm) {
251 double expcomp = pow(2.0, (double)bradj);
252 if (rgbinp == TM_XYZPRIM)
253 compxyz2rgbWBmat(xfm, monpri);
254 else
255 comprgb2rgbWBmat(xfm, rgbinp, monpri);
256 for (y = 0; y < 3; y++)
257 for (x = 0; x < 3; x++)
258 xfm[y][x] *= expcomp;
259 }
260 /* convert image */
261 if (inv) {
262 y = bwr->hdr->height - 1;
263 ystp = -1; yend = -1;
264 } else {
265 y = 0;
266 ystp = 1; yend = bwr->hdr->height;
267 }
268 /* convert each scanline */
269 for ( ; y != yend; y += ystp) {
270 if (freadcolrs(scanin, bwr->hdr->width, rfp) < 0)
271 quiterr("error reading Radiance picture");
272 if (usexfm)
273 for (x = bwr->hdr->width; x--; ) {
274 colr_color(cval, scanin[x]);
275 colortrans(cval, xfm, cval);
276 setcolr(scanin[x], colval(cval,RED),
277 colval(cval,GRN),
278 colval(cval,BLU));
279 }
280 else if (bradj)
281 shiftcolrs(scanin, bwr->hdr->width, bradj);
282 if (monpri == NULL && rgbinp != TM_XYZPRIM)
283 for (x = bwr->hdr->width; x--; )
284 scanin[x][GRN] = normbright(scanin[x]);
285 colrs_gambs(scanin, bwr->hdr->width);
286 if (monpri == NULL)
287 for (x = bwr->hdr->width; x--; )
288 bwr->scanline[x] = scanin[x][GRN];
289 else
290 for (x = bwr->hdr->width; x--; ) {
291 bwr->scanline[3*x] = scanin[x][BLU];
292 bwr->scanline[3*x+1] = scanin[x][GRN];
293 bwr->scanline[3*x+2] = scanin[x][RED];
294 }
295 bwr->yscan = y;
296 x = BMPwriteScanline(bwr);
297 if (x != BIR_OK)
298 quiterr(BMPerrorMessage(x));
299 }
300 /* free scanline */
301 free((void *)scanin);
302 }
303
304 /* convert BMP file to Radiance */
305 static void
306 bmp2rad(BMPReader *brd, FILE *rfp, int inv)
307 {
308 COLR *scanout;
309 int y, yend, ystp;
310 int x;
311 /* allocate scanline */
312 scanout = (COLR *)malloc(brd->hdr->width*sizeof(COLR));
313 if (scanout == NULL)
314 quiterr("out of memory in bmp2rad");
315 /* convert image */
316 if (inv) {
317 y = brd->hdr->height - 1;
318 ystp = -1; yend = -1;
319 } else {
320 y = 0;
321 ystp = 1; yend = brd->hdr->height;
322 }
323 /* convert each scanline */
324 for ( ; y != yend; y += ystp) {
325 x = BMPseekScanline(y, brd);
326 if (x != BIR_OK)
327 quiterr(BMPerrorMessage(x));
328 for (x = brd->hdr->width; x--; ) {
329 RGBquad rgbq = BMPdecodePixel(x, brd);
330 scanout[x][RED] = rgbq.r;
331 scanout[x][GRN] = rgbq.g;
332 scanout[x][BLU] = rgbq.b;
333 }
334 gambs_colrs(scanout, brd->hdr->width);
335 if (bradj)
336 shiftcolrs(scanout, brd->hdr->width, bradj);
337 if (fwritecolrs(scanout, brd->hdr->width, rfp) < 0)
338 quiterr("error writing Radiance picture");
339 }
340 /* clean up */
341 free((void *)scanout);
342 }
343
344 /* Tone-map and convert Radiance picture */
345 static void
346 tmap2bmp(char *fnin, char *fnout, char *expec, RGBPRIMP monpri, double gamval)
347 {
348 int tmflags;
349 BMPHeader *hdr;
350 BMPWriter *wtr;
351 FILE *fp;
352 int xr, yr;
353 BYTE *pa;
354 int i;
355 /* check tone-mapping spec */
356 i = strlen(expec);
357 if (i && !strncmp(expec, "auto", i))
358 tmflags = TM_F_CAMERA;
359 else if (i && !strncmp(expec, "human", i))
360 tmflags = TM_F_HUMAN & ~TM_F_UNIMPL;
361 else if (i && !strncmp(expec, "linear", i))
362 tmflags = TM_F_LINEAR;
363 else
364 quiterr("illegal exposure specification (auto|human|linear)");
365 if (monpri == NULL) {
366 tmflags |= TM_F_BW;
367 monpri = stdprims;
368 }
369 /* open Radiance input */
370 if (fnin == NULL)
371 fp = stdin;
372 else if ((fp = fopen(fnin, "r")) == NULL) {
373 fprintf(stderr, "%s: cannot open\n", fnin);
374 exit(1);
375 }
376 /* tone-map picture */
377 if (tmMapPicture(&pa, &xr, &yr, tmflags, monpri, gamval,
378 0., 0., fnin, fp) != TM_E_OK)
379 exit(1);
380 /* initialize BMP header */
381 if (tmflags & TM_F_BW) {
382 hdr = BMPmappedHeader(xr, yr, 0, 256);
383 if (fnout != NULL)
384 hdr->compr = BI_RLE8;
385 } else
386 hdr = BMPtruecolorHeader(xr, yr, 0);
387 if (hdr == NULL)
388 quiterr("cannot initialize BMP header");
389 /* open BMP output */
390 if (fnout != NULL)
391 wtr = BMPopenOutputFile(fnout, hdr);
392 else
393 wtr = BMPopenOutputStream(stdout, hdr);
394 if (wtr == NULL)
395 quiterr("cannot allocate writer structure");
396 /* write to BMP file */
397 while (wtr->yscan < yr) {
398 BYTE *scn = pa + xr*((tmflags & TM_F_BW) ? 1 : 3)*
399 (yr-1 - wtr->yscan);
400 if (tmflags & TM_F_BW)
401 memcpy((void *)wtr->scanline, (void *)scn, xr);
402 else
403 for (i = xr; i--; ) {
404 wtr->scanline[3*i] = scn[3*i+BLU];
405 wtr->scanline[3*i+1] = scn[3*i+GRN];
406 wtr->scanline[3*i+2] = scn[3*i+RED];
407 }
408 if ((i = BMPwriteScanline(wtr)) != BIR_OK)
409 quiterr(BMPerrorMessage(i));
410 }
411 /* flush output */
412 if (fflush((FILE *)wtr->c_data) < 0)
413 quiterr("error writing BMP output");
414 /* clean up */
415 if (fnin != NULL)
416 fclose(fp);
417 free((void *)pa);
418 BMPcloseOutput(wtr);
419 }