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.11 by greg, Fri May 20 02:06:39 2011 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>
10 #include  <string.h>
9  
10 + #include  "rtio.h"
11   #include  "platform.h"
12   #include  "color.h"
13   #include  "tonemap.h"
# Line 19 | Line 18 | int            bradj = 0;              /* brightness adjustment */
18  
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 < static void quiterr(const char *err);
25 < static void tmap2bmp(char *fnin, char *fnout, char *expec,
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 < static void rad2bmp(FILE *rfp, BMPWriter *bwr, int inv, RGBPRIMP monpri);
29 < static void bmp2rad(BMPReader *brd, FILE *rfp, int inv);
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 < static RGBPRIMP rgbinp = stdprims;      /* RGB input primitives */
35 < static RGBPRIMS myinprims;              /* custom primitives holder */
34 > #define add2info(s)     {int _n=strlen(s); memcpy(growInfo(_n), s, _n+1);}
35 > #define clearInfo()     growInfo(-infolen)
36  
37 < static gethfunc headline;
37 > RGBPRIMP        rgbinp = stdprims;      /* RGB input primitives */
38 > RGBPRIMS        myinprims;              /* custom primitives holder */
39  
40  
41   int
# Line 44 | Line 49 | main(int argc, char *argv[])
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] == '-' && argv[i][1])
# Line 96 | Line 101 | main(int argc, char *argv[])
101  
102          if (i == argc-2 && strcmp(argv[i+1], "-"))
103                  outfile = argv[i+1];
104 <                                        /* check for tone-mapping */
105 <        if (expec != NULL) {
104 >
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          }
106
107        setcolrgam(gamcor);             /* set up conversion */
108
111          if (reverse) {
112                  BMPReader       *rdr;
113                                          /* open BMP file or stream */
# Line 127 | 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 137 | 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 152 | Line 157 | main(int argc, char *argv[])
157                                          inpfile);
158                          exit(1);
159                  }
160 <                                        /* get header info. */
160 >                                        /* get/save header info. */
161                  if (getheader(stdin, headline, NULL) < 0 ||
162 <                                !fgetsresolu(&rs, stdin))
162 >                                        !fgetsresolu(&rs, stdin))
163                          quiterr("bad Radiance picture format");
164 <                                        /* initialize BMP header */
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), 0, 256);
169 >                                                numscans(&rs), infolen+1, 256);
170                          /*
171                          if (outfile != NULL)
172                                  hdr->compr = BI_RLE8;
173                          */
174                  } else
175                          hdr = BMPtruecolorHeader(scanlen(&rs),
176 <                                                numscans(&rs), 0);
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 = ((outfile == NULL) | (hdr->compr == BI_RLE8));
184                                          /* open BMP output */
# Line 178 | 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, rgbp);
195                                          /* flush output */
# Line 197 | Line 209 | userr:
209   }
210  
211   /* print message and exit */
212 < static void
212 > void
213   quiterr(const char *err)
214   {
215          if (err != NULL) {
# Line 207 | 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 < static int
249 > int
250   headline(char *s, void *p)
251   {
252 <        char    fmt[32];
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);
# Line 220 | Line 260 | headline(char *s, void *p)
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 */
# Line 227 | Line 269 | headline(char *s, void *p)
269                  rgbinp = myinprims;
270                  return(0);
271          }
272 <                                        /* should I grok colcorr also? */
273 <        return(0);
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 < static void
336 > void
337   rad2bmp(FILE *rfp, BMPWriter *bwr, int inv, RGBPRIMP monpri)
338   {
339          int     usexfm = 0;
# Line 247 | Line 347 | rad2bmp(FILE *rfp, BMPWriter *bwr, int inv, RGBPRIMP m
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);
350 >        usexfm = (monpri != NULL) ? (rgbinp != monpri) :
351 >                        ((rgbinp != TM_XYZPRIM) & (rgbinp != stdprims));
352          if (usexfm) {
353 <                double  expcomp = pow(2.0, (double)bradj);
353 >                RGBPRIMP        destpri = monpri != NULL ? monpri : stdprims;
354 >                double          expcomp = pow(2.0, (double)bradj);
355                  if (rgbinp == TM_XYZPRIM)
356 <                        compxyz2rgbWBmat(xfm, monpri);
356 >                        compxyz2rgbWBmat(xfm, destpri);
357                  else
358 <                        comprgb2rgbWBmat(xfm, rgbinp, monpri);
358 >                        comprgb2rgbWBmat(xfm, rgbinp, destpri);
359                  for (y = 0; y < 3; y++)
360                          for (x = 0; x < 3; x++)
361                                  xfm[y][x] *= expcomp;
# Line 269 | Line 370 | rad2bmp(FILE *rfp, BMPWriter *bwr, int inv, RGBPRIMP m
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 (usexfm)
376                          for (x = bwr->hdr->width; x--; ) {
# Line 281 | Line 382 | rad2bmp(FILE *rfp, BMPWriter *bwr, int inv, RGBPRIMP m
382                          }
383                  else if (bradj)
384                          shiftcolrs(scanin, bwr->hdr->width, bradj);
385 <                if (monpri == NULL && rgbinp != TM_XYZPRIM)
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);
# Line 299 | Line 400 | rad2bmp(FILE *rfp, BMPWriter *bwr, int inv, RGBPRIMP m
400                  if (x != BIR_OK)
401                          quiterr(BMPerrorMessage(x));
402          }
403 <                                                /* free scanline */
303 <        free((void *)scanin);
403 >        free(scanin);                           /* free scanline */
404   }
405  
406   /* convert BMP file to Radiance */
407 < static void
407 > void
408   bmp2rad(BMPReader *brd, FILE *rfp, int inv)
409   {
410          COLR    *scanout;
# Line 339 | 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 */
343 <        free((void *)scanout);
442 >        free(scanout);                          /* clean up */
443   }
444  
445   /* Tone-map and convert Radiance picture */
446 < static void
446 > void
447   tmap2bmp(char *fnin, char *fnout, char *expec, RGBPRIMP monpri, double gamval)
448   {
449          int             tmflags;
# Line 364 | Line 463 | tmap2bmp(char *fnin, char *fnout, char *expec, RGBPRIM
463                  tmflags = TM_F_LINEAR;
464          else
465                  quiterr("illegal exposure specification (auto|human|linear)");
466 <        if (monpri == NULL) {
467 <                tmflags |= TM_F_BW;
369 <                monpri = stdprims;
370 <        }
466 >
467 >        tmflags |= (monpri == NULL)*TM_F_BW;
468                                          /* open Radiance input */
469          if (fnin == NULL)
470                  fp = stdin;
# Line 376 | Line 473 | tmap2bmp(char *fnin, char *fnout, char *expec, RGBPRIM
473                  exit(1);
474          }
475                                          /* tone-map picture */
476 <        if (tmMapPicture(&pa, &xr, &yr, tmflags, monpri, gamval,
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, 0, 256);
487 >                hdr = BMPmappedHeader(xr, yr, infolen+1, 256);
488                  if (fnout != NULL)
489                          hdr->compr = BI_RLE8;
490          } else
491 <                hdr = BMPtruecolorHeader(xr, yr, 0);
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);
# Line 400 | Line 506 | tmap2bmp(char *fnin, char *fnout, char *expec, RGBPRIM
506                  uby8    *scn = pa + xr*((tmflags & TM_F_BW) ? 1 : 3)*
507                                                  (yr-1 - wtr->yscan);
508                  if (tmflags & TM_F_BW)
509 <                        memcpy((void *)wtr->scanline, (void *)scn, xr);
509 >                        memcpy(wtr->scanline, scn, xr);
510                  else
511                          for (i = xr; i--; ) {
512                                  wtr->scanline[3*i] = scn[3*i+BLU];
# Line 416 | Line 522 | tmap2bmp(char *fnin, char *fnout, char *expec, RGBPRIM
522                                          /* clean up */
523          if (fnin != NULL)
524                  fclose(fp);
525 <        free((void *)pa);
525 >        free(pa);
526          BMPcloseOutput(wtr);
527   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines