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 #include "draw.hh"
31 
DrawPar()32 PF::DrawPar::DrawPar():
33   OpParBase(),
34   pen_grey( "pen_grey", this, 0 ),
35   pen_R( "pen_R", this, 1 ),
36   pen_G( "pen_G", this, 1 ),
37   pen_B( "pen_B", this, 1 ),
38   pen_L( "pen_L", this, 1 ),
39   pen_a( "pen_a", this, 1 ),
40   pen_b( "pen_b", this, 1 ),
41   pen_C( "pen_C", this, 1 ),
42   pen_M( "pen_M", this, 1 ),
43   pen_Y( "pen_Y", this, 1 ),
44   pen_K( "pen_K", this, 1 ),
45   bgd_grey( "bgd_grey", this, 0 ),
46   bgd_R( "bgd_R", this, 0 ),
47   bgd_G( "bgd_G", this, 0 ),
48   bgd_B( "bgd_B", this, 0 ),
49   bgd_L( "bgd_L", this, 0 ),
50   bgd_a( "bgd_a", this, 0 ),
51   bgd_b( "bgd_b", this, 0 ),
52   bgd_C( "bgd_C", this, 0 ),
53   bgd_M( "bgd_M", this, 0 ),
54   bgd_Y( "bgd_Y", this, 0 ),
55   bgd_K( "bgd_K", this, 0 ),
56   pen_color( "pen_color", this, RGBColor(1,1,1) ),
57   bgd_color( "bgd_color", this, RGBColor(0,0,0) ),
58   bgd_transparent( "bgd_transparent", this, false ),
59   pen_size( "pen_size", this, 50 ),
60   pen_opacity( "pen_opacity", this, 1 ),
61   pen_smoothness( "pen_smoothness", this, 0 ),
62   strokes( "strokes", this ),
63   rawbuf(NULL),
64   diskbuf(NULL)
65 {
66   set_type( "draw" );
67 	//diskbuf = new_diskbuffer();
68 
69   set_default_name( _("freehand drawing") );
70 }
71 
72 
~DrawPar()73 PF::DrawPar::~DrawPar()
74 {
75   if( rawbuf )
76     delete( rawbuf );
77 }
78 
79 
init_buffer(unsigned int level)80 void PF::DrawPar::init_buffer( unsigned int level )
81 {
82   if( !rawbuf ) return;
83 
84   std::vector<float> bgdcol;
85   switch( get_colorspace() ) {
86   case PF::PF_COLORSPACE_GRAYSCALE:
87     bgdcol.push_back( bgd_color.get().r );
88     break;
89   case PF::PF_COLORSPACE_RGB:
90     bgdcol.push_back( bgd_color.get().r );
91     bgdcol.push_back( bgd_color.get().g );
92     bgdcol.push_back( bgd_color.get().b );
93     break;
94   case PF::PF_COLORSPACE_LAB:
95     bgdcol.push_back( bgd_L.get() );
96     bgdcol.push_back( bgd_a.get() );
97     bgdcol.push_back( bgd_b.get() );
98     break;
99   case PF::PF_COLORSPACE_CMYK:
100     bgdcol.push_back( bgd_C.get() );
101     bgdcol.push_back( bgd_M.get() );
102     bgdcol.push_back( bgd_Y.get() );
103     bgdcol.push_back( bgd_K.get() );
104     break;
105   default:
106     break;
107   }
108 
109   bool bgd_match = (rawbuf->get_bgd_color().size() == bgdcol.size()) ? true : false;
110   if( bgd_match ) {
111     for( unsigned int i = 0; i < bgdcol.size(); i++ ) {
112       if( rawbuf->get_bgd_color()[i] != bgdcol[i] ) {
113 				bgd_match = false;
114 				break;
115       }
116     }
117   }
118 
119   unsigned int buf_xsize = rawbuf->get_xsize();
120   unsigned int buf_ysize = rawbuf->get_ysize();
121   unsigned int img_xsize = get_xsize();
122   unsigned int img_ysize = get_ysize();
123 #ifndef NDEBUG
124   std::cout<<"DrawPar::init_buffer(): level="<<level<<"  buf. size: "<<buf_xsize<<","<<buf_ysize
125            <<"  img. size: "<<img_xsize<<","<<img_ysize<<std::endl;
126 #endif
127 
128   unsigned int cur_xsize = rawbuf->get_xsize();
129   unsigned int cur_ysize = rawbuf->get_ysize();
130   unsigned int new_xsize = get_xsize();
131   unsigned int new_ysize = get_ysize();
132   for( unsigned int l = 0; l < level; l++ ) {
133     cur_xsize /= 2;
134     cur_ysize /= 2;
135     new_xsize *= 2;
136     new_ysize *= 2;
137   }
138 
139   if( (bgd_match == false) ||
140       ((int)cur_xsize != get_xsize()) ||
141       ((int)cur_ysize != get_ysize()) ||
142       (rawbuf->get_nbands() != get_nbands()) ||
143       (rawbuf->get_format() != get_format()) ) {
144 #ifndef NDEBUG
145     std::cout<<"DrawPar::init_buffer(): reinitializing buffer, new size: "<<new_xsize<<","<<new_ysize<<std::endl;
146 #endif
147     rawbuf->set_xsize( new_xsize );
148     rawbuf->set_ysize( new_ysize );
149     rawbuf->set_nbands( get_nbands() );
150     rawbuf->set_format( get_format() );
151     rawbuf->set_interpretation( get_interpretation() );
152 
153     rawbuf->init( bgdcol );
154 
155     VipsRect update;
156     std::list< PF::Stroke<PF::Pencil> >::iterator si;
157     for( si = strokes.get().begin(); si != strokes.get().end(); si++ ) {
158       PF::Stroke<PF::Pencil>& stroke = *si;
159       PF::Pencil& pen = stroke.get_pen();
160       rawbuf->start_stroke();
161       std::list< std::pair<int, int> >::iterator pi;
162       for( pi = stroke.get_points().begin(); pi != stroke.get_points().end(); pi++ ) {
163 				rawbuf->draw_point( pen, pi->first, pi->second, update, false );
164       }
165       rawbuf->end_stroke();
166     }
167 
168     //rawbuf->get_pyramid().reset();
169   }
170 }
171 
172 
173 
build(std::vector<VipsImage * > & in,int first,VipsImage * imap,VipsImage * omap,unsigned int & level)174 VipsImage* PF::DrawPar::build(std::vector<VipsImage*>& in, int first,
175 															VipsImage* imap, VipsImage* omap,
176 															unsigned int& level)
177 {
178   scale_factor = 1;
179   for(unsigned int l = 0; l < level; l++ ) {
180     scale_factor *= 2;
181   }
182 
183   std::list< Stroke<Pencil> >& sl = strokes.get();
184   std::list< Stroke<Pencil> >::iterator si;
185   //std::cout<<"DrawPar::build(): sl.size()="<<sl.size()<<std::endl;
186   for( si = sl.begin(); si != sl.end(); si++ ) {
187     //std::cout<<"DrawPar::build(): updating stroke area"<<std::endl;
188     si->compute_area();
189   }
190 
191   return OpParBase::build( in, first, imap, omap, level );
192   /*
193   if( !rawbuf ) {
194 		rawbuf = new PF::RawBuffer();
195   }
196   if( !rawbuf )
197     return NULL;
198 
199   init_buffer( level );
200 	if(rawbuf->get_fd() < 0)
201 		return NULL;
202   */
203 	/*
204 	PF::DiskBufferPar* diskbufpar = dynamic_cast<PF::DiskBufferPar*>(diskbuf->get_par());
205 	diskbufpar->set_descriptor( rawbuf->get_fd() );
206 	diskbufpar->set_width( get_xsize() );
207 	diskbufpar->set_height( get_ysize() );
208 	diskbufpar->set_image_hints( get_xsize(), get_ysize(), get_interpretation() );
209 	diskbufpar->set_format( get_format() );
210 	diskbufpar->set_coding( get_coding() );
211 	diskbufpar->set_nbands( get_nbands() );
212 	VipsImage* out = diskbufpar->build( in, first, imap, omap, level );
213 	return out;
214 	*/
215 
216   PF::PyramidLevel* l = rawbuf->get_pyramid().get_level( level );
217   if( l ) {
218     std::vector<VipsImage*> in2;
219     if( in.size() > 0 ) {
220       in2.push_back( in[0] );
221       in2.push_back( l->image );
222     } else {
223       in2.push_back( NULL );
224       in2.push_back( l->image );
225     }
226     VipsImage* out = PF::OpParBase::build( in2, 0, NULL, omap, level );
227     //g_object_unref( l->image );
228     PF_UNREF( l->image, "PF::DrawPar::build(): l->image unref" );
229     return out;
230   }
231   return NULL;
232 }
233 
234 
235 
start_stroke(unsigned int pen_size,float opacity,float smoothness)236 void PF::DrawPar::start_stroke( unsigned int pen_size, float opacity, float smoothness )
237 {
238   //std::cout<<"DrawPar::start_stroke(): pen_color="<<pen_color.get().r<<","<<pen_color.get().g<<","<<pen_color.get().b<<std::endl;
239   strokes.get().push_back( PF::Stroke<PF::Pencil>() );
240 
241   PF::Stroke<PF::Pencil>& stroke = strokes.get().back();
242 
243   PF::Pencil& pen = stroke.get_pen();
244   pen.set_channel( 0, pen_color.get().r );
245   pen.set_channel( 1, pen_color.get().g );
246   pen.set_channel( 2, pen_color.get().b );
247   pen.set_size( pen_size );
248   pen.set_opacity( opacity );
249   pen.set_smoothness( smoothness );
250 
251   strokes.modified();
252 
253   /*
254   switch( get_colorspace() ) {
255   case PF::PF_COLORSPACE_GRAYSCALE:
256     pen.set_channel( 0, pen_color.get().r );
257     break;
258   case PF::PF_COLORSPACE_RGB:
259     pen.set_channel( 0, pen_color.get().r );
260     pen.set_channel( 1, pen_color.get().g );
261     pen.set_channel( 2, pen_color.get().b );
262     break;
263   case PF::PF_COLORSPACE_LAB:
264     pen.set_channel( 0, pen_L.get() );
265     pen.set_channel( 1, pen_a.get() );
266     pen.set_channel( 2, pen_b.get() );
267     break;
268   case PF::PF_COLORSPACE_CMYK:
269     pen.set_channel( 0, pen_C.get() );
270     pen.set_channel( 1, pen_M.get() );
271     pen.set_channel( 2, pen_Y.get() );
272     pen.set_channel( 3, pen_K.get() );
273     break;
274   default:
275     break;
276   }
277 
278   if( rawbuf )
279     rawbuf->start_stroke();
280     */
281 }
282 
283 
284 
end_stroke()285 void PF::DrawPar::end_stroke()
286 {
287 }
288 
289 
290 
draw_point(int x,int y,VipsRect & update)291 void PF::DrawPar::draw_point( int x, int y, VipsRect& update )
292 {
293   PF::Stroke<PF::Pencil>& stroke = strokes.get().back();
294 
295   if( !stroke.get_points().empty() ) {
296     if( (stroke.get_points().back().first == x ) &&
297 				(stroke.get_points().back().second == y ) )
298       return;
299   }
300 
301   stroke.get_points().push_back( std::make_pair(x, y) );
302   stroke.compute_area();
303 
304   strokes.modified();
305 
306   PF::Pencil& pen = stroke.get_pen();
307 
308   if( rawbuf )
309     rawbuf->draw_point( pen, x, y, update, true );
310   else {
311     update.left = x - pen.get_size();
312     update.top = y - pen.get_size();
313     update.width = update.height = pen.get_size()*2 + 1;
314   }
315 }
316