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