TuttleOFX
1
|
00001 #include "PrintAlgorithm.hpp" 00002 #include "PrintPlugin.hpp" 00003 00004 #include <terry/channel.hpp> 00005 #include <terry/algorithm/pixel_by_channel.hpp> 00006 00007 #include <cstdio> 00008 00009 namespace tuttle { 00010 namespace plugin { 00011 namespace print { 00012 00013 struct CacaImage 00014 { 00015 char *pixels; 00016 unsigned int w, h; 00017 caca_dither_t *dither; 00018 }; 00019 00020 template<class SView> 00021 CacaImage load_cacaimage_from_view( const SView sView ) 00022 { 00023 typedef typename boost::gil::channel_mapping_type<SView>::type Channel; 00024 typedef typename terry::channel_base_type<Channel>::type ChannelBaseType; 00025 00026 CacaImage im; 00027 unsigned int bpp, rmask, gmask, bmask, amask; 00028 00029 im.pixels = (char*)boost::gil::interleaved_view_get_raw_data( sView ); 00030 im.w = sView.width(); 00031 im.h = sView.height(); 00032 rmask = 0x000000ff; 00033 gmask = 0x0000ff00; 00034 bmask = 0x00ff0000; 00035 amask = 0x00000000; 00036 bpp = boost::gil::num_channels<SView>::value * sizeof( ChannelBaseType ) * 8; 00037 00038 // Create the libcaca dither 00039 im.dither = caca_create_dither( bpp, im.w, im.h, sView.pixels().row_size(), 00040 rmask, gmask, bmask, amask); 00041 00042 if( ! im.dither ) 00043 { 00044 BOOST_THROW_EXCEPTION( exception::Unknown() << exception::dev( "Unable to load buffer." ) ); 00045 } 00046 return im; 00047 } 00048 00049 template<> 00050 CacaImage load_cacaimage_from_view<boost::gil::gray8_view_t>( const boost::gil::gray8_view_t sView ) 00051 { 00052 typedef boost::gil::channel_mapping_type<boost::gil::gray8_view_t>::type Channel; 00053 typedef terry::channel_base_type<Channel>::type ChannelBaseType; 00054 00055 CacaImage im; 00056 unsigned int bpp, rmask, gmask, bmask, amask; 00057 00058 im.pixels = (char*)boost::gil::interleaved_view_get_raw_data( sView ); 00059 im.w = sView.width(); 00060 im.h = sView.height(); 00061 rmask = 0xff000000; 00062 gmask = 0x00ff0000; 00063 bmask = 0x0000ff00; 00064 amask = 0x00000000; 00065 bpp = boost::gil::num_channels<boost::gil::gray8_view_t>::value * sizeof( ChannelBaseType ) * 8; 00066 00067 // Create the libcaca dither 00068 im.dither = caca_create_dither( bpp, im.w, im.h, sView.pixels().row_size(), 00069 rmask, gmask, bmask, amask); 00070 00071 if( ! im.dither ) 00072 { 00073 BOOST_THROW_EXCEPTION( exception::Unknown() << exception::dev( "Unable to load buffer." ) ); 00074 } 00075 return im; 00076 } 00077 00078 template<typename Channel> 00079 struct channel_cout_t : public std::unary_function<Channel,Channel> { 00080 GIL_FORCEINLINE 00081 Channel operator()(typename boost::gil::channel_traits<Channel>::const_reference ch) const 00082 { 00083 std::cout << ch << " "; 00084 return ch; 00085 } 00086 }; 00087 00088 template<template<class> class Func> 00089 struct call_pixel_by_channel_t 00090 { 00091 template<typename Pixel> 00092 GIL_FORCEINLINE 00093 Pixel operator()( const Pixel& v ) const 00094 { 00095 static_for_each( v, Func<typename boost::gil::channel_type<Pixel>::type>() ); 00096 return v; 00097 } 00098 }; 00099 00100 template<class View> 00101 PrintProcess<View>::PrintProcess( PrintPlugin &effect ) 00102 : ImageGilFilterProcessor<View>( effect, eImageOrientationFromTopToBottom ) 00103 , _plugin( effect ) 00104 { 00105 this->setNoMultiThreading(); 00106 } 00107 00108 template<class View> 00109 PrintProcess<View>::~PrintProcess() 00110 { 00111 } 00112 00113 template<class View> 00114 void PrintProcess<View>::setup( const OFX::RenderArguments& args ) 00115 { 00116 ImageGilFilterProcessor<View>::setup( args ); 00117 _params = _plugin.getProcessParams( args.renderScale ); 00118 00119 } 00120 00121 /** 00122 * @brief Function called by rendering thread each time a process must be done. 00123 * @param[in] procWindowRoW Processing window 00124 */ 00125 template<class View> 00126 void PrintProcess<View>::multiThreadProcessImages( const OfxRectI& procWindowRoW ) 00127 { 00128 using namespace boost::gil; 00129 //OfxRectI procWindowOutput = this->translateRoWToOutputClipCoordinates( procWindowRoW ); 00130 00131 const OfxRectI procWindowSrc = translateRegion( procWindowRoW, this->_srcPixelRod ); 00132 00133 View src = this->_srcView; 00134 View dst = this->_dstView; 00135 00136 OfxRectI region = procWindowSrc; 00137 00138 copy_pixels( src, dst ); 00139 00140 switch( _params._mode ) 00141 { 00142 case eParamModePixel: 00143 { 00144 call_pixel_by_channel_t<channel_cout_t>()( src( _params._pixel ) ); 00145 std::cout << std::endl; 00146 break; 00147 } 00148 case eParamModeRegion: 00149 { 00150 src = subimage_view( this->_srcView, _params._region.x1, _params._region.y1, 00151 _params._region.x2 - _params._region.x1, 00152 _params._region.y2 - _params._region.y1 ); 00153 region = _params._region; 00154 // continue with #src as a part of the image... 00155 } 00156 case eParamModeImage: 00157 { 00158 switch( _params._output ) 00159 { 00160 case eParamOutputNumeric: 00161 { 00162 std::cout << std::fixed; 00163 std::cout << std::setprecision( 2 ); 00164 call_pixel_by_channel_t<channel_cout_t> proc; 00165 for( int y = region.y1; y < region.y2; ++y ) 00166 { 00167 std::cout << "| "; 00168 typename View::x_iterator src_it = this->_srcView.x_at( region.x1, y ); 00169 for( int x = region.x1; 00170 x < region.x2; 00171 ++x, ++src_it ) 00172 { 00173 proc( *src_it ); 00174 std::cout << " | "; 00175 } 00176 std::cout << "\n"; 00177 if( this->progressForward( region.x2 - region.x1 ) ) 00178 return; 00179 } 00180 break; 00181 } 00182 case eParamOutputAscii: 00183 { 00184 // temporary gray buffer to compute the char values. 00185 gray8_image_t gImgGray( src.dimensions() ); 00186 gray8_view_t gViewGray( view(gImgGray) ); 00187 rgb8_image_t gImg( src.dimensions() ); 00188 rgb8_view_t gView( view(gImg) ); 00189 00190 if( _params._flip ) 00191 { 00192 src = flipped_up_down_view( src ); 00193 } 00194 00195 switch(_params._colorMode) 00196 { 00197 case eParamColorMono : copy_and_convert_pixels( src, gViewGray ); break; 00198 case eParamColorGray : copy_and_convert_pixels( src, gViewGray ); break; 00199 default : copy_and_convert_pixels( src, gView ); break; 00200 } 00201 // libcaca context 00202 caca_canvas_t *cv = NULL; 00203 00204 try 00205 { 00206 struct CacaImage cacaImg; 00207 unsigned int cols = 0, lines = 0, font_width = 6, font_height = 10; 00208 char *dither = NULL; 00209 float gamma = -1, brightness = -1, contrast = -1; 00210 00211 cv = caca_create_canvas(0, 0); 00212 if( !cv ) 00213 { 00214 BOOST_THROW_EXCEPTION( exception::Failed() 00215 << exception::user( "Print: unable to initialise libcaca" ) ); 00216 } 00217 switch(_params._colorMode) 00218 { 00219 case eParamColorMono : cacaImg = load_cacaimage_from_view( gViewGray ); break; 00220 case eParamColorGray : cacaImg = load_cacaimage_from_view( gViewGray ); break; 00221 default : cacaImg = load_cacaimage_from_view( gView ); break; 00222 } 00223 00224 /* 00225 * - \c "mono": use light gray on a black background. 00226 * - \c "gray": use white and two shades of gray on a black background. 00227 * - \c "8": use the 8 ANSI colours on a black background. 00228 * - \c "16": use the 16 ANSI colours on a black background. 00229 * - \c "fullgray": use black, white and two shades of gray for both the 00230 * characters and the background. 00231 * - \c "full8": use the 8 ANSI colours for both the characters and the 00232 * background. 00233 * - \c "full16" or \c "default": use the 16 ANSI colours for both the 00234 * characters and the background. This is the default value. 00235 */ 00236 std::string colorMode; 00237 switch(_params._colorMode) 00238 { 00239 case eParamColorMono : colorMode = "mono"; break; 00240 case eParamColorGray : colorMode = "gray"; break; 00241 case eParamColor8 : colorMode = "8"; break; 00242 case eParamColor16 : colorMode = "16"; break; 00243 case eParamColorfullgray : colorMode = "fullgray"; break; 00244 case eParamColorfull8 : colorMode = "full8"; break; 00245 case eParamColorfull16 : colorMode = "full16"; break; 00246 } 00247 caca_set_dither_color( cacaImg.dither, colorMode.c_str() ); 00248 00249 if( !cols && !lines ) 00250 { 00251 cols = _params._cols + 1; 00252 lines = cols * cacaImg.h * font_width / cacaImg.w / font_height; 00253 } 00254 else if( cols && !lines ) 00255 { 00256 lines = cols * cacaImg.h * font_width / cacaImg.w / font_height; 00257 } 00258 else if( !cols && lines ) 00259 { 00260 cols = lines * cacaImg.w * font_height / cacaImg.h / font_width; 00261 } 00262 //TUTTLE_LOG_TRACE( "output : " << cols << " x " << lines ); 00263 caca_set_canvas_size( cv, cols, lines ); 00264 00265 caca_clear_canvas( cv ); 00266 00267 if( caca_set_dither_algorithm( cacaImg.dither, dither?dither:"fstein" ) ) 00268 { 00269 BOOST_THROW_EXCEPTION( exception::Unknown() 00270 << exception::dev() + "Can't dither image with algorithm " + dither ); 00271 } 00272 00273 if( brightness != -1 ) 00274 caca_set_dither_brightness( cacaImg.dither, brightness ); 00275 if( contrast != -1 ) 00276 caca_set_dither_contrast( cacaImg.dither, contrast ); 00277 if( gamma != -1 ) 00278 caca_set_dither_gamma( cacaImg.dither, gamma ); 00279 00280 caca_dither_bitmap( cv, 0, 0, cols, lines, cacaImg.dither, cacaImg.pixels ); 00281 00282 caca_free_dither( cacaImg.dither ); 00283 00284 00285 if( _params._openGlViewer == true ) 00286 { 00287 // show result in a new window 00288 caca_display_t *dp; 00289 caca_event_t ev; 00290 dp = caca_create_display (cv); 00291 00292 caca_set_display_title(dp, "Rendering image in ASCII Art"); 00293 00294 caca_refresh_display(dp); 00295 caca_get_event(dp, CACA_EVENT_KEY_PRESS | CACA_EVENT_QUIT |CACA_EVENT_MOUSE_RELEASE, &ev, -1); 00296 caca_free_display(dp); 00297 00298 caca_free_canvas( cv ); 00299 } 00300 else 00301 { 00302 //clear the sreen 00303 std::cout << std::string( 100, '\n' ); 00304 00305 size_t len; 00306 void *output; 00307 00308 output = caca_export_canvas_to_memory( cv, "ansi", &len ); 00309 fwrite( output, len, 1, stdout ); 00310 free( output ); 00311 00312 caca_free_canvas( cv ); 00313 } 00314 } 00315 catch(...) 00316 { 00317 TUTTLE_LOG_CURRENT_EXCEPTION; 00318 if(cv != NULL ) 00319 caca_free_canvas( cv ); 00320 } 00321 break; 00322 } 00323 } 00324 break; 00325 } 00326 } 00327 } 00328 00329 00330 } 00331 } 00332 }