1 /* 2 */ 3 4 /* 5 6 Copyright (C) 2014 Ferrero Andrea 7 8 This program is free software: you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation, either version 3 of the License, or 11 (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program. If not, see <http://www.gnu.org/licenses/>. 20 21 22 */ 23 24 /* 25 26 These files are distributed with PhotoFlow - http://aferrero2707.github.io/PhotoFlow/ 27 28 */ 29 30 #ifndef PF_DRAW_H 31 #define PF_DRAW_H 32 33 #include <string.h> 34 #include <iostream> 35 36 #include "../base/array2d.hh" 37 #include "../base/format_info.hh" 38 #include "../base/operation.hh" 39 #include "../base/processor.hh" 40 #include "../base/rawbuffer.hh" 41 42 //#include "diskbuffer.hh" 43 //#include "blender.hh" 44 45 namespace PF 46 { 47 48 struct RGBColor 49 { 50 float r, g, b; 51 RGBColorPF::RGBColor52 RGBColor(): r(0), g(0), b(0) {} RGBColorPF::RGBColor53 RGBColor( float _r, float _g, float _b ): r(_r), g(_g), b(_b) {} RGBColorPF::RGBColor54 RGBColor( const RGBColor& color ): 55 r( color.r ), g( color.g ), b( color.b ) 56 { 57 } operator =PF::RGBColor58 RGBColor & operator=(const RGBColor &c) 59 { 60 r = c.r; 61 g = c.g; 62 b = c.b; 63 return(*this); 64 } 65 }; 66 operator ==(const RGBColor & lhs,const RGBColor & rhs)67 inline bool operator==(const RGBColor& lhs, const RGBColor& rhs) 68 { 69 return( (lhs.r==rhs.r) && (lhs.g==rhs.g) && (lhs.b==rhs.b) ); 70 } 71 operator !=(const RGBColor & lhs,const RGBColor & rhs)72 inline bool operator!=(const RGBColor& lhs, const RGBColor& rhs) 73 { 74 return( !(lhs == rhs) ); 75 } 76 operator >>(std::istream & str,RGBColor & color)77 inline std::istream& operator >>( std::istream& str, RGBColor& color ) 78 { 79 str>>color.r>>color.g>>color.b; 80 return str; 81 } 82 operator <<(std::ostream & str,const RGBColor & color)83 inline std::ostream& operator <<( std::ostream& str, const RGBColor& color ) 84 { 85 str<<color.r<<" "<<color.g<<" "<<color.b<<" "; 86 return str; 87 } 88 89 template<> inline set_gobject_property(gpointer object,const std::string name,const RGBColor & value)90 void set_gobject_property<RGBColor>(gpointer object, const std::string name, const RGBColor& value) 91 { 92 //g_object_set( object, name.c_str(), value, NULL ); 93 } 94 95 96 97 class DrawPar: public OpParBase 98 { 99 Property<float> pen_grey, pen_R, pen_G, pen_B, pen_L, pen_a, pen_b, pen_C, pen_M, pen_Y, pen_K; 100 Property<float> bgd_grey, bgd_R, bgd_G, bgd_B, bgd_L, bgd_a, bgd_b, bgd_C, bgd_M, bgd_Y, bgd_K; 101 Property<RGBColor> pen_color; 102 Property<RGBColor> bgd_color; 103 Property<bool> bgd_transparent; 104 Property<int> pen_size; 105 Property<float> pen_opacity; 106 Property<float> pen_smoothness; 107 Property< std::list< Stroke<Pencil> > > strokes; 108 109 ProcessorBase* diskbuf; 110 RawBuffer* rawbuf; 111 112 unsigned int scale_factor; 113 114 Pencil pen; 115 116 public: 117 DrawPar(); 118 ~DrawPar(); 119 get_pen_grey()120 Property<float>& get_pen_grey() { return pen_grey; } get_pen_R()121 Property<float>& get_pen_R() { return pen_R; } get_pen_G()122 Property<float>& get_pen_G() { return pen_G; } get_pen_B()123 Property<float>& get_pen_B() { return pen_B; } get_pen_L()124 Property<float>& get_pen_L() { return pen_L; } get_pen_a()125 Property<float>& get_pen_a() { return pen_a; } get_pen_b()126 Property<float>& get_pen_b() { return pen_a; } get_pen_C()127 Property<float>& get_pen_C() { return pen_C; } get_pen_M()128 Property<float>& get_pen_M() { return pen_M; } get_pen_Y()129 Property<float>& get_pen_Y() { return pen_Y; } get_pen_K()130 Property<float>& get_pen_K() { return pen_K; } 131 get_bgd_grey()132 Property<float>& get_bgd_grey() { return bgd_grey; } get_bgd_R()133 Property<float>& get_bgd_R() { return bgd_R; } get_bgd_G()134 Property<float>& get_bgd_G() { return bgd_G; } get_bgd_B()135 Property<float>& get_bgd_B() { return bgd_B; } get_bgd_L()136 Property<float>& get_bgd_L() { return bgd_L; } get_bgd_a()137 Property<float>& get_bgd_a() { return bgd_a; } get_bgd_b()138 Property<float>& get_bgd_b() { return bgd_a; } get_bgd_C()139 Property<float>& get_bgd_C() { return bgd_C; } get_bgd_M()140 Property<float>& get_bgd_M() { return bgd_M; } get_bgd_Y()141 Property<float>& get_bgd_Y() { return bgd_Y; } get_bgd_K()142 Property<float>& get_bgd_K() { return bgd_K; } 143 get_pen_color()144 Property<RGBColor>& get_pen_color() { return pen_color; } get_bgd_color()145 Property<RGBColor>& get_bgd_color() { return bgd_color; } get_bgd_transparent()146 Property<bool>& get_bgd_transparent() { return bgd_transparent; } 147 has_intensity()148 bool has_intensity() { return false; } needs_input()149 bool needs_input() { return false; } 150 get_pen()151 Pencil& get_pen() { return pen; } 152 get_rawbuf()153 RawBuffer* get_rawbuf() { return rawbuf; } 154 155 void init_buffer( unsigned int level ); 156 get_scale_factor()157 unsigned int get_scale_factor() { return scale_factor; } 158 159 VipsImage* build(std::vector<VipsImage*>& in, int first, 160 VipsImage* imap, VipsImage* omap, 161 unsigned int& level); 162 start_stroke()163 void start_stroke() 164 { 165 start_stroke( pen_size.get(), pen_opacity.get(), pen_smoothness.get() ); 166 } 167 void start_stroke( unsigned int pen_size, float opacity, float smoothness ); 168 void end_stroke(); 169 get_strokes()170 Property< std::list< Stroke<Pencil> > >& get_strokes() { return strokes; } 171 172 void draw_point( int x, int y, VipsRect& update ); 173 }; 174 175 176 177 template < OP_TEMPLATE_DEF > 178 class DrawProc 179 { 180 public: render(VipsRegion ** ireg,int n,int in_first,VipsRegion * imap,VipsRegion * omap,VipsRegion * oreg,DrawPar * par)181 void render(VipsRegion** ireg, int n, int in_first, 182 VipsRegion* imap, VipsRegion* omap, 183 VipsRegion* oreg, DrawPar* par) 184 { 185 //std::cout<<"DrawProc::render() called"<<std::endl; 186 DrawPar* opar = par;//dynamic_cast<DrawPar*>(par); 187 if( !opar ) return; 188 std::list< Stroke<Pencil> >& strokes = opar->get_strokes().get(); 189 VipsRect *r = &oreg->valid; 190 //std::cout<<"nbands: "<<oreg->im->Bands<<std::endl; 191 //std::cout<<"r->left="<<r->left<<" r->top="<<r->top 192 // <<" r->width="<<r->width<<" r->height="<<r->height<<std::endl; 193 int line_size = r->width * oreg->im->Bands; //layer->in_all[0]->Bands; 194 //int width = r->width; 195 //int height = r->height; 196 197 //T* p; 198 T* pin; 199 T* pout; 200 T* ptemp; 201 int x, x0, y, y0, ch, row1, row2; 202 int point_clip_right, point_clip_bottom; 203 204 T** temp = new T*[r->height]; 205 for( y = 0; y < r->height; y++) temp[y] = new T[line_size]; 206 207 pout = (T*)VIPS_REGION_ADDR( oreg, r->left, r->top ); 208 //std::cout<<"pout="<<(void*)pout<<std::endl; 209 210 T val[16]; 211 //std::cout<<"DrawProc: bgd color: "<<opar->get_bgd_color().get().r<<" " 212 // <<opar->get_bgd_color().get().g<<" "<<opar->get_bgd_color().get().b<<std::endl; 213 val[0] = (T)(opar->get_bgd_color().get().r*FormatInfo<T>::RANGE + FormatInfo<T>::MIN); 214 val[1] = (T)(opar->get_bgd_color().get().g*FormatInfo<T>::RANGE + FormatInfo<T>::MIN); 215 val[2] = (T)(opar->get_bgd_color().get().b*FormatInfo<T>::RANGE + FormatInfo<T>::MIN); 216 //val[0] = (T)(1*FormatInfo<T>::RANGE + FormatInfo<T>::MIN); 217 //val[1] = (T)(0*FormatInfo<T>::RANGE + FormatInfo<T>::MIN); 218 //val[2] = (T)(0*FormatInfo<T>::RANGE + FormatInfo<T>::MIN); 219 220 if( opar->get_bgd_transparent().get() ) { 221 for( y = 0; y < r->height; y++ ) { 222 //p = (T*)VIPS_REGION_ADDR( ireg[in_first], point_clip.left, point_clip.top + y ); 223 pin = (T*)VIPS_REGION_ADDR( ireg[in_first], r->left, r->top + y ); 224 pout = (T*)VIPS_REGION_ADDR( oreg, r->left, r->top + y ); 225 for( x = 0; x < line_size; x += oreg->im->Bands ) { 226 for( ch = 0; ch < oreg->im->Bands; ch++ ) { 227 pout[x+ch] = pin[x+ch]; 228 } 229 } 230 } 231 } else { 232 for( y = 0; y < r->height; y++ ) { 233 pout = (T*)VIPS_REGION_ADDR( oreg, r->left, r->top + y ); 234 for( x = 0; x < line_size; x += oreg->im->Bands ) { 235 for( ch = 0; ch < oreg->im->Bands; ch++ ) { 236 pout[x+ch] = val[ch]; 237 } 238 } 239 } 240 } 241 242 PF::Array2D<float> opacity_max; 243 opacity_max.Init( r->width, r->height, r->top, r->left ); 244 245 std::list< Stroke<Pencil> >::iterator si; 246 std::list< std::pair<int, int> >::iterator pi; 247 VipsRect point_area; 248 VipsRect point_clip; 249 VipsRect stroke_area; 250 VipsRect stroke_clip; 251 //std::cout<<"DrawProc::render(): strokes.size()="<<strokes.size()<<std::endl; 252 int sn = 0; 253 for( si = strokes.begin(); si != strokes.end(); ++si, sn++ ) { 254 //std::cout<<"stroke area: "<<si->get_area().width<<","<<si->get_area().height 255 // <<"+"<<si->get_area().left<<"+"<<si->get_area().top<<std::endl; 256 stroke_area.left = si->get_area().left/static_cast<int>(opar->get_scale_factor()); 257 stroke_area.top = si->get_area().top/static_cast<int>(opar->get_scale_factor()); 258 stroke_area.width = si->get_area().width/static_cast<int>(opar->get_scale_factor()); 259 stroke_area.height = si->get_area().height/static_cast<int>(opar->get_scale_factor()); 260 //std::cout<<"stroke area: "<<stroke_area.width<<","<<stroke_area.height 261 // <<"+"<<stroke_area.left<<"+"<<stroke_area.top<<std::endl; 262 vips_rect_intersectrect( r, &stroke_area, &stroke_clip ); 263 //std::cout<<"stroke clip: "<<stroke_clip.width<<","<<stroke_clip.height 264 // <<"+"<<stroke_clip.left<<"+"<<stroke_clip.top<<std::endl; 265 if( (stroke_clip.width<1) || (stroke_clip.height<1) ) continue; 266 // copy current region to temp buffer 267 if( temp ) { 268 for( y = 0; y < r->height; y++ ) { 269 //p = (T*)VIPS_REGION_ADDR( ireg[in_first], point_clip.left, point_clip.top + y ); 270 pout = (T*)VIPS_REGION_ADDR( oreg, r->left, r->top + y ); 271 memcpy( temp[y], pout, line_size*sizeof(T) ); 272 } 273 } 274 275 Pencil& pen = si->get_pen(); 276 //std::cout<<" pen color: "<<pen.get_channel(0)<<std::endl; 277 int pen_size = (int)(pen.get_size()/opar->get_scale_factor()); 278 int pen_size2 = pen_size*pen_size; 279 for( ch = 0; ch < oreg->im->Bands; ch++ ) { 280 val[ch] = (T)(pen.get_channel(ch)*FormatInfo<T>::RANGE + FormatInfo<T>::MIN); 281 } 282 283 for( int ic = 0; ic < r->width; ic++ ) { 284 for( int ir = 0; ir < r->height; ir++ ) { 285 opacity_max.GetLocal(ir, ic) = 0; 286 } 287 } 288 289 point_area.width = point_area.height = pen_size*2 + 1; 290 PF::PencilMask* resized_mask = NULL; 291 PF::PencilMask* mask = &(pen.get_mask()); 292 if( pen_size != pen.get_size() ) { 293 resized_mask = new PF::PencilMask; 294 resized_mask->init( point_area.width, pen.get_opacity(), pen.get_smoothness() ); 295 mask = resized_mask; 296 } 297 298 std::list< std::pair<int, int> >& points = si->get_points(); 299 //std::cout<<"DrawProc::render(): points.size()="<<points.size()<<std::endl; 300 int pn = 0; 301 for( pi = points.begin(); pi != points.end(); ++pi, pn++ ) { 302 //std::cout<<"Drawing point "<<pi->first<<","<<pi->second<<std::endl; 303 point_area.left = pi->first/static_cast<int>(opar->get_scale_factor()) - pen_size; 304 point_area.top = pi->second/static_cast<int>(opar->get_scale_factor()) - pen_size; 305 //std::cout<<"Point area: "<<point_area.width<<","<<point_area.height 306 // <<"+"<<point_area.left<<"+"<<point_area.top<<std::endl; 307 vips_rect_intersectrect( r, &point_area, &point_clip ); 308 //std::cout<<"Point clip: "<<point_clip.width<<","<<point_clip.height 309 // <<"+"<<point_clip.left<<"+"<<point_clip.top<<std::endl; 310 if( (point_clip.width<1) || (point_clip.height<1) ) continue; 311 point_clip_right = point_clip.left + point_clip.width - 1; 312 point_clip_bottom = point_clip.top + point_clip.height - 1; 313 314 x0 = pi->first/opar->get_scale_factor(); 315 y0 = pi->second/opar->get_scale_factor(); 316 for( y = 0; y < point_area.height; y++ ) { 317 int row = y + point_area.top; 318 //std::cout<<" row="<<row<<std::endl; 319 if( row < point_clip.top ) continue; 320 if( row > point_clip_bottom ) break; 321 pout = (T*)VIPS_REGION_ADDR( oreg, point_area.left, row ); 322 ptemp = &(temp[point_area.top-r->top+y][(point_area.left-r->left)*oreg->im->Bands]); 323 for( x = 0; x < point_area.width; x++, pout += oreg->im->Bands, ptemp += oreg->im->Bands ) { 324 int col = x+point_area.left; 325 float mval = mask->get( x, y ); 326 //std::cout<<" col="<<col<<std::endl; 327 //mval = mval/2+0.5; 328 //std::cout<<" opacity_max.Get("<<row<<", "<<col<<")="<<opacity_max.Get(row, col)<<" mval="<<mval<<std::endl; 329 if( (col < point_clip.left) ) continue; 330 if( (col > point_clip_right) ) break; 331 if( mval < 0.00001 ) continue; 332 if( mval <= opacity_max.Get(row, col) ) continue; 333 opacity_max.Get(row, col) = mval; 334 for( ch = 0; ch < oreg->im->Bands; ch++ ) { 335 float out = mval*val[ch] + (1.0f-mval)*pout[ch]; 336 //std::cout<<" pout["<<ch<<"]= "<<pout[ch]<<" out["<<ch<<"]="<<out<<std::endl; 337 //if( pn == 0 ) 338 ptemp[ch] = static_cast<T>(out); 339 } 340 } 341 //if( pn > 0 && y > 1 ) break; 342 } 343 } 344 345 // copy temp buffer back to current region 346 if( temp ) { 347 for( y = 0; y < r->height; y++ ) { 348 //p = (T*)VIPS_REGION_ADDR( ireg[in_first], point_clip.left, point_clip.top + y ); 349 pout = (T*)VIPS_REGION_ADDR( oreg, r->left, r->top + y ); 350 memcpy( pout, temp[y], line_size*sizeof(T) ); 351 } 352 } 353 } 354 355 if( temp ) { 356 for( y = 0; y < r->height; y++) delete[] temp[y]; 357 delete[] temp; 358 } 359 } 360 }; 361 362 363 ProcessorBase* new_draw(); 364 } 365 366 #endif 367 368 369 370