ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/src/px/ra_bmp.c
(Generate patch)

Comparing src/px/ra_bmp.c (file contents):
Revision 2.2 by greg, Sat Mar 27 05:43:37 2004 UTC vs.
Revision 2.20 by greg, Sun Sep 14 17:11:29 2025 UTC

# Line 5 | Line 5 | static const char RCSid[] = "$Id$";
5   *  program to convert between RADIANCE and Windows BMP file
6   */
7  
8 < #include  <stdio.h>
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 */
17 > int             bradj = 0;              /* brightness adjustment */
18  
19 < double  gamcor = 2.2;                   /* gamma correction value */
19 > double          gamcor = 2.2;           /* gamma correction value */
20  
21 < char  *progname;
21 > char            *info = "";             /* information header string */
22 > int             infolen = 0;            /* information header length */
23  
24 < void    quiterr(const char *);
25 < void    rad2bmp(FILE *rfp, BMPWriter *bwr, int inv, int gry);
26 < void    bmp2rad(BMPReader *brd, FILE *rfp, int inv);
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 > 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 + #define add2info(s)     {int _n=strlen(s); memcpy(growInfo(_n), s, _n+1);}
35 + #define clearInfo()     growInfo(-infolen)
36  
37 + RGBPRIMP        rgbinp = stdprims;      /* RGB input primitives */
38 + RGBPRIMS        myinprims;              /* custom primitives holder */
39 +
40 +
41   int
42   main(int argc, char *argv[])
43   {
44 <        char    *inpfile=NULL, *outfile=NULL;
45 <        int     gryflag = 0;
46 <        int     reverse = 0;
47 <        RESOLU  rs;
48 <        int     i;
44 >        char            *inpfile=NULL, *outfile=NULL;
45 >        char            *expec = NULL;
46 >        int             reverse = 0;
47 >        RGBPRIMP        rgbp = stdprims;
48 >        RGBPRIMS        myprims;
49 >        RESOLU          rs;
50 >        int             i;
51          
52 <        progname = argv[0];
52 >        fixargv0(argv[0]);              /* assigns progname */
53  
54          for (i = 1; i < argc; i++)
55 <                if (argv[i][0] == '-')
55 >                if (argv[i][0] == '-' && argv[i][1])
56                          switch (argv[i][1]) {
57                          case 'b':
58 <                                gryflag = 1;
58 >                                rgbp = NULL;
59                                  break;
60                          case 'g':
61                                  gamcor = atof(argv[++i]);
62                                  break;
63                          case 'e':
64                                  if (argv[i+1][0] != '+' && argv[i+1][0] != '-')
65 +                                        expec = argv[++i];
66 +                                else
67 +                                        bradj = atoi(argv[++i]);
68 +                                break;
69 +                        case 'p':
70 +                                if (argc-i < 9)
71                                          goto userr;
72 <                                bradj = atoi(argv[++i]);
72 >                                myprims[RED][CIEX] = atof(argv[++i]);
73 >                                myprims[RED][CIEY] = atof(argv[++i]);
74 >                                myprims[GRN][CIEX] = atof(argv[++i]);
75 >                                myprims[GRN][CIEY] = atof(argv[++i]);
76 >                                myprims[BLU][CIEX] = atof(argv[++i]);
77 >                                myprims[BLU][CIEY] = atof(argv[++i]);
78 >                                myprims[WHT][CIEX] = atof(argv[++i]);
79 >                                myprims[WHT][CIEY] = atof(argv[++i]);
80 >                                if (rgbp == stdprims)
81 >                                        rgbp = myprims;
82                                  break;
83                          case 'r':
84                                  reverse = !reverse;
85                                  break;
53                        case '\0':
54                                break;
86                          default:
87                                  goto userr;
88                          }
# Line 71 | Line 102 | main(int argc, char *argv[])
102          if (i == argc-2 && strcmp(argv[i+1], "-"))
103                  outfile = argv[i+1];
104  
105 <        setcolrgam(gamcor);             /* set up conversion */
106 <
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 >        }
111          if (reverse) {
112                  BMPReader       *rdr;
113                                          /* open BMP file or stream */
# Line 94 | Line 129 | main(int argc, char *argv[])
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');
# Line 104 | Line 140 | main(int argc, char *argv[])
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)
# Line 119 | Line 157 | main(int argc, char *argv[])
157                                          inpfile);
158                          exit(1);
159                  }
160 <                                        /* get header info. */
161 <                if (checkheader(stdin, COLRFMT, NULL) < 0 ||
162 <                                !fgetsresolu(&rs, stdin))
160 >                                        /* get/save header info. */
161 >                if (getheader(stdin, headline, NULL) < 0 ||
162 >                                        !fgetsresolu(&rs, stdin))
163                          quiterr("bad Radiance picture format");
164 <                                        /* initialize BMP header */
165 <                if (gryflag) {
166 <                        hdr = BMPmappedHeader(numscans(&rs),
167 <                                                scanlen(&rs), 0, 256);
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), infolen+1, 256);
170 >                        /*
171                          if (outfile != NULL)
172                                  hdr->compr = BI_RLE8;
173 +                        */
174                  } else
175 <                        hdr = BMPtruecolorHeader(numscans(&rs),
176 <                                                scanlen(&rs), 0);
175 >                        hdr = BMPtruecolorHeader(scanlen(&rs),
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 = (rs.rt & YDECR) &&
139 <                                (outfile == NULL | hdr->compr == BI_RLE8);
183 >                hdr->yIsDown = ((outfile == NULL) | (hdr->compr == BI_RLE8));
184                                          /* open BMP output */
185                  if (outfile != NULL)
186                          wtr = BMPopenOutputFile(outfile, hdr);
# Line 144 | Line 188 | main(int argc, char *argv[])
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 && (rs.rt&YDECR), gryflag);
194 >                rad2bmp(stdin, wtr, !hdr->yIsDown, rgbp);
195                                          /* flush output */
196                  if (fflush((FILE *)wtr->c_data) < 0)
197                          quiterr("error writing BMP output");
198                  BMPcloseOutput(wtr);
199          }
200 <        exit(0);                        /* success */
200 >        return(0);                      /* success */
201   userr:
202          fprintf(stderr,
203 <                "Usage: %s [-r][-g gamma][-e +/-stops] [input [output]]\n",
203 > "Usage: %s [-b][-g gamma][-e spec][-p xr yr xg yg xb yb xw yw] [input|- [output]]\n",
204                          progname);
205 <        exit(1);
206 <        return(1);      /* gratis return */
205 >        fprintf(stderr,
206 >                "   or: %s -r [-g gamma][-e +/-stops] [input|- [output]]\n",
207 >                        progname);
208 >        return(1);
209   }
210  
211   /* print message and exit */
# Line 171 | Line 219 | quiterr(const char *err)
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 + 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);
259 +                if (!strcmp(fmt,CIEFMT)) {
260 +                        rgbinp = TM_XYZPRIM;
261 +                        return(0);
262 +                }
263 +                if (!strcmp(fmt,SPECFMT))
264 +                        return(0);
265 +                return(-1);
266 +        }
267 +        if (isprims(s)) {               /* get input primaries */
268 +                primsval(myinprims, s);
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);
279 +        }
280 +        if (iswlsplit(s)) {
281 +                wlsplitval(WLPART, s);
282 +                return(0);
283 +        }
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[196];
293 +        char    *cp = ibuf;
294 +
295 +        sprintf(cp, "GAMMA=%.2f\n", gamma);
296 +        cp += strlen(cp);
297 +        if (pp != NULL) {
298 +                sprintf(cp,
299 +                        "%s %.4f %.4f %.4f %.4f %.4f %.4f %.4f %.4f\n",
300 +                                PRIMARYSTR,
301 +                                pp[RED][CIEX],pp[RED][CIEY],
302 +                                pp[GRN][CIEX],pp[GRN][CIEY],
303 +                                pp[BLU][CIEX],pp[BLU][CIEY],
304 +                                pp[WHT][CIEX],pp[WHT][CIEY]);
305 +                /* cp += strlen(cp); */
306 +        }
307 +        add2info(ibuf);
308 + }
309 +
310 + /* write out Radiance header from BMP info string */
311 + void
312 + info2rad(char *infs, int len, FILE *fout)
313 + {
314 +        char    *cp;
315 +                                        /* must fit metadata profile */
316 +        if (len < 3 || infs[0] == '\n' ||
317 +                        infs[--len] != '\0' || infs[len-1] != '\n')
318 +                return;                 /* not what we expected */
319 +        if (strlen(infs) < len || strstr(infs, "\n\n") != NULL)
320 +                return;                 /* also not cool */
321 +                                        /* check for gamma */
322 +        if ((cp = strstr(infs, "GAMMA=")) != NULL) {
323 +                                        /* copy what came before */
324 +                fwrite(infs, 1, cp-infs, fout);
325 +                cp += 6;
326 +                gamcor = atof(cp);      /* record setting */
327 +                while (*cp++ != '\n')
328 +                        ;
329 +                len -= cp - infs;
330 +                infs = cp;              /* & elide from output */
331 +        }
332 +        fputs(infs, fout);              /* copy the remainder */
333 + }
334 +
335   /* convert Radiance picture to BMP */
336   void
337 < rad2bmp(FILE *rfp, BMPWriter *bwr, int inv, int gry)
337 > rad2bmp(FILE *rfp, BMPWriter *bwr, int inv, RGBPRIMP monpri)
338   {
339 +        int     usexfm = 0;
340 +        COLORMAT        xfm;
341          COLR    *scanin;
342 +        COLOR   cval;
343          int     y, yend, ystp;
344          int     x;
345                                                  /* allocate scanline */
346          scanin = (COLR *)malloc(bwr->hdr->width*sizeof(COLR));
347          if (scanin == NULL)
348                  quiterr("out of memory in rad2bmp");
349 +                                                /* set up color conversion */
350 +        usexfm = (monpri != NULL) ? (rgbinp != monpri) :
351 +                        ((rgbinp != TM_XYZPRIM) & (rgbinp != stdprims));
352 +        if (usexfm) {
353 +                RGBPRIMP        destpri = monpri != NULL ? monpri : stdprims;
354 +                double          expcomp = pow(2.0, (double)bradj);
355 +                if (rgbinp == TM_XYZPRIM)
356 +                        compxyz2rgbWBmat(xfm, destpri);
357 +                else
358 +                        comprgb2rgbWBmat(xfm, rgbinp, destpri);
359 +                for (y = 0; y < 3; y++)
360 +                        for (x = 0; x < 3; x++)
361 +                                xfm[y][x] *= expcomp;
362 +        }
363                                                  /* convert image */
364          if (inv) {
365                  y = bwr->hdr->height - 1;
# Line 192 | Line 370 | rad2bmp(FILE *rfp, BMPWriter *bwr, int inv, int gry)
370          }
371                                                  /* convert each scanline */
372          for ( ; y != yend; y += ystp) {
373 <                if (freadcolrs(scanin, bwr->hdr->width, rfp) < 0)
373 >                if (fread2colrs(scanin, bwr->hdr->width, rfp, NCSAMP, WLPART) < 0)
374                          quiterr("error reading Radiance picture");
375 <                if (bradj)
375 >                if (usexfm)
376 >                        for (x = bwr->hdr->width; x--; ) {
377 >                                colr_color(cval, scanin[x]);
378 >                                colortrans(cval, xfm, cval);
379 >                                setcolr(scanin[x], colval(cval,RED),
380 >                                                colval(cval,GRN),
381 >                                                colval(cval,BLU));
382 >                        }
383 >                else if (bradj)
384                          shiftcolrs(scanin, bwr->hdr->width, bradj);
385 <                for (x = gry ? bwr->hdr->width : 0; x--; )
386 <                        scanin[x][GRN] = normbright(scanin[x]);
385 >                if ((monpri == NULL) & (rgbinp != TM_XYZPRIM))
386 >                        for (x = bwr->hdr->width; x--; )
387 >                                scanin[x][GRN] = normbright(scanin[x]);
388                  colrs_gambs(scanin, bwr->hdr->width);
389 <                if (gry)
389 >                if (monpri == NULL)
390                          for (x = bwr->hdr->width; x--; )
391                                  bwr->scanline[x] = scanin[x][GRN];
392                  else
# Line 213 | Line 400 | rad2bmp(FILE *rfp, BMPWriter *bwr, int inv, int gry)
400                  if (x != BIR_OK)
401                          quiterr(BMPerrorMessage(x));
402          }
403 <                                                /* free scanline */
217 <        free((void *)scanin);
403 >        free(scanin);                           /* free scanline */
404   }
405  
406   /* convert BMP file to Radiance */
# Line 253 | Line 439 | bmp2rad(BMPReader *brd, FILE *rfp, int inv)
439                  if (fwritecolrs(scanout, brd->hdr->width, rfp) < 0)
440                          quiterr("error writing Radiance picture");
441          }
442 <                                                /* clean up */
443 <        free((void *)scanout);
442 >        free(scanout);                          /* clean up */
443 > }
444 >
445 > /* Tone-map and convert Radiance picture */
446 > void
447 > tmap2bmp(char *fnin, char *fnout, char *expec, RGBPRIMP monpri, double gamval)
448 > {
449 >        int             tmflags;
450 >        BMPHeader       *hdr;
451 >        BMPWriter       *wtr;
452 >        FILE            *fp;
453 >        int             xr, yr;
454 >        uby8            *pa;
455 >        int             i;
456 >                                        /* check tone-mapping spec */
457 >        i = strlen(expec);
458 >        if (i && !strncmp(expec, "auto", i))
459 >                tmflags = TM_F_CAMERA;
460 >        else if (i && !strncmp(expec, "human", i))
461 >                tmflags = TM_F_HUMAN & ~TM_F_UNIMPL;
462 >        else if (i && !strncmp(expec, "linear", i))
463 >                tmflags = TM_F_LINEAR;
464 >        else
465 >                quiterr("illegal exposure specification (auto|human|linear)");
466 >
467 >        tmflags |= (monpri == NULL)*TM_F_BW;
468 >                                        /* open Radiance input */
469 >        if (fnin == NULL)
470 >                fp = stdin;
471 >        else if ((fp = fopen(fnin, "r")) == NULL) {
472 >                fprintf(stderr, "%s: cannot open\n", fnin);
473 >                exit(1);
474 >        }
475 >                                        /* tone-map picture */
476 >        if (tmMapPicture(&pa, &xr, &yr, tmflags,
477 >                        tmflags&TM_F_BW ? stdprims : monpri, gamval,
478 >                        0., 0., fnin, fp) != TM_E_OK)
479 >                exit(1);
480 >                                        /* try to retrieve info */
481 >        if (fseek(fp, 0L, SEEK_SET) == 0)
482 >                getheader(fp, headline, NULL);
483 >                                        /* add output color space */
484 >        addBMPcspace(monpri, gamval);
485 >                                        /* initialize BMP header */
486 >        if (tmflags & TM_F_BW) {
487 >                hdr = BMPmappedHeader(xr, yr, infolen+1, 256);
488 >                if (fnout != NULL)
489 >                        hdr->compr = BI_RLE8;
490 >        } else
491 >                hdr = BMPtruecolorHeader(xr, yr, infolen+1);
492 >        if (hdr == NULL)
493 >                quiterr("cannot initialize BMP header");
494 >
495 >        strcpy(BMPinfo(hdr), info);     /* copy info if any */
496 >        clearInfo();
497 >                                        /* open BMP output */
498 >        if (fnout != NULL)
499 >                wtr = BMPopenOutputFile(fnout, hdr);
500 >        else
501 >                wtr = BMPopenOutputStream(stdout, hdr);
502 >        if (wtr == NULL)
503 >                quiterr("cannot allocate writer structure");
504 >                                        /* write to BMP file */
505 >        while (wtr->yscan < yr) {
506 >                uby8    *scn = pa + xr*((tmflags & TM_F_BW) ? 1 : 3)*
507 >                                                (yr-1 - wtr->yscan);
508 >                if (tmflags & TM_F_BW)
509 >                        memcpy(wtr->scanline, scn, xr);
510 >                else
511 >                        for (i = xr; i--; ) {
512 >                                wtr->scanline[3*i] = scn[3*i+BLU];
513 >                                wtr->scanline[3*i+1] = scn[3*i+GRN];
514 >                                wtr->scanline[3*i+2] = scn[3*i+RED];
515 >                        }
516 >                if ((i = BMPwriteScanline(wtr)) != BIR_OK)
517 >                        quiterr(BMPerrorMessage(i));
518 >        }
519 >                                        /* flush output */
520 >        if (fflush((FILE *)wtr->c_data) < 0)
521 >                quiterr("error writing BMP output");
522 >                                        /* clean up */
523 >        if (fnin != NULL)
524 >                fclose(fp);
525 >        free(pa);
526 >        BMPcloseOutput(wtr);
527   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines