TuttleOFX
1
|
00001 #include "OpenImageIOWriterDefinitions.hpp" 00002 #include "OpenImageIOWriterPlugin.hpp" 00003 00004 #include <terry/globals.hpp> 00005 #include <terry/openexr/half.hpp> 00006 00007 #include <tuttle/plugin/exceptions.hpp> 00008 00009 #include <imageio.h> 00010 #include <filesystem.h> 00011 00012 #include <boost/gil/gil_all.hpp> 00013 #include <boost/gil/extension/dynamic_image/dynamic_image_all.hpp> 00014 #include <boost/scoped_ptr.hpp> 00015 #include <boost/filesystem/fstream.hpp> 00016 #include <boost/mpl/map.hpp> 00017 #include <boost/mpl/integral_c.hpp> 00018 #include <boost/mpl/at.hpp> 00019 00020 namespace tuttle { 00021 namespace plugin { 00022 namespace openImageIO { 00023 namespace writer { 00024 00025 00026 template<class View> 00027 OpenImageIOWriterProcess<View>::OpenImageIOWriterProcess( OpenImageIOWriterPlugin& instance ) 00028 : ImageGilFilterProcessor<View>( instance, eImageOrientationFromTopToBottom ) 00029 , _plugin( instance ) 00030 { 00031 this->setNoMultiThreading(); 00032 } 00033 00034 /** 00035 * Deduce the best bitdepth when it hasn't been set by the user 00036 */ 00037 template<class View> 00038 ETuttlePluginBitDepth OpenImageIOWriterProcess<View>::getDefaultBitDepth(const std::string& filepath, const ETuttlePluginBitDepth &bitDepth){ 00039 if (bitDepth == eTuttlePluginBitDepthAuto) { 00040 std::string format = OpenImageIO::Filesystem::extension (filepath); 00041 if(format.find("exr") != std::string::npos || format.find("hdr") != std::string::npos || format.find("rgbe") != std::string::npos){ 00042 return eTuttlePluginBitDepth32f; 00043 }else if(format.find("jpg") != std::string::npos || format.find("jpeg") != std::string::npos || 00044 format.find("bmp") != std::string::npos || format.find("dds") != std::string::npos || 00045 format.find("ico") != std::string::npos || format.find("jfi") != std::string::npos || 00046 format.find("pgm") != std::string::npos || format.find("pnm") != std::string::npos || 00047 format.find("ppm") != std::string::npos || format.find("pbm") != std::string::npos || 00048 format.find("pic") != std::string::npos 00049 ) { 00050 return eTuttlePluginBitDepth8; 00051 }else{ 00052 //bmp, cin, dpx, fits, j2k, j2c, jp2, jpe, png, sgi, tga, tif, tiff, tpic, webp 00053 return eTuttlePluginBitDepth16; 00054 } 00055 00056 } 00057 return bitDepth; 00058 } 00059 00060 /** 00061 * @brief Function called by rendering thread each time a process must be done. 00062 * @param[in] procWindowRoW Processing window in RoW 00063 * @warning no multithread here ! 00064 */ 00065 template<class View> 00066 void OpenImageIOWriterProcess<View>::multiThreadProcessImages( const OfxRectI& procWindowRoW ) 00067 { 00068 BOOST_ASSERT( procWindowRoW == this->_srcPixelRod ); 00069 using namespace boost::gil; 00070 using namespace terry; 00071 params = _plugin.getProcessParams( this->_renderArgs.time ); 00072 00073 ETuttlePluginBitDepth finalBitDepth = getDefaultBitDepth(params._filepath,params._bitDepth); 00074 00075 try 00076 { 00077 switch( finalBitDepth ) 00078 { 00079 case eTuttlePluginBitDepthAuto: 00080 { 00081 boost::filesystem::path p ( params._filepath ); 00082 std::string ext = p.extension().string(); 00083 if( ext == ".cin" ) 00084 { 00085 switch ( _plugin._clipSrc->getPixelComponents() ) 00086 { 00087 case OFX::ePixelComponentAlpha: 00088 writeImage<gray16_image_t>( this->_srcView, params._filepath, eTuttlePluginBitDepth10 ); 00089 break; 00090 case OFX::ePixelComponentRGB: 00091 writeImage<rgb16_image_t>( this->_srcView, params._filepath, eTuttlePluginBitDepth10 ); 00092 break; 00093 case OFX::ePixelComponentRGBA: 00094 writeImage<rgba16_image_t>( this->_srcView, params._filepath, eTuttlePluginBitDepth10 ); 00095 break; 00096 default: 00097 BOOST_THROW_EXCEPTION( exception::Unsupported() 00098 << exception::user( "OIIO Writer: components not supported" ) ); 00099 break; 00100 } 00101 break; 00102 } 00103 if( ext == ".dpx" ) 00104 { 00105 writeImage<rgb16_image_t>( this->_srcView, params._filepath, eTuttlePluginBitDepth10 ); 00106 break; 00107 } 00108 if( ext == ".hdr" ) 00109 { 00110 writeImage<rgb32f_image_t>( this->_srcView, params._filepath, eTuttlePluginBitDepth32f ); 00111 break; 00112 } 00113 if( ext == ".jpg" || ext == ".jpeg" || ext == ".png" || ext == ".tga" ) 00114 { 00115 writeImage<rgb8_image_t>( this->_srcView, params._filepath, eTuttlePluginBitDepth8 ); 00116 break; 00117 } 00118 if( ext == ".j2k" || ext == ".jp2" || ext == ".j2c" ) 00119 { 00120 writeImage<rgb16_image_t>( this->_srcView, params._filepath, eTuttlePluginBitDepth12 ); 00121 break; 00122 } 00123 if( ext == ".tif" || ext == ".tiff" ) 00124 { 00125 switch ( _plugin._clipSrc->getPixelComponents() ) 00126 { 00127 case OFX::ePixelComponentAlpha: 00128 writeImage<gray16_image_t>( this->_srcView, params._filepath, eTuttlePluginBitDepth16 ); 00129 break; 00130 case OFX::ePixelComponentRGB: 00131 writeImage<rgb16_image_t>( this->_srcView, params._filepath, eTuttlePluginBitDepth16 ); 00132 break; 00133 case OFX::ePixelComponentRGBA: 00134 writeImage<rgba16_image_t>( this->_srcView, params._filepath, eTuttlePluginBitDepth16 ); 00135 break; 00136 default: 00137 BOOST_THROW_EXCEPTION( exception::Unsupported() 00138 << exception::user( "OIIO Writer: components not supported" ) ); 00139 break; 00140 } 00141 break; 00142 } 00143 00144 switch( _plugin._clipSrc->getPixelDepth() ) 00145 { 00146 case OFX::eBitDepthUByte: 00147 { 00148 switch( params._components ) 00149 { 00150 case eTuttlePluginComponentsAuto: 00151 { 00152 switch ( _plugin._clipSrc->getPixelComponents() ) 00153 { 00154 case OFX::ePixelComponentAlpha: 00155 writeImage<gray8_image_t>( this->_srcView, params._filepath, eTuttlePluginBitDepth8 ); 00156 break; 00157 case OFX::ePixelComponentRGB: 00158 writeImage<rgb8_image_t>( this->_srcView, params._filepath, eTuttlePluginBitDepth8 ); 00159 break; 00160 case OFX::ePixelComponentRGBA: 00161 writeImage<rgba8_image_t>( this->_srcView, params._filepath, eTuttlePluginBitDepth8 ); 00162 break; 00163 default: 00164 BOOST_THROW_EXCEPTION( exception::Unsupported() 00165 << exception::user( "OIIO Writer: components not supported" ) ); 00166 break; 00167 } 00168 break; 00169 } 00170 case eTuttlePluginComponentsGray: 00171 writeImage<gray8_image_t>( this->_srcView, params._filepath, eTuttlePluginBitDepth8 ); 00172 break; 00173 case eTuttlePluginComponentsRGBA: 00174 writeImage<rgba8_image_t>( this->_srcView, params._filepath, eTuttlePluginBitDepth8 ); 00175 break; 00176 case eTuttlePluginComponentsRGB: 00177 writeImage<rgb8_image_t>( this->_srcView, params._filepath, eTuttlePluginBitDepth8 ); 00178 break; 00179 } 00180 break; 00181 } 00182 case OFX::eBitDepthUShort: 00183 { 00184 switch( params._components ) 00185 { 00186 case eTuttlePluginComponentsAuto: 00187 { 00188 switch ( _plugin._clipSrc->getPixelComponents() ) 00189 { 00190 case OFX::ePixelComponentAlpha: 00191 writeImage<gray16_image_t>( this->_srcView, params._filepath, eTuttlePluginBitDepth16 ); 00192 break; 00193 case OFX::ePixelComponentRGB: 00194 writeImage<rgb16_image_t>( this->_srcView, params._filepath, eTuttlePluginBitDepth16 ); 00195 break; 00196 case OFX::ePixelComponentRGBA: 00197 writeImage<rgba16_image_t>( this->_srcView, params._filepath, eTuttlePluginBitDepth16 ); 00198 break; 00199 default: 00200 BOOST_THROW_EXCEPTION( exception::Unsupported() 00201 << exception::user( "OIIO Writer: components not supported" ) ); 00202 break; 00203 } 00204 break; 00205 } 00206 case eTuttlePluginComponentsGray: 00207 writeImage<gray16_image_t>( this->_srcView, params._filepath, eTuttlePluginBitDepth16 ); 00208 break; 00209 case eTuttlePluginComponentsRGBA: 00210 writeImage<rgba16_image_t>( this->_srcView, params._filepath, eTuttlePluginBitDepth16 ); 00211 break; 00212 case eTuttlePluginComponentsRGB: 00213 writeImage<rgb16_image_t>( this->_srcView, params._filepath, eTuttlePluginBitDepth16 ); 00214 break; 00215 } 00216 break; 00217 break; 00218 } 00219 case OFX::eBitDepthFloat: 00220 { 00221 switch( params._components ) 00222 { 00223 case eTuttlePluginComponentsAuto: 00224 { 00225 switch ( _plugin._clipSrc->getPixelComponents() ) 00226 { 00227 case OFX::ePixelComponentAlpha: 00228 writeImage<gray32f_image_t>( this->_srcView, params._filepath, eTuttlePluginBitDepth32f ); 00229 break; 00230 case OFX::ePixelComponentRGB: 00231 writeImage<rgb32f_image_t>( this->_srcView, params._filepath, eTuttlePluginBitDepth32f ); 00232 break; 00233 case OFX::ePixelComponentRGBA: 00234 writeImage<rgba32f_image_t>( this->_srcView, params._filepath, eTuttlePluginBitDepth32f ); 00235 break; 00236 default: 00237 BOOST_THROW_EXCEPTION( exception::Unsupported() 00238 << exception::user( "OIIO Writer: components not supported" ) ); 00239 break; 00240 } 00241 break; 00242 } 00243 case eTuttlePluginComponentsGray: 00244 writeImage<gray32f_image_t>( this->_srcView, params._filepath, eTuttlePluginBitDepth32f ); 00245 break; 00246 case eTuttlePluginComponentsRGBA: 00247 writeImage<rgba32f_image_t>( this->_srcView, params._filepath, eTuttlePluginBitDepth32f ); 00248 break; 00249 case eTuttlePluginComponentsRGB: 00250 writeImage<rgb32f_image_t>( this->_srcView, params._filepath, eTuttlePluginBitDepth32f ); 00251 break; 00252 } 00253 break; 00254 break; 00255 } 00256 case OFX::eBitDepthCustom: 00257 case OFX::eBitDepthNone: 00258 BOOST_THROW_EXCEPTION( exception::Unsupported() 00259 << exception::user( "OIIO Writer: bit depth not supported" ) ); 00260 } 00261 break; 00262 } 00263 case eTuttlePluginBitDepth8: 00264 { 00265 switch( params._components ) 00266 { 00267 case eTuttlePluginComponentsAuto: 00268 { 00269 switch ( _plugin._clipSrc->getPixelComponents() ) 00270 { 00271 case OFX::ePixelComponentAlpha: 00272 writeImage<gray8_image_t>( this->_srcView, params._filepath, params._bitDepth ); 00273 break; 00274 case OFX::ePixelComponentRGB: 00275 writeImage<rgb8_image_t>( this->_srcView, params._filepath, params._bitDepth ); 00276 break; 00277 case OFX::ePixelComponentRGBA: 00278 writeImage<rgba8_image_t>( this->_srcView, params._filepath, params._bitDepth ); 00279 break; 00280 default: 00281 BOOST_THROW_EXCEPTION( exception::Unsupported() 00282 << exception::user( "OIIO Writer: components not supported" ) ); 00283 break; 00284 } 00285 break; 00286 } 00287 case eTuttlePluginComponentsGray: 00288 writeImage<gray8_image_t>( this->_srcView, params._filepath, params._bitDepth ); 00289 break; 00290 case eTuttlePluginComponentsRGBA: 00291 writeImage<rgba8_image_t>( this->_srcView, params._filepath, params._bitDepth ); 00292 break; 00293 case eTuttlePluginComponentsRGB: 00294 writeImage<rgb8_image_t>( this->_srcView, params._filepath, params._bitDepth ); 00295 break; 00296 } 00297 break; 00298 } 00299 case eTuttlePluginBitDepth10: 00300 case eTuttlePluginBitDepth12: 00301 case eTuttlePluginBitDepth16: 00302 { 00303 switch( params._components ) 00304 { 00305 case eTuttlePluginComponentsAuto: 00306 { 00307 switch ( _plugin._clipSrc->getPixelComponents() ) 00308 { 00309 case OFX::ePixelComponentAlpha: 00310 writeImage<gray16_image_t>( this->_srcView, params._filepath, params._bitDepth ); 00311 break; 00312 case OFX::ePixelComponentRGB: 00313 writeImage<rgb16_image_t>( this->_srcView, params._filepath, params._bitDepth ); 00314 break; 00315 case OFX::ePixelComponentRGBA: 00316 writeImage<rgba16_image_t>( this->_srcView, params._filepath, params._bitDepth ); 00317 break; 00318 default: 00319 BOOST_THROW_EXCEPTION( exception::Unsupported() 00320 << exception::user( "OIIO Writer: components not supported" ) ); 00321 break; 00322 } 00323 break; 00324 } 00325 case eTuttlePluginComponentsGray: 00326 writeImage<gray16_image_t>( this->_srcView, params._filepath, params._bitDepth ); 00327 break; 00328 case eTuttlePluginComponentsRGBA: 00329 writeImage<rgba16_image_t>( this->_srcView, params._filepath, params._bitDepth ); 00330 break; 00331 case eTuttlePluginComponentsRGB: 00332 writeImage<rgb16_image_t>( this->_srcView, params._filepath, params._bitDepth ); 00333 break; 00334 } 00335 break; 00336 } 00337 case eTuttlePluginBitDepth16f: 00338 { 00339 switch( params._components ) 00340 { 00341 case eTuttlePluginComponentsAuto: 00342 { 00343 switch ( _plugin._clipSrc->getPixelComponents() ) 00344 { 00345 case OFX::ePixelComponentAlpha: 00346 writeImage<gray16h_image_t>( this->_srcView, params._filepath, params._bitDepth ); 00347 break; 00348 case OFX::ePixelComponentRGB: 00349 writeImage<rgb16h_image_t>( this->_srcView, params._filepath, params._bitDepth ); 00350 break; 00351 case OFX::ePixelComponentRGBA: 00352 writeImage<rgba16h_image_t>( this->_srcView, params._filepath, params._bitDepth ); 00353 break; 00354 default: 00355 BOOST_THROW_EXCEPTION( exception::Unsupported() 00356 << exception::user( "OIIO Writer: components not supported" ) ); 00357 break; 00358 } 00359 break; 00360 } 00361 case eTuttlePluginComponentsGray: 00362 writeImage<gray16h_image_t>( this->_srcView, params._filepath, params._bitDepth ); 00363 break; 00364 case eTuttlePluginComponentsRGBA: 00365 writeImage<rgba16h_image_t>( this->_srcView, params._filepath, params._bitDepth ); 00366 break; 00367 case eTuttlePluginComponentsRGB: 00368 writeImage<rgb16h_image_t>( this->_srcView, params._filepath, params._bitDepth ); 00369 break; 00370 } 00371 break; 00372 } 00373 case eTuttlePluginBitDepth32: 00374 { 00375 switch( params._components ) 00376 { 00377 case eTuttlePluginComponentsAuto: 00378 { 00379 switch ( _plugin._clipSrc->getPixelComponents() ) 00380 { 00381 case OFX::ePixelComponentAlpha: 00382 writeImage<gray32_image_t>( this->_srcView, params._filepath, params._bitDepth ); 00383 break; 00384 case OFX::ePixelComponentRGB: 00385 writeImage<rgb32_image_t>( this->_srcView, params._filepath, params._bitDepth ); 00386 break; 00387 case OFX::ePixelComponentRGBA: 00388 writeImage<rgba32_image_t>( this->_srcView, params._filepath, params._bitDepth ); 00389 break; 00390 default: 00391 BOOST_THROW_EXCEPTION( exception::Unsupported() 00392 << exception::user( "OIIO Writer: components not supported" ) ); 00393 break; 00394 } 00395 break; 00396 } 00397 case eTuttlePluginComponentsGray: 00398 writeImage<gray32_image_t>( this->_srcView, params._filepath, params._bitDepth ); 00399 break; 00400 case eTuttlePluginComponentsRGBA: 00401 writeImage<rgba32_image_t>( this->_srcView, params._filepath, params._bitDepth ); 00402 break; 00403 case eTuttlePluginComponentsRGB: 00404 writeImage<rgb32_image_t>( this->_srcView, params._filepath, params._bitDepth ); 00405 break; 00406 } 00407 break; 00408 } 00409 case eTuttlePluginBitDepth32f: 00410 { 00411 switch( params._components ) 00412 { 00413 case eTuttlePluginComponentsAuto: 00414 { 00415 switch ( _plugin._clipSrc->getPixelComponents() ) 00416 { 00417 case OFX::ePixelComponentAlpha: 00418 writeImage<gray32f_image_t>( this->_srcView, params._filepath, params._bitDepth ); 00419 break; 00420 case OFX::ePixelComponentRGB: 00421 writeImage<rgb32f_image_t>( this->_srcView, params._filepath, params._bitDepth ); 00422 break; 00423 case OFX::ePixelComponentRGBA: 00424 writeImage<rgba32f_image_t>( this->_srcView, params._filepath, params._bitDepth ); 00425 break; 00426 default: 00427 BOOST_THROW_EXCEPTION( exception::Unsupported() 00428 << exception::user( "OIIO Writer: components not supported" ) ); 00429 break; 00430 } 00431 break; 00432 } 00433 case eTuttlePluginComponentsGray: 00434 writeImage<gray32f_image_t>( this->_srcView, params._filepath, params._bitDepth ); 00435 break; 00436 case eTuttlePluginComponentsRGBA: 00437 writeImage<rgba32f_image_t>( this->_srcView, params._filepath, params._bitDepth ); 00438 break; 00439 case eTuttlePluginComponentsRGB: 00440 writeImage<rgb32f_image_t>( this->_srcView, params._filepath, params._bitDepth ); 00441 break; 00442 } 00443 break; 00444 } 00445 } 00446 } 00447 catch( exception::Common& e ) 00448 { 00449 e << exception::filename( params._filepath ); 00450 throw; 00451 } 00452 catch(... ) 00453 { 00454 BOOST_THROW_EXCEPTION( exception::Unknown() 00455 << exception::user( "OIIO Writer: Unable to write image") 00456 << exception::dev( boost::current_exception_diagnostic_information() ) 00457 << exception::filename(params._filepath) ); 00458 } 00459 copy_pixels( this->_srcView, this->_dstView ); // @todo ? 00460 } 00461 00462 /** 00463 * 00464 */ 00465 template<class View> 00466 template<class WImage> 00467 void OpenImageIOWriterProcess<View>::writeImage( View& src, const std::string& filepath, const ETuttlePluginBitDepth& bitDepth ) 00468 { 00469 using namespace boost; 00470 using namespace OpenImageIO; 00471 00472 boost::scoped_ptr<ImageOutput> out( ImageOutput::create( filepath ) ); 00473 if( out.get() == NULL ) 00474 { 00475 BOOST_THROW_EXCEPTION( exception::Bug() 00476 << exception::user( "OIIO Writer: error from writer while opening file." ) ); 00477 } 00478 WImage img( src.width(), src.height() ); 00479 00480 typename WImage::view_t vw( view( img ) ); 00481 copy_and_convert_pixels( src, vw ); 00482 00483 OpenImageIO::TypeDesc oiioBitDepth; 00484 size_t sizeOfChannel = 0; 00485 int bitsPerSample = 0; 00486 00487 ETuttlePluginBitDepth finalBitDepth = getDefaultBitDepth(filepath,bitDepth); 00488 00489 switch( finalBitDepth ) 00490 { 00491 case eTuttlePluginBitDepthAuto: 00492 BOOST_THROW_EXCEPTION( exception::Bug() 00493 << exception::user( "OIIO Writer: undefined output bit depth." ) ); 00494 case eTuttlePluginBitDepth8: 00495 oiioBitDepth = TypeDesc::UINT8; 00496 bitsPerSample = 8; 00497 sizeOfChannel = 1; 00498 break; 00499 case eTuttlePluginBitDepth10: 00500 oiioBitDepth = TypeDesc::UINT16; 00501 bitsPerSample = 10; 00502 sizeOfChannel = 2; 00503 break; 00504 case eTuttlePluginBitDepth12: 00505 oiioBitDepth = TypeDesc::UINT16; 00506 bitsPerSample = 12; 00507 sizeOfChannel = 2; 00508 break; 00509 case eTuttlePluginBitDepth16: 00510 oiioBitDepth = TypeDesc::UINT16; 00511 bitsPerSample = 16; 00512 sizeOfChannel = 2; 00513 break; 00514 case eTuttlePluginBitDepth16f: 00515 oiioBitDepth = TypeDesc::HALF; 00516 bitsPerSample = 16; 00517 sizeOfChannel = 2; 00518 break; 00519 case eTuttlePluginBitDepth32: 00520 oiioBitDepth = TypeDesc::UINT; 00521 bitsPerSample = 32; 00522 sizeOfChannel = 4; 00523 break; 00524 case eTuttlePluginBitDepth32f: 00525 oiioBitDepth = TypeDesc::FLOAT; 00526 bitsPerSample = 32; 00527 sizeOfChannel = 4; 00528 break; 00529 } 00530 00531 ImageSpec spec( src.width(), src.height(), gil::num_channels<WImage>::value, oiioBitDepth ); 00532 00533 spec.attribute( "oiio:BitsPerSample", bitsPerSample ); 00534 spec.attribute( "oiio:UnassociatedAlpha", params._premultiply ); 00535 spec.attribute( "CompressionQuality", params._quality ); 00536 spec.attribute( "Orientation", params._orientation ); 00537 00538 if( ! out->open( filepath, spec ) ) 00539 { 00540 BOOST_THROW_EXCEPTION( exception::Unknown() 00541 << exception::user( "OIIO Writer: " + out->geterror () ) 00542 << exception::filename(params._filepath) ); 00543 } 00544 00545 const stride_t xstride = gil::is_planar<WImage>::value ? sizeOfChannel : vw.num_channels() * sizeOfChannel; 00546 const stride_t ystride = vw.pixels().row_size(); 00547 const stride_t zstride = ystride * vw.height(); 00548 00549 typedef typename boost::gil::channel_type<WImage>::type channel_t; 00550 00551 out->write_image( 00552 oiioBitDepth, 00553 &( ( *vw.begin() )[0] ),// get the adress of the first channel value from the first pixel 00554 xstride, 00555 ystride, 00556 zstride, 00557 &progressCallback, 00558 this 00559 ); 00560 00561 out->close(); 00562 } 00563 00564 00565 00566 } 00567 } 00568 } 00569 }