Manta Interactive Ray Tracer Development Mailing List

Text archives Help


[Manta] r1848 - trunk/Image


Chronological Thread 
  • 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.

Top of page