TuttleOFX
1
|
00001 #include "Image.hpp" 00002 #include <tuttle/host/attribute/ClipImage.hpp> 00003 #include <tuttle/host/Core.hpp> 00004 00005 #include <tuttle/common/utils/global.hpp> 00006 00007 #include <boost/gil/image.hpp> 00008 #include <boost/gil/image_view.hpp> 00009 #include <boost/gil/typedefs.hpp> 00010 00011 #ifndef TUTTLE_PRODUCTION 00012 #ifdef TUTTLE_PNG_EXPORT_BETWEEN_NODES 00013 #define int_p_NULL (int *)NULL 00014 #include <boost/gil/extension/io/png_io.hpp> 00015 #endif 00016 #endif 00017 00018 namespace tuttle { 00019 namespace host { 00020 namespace attribute { 00021 00022 Image::Image( ClipImage& clip, const OfxTime time, const OfxRectD& bounds, const EImageOrientation orientation, const int rowDistanceBytes ) 00023 : ofx::imageEffect::OfxhImage( clip, time ) ///< this ctor will set basic props on the image 00024 , _memorySize( 0 ) 00025 , _pixelBytes( clip.getPixelMemorySize() ) 00026 , _rowAbsDistanceBytes( 0 ) 00027 , _orientation( orientation ) 00028 , _fullname( clip.getFullName() ) 00029 { 00030 // Set rod in canonical & pixel coord. 00031 const double par = clip.getPixelAspectRatio(); 00032 _bounds.x1 = std::floor(bounds.x1 / par); 00033 _bounds.x2 = std::ceil(bounds.x2 / par); 00034 _bounds.y1 = std::floor(bounds.y1); 00035 _bounds.y2 = std::ceil(bounds.y2); 00036 00037 const OfxPointI dimensions = { _bounds.x2 - _bounds.x1, _bounds.y2 - _bounds.y1 }; 00038 00039 // make some memory according to the bit depth 00040 const std::size_t automaticRowSize = dimensions.x * _pixelBytes; 00041 _memorySize = automaticRowSize * dimensions.y; 00042 00043 // render scale x and y of 1.0 00044 setDoubleProperty( kOfxImageEffectPropRenderScale, 1.0, 0 ); 00045 setDoubleProperty( kOfxImageEffectPropRenderScale, 1.0, 1 ); 00046 00047 // bounds and rod 00048 setIntProperty( kOfxImagePropBounds, _bounds.x1, 0 ); 00049 setIntProperty( kOfxImagePropBounds, _bounds.y1, 1 ); 00050 setIntProperty( kOfxImagePropBounds, _bounds.x2, 2 ); 00051 setIntProperty( kOfxImagePropBounds, _bounds.y2, 3 ); 00052 00053 /// @todo the same for bounds and rod, no tiles for the moment ! 00054 setIntProperty( kOfxImagePropRegionOfDefinition, _bounds.x1, 0 ); 00055 setIntProperty( kOfxImagePropRegionOfDefinition, _bounds.y1, 1 ); 00056 setIntProperty( kOfxImagePropRegionOfDefinition, _bounds.x2, 2 ); 00057 setIntProperty( kOfxImagePropRegionOfDefinition, _bounds.y2, 3 ); 00058 00059 // row bytes 00060 _rowAbsDistanceBytes = rowDistanceBytes != 0 ? rowDistanceBytes : automaticRowSize; 00061 setIntProperty( kOfxImagePropRowBytes, getOrientedRowDistanceBytes( eImageOrientationFromBottomToTop ) ); 00062 } 00063 00064 Image::~Image() 00065 { 00066 //TUTTLE_TLOG_VAR( TUTTLE_TRACE, getFullName() ); 00067 } 00068 00069 boost::uint8_t* Image::getPixelData() 00070 { 00071 return reinterpret_cast<boost::uint8_t*>( _data->data() ); 00072 } 00073 00074 void* Image::getVoidPixelData() 00075 { 00076 return reinterpret_cast<void*>( _data->data() ); 00077 } 00078 00079 char* Image::getCharPixelData() 00080 { 00081 return reinterpret_cast<char*>( _data->data() ); 00082 } 00083 00084 boost::uint8_t* Image::getOrientedPixelData( const EImageOrientation orientation ) 00085 { 00086 if( _orientation == orientation ) 00087 { 00088 return getPixelData(); 00089 } 00090 else 00091 { 00092 const std::ssize_t distance = getRowAbsDistanceBytes() * (_bounds.y2 - _bounds.y1 - 1); 00093 return reinterpret_cast<boost::uint8_t*>( getPixelData() + distance ); 00094 } 00095 } 00096 00097 00098 boost::uint8_t* Image::pixel( const int x, const int y ) 00099 { 00100 const OfxRectI bounds = getBounds(); 00101 00102 if( ( x >= bounds.x1 ) && ( x < bounds.x2 ) && ( y >= bounds.y1 ) && ( y < bounds.y2 ) ) 00103 { 00104 const int yOffset = ( _orientation == eImageOrientationFromTopToBottom ) ? ( y - bounds.y1 ) : ( y - bounds.y2 ); 00105 const int offset = yOffset * getRowAbsDistanceBytes() + ( x - bounds.x1 ) * _pixelBytes; 00106 return reinterpret_cast<boost::uint8_t*>( getPixelData() + offset ); 00107 } 00108 return NULL; 00109 } 00110 00111 template < class D_VIEW, class S_VIEW > 00112 void Image::copy( D_VIEW& dst, S_VIEW& src, const OfxPointI& dstCorner, 00113 const OfxPointI& srcCorner, const OfxPointI& count ) 00114 { 00115 using namespace boost::gil; 00116 if( src.width() >= ( count.x - srcCorner.x ) && 00117 src.height() >= ( count.y - srcCorner.y ) && 00118 dst.width() >= ( count.x - dstCorner.x ) && 00119 dst.height() >= ( count.y - dstCorner.y ) ) 00120 { 00121 S_VIEW subSrc = subimage_view( src, srcCorner.x, srcCorner.y, count.x, count.y ); 00122 D_VIEW subDst = subimage_view( dst, dstCorner.x, dstCorner.y, count.x, count.y ); 00123 copy_and_convert_pixels( subSrc, subDst ); 00124 } 00125 } 00126 00127 #ifndef TUTTLE_PRODUCTION 00128 #ifdef TUTTLE_PNG_EXPORT_BETWEEN_NODES 00129 void Image::debugSaveAsPng( const std::string& filename ) 00130 { 00131 using namespace boost::gil; 00132 switch( getComponentsType() ) 00133 { 00134 case ofx::imageEffect::ePixelComponentRGBA: 00135 switch( getBitDepth() ) 00136 { 00137 case ofx::imageEffect::eBitDepthUByte: 00138 { 00139 rgba8_view_t view = getGilView<rgba8_view_t >(); 00140 png_write_view( filename, view ); 00141 break; 00142 } 00143 case ofx::imageEffect::eBitDepthUShort: 00144 { 00145 rgba16_view_t view = getGilView<rgba16_view_t >(); 00146 png_write_view( filename, view ); 00147 break; 00148 } 00149 case ofx::imageEffect::eBitDepthFloat: 00150 { 00151 rgba32f_view_t view = getGilView<rgba32f_view_t >(); 00152 png_write_view( filename, color_converted_view<rgba8_pixel_t>( view ) ); 00153 break; 00154 } 00155 default: 00156 break; 00157 } 00158 break; 00159 case ofx::imageEffect::ePixelComponentAlpha: 00160 switch( getBitDepth() ) 00161 { 00162 case ofx::imageEffect::eBitDepthUByte: 00163 { 00164 gray8_view_t view = getGilView<gray8_view_t >(); 00165 png_write_view( filename, view ); 00166 break; 00167 } 00168 case ofx::imageEffect::eBitDepthUShort: 00169 { 00170 gray16_view_t view = getGilView<gray16_view_t >(); 00171 png_write_view( filename, view ); 00172 break; 00173 } 00174 case ofx::imageEffect::eBitDepthFloat: 00175 { 00176 gray32f_view_t view = getGilView<gray32f_view_t >(); 00177 png_write_view( filename, color_converted_view<rgb8_pixel_t>( view ) ); 00178 break; 00179 } 00180 default: 00181 break; 00182 } 00183 break; 00184 default: 00185 break; 00186 } 00187 } 00188 #endif 00189 #endif 00190 00191 /// Copy from gil image view to Image 00192 template < class S_VIEW > 00193 void Image::copy( Image* dst, S_VIEW& src, const OfxPointI& dstCorner, 00194 const OfxPointI& srcCorner, const OfxPointI& count ) 00195 { 00196 using namespace boost::gil; 00197 // Create destination 00198 switch( dst->getComponentsType() ) 00199 { 00200 case ofx::imageEffect::ePixelComponentRGBA: 00201 switch( dst->getBitDepth() ) 00202 { 00203 case ofx::imageEffect::eBitDepthUByte: 00204 { 00205 rgba8_view_t dView = dst->getGilView<rgba8_view_t >(); 00206 Image::copy( dView, src, dstCorner, srcCorner, count ); 00207 break; 00208 } 00209 case ofx::imageEffect::eBitDepthUShort: 00210 { 00211 rgba16_view_t dView = dst->getGilView<rgba16_view_t >(); 00212 Image::copy( dView, src, dstCorner, srcCorner, count ); 00213 break; 00214 } 00215 case ofx::imageEffect::eBitDepthFloat: 00216 { 00217 rgba32f_view_t dView = dst->getGilView<rgba32f_view_t >(); 00218 Image::copy( dView, src, dstCorner, srcCorner, count ); 00219 break; 00220 } 00221 default: 00222 break; 00223 } 00224 break; 00225 case ofx::imageEffect::ePixelComponentAlpha: 00226 switch( dst->getBitDepth() ) 00227 { 00228 case ofx::imageEffect::eBitDepthUByte: 00229 { 00230 gray8_view_t dView = dst->getGilView<gray8_view_t >(); 00231 Image::copy( dView, src, dstCorner, srcCorner, count ); 00232 break; 00233 } 00234 case ofx::imageEffect::eBitDepthUShort: 00235 { 00236 gray16_view_t dView = dst->getGilView<gray16_view_t >(); 00237 Image::copy( dView, src, dstCorner, srcCorner, count ); 00238 break; 00239 } 00240 case ofx::imageEffect::eBitDepthFloat: 00241 { 00242 gray32f_view_t dView = dst->getGilView<gray32f_view_t >(); 00243 Image::copy( dView, src, dstCorner, srcCorner, count ); 00244 break; 00245 } 00246 default: 00247 break; 00248 } 00249 break; 00250 default: 00251 break; 00252 } 00253 } 00254 00255 /// Copy from Image to Image 00256 void Image::copy( Image* dst, Image* src, const OfxPointI& dstCorner, 00257 const OfxPointI& srcCorner, const OfxPointI& count ) 00258 { 00259 using namespace boost::gil; 00260 switch( src->getComponentsType() ) 00261 { 00262 case ofx::imageEffect::ePixelComponentRGBA: 00263 switch( src->getBitDepth() ) 00264 { 00265 case ofx::imageEffect::eBitDepthUByte: 00266 { 00267 rgba8_view_t sView = src->getGilView<rgba8_view_t >(); 00268 Image::copy( dst, sView, dstCorner, srcCorner, count ); 00269 break; 00270 } 00271 case ofx::imageEffect::eBitDepthUShort: 00272 { 00273 rgba16_view_t sView = src->getGilView<rgba16_view_t >(); 00274 Image::copy( dst, sView, dstCorner, srcCorner, count ); 00275 break; 00276 } 00277 case ofx::imageEffect::eBitDepthFloat: 00278 { 00279 rgba32f_view_t sView = src->getGilView<rgba32f_view_t >(); 00280 Image::copy( dst, sView, dstCorner, srcCorner, count ); 00281 break; 00282 } 00283 default: 00284 break; 00285 } 00286 break; 00287 case ofx::imageEffect::ePixelComponentAlpha: 00288 switch( src->getBitDepth() ) 00289 { 00290 case ofx::imageEffect::eBitDepthUByte: 00291 { 00292 gray8_view_t sView = src->getGilView<gray8_view_t >(); 00293 Image::copy( dst, sView, dstCorner, srcCorner, count ); 00294 break; 00295 } 00296 case ofx::imageEffect::eBitDepthUShort: 00297 { 00298 gray16_view_t sView = src->getGilView<gray16_view_t >(); 00299 Image::copy( dst, sView, dstCorner, srcCorner, count ); 00300 break; 00301 } 00302 case ofx::imageEffect::eBitDepthFloat: 00303 { 00304 gray32f_view_t sView = src->getGilView<gray32f_view_t >(); 00305 Image::copy( dst, sView, dstCorner, srcCorner, count ); 00306 break; 00307 } 00308 default: 00309 break; 00310 } 00311 break; 00312 default: 00313 break; 00314 } 00315 } 00316 00317 } 00318 } 00319 }