00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "lux.h"
00026 #include "error.h"
00027 #include "color.h"
00028 #include "color.h"
00029 #include "spectrum.h"
00030 #include "imagereader.h"
00031
00032 #include <algorithm>
00033
00034 #include <boost/filesystem/path.hpp>
00035 #include <boost/filesystem/convenience.hpp>
00036
00037 #define cimg_display_type 0
00038
00039 #ifdef LUX_USE_CONFIG_H
00040 #include "config.h"
00041
00042 #ifdef PNG_FOUND
00043 #define cimg_use_png 1
00044 #endif
00045
00046 #ifdef JPEG_FOUND
00047 #define cimg_use_jpeg 1
00048 #endif
00049
00050 #ifdef TIFF_FOUND
00051 #define cimg_use_tiff 1
00052 #endif
00053
00054
00055 #else //LUX_USE_CONFIG_H
00056 #define cimg_use_png 1
00057 #define cimg_use_tiff 1
00058 #define cimg_use_jpeg 1
00059 #endif //LUX_USE_CONFIG_H
00060
00061
00062 #define cimg_debug 0 // Disable modal window in CImg exceptions.
00063
00064 #define cimg_plugin "greycstoration.h"
00065 #include "cimg.h"
00066 using namespace cimg_library;
00067
00068 #if defined(WIN32) && !defined(__CYGWIN__)
00069 #define hypotf hypot // For the OpenEXR headers
00070 #endif
00071
00072 #include <ImfInputFile.h>
00073 #include <ImfOutputFile.h>
00074 #include <ImfChannelList.h>
00075 #include <ImfFrameBuffer.h>
00076 #include <half.h>
00077
00078
00079
00080
00081
00082
00083 using namespace Imf;
00084 using namespace Imath;
00085 using namespace lux;
00086
00087 namespace lux {
00088
00089 template <class T >
00090 class StandardImageReader : public ImageReader {
00091 public:
00092 StandardImageReader() { };
00093 virtual ~StandardImageReader() { }
00094
00095 virtual ImageData* read(const string &name);
00096 };
00097
00098 template <class T>
00099 ImageData* createImageData( const string& name, const CImg<T>& image );
00100
00101
00102
00103 ImageData *ExrImageReader::read(const string &name) {
00104 try {
00105 stringstream ss;
00106 ss << "Loading OpenEXR Texture: '" << name << "'...";
00107 luxError(LUX_NOERROR, LUX_INFO, ss.str().c_str());
00108
00109 InputFile file(name.c_str());
00110 Box2i dw = file.header().dataWindow();
00111 int width = dw.max.x - dw.min.x + 1;
00112 int height = dw.max.y - dw.min.y + 1;
00113
00114 int noChannels = 3;
00115
00116 ss.str("");
00117 ss << width << "x" << height << " (" << noChannels << " channels)";
00118 luxError(LUX_NOERROR, LUX_INFO, ss.str().c_str());
00119
00120 half *rgb = new half[noChannels * width * height];
00121
00122 FrameBuffer frameBuffer;
00123 frameBuffer.insert("R", Slice(HALF, (char *) rgb,
00124 3 * sizeof (half), width * 3 * sizeof (half), 1, 1, 0.0));
00125 frameBuffer.insert("G", Slice(HALF, (char *) rgb + sizeof (half),
00126 3 * sizeof (half), width * 3 * sizeof (half), 1, 1, 0.0));
00127 frameBuffer.insert("B", Slice(HALF, (char *) rgb + 2 * sizeof (half),
00128 3 * sizeof (half), width * 3 * sizeof (half), 1, 1, 0.0));
00129
00130 file.setFrameBuffer(frameBuffer);
00131 file.readPixels(dw.min.y, dw.max.y);
00132 TextureColor<float, 3 > *ret = new TextureColor<float, 3 > [width * height];
00133 ImageData* data = new ImageData(width, height, ImageData::FLOAT_TYPE, noChannels, ret);
00134
00135
00136 for (int i = 0; i < width * height; ++i) {
00137 float c[3] = { rgb[(3 * i)], rgb[(3 * i) + 1], rgb[(3 * i) + 2] };
00138 ret[i] = TextureColor<float, 3 > (c);
00139
00140
00141 }
00142
00143 delete[] rgb;
00144
00145 return data;
00146 } catch (const std::exception &e) {
00147 std::stringstream ss;
00148 ss << "Unable to read EXR image file '" << name << "': " << e.what();
00149 luxError(LUX_BUG, LUX_ERROR, ss.str().c_str());
00150 return NULL;
00151 }
00152 }
00153
00154 template <typename T> ImageData * createImageData( const string& name, const CImg<T>& image ) {
00155 size_t size = sizeof (T);
00156
00157 ImageData::PixelDataType type;
00158 if (size == 1)
00159 type = ImageData::UNSIGNED_CHAR_TYPE;
00160 if (size == 2)
00161 type = ImageData::UNSIGNED_SHORT_TYPE;
00162 if (size == 4)
00163 type = ImageData::FLOAT_TYPE;
00164
00165 int width = image.dimx();
00166 int height = image.dimy();
00167 int noChannels = image.dimv();
00168 int pixels = width * height;
00169
00170 stringstream ss;
00171 ss.str("");
00172 ss << width << "x" << height << " (" << noChannels << " channels)";
00173 luxError(LUX_NOERROR, LUX_INFO, ss.str().c_str());
00174
00175 TextureColorBase* ret;
00176
00177 if (noChannels == 1)
00178 ret = new TextureColor<T, 1> [width * height];
00179 else if (noChannels == 3)
00180 ret = new TextureColor<T, 3> [width * height];
00181 else if (noChannels == 4)
00182 ret = new TextureColor<T, 4> [width * height];
00183 else {
00184 ss.str("");
00185 ss << "Unsupported channel count in StandardImageReader::read(" <<
00186 name << ": " << noChannels;
00187 luxError(LUX_SYSTEM, LUX_ERROR, ss.str().c_str());
00188
00189 return NULL;
00190 }
00191
00192 ImageData* data = new ImageData(width, height, type, noChannels, ret);
00193 T *c = new T[noChannels];
00194 c[0] = 0;
00195
00196 for (int i = 0; i < width; ++i)
00197 for (int j = 0; j < height; ++j) {
00198 for (int k = 0; k < noChannels; ++k) {
00199
00200 unsigned long off = i + (j * width) + (k * pixels);
00201
00202 if (noChannels == 1)
00203 ((TextureColor<T, 1> *)ret)[i + (j * width)].c[k] = image[off];
00204 else if (noChannels == 3)
00205 ((TextureColor<T, 3> *)ret)[i + (j * width)].c[k] = image[off];
00206 else
00207 ((TextureColor<T, 4> *)ret)[i + (j * width)].c[k] = image[off];
00208 }
00209 }
00210 delete [] c;
00211
00212 return data;
00213 }
00214
00215 template <typename T> ImageData * StandardImageReader<T>::read(const string &name) {
00216 try {
00217 stringstream ss;
00218 ss << "Loading Cimg Texture: '" << name << "'...";
00219 luxError(LUX_NOERROR, LUX_INFO, ss.str().c_str());
00220
00221 CImg<T> image(name.c_str());
00222 size_t size = sizeof (T);
00223
00224 if( size != 1 ) {
00225
00226 T maxVal = image.max();
00227 if( maxVal <= cimg::type<unsigned char>::max() ) {
00228 CImg<unsigned char> tmpImage = image;
00229 return createImageData( name, tmpImage );
00230 }
00231 }
00232 return createImageData( name, image );
00233 } catch (CImgIOException &e) {
00234 std::stringstream ss;
00235 ss << "Unable to read Cimg image file '" << name << "': " << e.message;
00236 luxError(LUX_BUG, LUX_ERROR, ss.str().c_str());
00237 return NULL;
00238 }
00239 return NULL;
00240 }
00241
00242 ImageData *ReadImage(const string &name) {
00243 try {
00244 boost::filesystem::path imagePath(name);
00245
00246
00247 if (!boost::filesystem::exists(imagePath)) {
00248 std::stringstream ss;
00249 ss << "Unable to open image file '" << imagePath.string() << "'";
00250 luxError(LUX_NOFILE, LUX_ERROR, ss.str().c_str());
00251 return NULL;
00252 }
00253
00254 std::string extension = boost::filesystem::extension(imagePath).substr(1);
00255
00256 #if defined(WIN32) && !defined(__CYGWIN__)
00257 std::transform(extension.begin(), extension.end(), extension.begin(), (int(*)(int)) tolower);
00258 #else
00259 std::transform(extension.begin(), extension.end(), extension.begin(), (int(*)(int)) std::tolower);
00260 #endif
00261
00262 if (extension == "exr") {
00263 ExrImageReader exrReader;
00264 ImageData* data = exrReader.read(name);
00265 data->setIsExrImage(true);
00266
00267 return data;
00268 }
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279 if ((extension == "raw") ||
00280 (extension == "asc") ||
00281 (extension == "hdr") ||
00282 (extension == "inr") ||
00283 (extension == "ppm") ||
00284 (extension == "pgm") ||
00285 (extension == "bmp") ||
00286 (extension == "pan") ||
00287 (extension == "dlm")) {
00288
00289 StandardImageReader<unsigned char> stdImageReader;
00290 return stdImageReader.read(name);
00291 }
00292
00293 if ((extension == "jpg") ||
00294 (extension == "jpeg")) {
00295
00296 StandardImageReader<unsigned char> stdImageReader;
00297 return stdImageReader.read(name);
00298 }
00299
00300 if((extension == "png") ||
00301 (extension == "tif") || (extension == "tiff") ||
00302 (extension == "tga") ) {
00303
00304 StandardImageReader<unsigned short> stdImageReader;
00305 return stdImageReader.read(name);
00306 }
00307
00308 std::stringstream ss;
00309 ss << "Cannot recognise file format for image '" << name << "'";
00310 luxError(LUX_BADFILE, LUX_ERROR, ss.str().c_str());
00311 return NULL;
00312 } catch (const std::exception &e) {
00313 std::stringstream ss;
00314 ss << "Unable to read image file '" << name << "': " << e.what();
00315 luxError(LUX_BUG, LUX_ERROR, ss.str().c_str());
00316 return NULL;
00317 }
00318 }
00319
00320 void WriteOpenEXRImage(int channeltype, bool halftype, bool savezbuf, int compressiontype, const string &name, vector<RGBColor> &pixels,
00321 vector<float> &alpha, int xRes, int yRes,
00322 int totalXRes, int totalYRes,
00323 int xOffset, int yOffset, vector<float> &zbuf) {
00324 Header header(totalXRes, totalYRes);
00325
00326
00327 switch(compressiontype)
00328 {
00329 case 0:
00330 header.compression() = RLE_COMPRESSION;
00331 break;
00332 case 1:
00333 header.compression() = PIZ_COMPRESSION;
00334 break;
00335 case 2:
00336 header.compression() = ZIP_COMPRESSION;
00337 break;
00338 case 3:
00339 header.compression() = PXR24_COMPRESSION;
00340 break;
00341 case 4:
00342 header.compression() = NO_COMPRESSION;
00343 break;
00344 default:
00345 header.compression() = RLE_COMPRESSION;
00346 break;
00347 }
00348
00349 Box2i dataWindow(V2i(xOffset, yOffset), V2i(xOffset + xRes - 1, yOffset + yRes - 1));
00350 header.dataWindow() = dataWindow;
00351
00352
00353 Imf::PixelType savetype = Imf::FLOAT;
00354 if(halftype)
00355 savetype = Imf::HALF;
00356
00357
00358 if(channeltype == 0) {
00359 header.channels().insert("Y", Channel(savetype));
00360 } else if(channeltype == 1) {
00361 header.channels().insert("Y", Channel(savetype));
00362 header.channels().insert("A", Channel(savetype));
00363 } else if(channeltype == 2) {
00364 header.channels().insert("R", Channel(savetype));
00365 header.channels().insert("G", Channel(savetype));
00366 header.channels().insert("B", Channel(savetype));
00367 } else {
00368 header.channels().insert("R", Channel(savetype));
00369 header.channels().insert("G", Channel(savetype));
00370 header.channels().insert("B", Channel(savetype));
00371 header.channels().insert("A", Channel(savetype));
00372 }
00373
00374
00375 if(savezbuf)
00376 header.channels().insert("Z", Channel(Imf::FLOAT));
00377
00378 FrameBuffer fb;
00379
00380
00381
00382
00383 float *fy = NULL;
00384 half *hy = NULL;
00385 half *hrgb = NULL;
00386 half *ha = NULL;
00387 const int bufSize = xRes * yRes;
00388 const int bufOffset = xOffset + yOffset * xRes;
00389
00390 if(!halftype) {
00391
00392 if(channeltype <= 1) {
00393
00394 fy = new float[bufSize];
00395
00396 for (int i = 0; i < bufSize; ++i)
00397 fy[i] = (0.3f * pixels[i].c[0]) + (0.59f * pixels[i].c[1]) + (0.11f * pixels[i].c[2]);
00398 fb.insert("Y", Slice(Imf::FLOAT, (char *)(fy - bufOffset), sizeof(float), xRes * sizeof(float)));
00399 } else if(channeltype >= 2) {
00400
00401 float *frgb = &pixels[0].c[0];
00402 fb.insert("R", Slice(Imf::FLOAT, (char *)(frgb - 3 * bufOffset), sizeof(RGBColor), xRes * sizeof(RGBColor)));
00403 fb.insert("G", Slice(Imf::FLOAT, (char *)(frgb - 3 * bufOffset) + sizeof(float), sizeof(RGBColor), xRes * sizeof(RGBColor)));
00404 fb.insert("B", Slice(Imf::FLOAT, (char *)(frgb - 3 * bufOffset) + 2 * sizeof(float), sizeof(RGBColor), xRes * sizeof(RGBColor)));
00405 }
00406 if(channeltype == 1 || channeltype == 3) {
00407
00408 float *fa = &alpha[0];
00409 fb.insert("A", Slice(Imf::FLOAT, (char *)(fa - bufOffset), sizeof(float), xRes * sizeof(float)));
00410 }
00411 } else {
00412
00413 if(channeltype <= 1) {
00414
00415 hy = new half[bufSize];
00416
00417 for (int i = 0; i < bufSize; ++i)
00418 hy[i] = (0.3f * pixels[i].c[0]) + (0.59f * pixels[i].c[1]) + (0.11f * pixels[i].c[2]);
00419 fb.insert("Y", Slice(HALF, (char *)(hy - bufOffset), sizeof(half), xRes * sizeof(half)));
00420 } else if(channeltype >= 2) {
00421
00422 hrgb = new half[3 * bufSize];
00423 for (int i = 0; i < bufSize; ++i)
00424 for( int j = 0; j < 3; j++)
00425 hrgb[3 * i + j] = pixels[i].c[j];
00426 fb.insert("R", Slice(HALF, (char *)(hrgb - 3 * bufOffset), 3 * sizeof(half), xRes * (3 * sizeof(half))));
00427 fb.insert("G", Slice(HALF, (char *)(hrgb - 3 * bufOffset) + sizeof(half), 3 * sizeof(half), xRes * (3 * sizeof(half))));
00428 fb.insert("B", Slice(HALF, (char *)(hrgb - 3 * bufOffset) + 2 * sizeof(half), 3 * sizeof (half), xRes * (3 * sizeof (half))));
00429 }
00430 if(channeltype == 1 || channeltype == 3) {
00431
00432 ha = new half[bufSize];
00433 for (int i = 0; i < bufSize; ++i)
00434 ha[i] = alpha[i];
00435 fb.insert("A", Slice(HALF, (char *)(ha - bufOffset), sizeof(half), xRes * sizeof(half)));
00436 }
00437 }
00438
00439 if(savezbuf) {
00440 float *fz = &zbuf[0];
00441
00442 fb.insert("Z", Slice(Imf::FLOAT, (char *)(fz - bufOffset), sizeof(float), xRes * sizeof(float)));
00443 }
00444
00445 try {
00446 OutputFile file(name.c_str(), header);
00447 file.setFrameBuffer(fb);
00448 file.writePixels(yRes);
00449 } catch (const std::exception &e) {
00450 std::stringstream ss;
00451 ss << "Unable to write image file '" << name << "': " << e.what();
00452 luxError(LUX_BUG, LUX_SEVERE, ss.str().c_str());
00453 }
00454
00455
00456
00457
00458 delete[] fy;
00459 delete[] hy;
00460 delete[] hrgb;
00461 delete[] ha;
00462
00463 }
00464 }