Back to index

radiance  4R0+20100331
ra_bmp.c
Go to the documentation of this file.
00001 #ifndef lint
00002 static const char RCSid[] = "$Id: ra_bmp.c,v 2.10 2004/10/04 17:44:22 greg Exp $";
00003 #endif
00004 /*
00005  *  program to convert between RADIANCE and Windows BMP file
00006  */
00007 
00008 #include  <stdio.h>
00009 #include  <math.h>
00010 #include  <string.h>
00011 
00012 #include  "platform.h"
00013 #include  "color.h"
00014 #include  "tonemap.h"
00015 #include  "resolu.h"
00016 #include  "bmpfile.h"
00017 
00018 int           bradj = 0;           /* brightness adjustment */
00019 
00020 double        gamcor = 2.2;        /* gamma correction value */
00021 
00022 char          *progname;
00023 
00024 static void quiterr(const char *err);
00025 static void tmap2bmp(char *fnin, char *fnout, char *expec,
00026                             RGBPRIMP monpri, double gamval);
00027 static void rad2bmp(FILE *rfp, BMPWriter *bwr, int inv, RGBPRIMP monpri);
00028 static void bmp2rad(BMPReader *brd, FILE *rfp, int inv);
00029 
00030 static RGBPRIMP      rgbinp = stdprims;   /* RGB input primitives */
00031 static RGBPRIMS      myinprims;           /* custom primitives holder */
00032 
00033 static gethfunc headline;
00034 
00035 
00036 int
00037 main(int argc, char *argv[])
00038 {
00039        char          *inpfile=NULL, *outfile=NULL;
00040        char          *expec = NULL;
00041        int           reverse = 0;
00042        RGBPRIMP      rgbp = stdprims;
00043        RGBPRIMS      myprims;
00044        RESOLU        rs;
00045        int           i;
00046        
00047        progname = argv[0];
00048 
00049        for (i = 1; i < argc; i++)
00050               if (argv[i][0] == '-' && argv[i][1])
00051                      switch (argv[i][1]) {
00052                      case 'b':
00053                             rgbp = NULL;
00054                             break;
00055                      case 'g':
00056                             gamcor = atof(argv[++i]);
00057                             break;
00058                      case 'e':
00059                             if (argv[i+1][0] != '+' && argv[i+1][0] != '-')
00060                                    expec = argv[++i];
00061                             else
00062                                    bradj = atoi(argv[++i]);
00063                             break;
00064                      case 'p':
00065                             if (argc-i < 9)
00066                                    goto userr;
00067                             myprims[RED][CIEX] = atof(argv[++i]);
00068                             myprims[RED][CIEY] = atof(argv[++i]);
00069                             myprims[GRN][CIEX] = atof(argv[++i]);
00070                             myprims[GRN][CIEY] = atof(argv[++i]);
00071                             myprims[BLU][CIEX] = atof(argv[++i]);
00072                             myprims[BLU][CIEY] = atof(argv[++i]);
00073                             myprims[WHT][CIEX] = atof(argv[++i]);
00074                             myprims[WHT][CIEY] = atof(argv[++i]);
00075                             if (rgbp == stdprims)
00076                                    rgbp = myprims;
00077                             break;
00078                      case 'r':
00079                             reverse = !reverse;
00080                             break;
00081                      default:
00082                             goto userr;
00083                      }
00084               else
00085                      break;
00086 
00087        if (i < argc-2)
00088               goto userr;
00089 
00090        SET_FILE_BINARY(stdin);
00091        SET_FILE_BINARY(stdout);
00092        SET_DEFAULT_BINARY();
00093 
00094        if (i <= argc-1 && strcmp(argv[i], "-"))
00095               inpfile = argv[i];
00096 
00097        if (i == argc-2 && strcmp(argv[i+1], "-"))
00098               outfile = argv[i+1];
00099                                    /* check for tone-mapping */
00100        if (expec != NULL) {
00101               if (reverse)
00102                      goto userr;
00103               tmap2bmp(inpfile, outfile, expec, rgbp, gamcor);
00104               return(0);
00105        }
00106 
00107        setcolrgam(gamcor);         /* set up conversion */
00108 
00109        if (reverse) {
00110               BMPReader       *rdr;
00111                                    /* open BMP file or stream */
00112               if (inpfile != NULL)
00113                      rdr = BMPopenInputFile(inpfile);
00114               else
00115                      rdr = BMPopenInputStream(stdin);
00116                      
00117               if (rdr == NULL) {
00118                      fprintf(stderr, "%s: cannot open or recognize BMP\n",
00119                             inpfile != NULL ? inpfile : "<stdin>");
00120                      exit(1);
00121               }
00122                                    /* open Radiance output */
00123               if (outfile != NULL && freopen(outfile, "w", stdout) == NULL) {
00124                      fprintf(stderr, "%s: cannot open for output\n",
00125                                    outfile);
00126                      exit(1);
00127               }
00128                                    /* put Radiance header */
00129               newheader("RADIANCE", stdout);
00130               printargs(i, argv, stdout);
00131               fputformat(COLRFMT, stdout);
00132               putchar('\n');
00133               rs.xr = rdr->hdr->width;
00134               rs.yr = rdr->hdr->height;
00135               rs.rt = YMAJOR;
00136                                    /* write scans downward if we can */
00137               if (rdr->hdr->yIsDown || inpfile != NULL)
00138                      rs.rt |= YDECR;
00139               fputsresolu(&rs, stdout);
00140                                    /* convert file */
00141               bmp2rad(rdr, stdout, !rdr->hdr->yIsDown && inpfile!=NULL);
00142                                    /* flush output */
00143               BMPcloseInput(rdr);
00144               if (fflush(stdout) < 0)
00145                      quiterr("error writing Radiance output");
00146        } else {
00147               BMPHeader       *hdr;
00148               BMPWriter       *wtr;
00149                                    /* open Radiance input */
00150               if (inpfile != NULL && freopen(inpfile, "r", stdin) == NULL) {
00151                      fprintf(stderr, "%s: cannot open input file\n",
00152                                    inpfile);
00153                      exit(1);
00154               }
00155                                    /* get header info. */
00156               if (getheader(stdin, headline, NULL) < 0 ||
00157                             !fgetsresolu(&rs, stdin))
00158                      quiterr("bad Radiance picture format");
00159                                    /* initialize BMP header */
00160               if (rgbp == NULL) {
00161                      hdr = BMPmappedHeader(scanlen(&rs),
00162                                           numscans(&rs), 0, 256);
00163                      /*
00164                      if (outfile != NULL)
00165                             hdr->compr = BI_RLE8;
00166                      */
00167               } else
00168                      hdr = BMPtruecolorHeader(scanlen(&rs),
00169                                           numscans(&rs), 0);
00170               if (hdr == NULL)
00171                      quiterr("cannot initialize BMP header");
00172                                    /* set up output direction */
00173               hdr->yIsDown = ((outfile == NULL) | (hdr->compr == BI_RLE8));
00174                                    /* open BMP output */
00175               if (outfile != NULL)
00176                      wtr = BMPopenOutputFile(outfile, hdr);
00177               else
00178                      wtr = BMPopenOutputStream(stdout, hdr);
00179               if (wtr == NULL)
00180                      quiterr("cannot allocate writer structure");
00181                                    /* convert file */
00182               rad2bmp(stdin, wtr, !hdr->yIsDown, rgbp);
00183                                    /* flush output */
00184               if (fflush((FILE *)wtr->c_data) < 0)
00185                      quiterr("error writing BMP output");
00186               BMPcloseOutput(wtr);
00187        }
00188        return(0);                  /* success */
00189 userr:
00190        fprintf(stderr,
00191 "Usage: %s [-b][-g gamma][-e spec][-p xr yr xg yg xb yb xw yw] [input|- [output]]\n",
00192                      progname);
00193        fprintf(stderr,
00194               "   or: %s -r [-g gamma][-e +/-stops] [input|- [output]]\n",
00195                      progname);
00196        return(1);
00197 }
00198 
00199 /* print message and exit */
00200 static void
00201 quiterr(const char *err)
00202 {
00203        if (err != NULL) {
00204               fprintf(stderr, "%s: %s\n", progname, err);
00205               exit(1);
00206        }
00207        exit(0);
00208 }
00209 
00210 /* process header line (don't echo) */
00211 static int
00212 headline(char *s, void *p)
00213 {
00214        char   fmt[32];
00215 
00216        if (formatval(fmt, s)) {    /* check if format string */
00217               if (!strcmp(fmt,COLRFMT))
00218                      return(0);
00219               if (!strcmp(fmt,CIEFMT)) {
00220                      rgbinp = TM_XYZPRIM;
00221                      return(0);
00222               }
00223               return(-1);
00224        }
00225        if (isprims(s)) {           /* get input primaries */
00226               primsval(myinprims, s);
00227               rgbinp = myinprims;
00228               return(0);
00229        }
00230                                    /* should I grok colcorr also? */
00231        return(0);
00232 }
00233 
00234 
00235 /* convert Radiance picture to BMP */
00236 static void
00237 rad2bmp(FILE *rfp, BMPWriter *bwr, int inv, RGBPRIMP monpri)
00238 {
00239        int    usexfm = 0;
00240        COLORMAT      xfm;
00241        COLR   *scanin;
00242        COLOR  cval;
00243        int    y, yend, ystp;
00244        int     x;
00245                                           /* allocate scanline */
00246        scanin = (COLR *)malloc(bwr->hdr->width*sizeof(COLR));
00247        if (scanin == NULL)
00248               quiterr("out of memory in rad2bmp");
00249                                           /* set up color conversion */
00250        usexfm = (monpri != NULL ? rgbinp != monpri :
00251                      rgbinp != TM_XYZPRIM && rgbinp != stdprims);
00252        if (usexfm) {
00253               double expcomp = pow(2.0, (double)bradj);
00254               if (rgbinp == TM_XYZPRIM)
00255                      compxyz2rgbWBmat(xfm, monpri);
00256               else
00257                      comprgb2rgbWBmat(xfm, rgbinp, monpri);
00258               for (y = 0; y < 3; y++)
00259                      for (x = 0; x < 3; x++)
00260                             xfm[y][x] *= expcomp;
00261        }
00262                                           /* convert image */
00263        if (inv) {
00264               y = bwr->hdr->height - 1;
00265               ystp = -1; yend = -1;
00266        } else {
00267               y = 0;
00268               ystp = 1; yend = bwr->hdr->height;
00269        }
00270                                           /* convert each scanline */
00271        for ( ; y != yend; y += ystp) {
00272               if (freadcolrs(scanin, bwr->hdr->width, rfp) < 0)
00273                      quiterr("error reading Radiance picture");
00274               if (usexfm)
00275                      for (x = bwr->hdr->width; x--; ) {
00276                             colr_color(cval, scanin[x]);
00277                             colortrans(cval, xfm, cval);
00278                             setcolr(scanin[x], colval(cval,RED),
00279                                           colval(cval,GRN),
00280                                           colval(cval,BLU));
00281                      }
00282               else if (bradj)
00283                      shiftcolrs(scanin, bwr->hdr->width, bradj);
00284               if (monpri == NULL && rgbinp != TM_XYZPRIM)
00285                      for (x = bwr->hdr->width; x--; )
00286                             scanin[x][GRN] = normbright(scanin[x]);
00287               colrs_gambs(scanin, bwr->hdr->width);
00288               if (monpri == NULL)
00289                      for (x = bwr->hdr->width; x--; )
00290                             bwr->scanline[x] = scanin[x][GRN];
00291               else
00292                      for (x = bwr->hdr->width; x--; ) {
00293                             bwr->scanline[3*x] = scanin[x][BLU];
00294                             bwr->scanline[3*x+1] = scanin[x][GRN];
00295                             bwr->scanline[3*x+2] = scanin[x][RED];
00296                      }
00297               bwr->yscan = y;
00298               x = BMPwriteScanline(bwr);
00299               if (x != BIR_OK)
00300                      quiterr(BMPerrorMessage(x));
00301        }
00302                                           /* free scanline */
00303        free((void *)scanin);
00304 }
00305 
00306 /* convert BMP file to Radiance */
00307 static void
00308 bmp2rad(BMPReader *brd, FILE *rfp, int inv)
00309 {
00310        COLR   *scanout;
00311        int    y, yend, ystp;
00312        int     x;
00313                                           /* allocate scanline */
00314        scanout = (COLR *)malloc(brd->hdr->width*sizeof(COLR));
00315        if (scanout == NULL)
00316               quiterr("out of memory in bmp2rad");
00317                                           /* convert image */
00318        if (inv) {
00319               y = brd->hdr->height - 1;
00320               ystp = -1; yend = -1;
00321        } else {
00322               y = 0;
00323               ystp = 1; yend = brd->hdr->height;
00324        }
00325                                           /* convert each scanline */
00326        for ( ; y != yend; y += ystp) {
00327               x = BMPseekScanline(y, brd);
00328               if (x != BIR_OK)
00329                      quiterr(BMPerrorMessage(x));
00330               for (x = brd->hdr->width; x--; ) {
00331                      RGBquad              rgbq = BMPdecodePixel(x, brd);
00332                      scanout[x][RED] = rgbq.r;
00333                      scanout[x][GRN] = rgbq.g;
00334                      scanout[x][BLU] = rgbq.b;
00335               }
00336               gambs_colrs(scanout, brd->hdr->width);
00337               if (bradj)
00338                      shiftcolrs(scanout, brd->hdr->width, bradj);
00339               if (fwritecolrs(scanout, brd->hdr->width, rfp) < 0)
00340                      quiterr("error writing Radiance picture");
00341        }
00342                                           /* clean up */
00343        free((void *)scanout);
00344 }
00345 
00346 /* Tone-map and convert Radiance picture */
00347 static void
00348 tmap2bmp(char *fnin, char *fnout, char *expec, RGBPRIMP monpri, double gamval)
00349 {
00350        int           tmflags;
00351        BMPHeader       *hdr;
00352        BMPWriter       *wtr;
00353        FILE          *fp;
00354        int           xr, yr;
00355        BYTE          *pa;
00356        int           i;
00357                                    /* check tone-mapping spec */
00358        i = strlen(expec);
00359        if (i && !strncmp(expec, "auto", i))
00360               tmflags = TM_F_CAMERA;
00361        else if (i && !strncmp(expec, "human", i))
00362               tmflags = TM_F_HUMAN & ~TM_F_UNIMPL;
00363        else if (i && !strncmp(expec, "linear", i))
00364               tmflags = TM_F_LINEAR;
00365        else
00366               quiterr("illegal exposure specification (auto|human|linear)");
00367        if (monpri == NULL) {
00368               tmflags |= TM_F_BW;
00369               monpri = stdprims;
00370        }
00371                                    /* open Radiance input */
00372        if (fnin == NULL)
00373               fp = stdin;
00374        else if ((fp = fopen(fnin, "r")) == NULL) {
00375               fprintf(stderr, "%s: cannot open\n", fnin);
00376               exit(1);
00377        }
00378                                    /* tone-map picture */
00379        if (tmMapPicture(&pa, &xr, &yr, tmflags, monpri, gamval,
00380                      0., 0., fnin, fp) != TM_E_OK)
00381               exit(1);
00382                                    /* initialize BMP header */
00383        if (tmflags & TM_F_BW) {
00384               hdr = BMPmappedHeader(xr, yr, 0, 256);
00385               if (fnout != NULL)
00386                      hdr->compr = BI_RLE8;
00387        } else
00388               hdr = BMPtruecolorHeader(xr, yr, 0);
00389        if (hdr == NULL)
00390               quiterr("cannot initialize BMP header");
00391                                    /* open BMP output */
00392        if (fnout != NULL)
00393               wtr = BMPopenOutputFile(fnout, hdr);
00394        else
00395               wtr = BMPopenOutputStream(stdout, hdr);
00396        if (wtr == NULL)
00397               quiterr("cannot allocate writer structure");
00398                                    /* write to BMP file */
00399        while (wtr->yscan < yr) {
00400               BYTE    *scn = pa + xr*((tmflags & TM_F_BW) ? 1 : 3)*
00401                                           (yr-1 - wtr->yscan);
00402               if (tmflags & TM_F_BW)
00403                      memcpy((void *)wtr->scanline, (void *)scn, xr);
00404               else
00405                      for (i = xr; i--; ) {
00406                             wtr->scanline[3*i] = scn[3*i+BLU];
00407                             wtr->scanline[3*i+1] = scn[3*i+GRN];
00408                             wtr->scanline[3*i+2] = scn[3*i+RED];
00409                      }
00410               if ((i = BMPwriteScanline(wtr)) != BIR_OK)
00411                      quiterr(BMPerrorMessage(i));
00412        }
00413                                    /* flush output */
00414        if (fflush((FILE *)wtr->c_data) < 0)
00415               quiterr("error writing BMP output");
00416                                    /* clean up */
00417        if (fnin != NULL)
00418               fclose(fp);
00419        free((void *)pa);
00420        BMPcloseOutput(wtr);
00421 }