ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/px/ra_bmp.c
Revision: 2.7
Committed: Fri Apr 30 21:16:58 2004 UTC (20 years ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.6: +4 -7 lines
Log Message:
Fixed inconsistent behavior with inverted Radiance pictures

File Contents

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