TuttleOFX  1
EXRReaderProcess.tcc
Go to the documentation of this file.
00001 #include "EXRReaderDefinitions.hpp"
00002 #include "EXRReaderPlugin.hpp"
00003 
00004 #include <tuttle/plugin/context/ReaderPlugin.hpp>
00005 
00006 #include <tuttle/plugin/ImageGilProcessor.hpp>
00007 #include <tuttle/plugin/exceptions.hpp>
00008 
00009 #include <terry/algorithm/transform_pixels.hpp>
00010 #include <terry/numeric/assign.hpp>
00011 
00012 #include <terry/globals.hpp>
00013 #include <terry/basic_colors.hpp>
00014 #include <terry/openexr/half.hpp>
00015 
00016 #include <ofxsImageEffect.h>
00017 #include <ofxsMultiThread.h>
00018 
00019 #include <ImfChannelList.h>
00020 #include <ImfArray.h>
00021 #include <ImathVec.h>
00022 
00023 #include <boost/gil/gil_all.hpp>
00024 #include <boost/gil/packed_pixel.hpp>
00025 
00026 #include <boost/integer.hpp>  // for boost::uint_t
00027 #include <boost/cstdint.hpp>
00028 #include <boost/mpl/vector.hpp>
00029 #include <boost/scoped_ptr.hpp>
00030 #include <boost/assert.hpp>
00031 #include <boost/filesystem/fstream.hpp>
00032 
00033 #include <algorithm>
00034 
00035 namespace tuttle {
00036 namespace plugin {
00037 namespace exr {
00038 namespace reader {
00039 
00040 namespace bfs = boost::filesystem;
00041 
00042 template<class View>
00043 EXRReaderProcess<View>::EXRReaderProcess( EXRReaderPlugin& instance )
00044         : ImageGilProcessor<View>( instance, eImageOrientationFromTopToBottom )
00045         , _plugin( instance )
00046 {
00047         this->setNoMultiThreading();
00048 }
00049 
00050 template<class View>
00051 void EXRReaderProcess<View>::setup( const OFX::RenderArguments& args )
00052 {
00053         ImageGilProcessor<View>::setup( args );
00054 
00055         _params = _plugin.getProcessParams( args.time );
00056 
00057         try
00058         {
00059                 _exrImage.reset( new Imf::InputFile( _params._filepath.c_str() ) );
00060         }
00061         catch( ... )
00062         {
00063                 BOOST_THROW_EXCEPTION( exception::File()
00064                 << exception::user( "EXR: Error when reading header." )
00065                 << exception::filename( _params._filepath.c_str() ) );
00066         }
00067 }
00068 
00069 /**
00070  * @brief Function called by rendering thread each time a process must be done.
00071  * @param[in] procWindowRoW  Processing window in RoW
00072  */
00073 template<class View>
00074 void EXRReaderProcess<View>::multiThreadProcessImages( const OfxRectI& procWindowRoW )
00075 {
00076         using namespace terry;
00077         BOOST_ASSERT( procWindowRoW == this->_dstPixelRod );
00078         
00079         try
00080         {
00081                 View dst = this->_dstView;
00082                 
00083                 //TUTTLE_LOG_VAR( TUTTLE_INFO, _params._fileComponents );
00084                 switch( _params._fileComponents )
00085                 {
00086                         case 1:
00087                         {
00088                                 gray32f_image_t img( this->_dstView.width(), this->_dstView.height() );
00089                                 typename gray32f_image_t::view_t dv( view( img ) );
00090                                 terry::algorithm::transform_pixels( dv, terry::numeric::pixel_assigns_color_t<gray32f_pixel_t>( gray32f_pixel_t( 0.0 ) ) );
00091                                 readImage( dv, _params._filepath );
00092                                 copy_and_convert_pixels( dv, dst );
00093                                 break;
00094                         }
00095                         case 3:
00096                         {
00097                                 rgb32f_image_t img( this->_dstView.width(), this->_dstView.height() );
00098                                 typename rgb32f_image_t::view_t dv( view( img ) );
00099                                 terry::algorithm::transform_pixels( dv, terry::numeric::pixel_assigns_color_t<rgb32f_pixel_t>( rgb32f_pixel_t( 0.0, 0.0, 0.0 ) ) );
00100                                 readImage( dv, _params._filepath );
00101                                 copy_and_convert_pixels( dv, dst );
00102                                 break;
00103                         }
00104                         case 4:
00105                         {
00106                                 rgba32f_image_t img( this->_dstView.width(), this->_dstView.height() );
00107                                 typename rgba32f_image_t::view_t dv( view( img ) );
00108                                 terry::algorithm::transform_pixels( dv, terry::numeric::pixel_assigns_color_t<rgba32f_pixel_t>( rgba32f_pixel_t( 0.0, 0.0, 0.0, 0.0 ) ) );
00109                                 readImage( dv, _params._filepath );
00110                                 copy_and_convert_pixels( dv, dst );
00111                                 break;
00112                         }
00113                         default:
00114                         {
00115                                 BOOST_THROW_EXCEPTION( exception::Unsupported()
00116                                     << exception::user( "ExrWriter: file channel not supported" ) );
00117                         }
00118                 }
00119         }
00120         catch( boost::exception& e )
00121         {
00122                 e << exception::filename( _params._filepath );
00123                 TUTTLE_TLOG( TUTTLE_ERROR, boost::diagnostic_information( e ) );
00124                 throw;
00125         }
00126         catch( ... )
00127         {
00128                 BOOST_THROW_EXCEPTION( exception::Unknown()
00129                         << exception::user( "Unable to read image")
00130                         << exception::dev( boost::current_exception_diagnostic_information() )
00131                         << exception::filename( _params._filepath ) );
00132         }
00133 }
00134 
00135 /**
00136  */
00137 template<class View>
00138 template<class DView>
00139 void EXRReaderProcess<View>::readImage( DView dst, const std::string& filepath )
00140 {
00141         using namespace boost;
00142         using namespace mpl;
00143         using namespace boost::gil;
00144         using namespace Imf;
00145 
00146         EXRReaderProcessParams params = _plugin.getProcessParams( this->_renderArgs.time );
00147         Imf::InputFile in( filepath.c_str() );
00148         Imf::FrameBuffer frameBuffer;
00149         const Imf::Header& header = in.header();
00150         const Imath::Box2i& dw    = header.dataWindow();
00151         typename Imath::V2i imageDims = dw.size();
00152         imageDims.x++;  // Width
00153         imageDims.y++;  // Height
00154         
00155         // Get number of output components
00156         switch( (EParamReaderChannel)params._outComponents )
00157         {
00158                 case eParamReaderChannelGray:
00159                 {
00160                         // Copy 1 channel seletected by alpha channel ( index 3 )
00161                         channelCopy( in, frameBuffer, params, dst, imageDims.x, imageDims.y, 1 );
00162                         break;
00163                 }
00164                 case eParamReaderChannelRGB:
00165                 {
00166                         // Copy 3 channels starting by the first channel (0, 1, 2)
00167                         channelCopy( in, frameBuffer, params, dst, imageDims.x, imageDims.y, 3 );
00168                         break;
00169                 }
00170                 case eParamReaderChannelRGBA:
00171                 {
00172                         // Copy 4 channels starting by the first channel (0, 1, 2, 3)
00173                         channelCopy( in, frameBuffer, params, dst, imageDims.x, imageDims.y, 4 );
00174                         break;
00175                 }
00176                 case eParamReaderChannelAuto:
00177                 {
00178                         if( ! ( _params._fileComponents == 1 || _params._fileComponents == 3 || _params._fileComponents == 4 ) )
00179                         {
00180                                 std::string msg = "EXR: not support ";
00181                                 msg += _params._fileComponents;
00182                                 msg += " channels.";
00183                                 BOOST_THROW_EXCEPTION( exception::FileNotExist()
00184                                                                            << exception::user( msg ) );
00185                         }
00186                         
00187                         channelCopy( in, frameBuffer, params, dst, imageDims.x, imageDims.y, _params._fileComponents );
00188                 }
00189         }
00190 }
00191 
00192 template<class View>
00193 template< typename PixelType >
00194 void EXRReaderProcess<View>::initExrChannel( DataVector& data, Imf::Slice& slice, Imf::FrameBuffer& frameBuffer, Imf::PixelType pixelType, std::string channelID, const Imath::Box2i& dw, int w, int h )
00195 {
00196         data.resize( sizeof( PixelType ) * w * h );
00197         
00198         slice.type = pixelType;
00199         slice.base = (char*) (&data[0] - sizeof( PixelType ) * ( dw.min.x + dw.min.y * w ) );
00200         slice.xStride   = sizeof( PixelType ) * 1;
00201         slice.yStride   = sizeof( PixelType ) * w;
00202         slice.xSampling = 1;
00203         slice.ySampling = 1;
00204         slice.fillValue = 1.0;
00205         
00206         frameBuffer.insert( channelID.c_str(), slice );
00207 }
00208 
00209 template<class View>
00210 template<class DView>
00211 void EXRReaderProcess<View>::channelCopy( Imf::InputFile& input, Imf::FrameBuffer& frameBuffer, const EXRReaderProcessParams& params,
00212                                                                                   DView& dst, int w, int h, size_t nc )
00213 {
00214         using namespace boost::gil;
00215         const Imf::Header& header = input.header();
00216         const Imath::Box2i& dw    = header.dataWindow();
00217 
00218         DataVector *data = new DataVector[nc];
00219         Imf::Slice *slices = new  Imf::Slice[nc];
00220 
00221         for( size_t layer = 0; layer < nc; ++layer )
00222         {
00223                 const Imf::ChannelList& cl( header.channels() );
00224                 const Imf::Channel& ch = cl[ getChannelName( layer ).c_str() ];
00225                 switch( ch.type )
00226                 {
00227                         case Imf::HALF:
00228                         {
00229                                 initExrChannel<half>( data[layer], slices[layer], frameBuffer, ch.type, getChannelName( layer ), dw, w, h );
00230                                 break;
00231                         }
00232                         case Imf::FLOAT:
00233                         {
00234                                 initExrChannel<float>( data[layer], slices[layer], frameBuffer, ch.type, getChannelName( layer ), dw, w, h );
00235                                 break;
00236                         }
00237                         case Imf::UINT:
00238                         {
00239                                 initExrChannel<boost::uint32_t>( data[layer], slices[layer], frameBuffer, ch.type, getChannelName( layer ), dw, w, h );
00240                                 break;
00241                         }
00242                         case Imf::NUM_PIXELTYPES:
00243                         {
00244                                 BOOST_THROW_EXCEPTION( exception::Value()
00245                                     << exception::user( "Pixel type not supported." ) );
00246                                 break;
00247                         }
00248                 }
00249         }
00250         
00251         input.setFrameBuffer( frameBuffer );
00252         input.readPixels( dw.min.y, dw.max.y );
00253 
00254         for( size_t layer = 0; layer < nc; ++layer )
00255         {
00256                 switch( slices[layer].type )
00257                 {
00258                         case Imf::HALF:
00259                         {
00260                                 sliceCopy<DView, gray16h_view_t>( input, &slices[layer], dst, params, w, h, layer );
00261                                 break;
00262                         }
00263                         case Imf::FLOAT:
00264                         {
00265                                 sliceCopy<DView, gray32f_view_t>( input, &slices[layer], dst, params, w, h, layer );
00266                                 break;
00267                         }
00268                         case Imf::UINT:
00269                         {
00270                                 sliceCopy<DView, gray32_view_t>( input, &slices[layer], dst, params, w, h, layer );
00271                                 break;
00272                         }
00273                         case Imf::NUM_PIXELTYPES:
00274                         {
00275                                 BOOST_THROW_EXCEPTION( exception::Value()
00276                                     << exception::user( "Pixel type not supported." ) );
00277                                 break;
00278                         }
00279                 }
00280         }
00281         delete []data;
00282         delete []slices;
00283 }
00284 
00285 template<class View>
00286 template<class DView, typename workingView>
00287 void EXRReaderProcess<View>::sliceCopy( Imf::InputFile& input, const Imf::Slice* slice, DView& dst, const EXRReaderProcessParams& params, int w, int h, int n )
00288 {
00289         using namespace terry;
00290         const Imath::Box2i& dataw    = input.header().dataWindow();
00291         const Imath::Box2i& dispw    = input.header().displayWindow();
00292         
00293         workingView vw( interleaved_view( w, h, ( typename workingView::value_type*)slice->base, w * sizeof( typename workingView::value_type ) ) );
00294         workingView subView;
00295         
00296         if( params._displayWindow )
00297         {
00298                 size_t xoffsetData = dataw.min.x + std::max( 0, dispw.min.x );
00299                 size_t yoffsetData = dataw.min.y + std::max( 0, dispw.min.y );
00300                 size_t xoffsetDisp = dataw.min.x - std::min( 0, dispw.min.x );
00301                 size_t yoffsetDisp = dataw.min.y - std::min( 0, dispw.min.y );
00302                 
00303                 size_t wView = std::min( dataw.max.x, dispw.max.x ) - std::max( dataw.min.x, dispw.min.x ) + 1;
00304                 size_t hView = std::min( dataw.max.y, dispw.max.y ) - std::max( dataw.min.y, dispw.min.y ) + 1;
00305 
00306                 TUTTLE_TLOG_VAR4( TUTTLE_WARNING, dataw.min.x, dataw.min.y, dataw.max.x, dataw.max.y );
00307                 TUTTLE_TLOG_VAR4( TUTTLE_WARNING, dispw.min.x, dispw.min.y, dispw.max.x, dispw.max.y );
00308                 TUTTLE_TLOG_VAR4( TUTTLE_WARNING, xoffsetData, yoffsetData, xoffsetDisp, yoffsetDisp );
00309                 TUTTLE_TLOG_VAR2( TUTTLE_WARNING, wView, hView );
00310                 
00311                 subView = subimage_view( vw,
00312                                                                  xoffsetData,
00313                                                                  yoffsetData,
00314                                                                  wView,
00315                                                                  hView
00316                                                                  );
00317 
00318                 DView dstView = subimage_view( dst,
00319                                                                  xoffsetDisp,
00320                                                                  yoffsetDisp,
00321                                                                  wView,
00322                                                                  hView
00323                                                                  );
00324                 
00325                 if( wView > 0 && hView > 0 )
00326                 {
00327                         copy_and_convert_pixels( subView, nth_channel_view( dstView, n ) );
00328                 }
00329         }
00330         else
00331         {
00332                 subView = subimage_view( vw, dataw.min.x, dataw.min.y, w, h );
00333                 copy_and_convert_pixels( subView, nth_channel_view( dst, n ) );
00334         }
00335 }
00336 
00337 template<class View>
00338 std::string EXRReaderProcess<View>::getChannelName( size_t index )
00339 {
00340         return _plugin.channelNames()[ _plugin.channelChoice()[index]->getValue() ];
00341 }
00342 
00343 }
00344 }
00345 }
00346 }