Back to index

radiance  4R0+20100331
tmapcolrs.c
Go to the documentation of this file.
00001 #ifndef lint
00002 static const char    RCSid[] = "$Id: tmapcolrs.c,v 3.26 2009/02/09 20:48:08 greg Exp $";
00003 #endif
00004 /*
00005  * Routines for tone mapping on Radiance RGBE and XYZE pictures.
00006  *
00007  * Externals declared in tonemap.h
00008  */
00009 
00010 #include "copyright.h"
00011 
00012 #include      <stdio.h>
00013 #include      <stdlib.h>
00014 #include      <string.h>
00015 #include      <math.h>
00016 #include      <time.h>
00017 
00018 #include      "tmprivat.h"
00019 #include      "resolu.h"
00020 #ifdef PCOND
00021 #include      "rtprocess.h"
00022 #endif
00023 
00024 #define GAMTSZ       1024
00025 
00026 typedef struct {
00027        BYTE          gamb[GAMTSZ]; /* gamma lookup table */
00028        int           clfb[3];      /* encoded tm->clf */
00029        int32         cmatb[3][3];  /* encoded color transform */
00030        TMbright      inpsfb;              /* encoded tm->inpsf */
00031 } COLRDATA;
00032 
00033 static MEM_PTR       colrInit(TMstruct *);
00034 static void   colrNewSpace(TMstruct *);
00035 static gethfunc headline;
00036 
00037 static struct tmPackage     colrPkg = {   /* our package functions */
00038        colrInit, colrNewSpace, free
00039 };
00040 static int    colrReg = -1;        /* our package registration number */
00041 
00042 #define       LOGISZ 260
00043 static TMbright      logi[LOGISZ];
00044 
00045 
00046 int
00047 tmCvColrs(                         /* convert RGBE/XYZE colors */
00048 TMstruct      *tms,
00049 TMbright      *ls,
00050 BYTE   *cs,
00051 COLR   *scan,
00052 int    len
00053 )
00054 {
00055        static const char    funcName[] = "tmCvColrs";
00056        int    cmon[4];
00057        register COLRDATA    *cd;
00058        register int  i, j, li, bi;
00059        int32  vl;
00060 
00061        if (tms == NULL)
00062               returnErr(TM_E_TMINVAL);
00063        if ((ls == NULL) | (scan == NULL) | (len < 0))
00064               returnErr(TM_E_ILLEGAL);
00065        if (colrReg < 0) {                 /* build tables if necessary */
00066               colrReg = tmRegPkg(&colrPkg);
00067               if (colrReg < 0)
00068                      returnErr(TM_E_CODERR1);
00069               for (i = 256; i--; )
00070                      logi[i] = TM_BRTSCALE*log((i+.5)/256.) - .5;
00071               for (i = 256; i < LOGISZ; i++)
00072                      logi[i] = 0;
00073               tmMkMesofact();
00074        }
00075        if ((cd = (COLRDATA *)tmPkgData(tms,colrReg)) == NULL)
00076               returnErr(TM_E_NOMEM);
00077        for (i = len; i--; ) {
00078               if (tmNeedMatrix(tms)) {           /* apply color xform */
00079                      for (j = 3; j--; ) {
00080                             vl =   cd->cmatb[j][RED]*(int32)scan[i][RED] +
00081                                    cd->cmatb[j][GRN]*(int32)scan[i][GRN] +
00082                                    cd->cmatb[j][BLU]*(int32)scan[i][BLU] ;
00083                             if (vl < 0) cmon[j] = vl/0x10000;
00084                             else cmon[j] = vl>>16;
00085                      }
00086                      cmon[EXP] = scan[i][EXP];
00087               } else
00088                      copycolr(cmon, scan[i]);
00089                                                  /* world luminance */
00090               li =   cd->clfb[RED]*cmon[RED] +
00091                      cd->clfb[GRN]*cmon[GRN] +
00092                      cd->clfb[BLU]*cmon[BLU] ;
00093               if (li >= 0xfff00) li = 255;
00094               else li >>= 12;
00095               bi = BRT2SCALE(cmon[EXP]-COLXS) + cd->inpsfb;
00096               if (li > 0)
00097                      bi += logi[li];
00098               else {
00099                      bi += logi[0];
00100                      li = 1;                            /* avoid /0 */
00101               }
00102               ls[i] = bi;
00103               if (cs == TM_NOCHROM)                     /* no color? */
00104                      continue;
00105                                                  /* mesopic adj. */
00106               if (tms->flags & TM_F_MESOPIC && bi < BMESUPPER) {
00107                      int    pf, sli = normscot(cmon);
00108                      if (bi < BMESLOWER) {
00109                             cmon[RED] = cmon[GRN] = cmon[BLU] = sli;
00110                      } else {
00111                             if (tms->flags & TM_F_BW)
00112                                    cmon[RED] = cmon[GRN] = cmon[BLU] = li;
00113                             pf = tmMesofact[bi-BMESLOWER];
00114                             sli *= 256 - pf;
00115                             for (j = 3; j--; ) {
00116                                    cmon[j] = sli + pf*cmon[j];
00117                                    if (cmon[j] <= 0) cmon[j] = 0;
00118                                    else cmon[j] >>= 8;
00119                             }
00120                      }
00121               } else if (tms->flags & TM_F_BW) {
00122                      cmon[RED] = cmon[GRN] = cmon[BLU] = li;
00123               } else {
00124                      for (j = 3; j--; )
00125                             if (cmon[j] < 0) cmon[j] = 0;
00126               }
00127               bi = ( (int32)GAMTSZ*cd->clfb[RED]*cmon[RED]/li ) >> 12;
00128               cs[3*i  ] = bi>=GAMTSZ ? 255 : cd->gamb[bi];
00129               bi = ( (int32)GAMTSZ*cd->clfb[GRN]*cmon[GRN]/li ) >> 12;
00130               cs[3*i+1] = bi>=GAMTSZ ? 255 : cd->gamb[bi];
00131               bi = ( (int32)GAMTSZ*cd->clfb[BLU]*cmon[BLU]/li ) >> 12;
00132               cs[3*i+2] = bi>=GAMTSZ ? 255 : cd->gamb[bi];
00133        }
00134        returnOK;
00135 }
00136 
00137 
00138 #define       FMTRGB        1      /* Input is RGBE */
00139 #define       FMTCIE        2      /* Input is CIE XYZE */
00140 #define FMTUNK              3      /* Input format is unspecified */
00141 #define FMTBAD              4      /* Input is not a recognized format */
00142 
00143 static struct radhead {
00144        int    format;              /* FMTRGB, FMTCIE, FMTUNK, FMTBAD */
00145        double expos;        /* input exposure value */
00146        RGBPRIMP      primp; /* input primaries */
00147        RGBPRIMS      mypri; /* custom primaries */
00148 } rhdefault = {FMTUNK, 1., stdprims, STDPRIMS};
00149 
00150 
00151 static int
00152 headline(                   /* grok a header line */
00153        register char *s,
00154        void   *vrh
00155 )
00156 {
00157        char   fmt[32];
00158        register struct radhead     *rh = vrh;
00159 
00160        if (formatval(fmt, s)) {
00161               if (!strcmp(fmt, COLRFMT))
00162                      rh->format = FMTRGB;
00163               else if (!strcmp(fmt, CIEFMT))
00164                      rh->format = FMTCIE;
00165               else
00166                      rh->format = FMTBAD;
00167               return(0);
00168        }
00169        if (isexpos(s)) {
00170               rh->expos *= exposval(s);
00171               return(0);
00172        }
00173        if (isprims(s)) {
00174               primsval(rh->mypri, s);
00175               rh->primp = rh->mypri;
00176               return(0);
00177        }
00178        return(0);
00179 }
00180 
00181 
00182 int
00183 tmLoadPicture(                            /* convert Radiance picture */
00184 TMstruct      *tms,
00185 TMbright      **lpp,
00186 BYTE   **cpp,
00187 int    *xp,
00188 int    *yp,
00189 char   *fname,
00190 FILE   *fp
00191 )
00192 {
00193        char   *funcName = fname==NULL ? "tmLoadPicture" : fname;
00194        FILE   *inpf;
00195        struct radhead       info;
00196        int    err;
00197        COLR   *scanin = NULL;
00198        int    i;
00199                                           /* check arguments */
00200        if (tms == NULL)
00201               returnErr(TM_E_TMINVAL);
00202        if ((lpp == NULL) | (xp == NULL) | (yp == NULL) |
00203                      ((fname == NULL) & (fp == TM_GETFILE)))
00204               returnErr(TM_E_ILLEGAL);
00205        *xp = *yp = 0;                            /* error precaution */
00206        if ((inpf = fp) == TM_GETFILE && (inpf = fopen(fname, "rb")) == NULL)
00207               returnErr(TM_E_BADFILE);
00208        *lpp = NULL;
00209        if (cpp != TM_NOCHROMP) *cpp = NULL;
00210        info = rhdefault;                  /* get our header */
00211        getheader(inpf, headline, &info);
00212        if ((info.format == FMTBAD) | (info.expos <= 0.) ||
00213                      fgetresolu(xp, yp, inpf) < 0) {
00214               err = TM_E_BADFILE; goto done;
00215        }
00216        if (info.format == FMTUNK)         /* assume RGBE format */
00217               info.format = FMTRGB;
00218        if (info.format == FMTRGB)
00219               info.expos /= WHTEFFICACY;
00220        else if (info.format == FMTCIE)
00221               info.primp = TM_XYZPRIM;
00222                                           /* prepare library */
00223        if ((err = tmSetSpace(tms, info.primp, 1./info.expos, NULL)) != TM_E_OK)
00224               goto done;
00225        err = TM_E_NOMEM;                  /* allocate arrays */
00226        *lpp = (TMbright *)malloc(sizeof(TMbright) * *xp * *yp);
00227        if (*lpp == NULL)
00228               goto done;
00229        if (cpp != TM_NOCHROMP) {
00230               *cpp = (BYTE *)malloc(3*sizeof(BYTE) * *xp * *yp);
00231               if (*cpp == NULL)
00232                      goto done;
00233        }
00234        scanin = (COLR *)malloc(sizeof(COLR) * *xp);
00235        if (scanin == NULL)
00236               goto done;
00237        err = TM_E_BADFILE;                /* read & convert scanlines */
00238        for (i = 0; i < *yp; i++) {
00239               if (freadcolrs(scanin, *xp, inpf) < 0) {
00240                      err = TM_E_BADFILE; break;
00241               }
00242               err = tmCvColrs(tms, *lpp + (i * *xp),
00243                      cpp==TM_NOCHROMP ? TM_NOCHROM : *cpp + (i * 3 * *xp),
00244                             scanin, *xp);
00245               if (err != TM_E_OK)
00246                      break;
00247        }
00248 done:                                     /* clean up */
00249        if (fp == NULL)
00250               fclose(inpf);
00251        if (scanin != NULL)
00252               free((MEM_PTR)scanin);
00253        if (err != TM_E_OK) {
00254               if (*lpp != NULL)
00255                      free((MEM_PTR)*lpp);
00256               if (cpp != TM_NOCHROMP && *cpp != NULL)
00257                      free((MEM_PTR)*cpp);
00258               returnErr(err);
00259        }
00260        returnOK;
00261 }
00262 
00263 
00264 #ifdef PCOND
00265 static int                                /* run pcond to map picture */
00266 dopcond(psp, xp, yp, flags, monpri, gamval, Lddyn, Ldmax, fname)
00267 BYTE   **psp;
00268 int    *xp, *yp;
00269 int    flags;
00270 RGBPRIMP      monpri;
00271 double gamval, Lddyn, Ldmax;
00272 char   *fname;
00273 {
00274        char   *funcName = fname;
00275        TMstruct      *tms = NULL;
00276        char   cmdbuf[1024];
00277        FILE   *infp;
00278        register COLR *scan;
00279        register BYTE *rp;
00280        int    y;
00281        register int  x;
00282                                    /* set up gamma correction */
00283        if (setcolrcor(pow, 1./gamval) < 0)
00284               returnErr(TM_E_NOMEM);
00285                                    /* create command */
00286        strcpy(cmdbuf, PCOND);
00287        if (flags & TM_F_HCONTR)
00288               strcat(cmdbuf, " -s");
00289        if (flags & TM_F_MESOPIC)
00290               strcat(cmdbuf, " -c");
00291        if (flags & TM_F_LINEAR)
00292               strcat(cmdbuf, " -l");
00293        if (flags & TM_F_ACUITY)
00294               strcat(cmdbuf, " -a");
00295        if (flags & TM_F_VEIL)
00296               strcat(cmdbuf, " -v");
00297        if (flags & TM_F_CWEIGHT)
00298               strcat(cmdbuf, " -w");
00299        if (monpri != stdprims)
00300               sprintf(cmdbuf+strlen(cmdbuf), " -p %f %f %f %f %f %f %f %f",
00301                             monpri[RED][CIEX], monpri[RED][CIEY],
00302                             monpri[GRN][CIEX], monpri[GRN][CIEY],
00303                             monpri[BLU][CIEX], monpri[BLU][CIEY],
00304                             monpri[WHT][CIEX], monpri[WHT][CIEY]);
00305        sprintf(cmdbuf+strlen(cmdbuf), " -d %f -u %f %s", Lddyn, Ldmax, fname);
00306                                    /* start pcond */
00307        if ((infp = popen(cmdbuf, "r")) == NULL)
00308               returnErr(TM_E_BADFILE);
00309                                    /* check picture format and size */
00310        if (checkheader(infp, COLRFMT, NULL) < 0 ||
00311                      fgetresolu(xp, yp, infp) < 0) {
00312               pclose(infp);
00313               returnErr(TM_E_BADFILE);
00314        }
00315                                    /* allocate arrays */
00316        scan = (COLR *)malloc(sizeof(COLR) * *xp);
00317        if (flags & TM_F_BW)
00318               rp = (BYTE *)malloc(sizeof(BYTE) * *xp * *yp);
00319        else
00320               rp = (BYTE *)malloc(3*sizeof(BYTE) * *xp * *yp);
00321        if (((*psp = rp) == NULL) | (scan == NULL)) {
00322               pclose(infp);
00323               returnErr(TM_E_NOMEM);
00324        }
00325                                    /* read and gamma map file */
00326        for (y = 0; y < *yp; y++) {
00327               if (freadcolrs(scan, *xp, infp) < 0) {
00328                      pclose(infp);
00329                      free((MEM_PTR)scan);
00330                      free((MEM_PTR)*psp);
00331                      *psp = NULL;
00332                      returnErr(TM_E_BADFILE);
00333               }
00334               colrs_gambs(scan, *xp);
00335               if (flags & TM_F_BW)
00336                      for (x = 0; x < *xp; x++)
00337                             *rp++ = normbright(scan[x]);
00338               else
00339                      for (x = 0; x < *xp; x++) {
00340                             *rp++ = scan[x][RED];
00341                             *rp++ = scan[x][GRN];
00342                             *rp++ = scan[x][BLU];
00343                      }
00344        }
00345        free((MEM_PTR)scan);
00346        pclose(infp);
00347        returnOK;
00348 }
00349 #endif
00350 
00351 
00352 int                                /* map a Radiance picture */
00353 tmMapPicture(psp, xp, yp, flags, monpri, gamval, Lddyn, Ldmax, fname, fp)
00354 BYTE   **psp;
00355 int    *xp, *yp;
00356 int    flags;
00357 RGBPRIMP      monpri;
00358 double gamval, Lddyn, Ldmax;
00359 char   *fname;
00360 FILE   *fp;
00361 {
00362        char   *funcName = fname==NULL ? "tmMapPicture" : fname;
00363        TMstruct      *tms;
00364        BYTE   *cp;
00365        TMbright      *lp;
00366        int    err;
00367                                           /* check arguments */
00368        if ((psp == NULL) | (xp == NULL) | (yp == NULL) | (monpri == NULL) |
00369                      ((fname == NULL) & (fp == TM_GETFILE)))
00370               returnErr(TM_E_ILLEGAL);
00371                                           /* set defaults */
00372        if (gamval < MINGAM) gamval = DEFGAM;
00373        if (Lddyn < MINLDDYN) Lddyn = DEFLDDYN;
00374        if (Ldmax < MINLDMAX) Ldmax = DEFLDMAX;
00375        if (flags & TM_F_BW) monpri = stdprims;
00376 #ifdef PCOND
00377                                           /* check for pcond run */
00378        if (fp == TM_GETFILE && flags & TM_F_UNIMPL)
00379               return( dopcond(psp, xp, yp, flags,
00380                             monpri, gamval, Lddyn, Ldmax, fname) );
00381 #endif
00382                                           /* initialize tone mapping */
00383        if ((tms = tmInit(flags, monpri, gamval)) == NULL)
00384               returnErr(TM_E_NOMEM);
00385                                           /* load & convert picture */
00386        err = tmLoadPicture(tms, &lp, (flags&TM_F_BW) ? TM_NOCHROMP : &cp,
00387                      xp, yp, fname, fp);
00388        if (err != TM_E_OK) {
00389               tmDone(tms);
00390               return(err);
00391        }
00392                                           /* allocate space for result */
00393        if (flags & TM_F_BW) {
00394               *psp = (BYTE *)malloc(sizeof(BYTE) * *xp * *yp);
00395               if (*psp == NULL) {
00396                      free((MEM_PTR)lp);
00397                      tmDone(tms);
00398                      returnErr(TM_E_NOMEM);
00399               }
00400               cp = TM_NOCHROM;
00401        } else
00402               *psp = cp;
00403                                           /* compute color mapping */
00404        err = tmAddHisto(tms, lp, *xp * *yp, 1);
00405        if (err != TM_E_OK)
00406               goto done;
00407        err = tmComputeMapping(tms, gamval, Lddyn, Ldmax);
00408        if (err != TM_E_OK)
00409               goto done;
00410                                           /* map colors */
00411        err = tmMapPixels(tms, *psp, lp, cp, *xp * *yp);
00412 
00413 done:                                     /* clean up */
00414        free((MEM_PTR)lp);
00415        tmDone(tms);
00416        if (err != TM_E_OK) {                     /* free memory on error */
00417               free((MEM_PTR)*psp);
00418               *psp = NULL;
00419               returnErr(err);
00420        }
00421        returnOK;
00422 }
00423 
00424 
00425 static void
00426 colrNewSpace(tms)           /* color space changed for tone mapping */
00427 register TMstruct    *tms;
00428 {
00429        register COLRDATA    *cd;
00430        double d;
00431        int    i, j;
00432 
00433        cd = (COLRDATA *)tms->pd[colrReg];
00434        for (i = 3; i--; )
00435               cd->clfb[i] = 0x1000*tms->clf[i] + .5;
00436        cd->inpsfb = tmCvLuminance(tms->inpsf);
00437        for (i = 3; i--; )
00438               for (j = 3; j--; ) {
00439                      d = tms->cmat[i][j] / tms->inpsf;
00440                      cd->cmatb[i][j] = 0x10000*d + (d<0. ? -.5 : .5);
00441               }
00442 }
00443 
00444 
00445 static MEM_PTR
00446 colrInit(tms)               /* initialize private data for tone mapping */
00447 register TMstruct    *tms;
00448 {
00449        register COLRDATA    *cd;
00450        register int  i;
00451                                    /* allocate our data */
00452        cd = (COLRDATA *)malloc(sizeof(COLRDATA));
00453        if (cd == NULL)
00454               return(NULL);
00455        tms->pd[colrReg] = (MEM_PTR)cd;
00456                                    /* compute gamma table */
00457        for (i = GAMTSZ; i--; )
00458               cd->gamb[i] = 256.*pow((i+.5)/GAMTSZ, 1./tms->mongam);
00459                                    /* compute color and scale factors */
00460        colrNewSpace(tms);
00461        return((MEM_PTR)cd);
00462 }