ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/px/ra_bmp.c
Revision: 2.17
Committed: Sat Jun 7 05:09:46 2025 UTC (2 weeks ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 2.16: +1 -2 lines
Log Message:
refactor: Put some declarations into "paths.h" and included in "platform.h"

File Contents

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