TuttleOFX
1
|
00001 #include "Jpeg2000ReaderPlugin.hpp" 00002 #include "Jpeg2000ReaderProcess.hpp" 00003 #include "Jpeg2000ReaderDefinitions.hpp" 00004 00005 #include <tuttle/plugin/context/WriterDefinition.hpp> 00006 #include <tuttle/plugin/global.hpp> 00007 00008 #include <ofxsImageEffect.h> 00009 #include <ofxsMultiThread.h> 00010 00011 #include <boost/gil/gil_all.hpp> 00012 #include <boost/filesystem.hpp> 00013 #include <boost/lexical_cast.hpp> 00014 00015 namespace tuttle { 00016 namespace plugin { 00017 namespace jpeg2000 { 00018 namespace reader { 00019 00020 using namespace tuttle::io; 00021 using namespace boost::gil; 00022 using namespace boost::filesystem; 00023 00024 Jpeg2000ReaderPlugin::Jpeg2000ReaderPlugin( OfxImageEffectHandle handle ) 00025 : ReaderPlugin( handle ) 00026 { 00027 } 00028 00029 Jpeg2000ReaderPlugin::~Jpeg2000ReaderPlugin() 00030 { 00031 _reader.close(); 00032 } 00033 00034 Jpeg2000ReaderProcessParams Jpeg2000ReaderPlugin::getProcessParams(const OfxTime time) 00035 { 00036 if( varyOnTime() && 00037 ( time < getFirstTime() || time > getLastTime() ) ) 00038 { 00039 BOOST_THROW_EXCEPTION( exception::BadIndex() 00040 << exception::user("Time value outside bounds.") ); 00041 } 00042 Jpeg2000ReaderProcessParams params; 00043 00044 params._paramFilepath = getAbsoluteFilenameAt(time); 00045 00046 return params; 00047 } 00048 00049 void Jpeg2000ReaderPlugin::changedParam( const OFX::InstanceChangedArgs &args, const std::string ¶mName ) 00050 { 00051 if( paramName == kTuttlePluginFilename ) 00052 { 00053 _reader.close(); 00054 _fileInfos._failed = true; 00055 } 00056 ReaderPlugin::changedParam(args, paramName); 00057 } 00058 00059 bool Jpeg2000ReaderPlugin::getRegionOfDefinition( const OFX::RegionOfDefinitionArguments& args, OfxRectD& rod ) 00060 { 00061 FileInfo fileInfo = retrieveFileInfo( args.time ); 00062 if ( fileInfo._failed ) 00063 { 00064 BOOST_THROW_EXCEPTION( exception::FileInSequenceNotExist() 00065 << exception::user( "Jpeg2000: Unable to open file" ) 00066 << exception::filename( getAbsoluteFilenameAt( args.time ) ) ); 00067 } 00068 00069 rod.x1 = 0; 00070 rod.x2 = fileInfo._width; 00071 rod.y1 = 0; 00072 rod.y2 = fileInfo._height; 00073 00074 return true; 00075 } 00076 00077 void Jpeg2000ReaderPlugin::getClipPreferences( OFX::ClipPreferencesSetter& clipPreferences ) 00078 { 00079 // TUTTLE_LOG_VAR( TUTTLE_INFO, _paramFilepath->getValue() ); 00080 // TUTTLE_LOG_VAR( TUTTLE_INFO, getAbsoluteFirstFilename() ); 00081 // TUTTLE_LOG_VAR( TUTTLE_INFO, getFirstTime() ); 00082 // TUTTLE_LOG_VAR( TUTTLE_INFO, getAbsoluteFilenameAt(getFirstTime()) ); 00083 00084 ReaderPlugin::getClipPreferences( clipPreferences ); 00085 00086 FileInfo fileInfo = retrieveFileInfo( getFirstTime() ); 00087 if ( fileInfo._failed ) 00088 { 00089 BOOST_THROW_EXCEPTION( exception::Failed() 00090 << exception::user( "Jpeg2000: Unable to read file infos." ) ); 00091 } 00092 00093 if( getExplicitBitDepthConversion() == eParamReaderBitDepthAuto ) 00094 { 00095 clipPreferences.setClipBitDepth( *_clipDst, fileInfo._precisionType ); 00096 } 00097 else // if we explicitly specify which conversion we want 00098 { 00099 clipPreferences.setClipBitDepth( *_clipDst, getOfxExplicitConversion() ); 00100 } 00101 00102 if( getExplicitChannelConversion() == eParamReaderChannelAuto ) 00103 { 00104 switch( fileInfo._components ) 00105 { 00106 case 1: 00107 clipPreferences.setClipComponents( *_clipDst, OFX::ePixelComponentAlpha ); 00108 break; 00109 case 3: 00110 clipPreferences.setClipComponents( *_clipDst, OFX::ePixelComponentRGB ); 00111 break; 00112 case 4: 00113 clipPreferences.setClipComponents( *_clipDst, OFX::ePixelComponentRGBA ); 00114 break; 00115 default: 00116 { 00117 BOOST_THROW_EXCEPTION( exception::ImageFormat() 00118 << exception::user() + "Jpeg2000: Unexpected number of channels (" + fileInfo._components + ")" ); 00119 } 00120 } 00121 } 00122 00123 clipPreferences.setPixelAspectRatio( *_clipDst, 1.0 ); 00124 } 00125 00126 /** 00127 * @brief The overridden render function 00128 * @param[in] args Rendering parameters 00129 */ 00130 void Jpeg2000ReaderPlugin::render( const OFX::RenderArguments &args ) 00131 { 00132 if( retrieveFileInfo(args.time)._failed ) 00133 { 00134 BOOST_THROW_EXCEPTION( exception::BitDepthMismatch() 00135 << exception::user( "Jpeg2000: get file info failed" ) ); 00136 } 00137 // Full image decoding 00138 _reader.decode(); 00139 00140 // instantiate the render code based on the pixel depth of the dst clip 00141 OFX::EBitDepth dstBitDepth = this->_clipDst->getPixelDepth(); 00142 OFX::EPixelComponent dstComponents = this->_clipDst->getPixelComponents(); 00143 // do the rendering 00144 if( dstComponents == OFX::ePixelComponentRGBA ) 00145 { 00146 switch( dstBitDepth ) 00147 { 00148 case OFX::eBitDepthUByte: 00149 { 00150 Jpeg2000ReaderProcess<rgba8_view_t> fred( *this ); 00151 fred.setupAndProcess( args ); 00152 break; 00153 } 00154 case OFX::eBitDepthUShort: 00155 { 00156 Jpeg2000ReaderProcess<rgba16_view_t> fred( *this ); 00157 fred.setupAndProcess( args ); 00158 break; 00159 } 00160 case OFX::eBitDepthFloat: 00161 { 00162 Jpeg2000ReaderProcess<rgba32f_view_t> fred( *this ); 00163 fred.setupAndProcess( args ); 00164 break; 00165 } 00166 case OFX::eBitDepthNone: 00167 case OFX::eBitDepthCustom: 00168 { 00169 BOOST_THROW_EXCEPTION( exception::BitDepthMismatch() 00170 << exception::user( "Jpeg2000: BitDepthCustom not recognize" ) ); 00171 } 00172 } 00173 } 00174 else if( dstComponents == OFX::ePixelComponentRGB ) 00175 { 00176 switch( dstBitDepth ) 00177 { 00178 case OFX::eBitDepthUByte: 00179 { 00180 Jpeg2000ReaderProcess<rgb8_view_t> fred( *this ); 00181 fred.setupAndProcess( args ); 00182 break; 00183 } 00184 case OFX::eBitDepthUShort: 00185 { 00186 Jpeg2000ReaderProcess<rgb16_view_t> fred( *this ); 00187 fred.setupAndProcess( args ); 00188 break; 00189 } 00190 case OFX::eBitDepthFloat: 00191 { 00192 Jpeg2000ReaderProcess<rgb32f_view_t> fred( *this ); 00193 fred.setupAndProcess( args ); 00194 break; 00195 } 00196 case OFX::eBitDepthNone: 00197 case OFX::eBitDepthCustom: 00198 { 00199 BOOST_THROW_EXCEPTION( exception::BitDepthMismatch() 00200 << exception::user( "Jpeg2000: BitDepthCustom not recognize" ) ); 00201 } 00202 } 00203 } 00204 else if( dstComponents == OFX::ePixelComponentAlpha ) 00205 { 00206 switch( dstBitDepth ) 00207 { 00208 case OFX::eBitDepthUByte: 00209 { 00210 Jpeg2000ReaderProcess<gray8_view_t> fred( *this ); 00211 fred.setupAndProcess( args ); 00212 break; 00213 } 00214 case OFX::eBitDepthUShort: 00215 { 00216 Jpeg2000ReaderProcess<gray16_view_t> fred( *this ); 00217 fred.setupAndProcess( args ); 00218 break; 00219 } 00220 case OFX::eBitDepthFloat: 00221 { 00222 Jpeg2000ReaderProcess<gray32f_view_t> fred( *this ); 00223 fred.setupAndProcess( args ); 00224 break; 00225 } 00226 case OFX::eBitDepthNone: 00227 case OFX::eBitDepthCustom: 00228 { 00229 BOOST_THROW_EXCEPTION( exception::BitDepthMismatch() 00230 << exception::user( "Jpeg2000: BitDepthCustom not recognize" ) ); 00231 } 00232 } 00233 } 00234 else 00235 { 00236 TUTTLE_LOG_FATAL( dstComponents << " not recognize." ); 00237 BOOST_THROW_EXCEPTION( exception::Unknown() ); 00238 } 00239 } 00240 00241 Jpeg2000ReaderPlugin::FileInfo Jpeg2000ReaderPlugin::retrieveFileInfo( const OfxTime time ) 00242 { 00243 if( !_fileInfos._failed ) 00244 { 00245 if( time == _fileInfos._time && _reader.imageReady() ) 00246 { 00247 return _fileInfos; 00248 } 00249 00250 if( _reader.imageReady() ) 00251 { 00252 _reader.close(); 00253 } 00254 } 00255 00256 // Open new source 00257 std::string filename = getAbsoluteFilenameAt(time); 00258 try 00259 { 00260 _reader.open( filename ); 00261 } 00262 catch( boost::exception & e ) 00263 { 00264 _fileInfos._failed = true; 00265 BOOST_THROW_EXCEPTION( exception::FileNotExist() 00266 << exception::user( "Jpeg2000: Unable to open file" ) 00267 << exception::filename( filename ) ); 00268 } 00269 _fileInfos._failed = false; 00270 // No choice if we want to get 00271 // the image dimensions later 00272 try 00273 { 00274 _reader.decode(true); 00275 } 00276 catch( boost::exception & e ) 00277 { 00278 _fileInfos._failed = true; 00279 BOOST_THROW_EXCEPTION( exception::File() 00280 << exception::user( "Jpeg2000: Unable to decode file" ) 00281 << exception::filename( filename ) ); 00282 } 00283 00284 if( !_reader.componentsConform() ) 00285 { 00286 _fileInfos._failed = true; 00287 BOOST_THROW_EXCEPTION( exception::ImageFormat() 00288 << exception::user( "Jpeg2000 image components aren't conform." ) 00289 << exception::filename( filename ) 00290 << exception::time( time ) ); 00291 } 00292 00293 _fileInfos._time = time; 00294 _fileInfos._width = _reader.width(); 00295 _fileInfos._height = _reader.height(); 00296 _fileInfos._components = _reader.components(); 00297 _fileInfos._precision = _reader.precision(); 00298 00299 switch( _fileInfos._precision ) 00300 { 00301 case 8: 00302 _fileInfos._precisionType = OFX::eBitDepthUByte; 00303 break; 00304 case 12: 00305 case 16: 00306 _fileInfos._precisionType = OFX::eBitDepthUShort; 00307 break; 00308 case 32: 00309 _fileInfos._precisionType = OFX::eBitDepthFloat; 00310 break; 00311 default: 00312 _fileInfos._failed = true; 00313 BOOST_THROW_EXCEPTION( exception::ImageFormat() 00314 << exception::user() + "Jpeg2000: Bit depth not handled ! (" + _reader.precision() + ")" 00315 << exception::filename( filename ) 00316 << exception::time( time ) ); 00317 } 00318 00319 return _fileInfos; 00320 } 00321 00322 } 00323 } 00324 } 00325 }