Back to index

radiance  4R0+20100331
ra_tiff.c
Go to the documentation of this file.
00001 #ifndef lint
00002 static const char    RCSid[] = "$Id: ra_tiff.c,v 2.33 2008/11/10 19:08:19 greg Exp $";
00003 #endif
00004 /*
00005  *  Program to convert between RADIANCE and TIFF files.
00006  *  Added LogLuv encodings 7/97 (GWL).
00007  *  Added white-balance adjustment 10/01 (GW).
00008  */
00009 
00010 #include  <stdio.h>
00011 #include  <math.h>
00012 #include  <ctype.h>
00013 #include  <time.h>
00014 #include  <string.h>
00015 
00016 #include  "tiffio.h"
00017 #include  "color.h"
00018 #include  "resolu.h"
00019 
00020 #define  GAMCOR             2.2           /* default gamma */
00021 
00022                             /* conversion flags */
00023 #define C_CXFM              0x1           /* needs color transformation */
00024 #define C_GAMUT             0x2           /* needs gamut mapping */
00025 #define C_GAMMA             0x4           /* needs gamma correction */
00026 #define C_GRY        0x8           /* TIFF is greyscale */
00027 #define C_XYZE              0x10          /* Radiance is XYZE */
00028 #define C_RFLT              0x20          /* Radiance data is float */
00029 #define C_TFLT              0x40          /* TIFF data is float */
00030 #define C_TWRD              0x80          /* TIFF data is 16-bit */
00031 #define C_PRIM              0x100         /* has assigned primaries */
00032 
00033 typedef void colcvf_t(uint32 y);
00034 
00035 struct {
00036        uint16 flags;        /* conversion flags (defined above) */
00037        char   capdate[20];  /* capture date/time */
00038        char   owner[256];   /* content owner */
00039        uint16 comp;         /* TIFF compression type */
00040        uint16 phot;         /* TIFF photometric type */
00041        uint16 pconf;        /* TIFF planar configuration */
00042        float  gamcor;              /* gamma correction value */
00043        short  bradj;        /* Radiance exposure adjustment (stops) */
00044        uint16 orient;              /* visual orientation (TIFF spec.) */
00045        double stonits;      /* input conversion to nits */
00046        float  pixrat;              /* pixel aspect ratio */
00047        FILE   *rfp;         /* Radiance stream pointer */
00048        TIFF   *tif;         /* TIFF pointer */
00049        uint32 xmax, ymax;   /* image dimensions */
00050        COLORMAT      cmat;  /* color transformation matrix */
00051        RGBPRIMS      prims; /* RGB primaries */
00052        union {
00053               COLR   *colrs;              /* 4-byte ???E pointer */
00054               COLOR  *colors;      /* float array pointer */
00055               char   *p;           /* generic pointer */
00056        } r;                 /* Radiance scanline */
00057        union {
00058               uint8  *bp;          /* byte pointer */
00059               uint16 *wp;          /* word pointer */
00060               float  *fp;          /* float pointer */
00061               char   *p;           /* generic pointer */
00062        } t;                 /* TIFF scanline */
00063        colcvf_t *tf; /* translation procedure */
00064 }      cvts = {      /* conversion structure */
00065        0, "", "", COMPRESSION_NONE, PHOTOMETRIC_RGB,
00066        PLANARCONFIG_CONTIG, GAMCOR, 0, 1, 1., 1.,
00067 };
00068 
00069 #define CHK(f)              (cvts.flags & (f))
00070 #define SET(f)              (cvts.flags |= (f))
00071 #define CLR(f)              (cvts.flags &= ~(f))
00072 #define TGL(f)              (cvts.flags ^= (f))
00073 
00074 static colcvf_t Luv2Color, L2Color, RGB2Colr, Gry2Colr;
00075 static colcvf_t Color2Luv, Color2L, Colr2RGB, Colr2Gry;
00076 static colcvf_t RRGGBB2Color, GGry2Color, Color2RRGGBB, Color2GGry;
00077 
00078 static gethfunc headline;
00079 static void quiterr(char *err);
00080 static void allocbufs(void);
00081 static void initfromtif(void);
00082 static void tiff2ra(int  ac, char  *av[]);
00083 static void initfromrad(void);
00084 static void ra2tiff(int  ac, char  *av[]);
00085 
00086 
00087 
00088 #define RfGfBf2Color Luv2Color
00089 #define Gryf2Color   L2Color
00090 #define       Color2Gryf    Color2L
00091 #define Color2RfGfBf Color2Luv
00092 
00093 short  ortab[8] = {         /* orientation conversion table */
00094        YMAJOR|YDECR,
00095        YMAJOR|YDECR|XDECR,
00096        YMAJOR|XDECR,
00097        YMAJOR,
00098        YDECR,
00099        XDECR|YDECR,
00100        XDECR,
00101        0
00102 };
00103 
00104 #define pixorder()   ortab[cvts.orient-1]
00105 
00106 extern char   TMSTR[];      /* "CAPDATE=" from header.c */
00107 char          OWNSTR[] = "OWNER=";
00108 
00109 char  *progname;
00110 
00111 
00112 int
00113 main(int  argc, char  *argv[])
00114 {
00115        int  reverse = 0;
00116        int  i;
00117        
00118        progname = argv[0];
00119 
00120        for (i = 1; i < argc; i++)
00121               if (argv[i][0] == '-')
00122                      switch (argv[i][1]) {
00123                      case 'g':            /* gamma correction */
00124                             cvts.gamcor = atof(argv[++i]);
00125                             break;
00126                      case 'x':            /* XYZE Radiance output */
00127                             TGL(C_XYZE);
00128                             break;
00129                      case 'z':            /* LZW compressed output */
00130                             cvts.comp = COMPRESSION_LZW;
00131                             break;
00132                      case 'L':            /* LogLuv 32-bit output */
00133                             cvts.comp = COMPRESSION_SGILOG;
00134                             cvts.phot = PHOTOMETRIC_LOGLUV;
00135                             break;
00136                      case 'l':            /* LogLuv 24-bit output */
00137                             cvts.comp = COMPRESSION_SGILOG24;
00138                             cvts.phot = PHOTOMETRIC_LOGLUV;
00139                             break;
00140                      case 'w':            /* 16-bit/primary output? */
00141                             TGL(C_TWRD);
00142                             break;
00143                      case 'f':            /* IEEE float output? */
00144                             TGL(C_TFLT);
00145                             break;
00146                      case 'b':            /* greyscale output? */
00147                             TGL(C_GRY);
00148                             break;
00149                      case 'e':            /* exposure adjustment */
00150                             if (argv[i+1][0] != '+' && argv[i+1][0] != '-')
00151                                    goto userr;
00152                             cvts.bradj = atoi(argv[++i]);
00153                             break;
00154                      case 'r':            /* reverse conversion? */
00155                             reverse = !reverse;
00156                             break;
00157                      case '\0':
00158                             goto doneopts;
00159                      default:
00160                             goto userr;
00161                      }
00162               else
00163                      break;
00164 doneopts:
00165        if (reverse) {
00166 
00167               if (i != argc-2 && i != argc-1)
00168                      goto userr;
00169 
00170               tiff2ra(i, argv);
00171 
00172        } else {
00173 
00174               if (i != argc-2)
00175                      goto userr;
00176                                           /* consistency checks */
00177               if (CHK(C_GRY)) {
00178                      if (cvts.phot == PHOTOMETRIC_RGB)
00179                             cvts.phot = PHOTOMETRIC_MINISBLACK;
00180                      else {
00181                             cvts.phot = PHOTOMETRIC_LOGL;
00182                             cvts.comp = COMPRESSION_SGILOG;
00183                      }
00184               }
00185               if (CHK(C_TWRD|C_TFLT) == (C_TWRD|C_TFLT))
00186                      goto userr;
00187 
00188               ra2tiff(i, argv);
00189        }
00190 
00191        exit(0);
00192 userr:
00193        fprintf(stderr,
00194        "Usage: %s [-z|-L|-l|-f|-w][-b][-e +/-stops][-g gamma] {in.hdr|-} out.tif\n",
00195                      progname);
00196        fprintf(stderr,
00197        "   Or: %s -r [-x][-e +/-stops][-g gamma] in.tif [out.hdr|-]\n",
00198                      progname);
00199        exit(1);
00200 }
00201 
00202 
00203 static void
00204 quiterr(             /* print message and exit */
00205        char  *err
00206 )
00207 {
00208        if (err != NULL) {
00209               fprintf(stderr, "%s: %s\n", progname, err);
00210               exit(1);
00211        }
00212        exit(0);
00213 }
00214 
00215 
00216 static void
00217 allocbufs(void)                    /* allocate scanline buffers */
00218 {
00219        int    rsiz, tsiz;
00220 
00221        rsiz = CHK(C_RFLT) ? sizeof(COLOR) : sizeof(COLR);
00222        tsiz = (CHK(C_TFLT) ? sizeof(float) : 
00223                      CHK(C_TWRD) ? sizeof(uint16) : sizeof(uint8)) *
00224                      (CHK(C_GRY) ? 1 : 3);
00225        cvts.r.p = (char *)malloc(rsiz*cvts.xmax);
00226        cvts.t.p = (char *)malloc(tsiz*cvts.xmax);
00227        if ((cvts.r.p == NULL) | (cvts.t.p == NULL))
00228               quiterr("no memory to allocate scanline buffers");
00229 }
00230 
00231 
00232 static void
00233 initfromtif(void)           /* initialize conversion from TIFF input */
00234 {
00235        uint16 hi;
00236        char   *cp;
00237        float  *fa, f1, f2;
00238 
00239        CLR(C_GRY|C_GAMMA|C_PRIM|C_RFLT|C_TFLT|C_TWRD|C_CXFM);
00240 
00241        TIFFGetFieldDefaulted(cvts.tif, TIFFTAG_PLANARCONFIG, &cvts.pconf);
00242 
00243        if (TIFFGetField(cvts.tif, TIFFTAG_PRIMARYCHROMATICITIES, &fa)) {
00244               cvts.prims[RED][CIEX] = fa[0];
00245               cvts.prims[RED][CIEY] = fa[1];
00246               cvts.prims[GRN][CIEX] = fa[2];
00247               cvts.prims[GRN][CIEY] = fa[3];
00248               cvts.prims[BLU][CIEX] = fa[4];
00249               cvts.prims[BLU][CIEY] = fa[5];
00250               cvts.prims[WHT][CIEX] = 1./3.;
00251               cvts.prims[WHT][CIEY] = 1./3.;
00252               if (TIFFGetField(cvts.tif, TIFFTAG_WHITEPOINT, &fa)) {
00253                      cvts.prims[WHT][CIEX] = fa[0];
00254                      cvts.prims[WHT][CIEY] = fa[1];
00255               }
00256               SET(C_PRIM);
00257        }
00258 
00259        if (!TIFFGetField(cvts.tif, TIFFTAG_COMPRESSION, &cvts.comp))
00260               cvts.comp = COMPRESSION_NONE;
00261 
00262        if (TIFFGetField(cvts.tif, TIFFTAG_XRESOLUTION, &f1) &&
00263                      TIFFGetField(cvts.tif, TIFFTAG_YRESOLUTION, &f2))
00264               cvts.pixrat = f1/f2;
00265 
00266        TIFFGetFieldDefaulted(cvts.tif, TIFFTAG_ORIENTATION, &cvts.orient);
00267 
00268        if (!TIFFGetFieldDefaulted(cvts.tif, TIFFTAG_PHOTOMETRIC, &cvts.phot))
00269               quiterr("TIFF has unspecified photometric type");
00270 
00271        switch (cvts.phot) {
00272        case PHOTOMETRIC_LOGLUV:
00273               SET(C_RFLT|C_TFLT);
00274               if (!CHK(C_XYZE)) {
00275                      cpcolormat(cvts.cmat, xyz2rgbmat);
00276                      SET(C_CXFM|C_GAMUT);
00277               } else if (cvts.comp == COMPRESSION_SGILOG)
00278                      SET(C_GAMUT);        /* may be outside XYZ gamut */
00279               if (cvts.pconf != PLANARCONFIG_CONTIG)
00280                      quiterr("cannot handle separate Luv planes");
00281               TIFFSetField(cvts.tif, TIFFTAG_SGILOGDATAFMT,
00282                             SGILOGDATAFMT_FLOAT);
00283               cvts.tf = Luv2Color;
00284               break;
00285        case PHOTOMETRIC_LOGL:
00286               SET(C_GRY|C_RFLT|C_TFLT|C_GAMUT);
00287               cvts.pconf = PLANARCONFIG_CONTIG;
00288               TIFFSetField(cvts.tif, TIFFTAG_SGILOGDATAFMT,
00289                             SGILOGDATAFMT_FLOAT);
00290               cvts.tf = L2Color;
00291               break;
00292        case PHOTOMETRIC_YCBCR:
00293               if (cvts.comp == COMPRESSION_JPEG &&
00294                             cvts.pconf == PLANARCONFIG_CONTIG) {
00295                      TIFFSetField(cvts.tif, TIFFTAG_JPEGCOLORMODE,
00296                                    JPEGCOLORMODE_RGB);
00297                      cvts.phot = PHOTOMETRIC_RGB;
00298               } else
00299                      quiterr("unsupported photometric type");
00300               /* fall through */
00301        case PHOTOMETRIC_RGB:
00302               SET(C_GAMMA);
00303               setcolrgam(cvts.gamcor);
00304               if (CHK(C_XYZE)) {
00305                      comprgb2xyzWBmat(cvts.cmat,
00306                                    CHK(C_PRIM) ? cvts.prims : stdprims);
00307                      SET(C_CXFM);
00308               }
00309               if (!TIFFGetField(cvts.tif, TIFFTAG_SAMPLESPERPIXEL, &hi) ||
00310                             hi != 3)
00311                      quiterr("unsupported samples per pixel for RGB");
00312               if (!TIFFGetField(cvts.tif, TIFFTAG_BITSPERSAMPLE, &hi))
00313                      hi = -1;
00314               switch (hi) {
00315               case 8:
00316                      cvts.tf = RGB2Colr;
00317                      break;
00318               case 16:
00319                      cvts.tf = RRGGBB2Color;
00320                      SET(C_RFLT|C_TWRD);
00321                      break;
00322               case 32:
00323                      cvts.tf = RfGfBf2Color;
00324                      SET(C_RFLT|C_TFLT);
00325                      break;
00326               default:
00327                      quiterr("unsupported bits per sample for RGB");
00328               }
00329               break;
00330        case PHOTOMETRIC_MINISBLACK:
00331               SET(C_GRY|C_GAMMA);
00332               setcolrgam(cvts.gamcor);
00333               cvts.pconf = PLANARCONFIG_CONTIG;
00334               if (!TIFFGetField(cvts.tif, TIFFTAG_SAMPLESPERPIXEL, &hi) ||
00335                             hi != 1)
00336                      quiterr("unsupported samples per pixel for greyscale");
00337               if (!TIFFGetField(cvts.tif, TIFFTAG_BITSPERSAMPLE, &hi))
00338                      hi = -1;
00339               switch (hi) {
00340               case 8:
00341                      cvts.tf = Gry2Colr;
00342                      break;
00343               case 16:
00344                      cvts.tf = GGry2Color;
00345                      SET(C_RFLT|C_TWRD);
00346                      break;
00347               case 32:
00348                      cvts.tf = Gryf2Color;
00349                      SET(C_RFLT|C_TFLT);
00350                      break;
00351               default:
00352                      quiterr("unsupported bits per sample for Gray");
00353               }
00354               break;
00355        default:
00356               quiterr("unsupported photometric type");
00357               break;
00358        }
00359 
00360        if (!TIFFGetField(cvts.tif, TIFFTAG_IMAGEWIDTH, &cvts.xmax) ||
00361               !TIFFGetField(cvts.tif, TIFFTAG_IMAGELENGTH, &cvts.ymax))
00362               quiterr("unknown input image resolution");
00363 
00364        if (!TIFFGetField(cvts.tif, TIFFTAG_STONITS, &cvts.stonits))
00365               cvts.stonits = -1.;
00366 
00367        if (!TIFFGetField(cvts.tif, TIFFTAG_DATETIME, &cp))
00368               cvts.capdate[0] = '\0';
00369        else {
00370               strncpy(cvts.capdate, cp, 19);
00371               cvts.capdate[19] = '\0';
00372        }
00373        if (!TIFFGetField(cvts.tif, TIFFTAG_ARTIST, &cp))
00374               cvts.owner[0] = '\0';
00375        else {
00376               strncpy(cvts.owner, cp, sizeof(cvts.owner));
00377               cvts.owner[sizeof(cvts.owner)-1] = '\0';
00378        }
00379                                    /* add to Radiance header */
00380        if (cvts.pixrat < .99 || cvts.pixrat > 1.01)
00381               fputaspect(cvts.pixrat, cvts.rfp);
00382        if (CHK(C_XYZE)) {
00383               if (cvts.stonits > .0)
00384                      fputexpos(pow(2.,(double)cvts.bradj)/cvts.stonits, cvts.rfp);
00385               fputformat(CIEFMT, cvts.rfp);
00386        } else {
00387               if (CHK(C_PRIM))
00388                      fputprims(cvts.prims, cvts.rfp);
00389               if (cvts.stonits > .0)
00390                      fputexpos(WHTEFFICACY*pow(2.,(double)cvts.bradj)/cvts.stonits,
00391                                    cvts.rfp);
00392               fputformat(COLRFMT, cvts.rfp);
00393        }
00394        if (cvts.capdate[0])
00395               fprintf(cvts.rfp, "%s %s\n", TMSTR, cvts.capdate);
00396        if (cvts.owner[0])
00397               fprintf(cvts.rfp, "%s %s\n", OWNSTR, cvts.owner);
00398 
00399        allocbufs();                /* allocate scanline buffers */
00400 }
00401 
00402 
00403 static void
00404 tiff2ra(             /* convert TIFF image to Radiance picture */
00405        int  ac,
00406        char  *av[]
00407 )
00408 {
00409        int32  y;
00410                                    /* open TIFF input */
00411        if ((cvts.tif = TIFFOpen(av[ac], "r")) == NULL)
00412               quiterr("cannot open TIFF input");
00413                                    /* open Radiance output */
00414        if (av[ac+1] == NULL || !strcmp(av[ac+1], "-"))
00415               cvts.rfp = stdout;
00416        else if ((cvts.rfp = fopen(av[ac+1], "w")) == NULL)
00417               quiterr("cannot open Radiance output picture");
00418                                    /* start output header */
00419        newheader("RADIANCE", cvts.rfp);
00420        printargs(ac, av, cvts.rfp);
00421 
00422        initfromtif();                     /* initialize conversion */
00423 
00424        fputc('\n', cvts.rfp);             /* finish Radiance header */
00425        fputresolu(pixorder(), (int)cvts.xmax, (int)cvts.ymax, cvts.rfp);
00426 
00427        for (y = 0; y < cvts.ymax; y++)           /* convert image */
00428               (*cvts.tf)(y);
00429                                           /* clean up */
00430        fclose(cvts.rfp);
00431        TIFFClose(cvts.tif);
00432 }
00433 
00434 
00435 static int
00436 headline(                   /* process Radiance input header line */
00437        char   *s,
00438        void   *p
00439 )
00440 {
00441        static int    tmstrlen = 0;
00442        static int    ownstrlen = 0;
00443        char   fmt[32];
00444 
00445        if (!tmstrlen)
00446               tmstrlen = strlen(TMSTR);
00447        if (!ownstrlen)
00448               ownstrlen = strlen(OWNSTR);
00449        if (formatval(fmt, s)) {
00450               if (!strcmp(fmt, COLRFMT))
00451                      CLR(C_XYZE);
00452               else if (!strcmp(fmt, CIEFMT))
00453                      SET(C_XYZE);
00454               else
00455                      quiterr("unrecognized input picture format");
00456               return(1);
00457        }
00458        if (isexpos(s)) {
00459               cvts.stonits /= exposval(s);
00460               return(1);
00461        }
00462        if (isaspect(s)) {
00463               cvts.pixrat *= aspectval(s);
00464               return(1);
00465        }
00466        if (isprims(s)) {
00467               primsval(cvts.prims, s);
00468               SET(C_PRIM);
00469               return(1);
00470        }
00471        if (isdate(s)) {
00472               if (s[tmstrlen] == ' ')
00473                      strncpy(cvts.capdate, s+tmstrlen+1, 19);
00474               else
00475                      strncpy(cvts.capdate, s+tmstrlen, 19);
00476               cvts.capdate[19] = '\0';
00477               return(1);
00478        }
00479        if (!strncmp(s, OWNSTR, ownstrlen)) {
00480               register char *cp = s + ownstrlen;
00481 
00482               while (isspace(*cp))
00483                      ++cp;
00484               strncpy(cvts.owner, cp, sizeof(cvts.owner));
00485               cvts.owner[sizeof(cvts.owner)-1] = '\0';
00486               for (cp = cvts.owner; *cp; cp++)
00487                      ;
00488               while (cp > cvts.owner && isspace(cp[-1]))
00489                      *--cp = '\0';
00490               return(1);
00491        }
00492        return(0);
00493 }
00494 
00495 
00496 static void
00497 initfromrad(void)                  /* initialize input from a Radiance picture */
00498 {
00499        int    i1, i2, po;
00500                                           /* read Radiance header */
00501        CLR(C_RFLT|C_XYZE|C_PRIM|C_GAMMA|C_CXFM);
00502        cvts.capdate[0] = '\0';
00503        cvts.owner[0] = '\0';
00504        cvts.stonits = 1.;
00505        cvts.pixrat = 1.;
00506        cvts.pconf = PLANARCONFIG_CONTIG;
00507        getheader(cvts.rfp, headline, NULL);
00508        if ((po = fgetresolu(&i1, &i2, cvts.rfp)) < 0)
00509               quiterr("bad Radiance picture");
00510        cvts.xmax = i1; cvts.ymax = i2;
00511        for (i1 = 0; i1 < 8; i1++)         /* interpret orientation */
00512               if (ortab[i1] == po) {
00513                      cvts.orient = i1 + 1;
00514                      break;
00515               }
00516        if (i1 >= 8)
00517               quiterr("internal error 1 in initfromrad");
00518        if (!(po & YMAJOR))
00519               cvts.pixrat = 1./cvts.pixrat;
00520        if (!CHK(C_XYZE))
00521               cvts.stonits *= WHTEFFICACY;
00522                                           /* set up conversion */
00523        TIFFSetField(cvts.tif, TIFFTAG_COMPRESSION, cvts.comp);
00524        TIFFSetField(cvts.tif, TIFFTAG_PHOTOMETRIC, cvts.phot);
00525 
00526        switch (cvts.phot) {
00527        case PHOTOMETRIC_LOGLUV:
00528               SET(C_RFLT|C_TFLT);
00529               CLR(C_GRY|C_TWRD);
00530               if (!CHK(C_XYZE)) {
00531                      comprgb2xyzWBmat(cvts.cmat,
00532                                    CHK(C_PRIM) ? cvts.prims : stdprims);
00533                      SET(C_CXFM);
00534               }
00535               if (cvts.comp != COMPRESSION_SGILOG &&
00536                             cvts.comp != COMPRESSION_SGILOG24)
00537                      quiterr("internal error 2 in initfromrad");
00538               TIFFSetField(cvts.tif, TIFFTAG_SGILOGDATAFMT,
00539                             SGILOGDATAFMT_FLOAT);
00540               cvts.tf = Color2Luv;
00541               break;
00542        case PHOTOMETRIC_LOGL:
00543               SET(C_GRY|C_RFLT|C_TFLT);
00544               CLR(C_TWRD);
00545               if (cvts.comp != COMPRESSION_SGILOG)      
00546                      quiterr("internal error 3 in initfromrad");
00547               TIFFSetField(cvts.tif, TIFFTAG_SGILOGDATAFMT,
00548                             SGILOGDATAFMT_FLOAT);
00549               cvts.tf = Color2L;
00550               break;
00551        case PHOTOMETRIC_RGB:
00552               SET(C_GAMMA|C_GAMUT);
00553               CLR(C_GRY);
00554               setcolrgam(cvts.gamcor);
00555               if (CHK(C_XYZE)) {
00556                      compxyz2rgbWBmat(cvts.cmat,
00557                                    CHK(C_PRIM) ? cvts.prims : stdprims);
00558                      SET(C_CXFM);
00559               }
00560               if (CHK(C_PRIM)) {
00561                      TIFFSetField(cvts.tif, TIFFTAG_PRIMARYCHROMATICITIES,
00562                                    (float *)cvts.prims);
00563                      TIFFSetField(cvts.tif, TIFFTAG_WHITEPOINT,
00564                                    (float *)cvts.prims[WHT]);
00565               }
00566               if (CHK(C_TWRD)) {
00567                      cvts.tf = Color2RRGGBB;
00568                      SET(C_RFLT);
00569               } else if (CHK(C_TFLT)) {
00570                      TIFFSetField(cvts.tif, TIFFTAG_SAMPLEFORMAT,
00571                                    SAMPLEFORMAT_IEEEFP);
00572                      cvts.tf = Color2RfGfBf;
00573                      SET(C_RFLT);
00574                      CLR(C_GAMUT);
00575               } else
00576                      cvts.tf = Colr2RGB;
00577               break;
00578        case PHOTOMETRIC_MINISBLACK:
00579               SET(C_GRY|C_GAMMA|C_GAMUT);
00580               setcolrgam(cvts.gamcor);
00581               if (CHK(C_TWRD)) {
00582                      cvts.tf = Color2GGry;
00583                      SET(C_RFLT);
00584               } else if (CHK(C_TFLT)) {
00585                      TIFFSetField(cvts.tif, TIFFTAG_SAMPLEFORMAT,
00586                                    SAMPLEFORMAT_IEEEFP);
00587                      cvts.tf = Color2Gryf;
00588                      SET(C_RFLT);
00589               } else
00590                      cvts.tf = Colr2Gry;
00591               break;
00592        default:
00593               quiterr("internal error 4 in initfromrad");
00594               break;
00595        }
00596                                           /* set other TIFF fields */
00597        TIFFSetField(cvts.tif, TIFFTAG_IMAGEWIDTH, cvts.xmax);
00598        TIFFSetField(cvts.tif, TIFFTAG_IMAGELENGTH, cvts.ymax);
00599        TIFFSetField(cvts.tif, TIFFTAG_SAMPLESPERPIXEL, CHK(C_GRY) ? 1 : 3);
00600        TIFFSetField(cvts.tif, TIFFTAG_BITSPERSAMPLE,
00601                      CHK(C_TFLT) ? 32 : CHK(C_TWRD) ? 16 : 8);
00602        TIFFSetField(cvts.tif, TIFFTAG_XRESOLUTION, 72.);
00603        TIFFSetField(cvts.tif, TIFFTAG_YRESOLUTION, 72./cvts.pixrat);
00604        TIFFSetField(cvts.tif, TIFFTAG_ORIENTATION, cvts.orient);
00605        TIFFSetField(cvts.tif, TIFFTAG_RESOLUTIONUNIT, 2);
00606        TIFFSetField(cvts.tif, TIFFTAG_PLANARCONFIG, cvts.pconf);
00607        TIFFSetField(cvts.tif, TIFFTAG_STONITS,
00608                      cvts.stonits/pow(2.,(double)cvts.bradj));
00609        if (cvts.capdate[0])
00610               TIFFSetField(cvts.tif, TIFFTAG_DATETIME, cvts.capdate);
00611        if (cvts.owner[0])
00612               TIFFSetField(cvts.tif, TIFFTAG_ARTIST, cvts.owner);
00613        if (cvts.comp == COMPRESSION_NONE)
00614               i1 = TIFFScanlineSize(cvts.tif);
00615        else
00616               i1 = 3*cvts.xmax;    /* conservative guess */
00617        i2 = 8192/i1;                      /* compute good strip size */
00618        if (i2 < 1) i2 = 1;
00619        TIFFSetField(cvts.tif, TIFFTAG_ROWSPERSTRIP, (uint32)i2);
00620 
00621        allocbufs();                       /* allocate scanline buffers */
00622 }
00623 
00624 
00625 static void
00626 ra2tiff(             /* convert Radiance picture to TIFF image */
00627        int  ac,
00628        char  *av[]
00629 )
00630 {
00631        uint32 y;
00632                                           /* open Radiance file */
00633        if (!strcmp(av[ac], "-"))
00634               cvts.rfp = stdin;
00635        else if ((cvts.rfp = fopen(av[ac], "r")) == NULL)
00636               quiterr("cannot open Radiance input picture");
00637                                           /* open TIFF file */
00638        if ((cvts.tif = TIFFOpen(av[ac+1], "w")) == NULL)
00639               quiterr("cannot open TIFF output");
00640 
00641        initfromrad();                            /* initialize conversion */
00642 
00643        for (y = 0; y < cvts.ymax; y++)           /* convert image */
00644               (*cvts.tf)(y);
00645                                           /* clean up */
00646        TIFFClose(cvts.tif);
00647        fclose(cvts.rfp);
00648 }
00649 
00650 
00651 static void
00652 Luv2Color(                  /* read/convert/write Luv->COLOR scanline */
00653        uint32 y
00654 )
00655 {
00656        register int  x;
00657 
00658        if (CHK(C_RFLT|C_TWRD|C_TFLT|C_GRY) != (C_RFLT|C_TFLT))
00659               quiterr("internal error 1 in Luv2Color");
00660 
00661        if (cvts.pconf != PLANARCONFIG_CONTIG)
00662               quiterr("cannot handle separate 32-bit color planes");
00663 
00664        if (TIFFReadScanline(cvts.tif, cvts.t.p, y, 0) < 0)
00665               quiterr("error reading TIFF input");
00666                                    /* also works for float RGB */
00667        for (x = cvts.xmax; x--; ) {
00668               setcolor(cvts.r.colors[x], 
00669                             cvts.t.fp[3*x],
00670                             cvts.t.fp[3*x + 1],
00671                             cvts.t.fp[3*x + 2]);
00672               if (CHK(C_CXFM))
00673                      colortrans(cvts.r.colors[x], cvts.cmat,
00674                                    cvts.r.colors[x]);
00675               if (CHK(C_GAMUT))
00676                      clipgamut(cvts.r.colors[x], cvts.t.fp[3*x + 1],
00677                                    CGAMUT_LOWER, cblack, cwhite);
00678        }
00679        if (cvts.bradj) {
00680               double m = pow(2.,(double)cvts.bradj);
00681               for (x = cvts.xmax; x--; )
00682                      scalecolor(cvts.r.colors[x], m);
00683        }
00684 
00685        if (fwritescan(cvts.r.colors, cvts.xmax, cvts.rfp) < 0)
00686               quiterr("error writing Radiance picture");
00687 }
00688 
00689 
00690 static void
00691 RRGGBB2Color(               /* read/convert/write RGB16->COLOR scanline */
00692        uint32 y
00693 )
00694 {
00695        int    dogamma = (cvts.gamcor < 0.99) | (cvts.gamcor > 1.01);
00696        register double      d;
00697        register int  x;
00698 
00699        if (CHK(C_RFLT|C_TWRD|C_TFLT|C_GRY) != (C_TWRD|C_RFLT))
00700               quiterr("internal error 1 in RRGGBB2Color");
00701 
00702        if (cvts.pconf != PLANARCONFIG_CONTIG)
00703               quiterr("cannot handle separate 16-bit color planes");
00704 
00705        if (TIFFReadScanline(cvts.tif, cvts.t.p, y, 0) < 0)
00706               quiterr("error reading TIFF input");
00707        
00708        for (x = cvts.xmax; x--; ) {
00709               d = (cvts.t.wp[3*x] + 0.5)*(1./(1L<<16));
00710               if (dogamma) d = pow(d, cvts.gamcor);
00711               colval(cvts.r.colors[x],RED) = d;
00712               d = (cvts.t.wp[3*x + 1] + 0.5)*(1./(1L<<16));
00713               if (dogamma) d = pow(d, cvts.gamcor);
00714               colval(cvts.r.colors[x],GRN) = d;
00715               d = (cvts.t.wp[3*x + 2] + 0.5)*(1./(1L<<16));
00716               if (dogamma) d = pow(d, cvts.gamcor);
00717               colval(cvts.r.colors[x],BLU) = d;
00718               if (CHK(C_CXFM))
00719                      colortrans(cvts.r.colors[x], cvts.cmat,
00720                                    cvts.r.colors[x]);
00721        }
00722        if (cvts.bradj) {
00723               d = pow(2.,(double)cvts.bradj);
00724               for (x = cvts.xmax; x--; )
00725                      scalecolor(cvts.r.colors[x], d);
00726        }
00727 
00728        if (fwritescan(cvts.r.colors, cvts.xmax, cvts.rfp) < 0)
00729               quiterr("error writing Radiance picture");
00730 }
00731 
00732 
00733 static void
00734 L2Color(                    /* read/convert/write Lfloat->COLOR scanline */
00735        uint32 y
00736 )
00737 {
00738        float  m = pow(2., (double)cvts.bradj);
00739        register int  x;
00740 
00741        if (CHK(C_RFLT|C_TWRD|C_TFLT|C_GRY) != (C_RFLT|C_TFLT|C_GRY))
00742               quiterr("internal error 1 in L2Color");
00743 
00744        if (TIFFReadScanline(cvts.tif, cvts.t.p, y, 0) < 0)
00745               quiterr("error reading TIFF input");
00746                                    /* also works for float greyscale */
00747        for (x = cvts.xmax; x--; ) {
00748               register float       f = cvts.t.fp[x];
00749               if (cvts.bradj) f *= m;
00750               setcolor(cvts.r.colors[x], f, f, f);
00751        }
00752        if (fwritescan(cvts.r.colors, cvts.xmax, cvts.rfp) < 0)
00753               quiterr("error writing Radiance picture");
00754 }
00755 
00756 
00757 static void
00758 RGB2Colr(                   /* read/convert/write RGB->COLR scanline */
00759        uint32 y
00760 )
00761 {
00762        COLOR  ctmp;
00763        register int  x;
00764 
00765        if (CHK(C_RFLT|C_TWRD|C_TFLT|C_GRY))
00766               quiterr("internal error 1 in RGB2Colr");
00767 
00768        if (cvts.pconf == PLANARCONFIG_CONTIG) {
00769               if (TIFFReadScanline(cvts.tif, cvts.t.p, y, 0) < 0)
00770                      goto readerr;
00771               for (x = cvts.xmax; x--; ) {
00772                      cvts.r.colrs[x][RED] = cvts.t.bp[3*x];
00773                      cvts.r.colrs[x][GRN] = cvts.t.bp[3*x + 1];
00774                      cvts.r.colrs[x][BLU] = cvts.t.bp[3*x + 2];
00775               }
00776        } else {
00777               if (TIFFReadScanline(cvts.tif, cvts.t.p, y, 0) < 0)
00778                      goto readerr;
00779               if (TIFFReadScanline(cvts.tif,
00780                             (tdata_t)(cvts.t.bp + cvts.xmax), y, 1) < 0)
00781                      goto readerr;
00782               if (TIFFReadScanline(cvts.tif,
00783                             (tdata_t)(cvts.t.bp + 2*cvts.xmax), y, 2) < 0)
00784                      goto readerr;
00785               for (x = cvts.xmax; x--; ) {
00786                      cvts.r.colrs[x][RED] = cvts.t.bp[x];
00787                      cvts.r.colrs[x][GRN] = cvts.t.bp[cvts.xmax + x];
00788                      cvts.r.colrs[x][BLU] = cvts.t.bp[2*cvts.xmax + x];
00789               }
00790        }
00791 
00792        gambs_colrs(cvts.r.colrs, cvts.xmax);
00793        if (CHK(C_CXFM))
00794               for (x = cvts.xmax; x--; ) {
00795                      colr_color(ctmp, cvts.r.colrs[x]);
00796                      colortrans(ctmp, cvts.cmat, ctmp);
00797                      if (CHK(C_GAMUT))    /* !CHK(C_XYZE) */
00798                             clipgamut(ctmp, bright(ctmp), CGAMUT_LOWER,
00799                                           cblack, cwhite);
00800                      setcolr(cvts.r.colrs[x], colval(ctmp,RED),
00801                                    colval(ctmp,GRN), colval(ctmp,BLU));
00802               }
00803        if (cvts.bradj)
00804               shiftcolrs(cvts.r.colrs, cvts.xmax, cvts.bradj);
00805 
00806        if (fwritecolrs(cvts.r.colrs, cvts.xmax, cvts.rfp) < 0)
00807               quiterr("error writing Radiance picture");
00808        return;
00809 readerr:
00810        quiterr("error reading TIFF input");
00811 }
00812 
00813 
00814 static void
00815 Gry2Colr(                   /* read/convert/write G8->COLR scanline */
00816        uint32 y
00817 )
00818 {
00819        register int  x;
00820 
00821        if (CHK(C_RFLT|C_TWRD|C_TFLT|C_GRY) != C_GRY)
00822               quiterr("internal error 1 in Gry2Colr");
00823 
00824        if (TIFFReadScanline(cvts.tif, cvts.t.p, y, 0) < 0)
00825               quiterr("error reading TIFF input");
00826 
00827        for (x = cvts.xmax; x--; )
00828               cvts.r.colrs[x][RED] =
00829               cvts.r.colrs[x][GRN] =
00830               cvts.r.colrs[x][BLU] = cvts.t.bp[x];
00831 
00832        gambs_colrs(cvts.r.colrs, cvts.xmax);
00833        if (cvts.bradj)
00834               shiftcolrs(cvts.r.colrs, cvts.xmax, cvts.bradj);
00835 
00836        if (fwritecolrs(cvts.r.colrs, cvts.xmax, cvts.rfp) < 0)
00837               quiterr("error writing Radiance picture");
00838 }
00839 
00840 
00841 static void
00842 GGry2Color(                 /* read/convert/write G16->COLOR scanline */
00843        uint32 y
00844 )
00845 {
00846        int    dogamma = (cvts.gamcor < 0.99) | (cvts.gamcor > 1.01);
00847        double m;
00848        register double      d;
00849        register int  x;
00850 
00851        if (CHK(C_TFLT|C_TWRD|C_GRY|C_RFLT) != (C_GRY|C_RFLT|C_TWRD))
00852               quiterr("internal error 1 in GGry2Color");
00853 
00854        if (TIFFReadScanline(cvts.tif, cvts.t.p, y, 0) < 0)
00855               quiterr("error reading TIFF input");
00856 
00857        if (cvts.bradj)
00858               m = pow(2., (double)cvts.bradj);
00859        for (x = cvts.xmax; x--; ) {
00860               d = (cvts.t.wp[x] + 0.5)*(1./(1L<<16));
00861               if (dogamma) d = pow(d, cvts.gamcor);
00862               if (cvts.bradj) d *= m;
00863               colval(cvts.r.colors[x],RED) =
00864               colval(cvts.r.colors[x],GRN) =
00865               colval(cvts.r.colors[x],BLU) = d;
00866        }
00867        if (fwritescan(cvts.r.colors, cvts.xmax, cvts.rfp) < 0)
00868               quiterr("error writing Radiance picture");
00869 }
00870 
00871 
00872 static void
00873 Color2GGry(                 /* read/convert/write COLOR->G16 scanline */
00874        uint32 y
00875 )
00876 {
00877        int    dogamma = (cvts.gamcor < 0.99) | (cvts.gamcor > 1.01);
00878        float  m = pow(2.,(double)cvts.bradj);
00879        register int  x;
00880 
00881        if (CHK(C_RFLT|C_TFLT|C_TWRD|C_GRY) != (C_RFLT|C_TWRD|C_GRY))
00882               quiterr("internal error 1 in Color2GGry");
00883 
00884        if (freadscan(cvts.r.colors, cvts.xmax, cvts.rfp) < 0)
00885               quiterr("error reading Radiance picture");
00886 
00887        for (x = cvts.xmax; x--; ) {
00888               register float       f = m*( CHK(C_XYZE) ?
00889                                           colval(cvts.r.colors[x],CIEY)
00890                                           : bright(cvts.r.colors[x]) );
00891               if (f <= 0)
00892                      cvts.t.wp[x] = 0;
00893               else if (f >= 1)
00894                      cvts.t.wp[x] = 0xffff;
00895               else if (dogamma)
00896                      cvts.t.wp[x] = (int)((float)(1L<<16) *
00897                                           pow(f, 1./cvts.gamcor));
00898               else
00899                      cvts.t.wp[x] = (int)((float)(1L<<16) * f);
00900        }
00901 
00902        if (TIFFWriteScanline(cvts.tif, cvts.t.p, y, 0) < 0)
00903               quiterr("error writing TIFF output");
00904 }
00905 
00906 
00907 static void
00908 Color2L(                    /* read/convert/write COLOR->Lfloat scanline */
00909        uint32 y
00910 )
00911 {
00912        float  m = pow(2.,(double)cvts.bradj);
00913        register int  x;
00914 
00915        if (CHK(C_RFLT|C_TFLT|C_TWRD|C_GRY) != (C_RFLT|C_TFLT|C_GRY))
00916               quiterr("internal error 1 in Color2L");
00917 
00918        if (freadscan(cvts.r.colors, cvts.xmax, cvts.rfp) < 0)
00919               quiterr("error reading Radiance picture");
00920 
00921        for (x = cvts.xmax; x--; )
00922               cvts.t.fp[x] = m*( CHK(C_XYZE) ? colval(cvts.r.colors[x],CIEY)
00923                                           : bright(cvts.r.colors[x]) );
00924 
00925        if (TIFFWriteScanline(cvts.tif, cvts.t.p, y, 0) < 0)
00926               quiterr("error writing TIFF output");
00927 }
00928 
00929 
00930 static void
00931 Color2Luv(                  /* read/convert/write COLOR->Luv scanline */
00932        uint32 y
00933 )
00934 {
00935        register int  x;
00936 
00937        if (CHK(C_RFLT|C_TWRD|C_TFLT|C_GRY) != (C_RFLT|C_TFLT))
00938               quiterr("internal error 1 in Color2Luv");
00939 
00940        if (freadscan(cvts.r.colors, cvts.xmax, cvts.rfp) < 0)
00941               quiterr("error reading Radiance picture");
00942 
00943        if (CHK(C_CXFM))
00944               for (x = cvts.xmax; x--; )
00945                      colortrans(cvts.r.colors[x], cvts.cmat,
00946                                    cvts.r.colors[x]);
00947        if (cvts.bradj) {
00948               double m = pow(2.,(double)cvts.bradj);
00949               for (x = cvts.xmax; x--; )
00950                      scalecolor(cvts.r.colors[x], m);
00951        }
00952                                    /* also works for float RGB */
00953        for (x = cvts.xmax; x--; ) {
00954               cvts.t.fp[3*x] = colval(cvts.r.colors[x],CIEX);
00955               cvts.t.fp[3*x+1] = colval(cvts.r.colors[x],CIEY);
00956               cvts.t.fp[3*x+2] = colval(cvts.r.colors[x],CIEZ);
00957        }
00958 
00959        if (TIFFWriteScanline(cvts.tif, cvts.t.p, y, 0) < 0)
00960               quiterr("error writing TIFF output");
00961 }
00962 
00963 
00964 static void
00965 Color2RRGGBB(               /* read/convert/write COLOR->RGB16 scanline */
00966        uint32 y
00967 )
00968 {
00969        int    dogamma = (cvts.gamcor < 0.99) | (cvts.gamcor > 1.01);
00970        float  m = pow(2.,(double)cvts.bradj);
00971        register int  x, i;
00972 
00973        if (CHK(C_RFLT|C_TFLT|C_TWRD|C_GRY) != (C_RFLT|C_TWRD))
00974               quiterr("internal error 1 in Color2RRGGBB");
00975 
00976        if (freadscan(cvts.r.colors, cvts.xmax, cvts.rfp) < 0)
00977               quiterr("error reading Radiance picture");
00978 
00979        for (x = cvts.xmax; x--; ) {
00980            if (CHK(C_CXFM)) {
00981                      colortrans(cvts.r.colors[x], cvts.cmat,
00982                                    cvts.r.colors[x]);
00983               if (CHK(C_GAMUT))
00984                      clipgamut(cvts.r.colors[x], bright(cvts.r.colors[x]),
00985                                    CGAMUT_LOWER, cblack, cwhite);
00986            }
00987            for (i = 3; i--; ) {
00988               register float       f = m*colval(cvts.r.colors[x],i);
00989               if (f <= 0)
00990                      cvts.t.wp[3*x + i] = 0;
00991               else if (f >= 1)
00992                      cvts.t.wp[3*x + i] = 0xffff;
00993               else if (dogamma)
00994                      cvts.t.wp[3*x + i] = (int)((float)(1L<<16) *
00995                                           pow(f, 1./cvts.gamcor));
00996               else
00997                      cvts.t.wp[3*x + i] = (int)((float)(1L<<16)*f);
00998            }
00999        }
01000 
01001        if (TIFFWriteScanline(cvts.tif, cvts.t.p, y, 0) < 0)
01002               quiterr("error writing TIFF output");
01003 }
01004 
01005 
01006 static void
01007 Colr2Gry(                   /* read/convert/write COLR->RGB scanline */
01008        uint32 y
01009 )
01010 {
01011        register int  x;
01012 
01013        if (CHK(C_RFLT|C_TWRD|C_TFLT|C_GRY) != C_GRY)
01014               quiterr("internal error 1 in Colr2Gry");
01015 
01016        if (freadcolrs(cvts.r.colrs, cvts.xmax, cvts.rfp) < 0)
01017               quiterr("error reading Radiance picture");
01018 
01019        if (cvts.bradj)
01020               shiftcolrs(cvts.r.colrs, cvts.xmax, cvts.bradj);
01021        for (x = cvts.xmax; x--; )
01022               colval(cvts.r.colrs[x],CIEY) = normbright(cvts.r.colrs[x]);
01023        colrs_gambs(cvts.r.colrs, cvts.xmax);
01024 
01025        for (x = cvts.xmax; x--; )
01026               cvts.t.bp[x] = colval(cvts.r.colrs[x],CIEY);
01027 
01028        if (TIFFWriteScanline(cvts.tif, cvts.t.p, y, 0) < 0)
01029               quiterr("error writing TIFF output");
01030 }
01031 
01032 
01033 static void
01034 Colr2RGB(                   /* read/convert/write COLR->RGB scanline */
01035        uint32 y
01036 )
01037 {
01038        COLOR  ctmp;
01039        register int  x;
01040 
01041        if (CHK(C_RFLT|C_TFLT|C_TWRD|C_GRY))
01042               quiterr("internal error 1 in Colr2RGB");
01043 
01044        if (freadcolrs(cvts.r.colrs, cvts.xmax, cvts.rfp) < 0)
01045               quiterr("error reading Radiance picture");
01046 
01047        if (cvts.bradj)
01048               shiftcolrs(cvts.r.colrs, cvts.xmax, cvts.bradj);
01049        if (CHK(C_CXFM))
01050               for (x = cvts.xmax; x--; ) {
01051                      colr_color(ctmp, cvts.r.colrs[x]);
01052                      colortrans(ctmp, cvts.cmat, ctmp);
01053                      if (CHK(C_GAMUT))
01054                             clipgamut(ctmp, bright(ctmp), CGAMUT,
01055                                           cblack, cwhite);
01056                      setcolr(cvts.r.colrs[x], colval(ctmp,RED),
01057                                    colval(ctmp,GRN), colval(ctmp,BLU));
01058               }
01059        colrs_gambs(cvts.r.colrs, cvts.xmax);
01060 
01061        for (x = cvts.xmax; x--; ) {
01062               cvts.t.bp[3*x] = cvts.r.colrs[x][RED];
01063               cvts.t.bp[3*x+1] = cvts.r.colrs[x][GRN];
01064               cvts.t.bp[3*x+2] = cvts.r.colrs[x][BLU];
01065        }
01066 
01067        if (TIFFWriteScanline(cvts.tif, cvts.t.p, y, 0) < 0)
01068               quiterr("error writing TIFF output");
01069 }