Text archives Help
- From: kmorley@sci.utah.edu
- To: manta@sci.utah.edu
- Subject: [Manta] r1848 - trunk/Image
- Date: Tue, 13 Nov 2007 13:43:58 -0700 (MST)
Author: kmorley
Date: Tue Nov 13 13:43:57 2007
New Revision: 1848
Modified:
trunk/Image/EXRFile.cc
trunk/Image/EXRFile.h
Log:
More OpenEXR support
Modified: trunk/Image/EXRFile.cc
==============================================================================
--- trunk/Image/EXRFile.cc (original)
+++ trunk/Image/EXRFile.cc Tue Nov 13 13:43:57 2007
@@ -74,137 +74,13 @@
void writeEXR( const Image* image, const std::string& file_name,
int which )
{
+ throw OutputError( " writeEXR not implemented yet" );
}
extern "C"
Image* readEXR( const std::string& filename )
{
-#if 0
-
- Imf::InputFile file( filename.c_str() );
-
- Imath::Box2i dw = file.header().dataWindow();
- long width = dw.max.x - dw.min.x + 1;
- long height = dw.max.y - dw.min.y + 1;
-
- std::cerr << " width : " << width << " height: " << height << std::endl;
-
- Imf::Array2D<half> r_pixels( height, width );
- Imf::Array2D<half> g_pixels( height, width );
- Imf::Array2D<half> b_pixels( height, width );
- Imf::Array2D<half> a_pixels( height, width );
- std::string red_name, green_name, blue_name, alpha_name;
-
- Imf::FrameBuffer frame_buffer;
-
- const Imf::ChannelList &channels = file.header().channels();
- for ( Imf::ChannelList::ConstIterator iter = channels.begin();
- iter != channels.end(); ++iter )
- {
- std::string name = iter.name();
- const Imf::Channel& channel = iter.channel();
-
-
- std::cerr << " channel found: '" << name << "'" << std::endl;
-
- Imf::Array2D<half>* array;
- if ( name == "R" || name == "r" || name == "Red" ||
- name == "RED" || name == "red" ) {
- array = &r_pixels;
- red_name = name;
- }
- else if ( name == "G" || name == "g" || name == "Green" ||
- name == "GREEN" || name == "green" ) {
- array = &g_pixels;
- green_name = name;
- }
- else if ( name == "B" || name == "b" || name == "Blue" ||
- name == "BLUE" || name == "blue" ) {
- array = &b_pixels;
- blue_name = name;
- }
- else if ( name == "A" || name == "a" || name == "Alpha" ||
- name == "ALPHA" || name == "alpha" ) {
- array = &a_pixels;
- alpha_name = name;
- } else {
- std::cerr << __FILE__ << ":" << __FUNCTION__ << " Unknown channel type
'"
- << name << "' ... ignoring" << std::endl;
- continue;
- }
- frame_buffer.insert( name.c_str(),
- Imf::Slice(
- channel.type, // type
- (char*)(&(*array[0][0]) - dw.min.x - dw.min.y * width), // base
- sizeof (*array[0][0]) * 1, // xStride
- sizeof (*array[0][0]) * width, // yStride
- channel.xSampling, // x sampling
- channel.ySampling, // y sampling
- 0.0 ) ); // fillValue
-
- }
-
- file.setFrameBuffer( frame_buffer );
- file.readPixels( dw.min.y, dw.max.y );
-
- SimpleImage<RGBAfloatPixel>* image =
- new SimpleImage<RGBAfloatPixel>( false, width,
- height );
-
- for ( int i = 0; i < width; ++i ) {
- for ( int j = 0; j < height; ++j ) {
-
- std::cerr << r_pixels[i][j] << " "
- << g_pixels[i][j] << " "
- << b_pixels[i][j] << std::endl;
-
- RGBAfloatPixel pixel;
- RGBColor color( r_pixels[i][j], g_pixels[i][j], b_pixels[i][j] );
-
- convertToPixel( pixel, color );
- image->set( pixel, i, j, 0 );
- }
- }
- return image;
-#endif
-
-#if 0
- Imf::RgbaInputFile file( filename.c_str() );
-
- Imath::Box2i dw = file.dataWindow();
- int width = dw.max.x - dw.min.x + 1;
- int height = dw.max.y - dw.min.y + 1;
- Imf::Array2D<Imf::Rgba> pixels( height, width );
-
- file.setFrameBuffer (&pixels[0][0] - dw.min.x - dw.min.y * width, 1,
width);
- file.readPixels (dw.min.y, dw.max.y);
-
- SimpleImage<RGBAfloatPixel>* image =
- new SimpleImage<RGBAfloatPixel>( false, width, height );
-
- for ( int i = 0; i < width; ++i ) {
- for ( int j = 0; j < height; ++j ) {
-
- float r = pixels[height-1-j][i].r;
- float g = pixels[height-1-j][i].g;
- float b = pixels[height-1-j][i].b;
- RGBColor color( r, g, b );
-
- //std::cerr << float( pixels[i][j].r ) << " "
- // << float( pixels[i][j].g ) << " "
- // << float( pixels[i][j].b ) << std::endl;
-
- RGBAfloatPixel pixel;
- convertToPixel( pixel, color );
- image->set( pixel, i, j, 0 );
- }
- }
-
- return image;
-
-#endif
-
EXR::InputFile input_file( filename );
Image* image = input_file.getImage();
return image;
@@ -218,43 +94,103 @@
}
-///////////////////////////////////////////////////////////////////////////////
+unsigned int EXR::pixelTypeSize( EXR::PixelType type )
+{
+ return type == EXR::UINT ? sizeof( unsigned int ) :
+ type == EXR::HALF ? sizeof( half ) :
+ sizeof( float );
+}
+
+
+//-----------------------------------------------------------------------------
//
-// EXRInputFile
+// EXRInputFile class
//
+//-----------------------------------------------------------------------------
EXR::InputFile::InputFile( const std::string& filename )
: _filename( filename )
{
+
+ // Grab the header via in InputFile
+ bool is_rgba = true;
try {
- Imf::RgbaInputFile file( filename.c_str() );
- Imath::Box2i dw = file.dataWindow();
+ // Test to see if we have something that can reasonably be read as Rgba
+ Imf::InputFile ifile( filename.c_str() );
+ const Imf::ChannelList &chans = ifile.header().channels();
+ is_rgba = chans.findChannel( "R" ) && chans["R"].type == Imf::HALF &&
+ chans.findChannel( "G" ) && chans["G"].type == Imf::HALF &&
+ chans.findChannel( "B" ) && chans["B"].type == Imf::HALF;
- _width = dw.max.x - dw.min.x + 1;
- _height = dw.max.y - dw.min.y + 1;
+
+ } catch( std::exception& e ) {
+ throw InputError( std::string("OpenEXR lib read failed: ") + e.what() );
+ }
- _rgbas = new(std::nothrow) Imf::Rgba[ _width*_height ];
+ // Use the Rgba convenience class if possible
+ if ( is_rgba ) {
+ try {
- file.setFrameBuffer (&_rgbas[0] - dw.min.x - dw.min.y * _width, 1,
_width);
- file.readPixels (dw.min.y, dw.max.y);
+ Imf::RgbaInputFile file( filename.c_str() );
+ Imath::Box2i dw = file.dataWindow();
- } catch( std::exception& e ) {
- throw InputError( std::string( "OpenEXR lib read failed: " ) + e.what()
);
- }
+ _width = dw.max.x - dw.min.x + 1;
+ _height = dw.max.y - dw.min.y + 1;
- /*
- int width = 512, height = 512;
- float* floats = new float[ width*height ];
- for (int i = 0; i < width*height; ++i )
- floats[i] = float(i) / (width * height);
-
- ChannelList clist;
- clist.push_back( new Channel( "R", FLOAT, reinterpret_cast<char*>(floats)
) );
- EXR::OutputFile out( clist, 512, 512 );
- out.write( "/Users/kmorley/Desktop/foo.exr" );
- */
+ _rgbas = new Imf::Rgba[ _width*_height ];
+ file.setFrameBuffer ( &_rgbas[0] - dw.min.x - dw.min.y*_width, 1,
_width);
+ file.readPixels (dw.min.y, dw.max.y);
+
+ } catch( std::exception& e ) {
+ throw InputError( std::string("OpenEXR lib read failed: ") + e.what()
);
+ }
+
+ // Not Rgba-like, so we will have to load it channel by channel
+ } else {
+ try {
+
+ Imf::InputFile file( filename.c_str() );
+
+ Imath::Box2i dw = file.header().dataWindow();
+
+ _width = dw.max.x - dw.min.x + 1;
+ _height = dw.max.y - dw.min.y + 1;
+
+ Imf::FrameBuffer frame_buffer;
+
+ // Iterate over channels, adding a buffer slice for each
+ const Imf::ChannelList &channels = file.header().channels();
+ for ( Imf::ChannelList::ConstIterator iter = channels.begin();
+ iter != channels.end(); ++iter ) {
+
+ const Imf::Channel& chan = iter.channel();
+ EXR::Channel* exr_chan = new EXR::Channel();
+
+ exr_chan->type = static_cast<EXR::PixelType>( chan.type );
+ exr_chan->name = iter.name();
+ unsigned int data_size = pixelTypeSize( exr_chan->type );
+ exr_chan->data = new char[ _width*_height*data_size ];
+
+ frame_buffer.insert( exr_chan->name.c_str(),
+ Imf::Slice(
+ chan.type, // type
+ exr_chan->data - dw.min.x - dw.min.y * _width, // base
+ data_size * 1, // xStride
+ data_size * _width, // yStride
+ chan.xSampling, // x
sampling
+ chan.ySampling, // y
sampling
+ 0.0 ) ); //
fillValue
+ }
+
+ file.setFrameBuffer( frame_buffer );
+ file.readPixels( dw.min.y, dw.max.y );
+
+ } catch( std::exception& e ) {
+ throw InputError( std::string("OpenEXR lib read failed: ") + e.what()
);
+ }
+ }
}
@@ -296,17 +232,22 @@
return image;
} else {
- throw InputError( "Non-RGBA image reading not supported yet" );
+ // Need to add support for creating Image from arbitrary channel
+ // list -- perhaps we only need to support single channel if the
+ // image is not RGB or RGBA-like. This would require FloatPixel
+ // or LongPixel types to be added to Pixel.h
+ throw InputError( "Non-RGBA image reading not fully supported yet" );
}
}
-///////////////////////////////////////////////////////////////////////////////
+
+//-----------------------------------------------------------------------------
//
-// EXROutputFile
+// EXROutputFile class
//
-
+//-----------------------------------------------------------------------------
EXR::OutputFile::OutputFile( Imf::Rgba* pixels, unsigned int x, unsigned int
y,
unsigned int min_x, unsigned int max_x, unsigned int min_y,
@@ -319,6 +260,7 @@
to constructor " );
}
+ // If zero-area data window set data window to entire display window
Imath::Box2i dw( Imath::V2i(0, 0), Imath::V2i (x-1, y-1) );
if ( max_x != min_x && max_y != min_y ) {
dw = Imath::Box2i( Imath::V2i(min_x, min_y), Imath::V2i (max_x, max_y) );
@@ -329,9 +271,12 @@
}
-EXR::OutputFile::OutputFile( const ChannelList& channels, unsigned int x,
- unsigned int y, unsigned int min_x, unsigned int max_x, unsigned int
min_y,
- unsigned int max_y, float aspect, float screen_width)
+EXR::OutputFile::OutputFile( const ChannelList& channels,
+ unsigned int x, unsigned int y,
+ unsigned int min_x, unsigned int max_x,
+ unsigned int min_y, unsigned int max_y,
+ float aspect,
+ float screen_width)
: _channels( channels )
{
if ( min_x < 0 || min_x > max_x ||
@@ -368,50 +313,57 @@
void EXR::OutputFile::write( const std::string& filename )
{
- Imath::Box2i dw = _header->dataWindow();
- int width = dw.max.x - dw.min.x + 1;
- int height = dw.max.y - dw.min.y + 1;
+ // Get image dimensions
+ Imath::Box2i data_win = _header->dataWindow();
+ Imath::Box2i disp_win = _header->dataWindow();
+ int width = disp_win.max.x - disp_win.min.x + 1;
+ int height = disp_win.max.y - disp_win.min.y + 1;
+ // Easy case, let the OpenEXR lib do the work with RGBA images
if ( _rgbas ) {
+
+ try {
+ Imf::RgbaOutputFile file ( filename.c_str(), *_header );
+ file.setFrameBuffer ( _rgbas, 1, width);
+ file.writePixels ( data_win.max.y - data_win.min.y + 1);
+ } catch( std::exception& e ) {
+ throw InputError( std::string( "OpenEXR lib write failed: " )+e.what()
);
+ }
-
- // NOT FINISHED YET
-
+ // Else we need to manually create a framebuffer from channels
} else if ( _channels.size() > 0 ) {
try {
+ // Iterate over channels inserting a buffer slice for each
Imf::FrameBuffer frameBuffer;
for ( ChannelIter it = _channels.begin(); it != _channels.end(); ++it
) {
+
Channel* chan = *it;
int data_size = chan->type == UINT ? sizeof( unsigned int ) :
- chan->type == HALF ? sizeof( half ) :
- sizeof( float );
+ chan->type == HALF ? sizeof( half ) :
+ sizeof( float );
frameBuffer.insert ( chan->name.c_str(),
Imf::Slice ( static_cast<Imf::PixelType>( chan->type ),
- reinterpret_cast<char*>( chan->data ),
+ chan->data,
data_size * 1,
data_size * width ) );
}
+ // Write out the image
Imf::OutputFile file(filename.c_str(), *_header);
file.setFrameBuffer (frameBuffer);
-
file.writePixels (height);
} catch( std::exception& e ) {
-
throw InputError( std::string( "OpenEXR lib write failed: " )+e.what()
);
-
}
} else {
-
throw OutputError( "EXROutputFile::write called without Pixel data" );
}
-
}
Modified: trunk/Image/EXRFile.h
==============================================================================
--- trunk/Image/EXRFile.h (original)
+++ trunk/Image/EXRFile.h Tue Nov 13 13:43:57 2007
@@ -44,6 +44,11 @@
namespace Manta
{
+
//---------------------------------------------------------------------------
+ //
+ // Standard Manta Image IO functions
+ //
+
//---------------------------------------------------------------------------
class Image;
extern "C"
@@ -60,11 +65,19 @@
bool EXRSupported();
+
//---------------------------------------------------------------------------
+ //
+ // EXR helpers
+ //
+
//---------------------------------------------------------------------------
namespace EXR
{
- enum PixelType // Should be identical to Imf::PixelType
+ //
+ // Should be identical to Imf::PixelType
+ //
+ enum PixelType
{
UINT = 0, // unsigned int (32 bit)
HALF = 1, // half (16 bit floating point)
@@ -72,6 +85,9 @@
NUM_PIXELTYPES // number of different pixel types
};
+ //
+ // Represents an OpenEXR buffer slice
+ //
struct Channel
{
Channel() : type( HALF ), data( NULL ) {}
@@ -87,7 +103,14 @@
typedef ChannelList::iterator ChannelIter;
+ unsigned int pixelTypeSize( PixelType type );
+
+
//-------------------------------------------------------------------------
+ //
+ // Wrapper for Imf::InputFile and ImfRgbaInputFile
+ //
+
//-------------------------------------------------------------------------
class InputFile
{
public:
@@ -95,7 +118,8 @@
InputFile( const std::string& filename );
~InputFile();
- Image* getImage();
+ Image* getImage()const;
+ std::string filename()const { return _filename; }
private:
InputFile() {}
@@ -110,9 +134,28 @@
+
//-------------------------------------------------------------------------
+ //
+ // Wrapper for Imf::OutputFile and ImfRgbaOutputFile
+ //
+
//-------------------------------------------------------------------------
class OutputFile
{
public:
+ //
+ // Create output file from list of Rgba pixels
+ //
+ // x : Image width
+ // y : Image height
+ //
+ // min_x :
+ // max_x : Cropped data window max and min
+ // min_y : coordinates
+ // max_y :
+ //
+ // aspect : Pixel aspect ratio
+ // screen_width : Screen window width
+ //
OutputFile( Imf::Rgba* pixels,
unsigned int x,
unsigned int y,
@@ -124,6 +167,10 @@
float screen_width=1.0f
);
+ //
+ // Create output file from list of channels. Other params
+ // same as Rgba* constructor
+ //
OutputFile( const ChannelList& channels,
unsigned int x,
unsigned int y,
@@ -135,8 +182,12 @@
float screen_width=1.0f
);
+
~OutputFile();
+ //
+ // Write the OutputFile to disk
+ //
void write( const std::string& filename );
private:
@@ -147,6 +198,7 @@
ChannelList _channels; // List of arbitrary channels
Imf::Rgba* _rgbas; // Array of Rgba Halfs. Null if using
channels
};
+
} // namespace EXR
- [Manta] r1848 - trunk/Image, kmorley, 11/13/2007
Archive powered by MHonArc 2.6.16.