00001
00002
00003
00004
00005
00006
00007 #include <stdio.h>
00008 #include <stdlib.h>
00009 #include <tiffio.h>
00010 #include <ImfInputFile.h>
00011 #include <ImfChannelList.h>
00012 #include <ImfFrameBuffer.h>
00013 #include <half.h>
00014
00015 #include "pbrt.h"
00016 #include "film.h"
00017 #include "paramset.h"
00018
00019 using namespace Imf;
00020 using namespace Imath;
00021
00022 static bool ReadEXR(const char *name, float *&rgba, int &xRes, int &yRes, bool &hasAlpha);
00023 static void WriteTIFF(const char *name, float *rgba, int xRes, int yRes, bool hasAlpha);
00024
00025 static void usage() {
00026 fprintf( stderr, "usage: exrtotiff [options] <input.exr> <output.tiff>\n" );
00027 fprintf( stderr, "Supported options:\n");
00028 fprintf( stderr, "\t-scale scale\n" );
00029 fprintf( stderr, "\t-gamma gamma\n" );
00030 fprintf( stderr, "\t-tonemap mapname\n" );
00031 fprintf( stderr, "\t-param name value (set tone map parameter)\n" );
00032 fprintf( stderr, "\t-bloomRadius radius\n" );
00033 fprintf( stderr, "\t-bloomWeight weight\n" );
00034 fprintf( stderr, "\t-bg bg-grey color\n");
00035 exit(1);
00036 }
00037
00038 int main(int argc, char *argv[])
00039 {
00040 float scale = 1.f, gamma = 2.2f;
00041 float bloomRadius = 0.f, bloomWeight = .2f;
00042 float bggray = -1.f;
00043 char *toneMap = NULL;
00044 ParamSet toneMapParams;
00045
00046 int argNum = 1;
00047 while (argNum < argc && argv[argNum][0] == '-') {
00048 #define ARG(name, var) \
00049 else if (!strcmp(argv[argNum], "-" name)) { \
00050 if (argNum+1 == argc) \
00051 usage(); \
00052 var = atof(argv[argNum+1]); \
00053 ++argNum; \
00054 }
00055
00056 if (!strcmp(argv[argNum], "-tonemap")) {
00057 if (argNum+1 == argc)
00058 usage();
00059 toneMap = argv[argNum+1];
00060 ++argNum;
00061 }
00062 else if (!strcmp(argv[argNum], "-param")) {
00063 if (argNum+2 >= argc)
00064 usage();
00065 float val = atof(argv[argNum+2]);
00066 toneMapParams.AddFloat(argv[argNum+1], &val);
00067 argNum += 2;
00068 }
00069 ARG("scale", scale)
00070 ARG("gamma", gamma)
00071 ARG("bg", bggray)
00072 ARG("bloomRadius", bloomRadius)
00073 ARG("bloomWeight", bloomWeight)
00074 else
00075 usage();
00076 ++argNum;
00077
00078 }
00079 if (argNum + 2 > argc) usage();
00080
00081 char *inFile = argv[argNum], *outFile = argv[argNum+1];
00082 float *rgba;
00083 int xRes, yRes;
00084 bool hasAlpha;
00085 pbrtInit();
00086
00087 if (ReadEXR(inFile, rgba, xRes, yRes, hasAlpha)) {
00088 float *rgb = new float[xRes*yRes*3];
00089 for (int i = 0; i < xRes*yRes; ++i) {
00090 for (int j = 0; j < 3; ++j) {
00091 rgb[3*i+j] = scale * rgba[4*i+j];
00092
00093
00094 if (bggray > 0)
00095 rgb[3*i+j] = rgba[4*i+3] * rgb[3*i+j] + (1.f - rgba[4*i+3]) * bggray;
00096 }
00097 if (bggray > 0)
00098 rgba[4*i+3] = 1.f;
00099 }
00100
00101 ApplyImagingPipeline(rgb, xRes, yRes, NULL, bloomRadius,
00102 bloomWeight, toneMap, &toneMapParams,
00103 gamma, 0.f, 255);
00104
00105 for (int i = 0; i < xRes*yRes; ++i) {
00106 for (int j = 0; j < 3; ++j) {
00107 rgba[4*i+j] = rgb[3*i+j];
00108 if (rgba[4*i+3] != 0.f)
00109 rgba[4*i+j] /= rgba[4*i+3];
00110 }
00111 rgba[4*i+3] *= 255.f;
00112 }
00113
00114 WriteTIFF(outFile, rgba, xRes, yRes, hasAlpha);
00115 }
00116 pbrtCleanup();
00117 return 0;
00118 }
00119
00120 void WriteTIFF(const char *name, float *rgba, int XRes, int YRes, bool hasAlpha)
00121 {
00122
00123 TIFF *tiff = TIFFOpen(name, "w");
00124 if (!tiff) {
00125 fprintf(stderr, "Unable to open TIFF %s for writing", name);
00126 return;
00127 }
00128
00129 int nChannels = hasAlpha ? 4 : 3;
00130 TIFFSetField(tiff, TIFFTAG_SAMPLESPERPIXEL, nChannels);
00131 if (hasAlpha) {
00132 short int extra[] = { EXTRASAMPLE_ASSOCALPHA };
00133 TIFFSetField(tiff, TIFFTAG_EXTRASAMPLES, (short)1, extra);
00134 }
00135
00136 TIFFSetField(tiff, TIFFTAG_IMAGEWIDTH, XRes);
00137 TIFFSetField(tiff, TIFFTAG_IMAGELENGTH, YRes);
00138 TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, 8);
00139 TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
00140
00141 TIFFSetField(tiff, TIFFTAG_ROWSPERSTRIP, 1);
00142 TIFFSetField(tiff, TIFFTAG_XRESOLUTION, 1.f);
00143 TIFFSetField(tiff, TIFFTAG_YRESOLUTION, 1.f);
00144 TIFFSetField(tiff, TIFFTAG_RESOLUTIONUNIT, (short)1);
00145 TIFFSetField(tiff, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
00146 TIFFSetField(tiff, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
00147 TIFFSetField(tiff, TIFFTAG_ORIENTATION, (int)ORIENTATION_TOPLEFT);
00148
00149 u_char *buf = new u_char[nChannels * XRes];
00150 for (int y = 0; y < YRes; ++y) {
00151 u_char *bufp = buf;
00152 for (int x = 0; x < XRes; ++x) {
00153
00154 for (int s = 0; s < nChannels; ++s)
00155 *bufp++ = (u_char)*rgba++;
00156 }
00157 TIFFWriteScanline(tiff, buf, y, 1);
00158 }
00159
00160 delete[] buf;
00161 TIFFClose(tiff);
00162 }
00163
00164 static bool ReadEXR(const char *name, float *&rgba, int &xRes, int &yRes, bool &hasAlpha)
00165 {
00166 InputFile file(name);
00167 Box2i dw = file.header().dataWindow();
00168 xRes = dw.max.x - dw.min.x + 1;
00169 yRes = dw.max.y - dw.min.y + 1;
00170
00171 half *hrgba = new half[4 * xRes * yRes];
00172
00173
00174 hasAlpha = true;
00175 int nChannels = 4;
00176
00177 half *hp = hrgba - nChannels * (dw.min.x + dw.min.y * xRes);
00178
00179 FrameBuffer frameBuffer;
00180 frameBuffer.insert("R", Slice(HALF, (char *)hp,
00181 4*sizeof(half), xRes * 4 * sizeof(half), 1, 1, 0.0));
00182 frameBuffer.insert("G", Slice(HALF, (char *)hp+sizeof(half),
00183 4*sizeof(half), xRes * 4 * sizeof(half), 1, 1, 0.0));
00184 frameBuffer.insert("B", Slice(HALF, (char *)hp+2*sizeof(half),
00185 4*sizeof(half), xRes * 4 * sizeof(half), 1, 1, 0.0));
00186 frameBuffer.insert("A", Slice(HALF, (char *)hp+3*sizeof(half),
00187 4*sizeof(half), xRes * 4 * sizeof(half), 1, 1, 1.0));
00188
00189 file.setFrameBuffer(frameBuffer);
00190 file.readPixels(dw.min.y, dw.max.y);
00191
00192 rgba = new float[nChannels * xRes * yRes];
00193 for (int i = 0; i < nChannels * xRes * yRes; ++i)
00194 rgba[i] = hrgba[i];
00195 delete[] hrgba;
00196
00197 return rgba;
00198 }