Commit 98c80820 authored by Laurent Belcour's avatar Laurent Belcour

[EXR] Almost working port to TinyEXR

parent 0318c022
......@@ -189,12 +189,17 @@ def library_available(env, pkgspec='', lib='', header='',
return result
def openexr_available(env):
"""Return True if OpenEXR is available."""
return library_available(env, pkgspec='OpenEXR',
inc_var='OPENEXR_INC',
lib_var='OPENEXR_DIR',
lib='OPENEXR_LIB',
header='ImfRgbaFile.h')
"""Return True if OpenEXR is available."""
env.AppendUnique(CPPPATH = '#external')
conf = Configure(env)
has_tinyexr = conf.CheckCXXHeader('tinyexr/tinyexr.h')
conf.Finish()
return has_tinyexr
#return library_available(env, pkgspec='OpenEXR',
# inc_var='OPENEXR_INC',
# lib_var='OPENEXR_DIR',
# lib='OPENEXR_LIB',
# header='ImfRgbaFile.h')
def CheckOpenMP(context):
"""
......
#ifndef EXR_IO_H_
#define EXR_IO_H_
/*
* Author: Cyril Soler
#pragma once
/* EXR_IO provides static method to either load an RGB EXR file into a floatting
* point array or save a RGB floatting point array to disk._data
*
* Original author: Cyril Soler
* Modified by: Laurent Belcour
*/
#include <stdexcept>
#include <cassert>
#include <ImfRgbaFile.h>
#include <ImfArray.h>
// XXX: This header is not installed as of version 2.2.0 of OpenEXR, see
// <https://lists.nongnu.org/archive/html/openexr-devel/2016-06/msg00001.html>
// and <https://github.com/openexr/openexr/pull/184>.
#include <ImfStdIO.h>
#ifdef USE_OPENEXR
#include <ImfRgbaFile.h>
#include <ImfArray.h>
// XXX: This header is not installed as of version 2.2.0 of OpenEXR, see
// <https://lists.nongnu.org/archive/html/openexr-devel/2016-06/msg00001.html>
// and <https://github.com/openexr/openexr/pull/184>.
#include <ImfStdIO.h>
#else
#define TINYEXR_IMPLEMENTATION
#include <tinyexr/tinyexr.h>
#endif
template<typename FType>
class t_EXR_IO
......@@ -22,15 +28,17 @@ class t_EXR_IO
public:
static bool LoadEXR(std::istream& input, int& W,int& H, FType *& pix,int nC=3)
{
// XXX: OpenEXR implements its own IStream and OStream classes, but
// they are completely independent from those of libstdc++. The
// closest thing it has is 'StdIFStream', hence this hack.
std::ifstream* ifstream = dynamic_cast<std::ifstream*>(&input);
assert(ifstream != NULL);
#ifdef USE_OPENEXR
/* XXX: OpenEXR implements its own IStream and OStream classes, but
* they are completely independent from those of libstdc++. The
* closest thing it has is 'StdIFStream', hence this hack.
*/
std::ifstream* ifstream = dynamic_cast<std::ifstream*>(&input);
assert(ifstream != NULL);
Imf::StdIFStream iifstream(*ifstream, "unknown file name");
Imf::StdIFStream iifstream(*ifstream, "unknown file name");
Imf::RgbaInputFile file(iifstream);
Imf::RgbaInputFile file(iifstream);
Imath::Box2i dw = file.dataWindow();
W = dw.max.x - dw.min.x + 1;
......@@ -62,15 +70,83 @@ class t_EXR_IO
default:
throw std::runtime_error("Unexpected case in EXR_IO.") ;
}
#else
/* Convert the input std::istream into an unsigned char array */
std::vector<unsigned char> _memory;
size_t _n = 0, _m = 0;
while(input.good()) {
if(_n == _m) {
_m += 256;
_memory.resize(_m);
}
_memory[_n++] = (unsigned char)input.get();
}
/* Check the different part of loading */
int _r = -1;
const char* _err;
/* Load the EXR version using TinyEXR */
EXRVersion _version;
_r = ParseEXRVersionFromMemory(&_version, &_memory[0]);
if(_r != 0) {
std::cerr << "<<ERROR>> Could not load EXR version from stream" << std::endl;
return false;
} else {
std::cout << "<<DEBUG>> Loading a v" << _version.version << " EXR file" << std::endl;
}
/* Load the EXR header */
EXRHeader _header;
InitEXRHeader(&_header);
_r = ParseEXRHeaderFromMemory(&_header, &_version, &_memory[0], &_err);
if(_r != 0) {
std::cerr << "<<ERROR>> Could not load EXR header from stream" << std::endl;
std::cerr << "<<ERROR>> " << _err << std::endl;
return false;
} else {
std::cout << "<<DEBUG>> Loading a " << _header.num_channels << " channels EXR file" << std::endl;
}
/* Load the EXR image */
EXRImage _image;
InitEXRImage(&_image);
_r = LoadEXRImageFromMemory(&_image, &_header, &_memory[0], &_err);
if (_r != 0) {
std::cerr << "<<ERROR>> Could not load EXR image from stream" << std::endl;
std::cerr << "<<ERROR>> " << _err << std::endl;
return false;
} else {
std::cout << "<<DEBUG>> Loading a " << _image.width << "x" << _image.height << " EXR file" << std::endl;
}
/*! \todo Check the different channels if they match RGB */
/*! \todo handle VS data using multi-channel */
/* Recopy the image into the provided pixel array */
W = _image.width;
H = _image.height;
pix = new FType[W*H*3];
for(int i=0; i<W*H; ++i) {
pix[3*i + 0] = _image.images[0][i];
pix[3*i + 1] = _image.images[1][i];
pix[3*i + 2] = _image.images[2][i];
}
/*! \todo Free TinyEXR memory : _image, _header and _version */
#endif
return true ;
}
static bool SaveEXR(const char *filename,int W,int H, const FType *pix,int nC=3)
{
#ifdef USE_OPENEXR
Imf::Array2D<Imf::Rgba> pixels(H,W);
/* Convert separated channel representation to per pixel representation */
switch(nC)
{
case 3:
......@@ -106,11 +182,64 @@ class t_EXR_IO
file.setFrameBuffer(&pixels[0][0], 1, W);
file.writePixels(H);
return true ;
}
};
#else
EXRHeader header;
InitEXRHeader(&header);
typedef t_EXR_IO<float> EXR_IO ;
EXRImage image;
InitEXRImage(&image);
image.num_channels = 3;
std::vector<float> images[3];
images[0].resize(W*H);
images[1].resize(W*H);
images[2].resize(W*H);
// Split RGBRGBRGB... into R, G and B layer
for (int i = 0; i < W*H; i++) {
images[0][i] = pix[3*i+0];
images[1][i] = pix[3*i+1];
images[2][i] = pix[3*i+2];
}
float* image_ptr[3];
image_ptr[0] = &(images[2].at(0)); // B
image_ptr[1] = &(images[1].at(0)); // G
image_ptr[2] = &(images[0].at(0)); // R
image.images = (unsigned char**)image_ptr;
image.width = W;
image.height = H;
header.num_channels = 3;
header.channels = (EXRChannelInfo *)malloc(sizeof(EXRChannelInfo) * header.num_channels);
// Must be (A)BGR order, since most of EXR viewers expect this channel order.
strncpy(header.channels[0].name, "B", 255); header.channels[0].name[strlen("B")] = '\0';
strncpy(header.channels[1].name, "G", 255); header.channels[1].name[strlen("G")] = '\0';
strncpy(header.channels[2].name, "R", 255); header.channels[2].name[strlen("R")] = '\0';
header.pixel_types = (int *)malloc(sizeof(int) * header.num_channels);
header.requested_pixel_types = (int *)malloc(sizeof(int) * header.num_channels);
for (int i = 0; i < header.num_channels; i++) {
header.pixel_types[i] = TINYEXR_PIXELTYPE_FLOAT; // pixel type of input image
header.requested_pixel_types[i] = TINYEXR_PIXELTYPE_HALF; // pixel type of output image to be stored in .EXR
}
const char* err;
int ret = SaveEXRImageToFile(&image, &header, filename, &err);
if (ret != TINYEXR_SUCCESS) {
std::cerr << "<<ERROR>> Unable to save to EXR file" << std::endl;
std::cerr << "<<ERROR>> " << err << std::endl;
return ret;
}
free(header.channels);
free(header.pixel_types);
free(header.requested_pixel_types);
#endif
return true ;
}
};
typedef t_EXR_IO<float> EXR_IO ;
\ No newline at end of file
......@@ -8,7 +8,7 @@ if have_openexr:
# does not install:
# <https://lists.nongnu.org/archive/html/openexr-devel/2016-06/msg00001.html>.
conf = Configure(env)
have_openexr = conf.CheckCXXHeader('ImfStdIO.h')
have_openexr = conf.CheckCXXHeader('tinyexr/tinyexr.h')
conf.Finish()
# Special linking flags, defined in the OS dependant configuration file
......
......@@ -90,7 +90,7 @@ private: // data
public: // methods
MERL(const parameters& params) :
data(params, MERL_SIZE), _nSlice(MERL_SIZE) {
data(parameters(3, 3, params::RUSIN_TH_TD_PD, params::RGB_COLOR), MERL_SIZE), _nSlice(MERL_SIZE) {
brdf = new double[3*_nSlice];
std::fill(brdf, brdf + 3*_nSlice, 0.0);
......@@ -151,7 +151,7 @@ public: // methods
}
void set(int i, const vec& x) {
assert(x.size() == parametrization().dimY());
assert(x.size() == parametrization().dimX() + parametrization().dimY());
int iR = i;
int iG = iR + _nSlice;
int iB = iG + _nSlice;
......
......@@ -18,8 +18,9 @@
using namespace alta;
// Allow for a different parametrization depending on the arguments provided.
static const parameters
static const alta::parameters
brdf_slice_parameters(const arguments& args)
{
auto result = alta::parameters(2, 3,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment