ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/px/ra_bmp.c
Revision: 2.15
Committed: Tue Sep 10 20:24:42 2024 UTC (6 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 2.14: +12 -2 lines
Log Message:
feat(ra_bmp,ra_rgbe,ximage): Added quick conversion of spectral inputs to RGB

File Contents

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