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 
31 #ifndef RAW_BUFFER_H
32 #define RAW_BUFFER_H
33 
34 #include <math.h>
35 
36 #include <string>
37 #include <list>
38 #include <vector>
39 #include <iostream>
40 #include <fstream>
41 
42 
43 #include <vips/vips.h>
44 //#include <vips/vips>
45 
46 #include "pftypes.hh"
47 
48 #include "format_info.hh"
49 
50 #include "property.hh"
51 
52 #include "imagepyramid.hh"
53 
54 
55 
56 namespace PF
57 {
58 
59 class PencilMask
60 {
61   unsigned int size;
62   float opacity;
63   float smoothness;
64   float** mask;
65 public:
PencilMask()66   PencilMask(): size(0), opacity(1), smoothness(0), mask(NULL)
67 {
68     //std::cout<<"PencilMask() called"<<std::endl;
69 }
70 
PencilMask(const PencilMask & sm)71   PencilMask( const PencilMask& sm ):
72     size(0),
73     opacity(1),
74     smoothness(0),
75     mask(NULL)
76   {
77     init( sm.get_size(), sm.get_opacity(), sm.get_smoothness() );
78     //std::cout<<"PencilMask(const PencilMask& sm) called"<<std::endl;
79   }
80 
~PencilMask()81   ~PencilMask()
82   {
83     //std::cout<<"~PencilMask() called. this="<<(void*)this<<"  mask="<<mask<<"  size="<<size<<std::endl;
84     //return;
85     if( mask ) {
86       for( unsigned int i = 0; i < size; i++) delete[] mask[i];
87       delete[] mask;
88       mask = NULL;
89     }
90     //std::cout<<"~PencilMask() finished"<<std::endl;
91   }
92 
operator =(const PencilMask & sm)93   PencilMask& operator=( const PencilMask& sm )
94   {
95     init( sm.get_size(), sm.get_opacity(), sm.get_smoothness() );
96     //std::cout<<"PencilMask& operator=(const PencilMask& sm) called"<<std::endl;
97     return ( *this );
98   }
99 
get_size() const100   unsigned int get_size() const { return size; }
get_opacity() const101   float get_opacity() const { return opacity; }
get_smoothness() const102   float get_smoothness() const { return smoothness; }
103 
104   void init(unsigned int s, float op, float sm);
105 
get(int x,int y)106   float get(int x, int y )
107   {
108     if( !mask ) {
109       std::cout<<"PencilMask::get(): WARNING: mask = NULL"<<std::endl;
110       return 1;
111     }
112     if( x < 0 || x >= (int)size) {
113       std::cout<<"PencilMask::get(): WARNING: x value out of range ("<<x<<")"<<std::endl;
114       return 1;
115     }
116     if( y < 0 || y >= (int)size) {
117       std::cout<<"PencilMask::get(): WARNING: y value out of range ("<<y<<")"<<std::endl;
118       return 1;
119     }
120     return mask[y][x];
121   }
122 };
123 
124 
125 
126 class Pencil
127 {
128   std::vector<float> color;
129   int size;
130   float opacity;
131   float smoothness;
132   PencilMask mask;
133 public:
Pencil()134   Pencil(): size(0), opacity(1), smoothness(0.5) {}
Pencil(const Pencil & p)135   Pencil( const Pencil& p )
136   {
137     //std::cout<<"Stamp(const Stamp& s) called."<<std::endl;
138     size = p.get_size();
139     opacity = p.get_opacity();
140     smoothness = p.get_smoothness();
141     init_mask();
142   }
143 
set_size(int s)144   void set_size( int s ) { size = s; init_mask(); }
get_size() const145   int get_size() const { return size; }
146 
set_channel(unsigned int ch,float val)147   void set_channel( unsigned int ch, float val )
148   {
149     if( color.size() <= ch )
150       color.resize( ch+1 );
151     color[ch] = val;
152   }
get_channel(unsigned int ch) const153   float get_channel( unsigned int ch ) const
154   {
155     if( color.size() <= ch ) return 0;
156     return color[ch];
157   }
get_color()158   std::vector<float>& get_color() { return color; }
get_color() const159   const std::vector<float>& get_color() const { return color; }
160 
set_opacity(float val)161   void set_opacity( float val ) { opacity = val; }
get_opacity() const162   float get_opacity() const { return opacity; }
163 
set_smoothness(float val)164   void set_smoothness( float val ) { smoothness = val; init_mask(); }
get_smoothness() const165   float get_smoothness() const { return smoothness; }
166 
init_mask()167   void init_mask()
168   {
169     mask.init( size*2+1, opacity, smoothness );
170   }
get_mask()171   PencilMask& get_mask() { return mask; }
172 
operator =(const Pencil & p)173   Pencil & operator=(const Pencil &p)
174   {
175     color = p.get_color();
176     size = p.get_size();
177     opacity = p.get_opacity();
178     smoothness = p.get_smoothness();
179     init_mask();
180     return(*this);
181   }
182 };
183 
184 
185 inline
operator ==(const Pencil & l,const Pencil & r)186 bool operator ==(const Pencil& l, const Pencil& r)
187 {
188   if( l.get_color() != r.get_color() ) return false;
189   if( l.get_opacity() != r.get_opacity() ) return false;
190   if( l.get_size() != r.get_size() ) return false;
191   if( l.get_smoothness() != r.get_smoothness() ) return false;
192   return true;
193 }
194 
195 inline
operator !=(const Pencil & l,const Pencil & r)196 bool operator !=(const Pencil& l, const Pencil& r)
197 {
198   return( !(l==r) );
199 }
200 
201 
202 
203 
204 class Segment
205 {
206   unsigned int x1, y1, x2, y2;
207 public:
Segment()208   Segment(): x1(0), y1(0), x2(0), y2(0) {}
set(unsigned int _x1,unsigned int _y1,unsigned int _x2,unsigned int _y2)209   void set( unsigned int _x1, unsigned int _y1,
210       unsigned int _x2, unsigned int _y2 )
211   {
212     x1 = _x1; y1 = _y1; x2 = _x2; y2 = _y2;
213   }
get_x1()214   unsigned int get_x1() { return x1; }
get_y1()215   unsigned int get_y1() { return y1; }
get_x2()216   unsigned int get_x2() { return x2; }
get_y2()217   unsigned int get_y2() { return y2; }
218 };
219 
220 
221 
222 
223 template <class Pen>
224 class Stroke
225 {
226   Pen pen;
227   std::list<Segment> segments;
228   std::list< std::pair<int, int> > points;
229 
230   VipsRect area;
231 
232 public:
Stroke()233   Stroke()
234   {
235     //std::cout<<"Calling Stroke()"<<std::endl;
236   }
237 
Stroke(const Stroke & s)238   Stroke(const Stroke& s)
239   {
240     //std::cout<<"Calling Stroke(const Stroke& s)"<<std::endl;
241     pen = s.get_pen();
242     segments = s.get_segments();
243     points = s.get_points();
244     area.width = s.get_area().width;
245     area.height = s.get_area().height;
246     area.left = s.get_area().left;
247     area.top = s.get_area().top;
248     //std::cout<<"Stroke(const Stroke& s) finished"<<std::endl;
249   }
250 
operator =(const Stroke & s)251   Stroke& operator=(const Stroke& s)
252   {
253     //std::cout<<"Calling Stroke& operator=(const Stroke& s)"<<std::endl;
254     pen = s.get_pen();
255     segments = s.get_segments();
256     points = s.get_points();
257     area.width = s.get_area().width;
258     area.height = s.get_area().height;
259     area.left = s.get_area().left;
260     area.top = s.get_area().top;
261     //std::cout<<"Stroke& operator=(const Stroke& s) finished"<<std::endl;
262     return *this;
263   }
264 
~Stroke()265   ~Stroke()
266   {
267     //std::cout<<"Calling ~Stroke()"<<std::endl;
268   }
269 
get_pen()270   Pen& get_pen() { return pen; }
get_pen() const271   const Pen& get_pen() const { return pen; }
get_points()272   std::list< std::pair<int, int> >& get_points() { return points; }
get_points() const273   const std::list< std::pair<int, int> >& get_points() const { return points; }
get_segments()274   std::list< Segment >& get_segments() { return segments; }
get_segments() const275   const std::list< Segment >& get_segments() const { return segments; }
get_area()276   VipsRect& get_area() { return area; }
get_area() const277   const VipsRect& get_area() const { return area; }
278   void compute_area();
279 };
280 
281 
282 template <class Pen>
compute_area()283 void PF::Stroke<Pen>::compute_area()
284 {
285   int xmin = 10000000, xmax = -10000000;
286   int ymin = 10000000, ymax = -10000000;
287   std::list< std::pair<int, int> >::iterator pi;
288   for( pi = points.begin(); pi != points.end(); pi++ ) {
289     int x1 = pi->first - pen.get_size();
290     int x2 = pi->first + pen.get_size();
291     int y1 = pi->second - pen.get_size();
292     int y2 = pi->second + pen.get_size();
293 
294     xmin = MIN( xmin, x1 );
295     xmax = MAX( xmax, x2 );
296     ymin = MIN( ymin, y1 );
297     ymax = MAX( ymax, y2 );
298   }
299 
300   //std::cout<<"Stroke<Pen>::compute_area(): points.size()="<<points.size()<<"  xmin="<<xmin<<"  xmax="<<xmax<<"  ymin="<<ymin<<"  ymax="<<ymax<<std::endl;
301 
302   area.left = xmin;
303   area.top = ymin;
304   area.width = xmax - xmin + 1;
305   area.height = ymax - ymin + 1;
306 }
307 
308 
309 
310 template <class Pen>
operator ==(const Stroke<Pen> & l,const Stroke<Pen> & r)311 inline bool operator ==(const Stroke<Pen>& l, const Stroke<Pen>& r)
312 {
313   if( l.get_pen() != r.get_pen() ) return false;
314   if( l.get_points() != r.get_points() ) return false;
315   return true;
316 }
317 
318 template <class Pen>
operator !=(const Stroke<Pen> & l,const Stroke<Pen> & r)319 inline bool operator !=(const Stroke<Pen>& l, const Stroke<Pen>& r)
320 {
321   return( !(l==r) );
322 }
323 
324 
operator >>(std::istream & str,Pencil & pen)325 inline std::istream& operator >>( std::istream& str, Pencil& pen )
326 {
327   unsigned int nch;
328   str>>nch;
329   std::vector<float>& color = pen.get_color();
330   color.clear();
331   for( unsigned int i = 0; i < nch; i++ ) {
332     float val;
333     str>>val;
334     color.push_back( val );
335   }
336   unsigned int size;
337   //float opacity;
338   //str>>size>>opacity;
339   float sharpness;
340   str>>size>>sharpness;
341   pen.set_size( size );
342   //pen.set_opacity( opacity );
343   pen.set_smoothness( 1.0f-sharpness );
344   return str;
345 }
346 
operator <<(std::ostream & str,const Pencil & pen)347 inline std::ostream& operator <<( std::ostream& str, const Pencil& pen )
348 {
349   const std::vector<float>& color = pen.get_color();
350   str<<color.size()<<" ";
351   std::list< std::pair<unsigned int, unsigned int> >::iterator i;
352   for( unsigned int i = 0; i < color.size(); i++ ) {
353     str<<color[i]<<" ";
354   }
355   //str<<pen.get_size()<<" "<<pen.get_opacity()<<" ";
356   str<<pen.get_size()<<" "<<1.0f-pen.get_smoothness()<<" ";
357   return str;
358 }
359 
360 
361 
362 template <class Pen>
operator >>(std::istream & str,Stroke<Pen> & stroke)363 inline std::istream& operator >>( std::istream& str, Stroke<Pen>& stroke )
364 {
365   str>>stroke.get_pen();
366   std::list< std::pair<int, int> >& points = stroke.get_points();
367   points.clear();
368   int npoints;
369   str>>npoints;
370   for( int i = 0; i < npoints; i++ ) {
371     int a, b;
372     str>>a>>b;
373     points.push_back( std::make_pair(a,b) );
374   }
375   return str;
376 }
377 
378 template <class Pen>
operator <<(std::ostream & str,const Stroke<Pen> & stroke)379 inline std::ostream& operator <<( std::ostream& str, const Stroke<Pen>& stroke )
380 {
381   str<<stroke.get_pen();
382   const std::list< std::pair<int, int> >& points = stroke.get_points();
383   str<<points.size()<<" ";
384   std::list< std::pair<int, int> >::const_iterator i;
385   for( i = points.begin(); i != points.end(); i++ ) {
386     str<<i->first<<" "<<i->second<<" ";
387   }
388   return str;
389 }
390 
391 
392 /*
393   template <class Pen>
394   inline std::istream& operator >>( std::istream& str, std::list< Stroke<Pen> >& strokes )
395   {
396     strokes.clear();
397     int nstrokes;
398     str>>nstrokes;
399     for( int i = 0; i < nstrokes; i++ ) {
400       strokes.push_back( Stroke<Pen>() );
401       Stroke<Pen>& stroke = strokes.back();
402       str>>stroke;
403     }
404     return str;
405   }
406 
407   template <class Pen>
408   inline std::ostream& operator <<( std::ostream& str, const std::list< Stroke<Pen> >& strokes )
409   {
410     str<<strokes.size()<<" ";
411     typename std::list< Stroke<Pen> >::const_iterator i;
412     for( i = strokes.begin(); i != strokes.end(); i++ ) {
413       str<<(*i);
414     }
415     return str;
416   }
417  */
418 
419 /*
420   template <class T>
421   inline bool operator ==(const std::list<T>& l, const std::list<T>& r)
422   {
423     if( l.size() != r.size() ) return false;
424     typename std::list<T>::const_iterator i, j;
425     for( i = l.begin(), j = r.begin(); i != l.end(); i++, j++ ) {
426       if( (*i) != (*j) ) return false;
427     }
428     return true;
429   }
430 
431   template <class T>
432   inline bool operator !=(const std::list<T>& l, const std::list<T>& r)
433   {
434     return( !(l==r) );
435   }
436  */
437 
438 /*
439   template <class T>
440   inline std::istream& operator >>( std::istream& str, std::list<T>& list )
441   {
442     list.clear();
443     int n;
444     str>>n;
445     for( int i = 0; i < n; i++ ) {
446       list.push_back( T() );
447       T& val = list.back();
448       str>>val;
449     }
450     return str;
451   }
452 
453   template <class T>
454   inline std::ostream& operator <<( std::ostream& str, const std::list<T>& list )
455   {
456     str<<list.size()<<" ";
457     typename std::list<T>::const_iterator i;
458     for( i = list.begin(); i != list.end(); i++ ) {
459       str<<(*i);
460     }
461     return str;
462   }
463  */
464 
465 
466 template<> inline
set_gobject_property(gpointer object,const std::string name,const std::list<Stroke<Pencil>> & value)467 void set_gobject_property< std::list< Stroke<Pencil> > >(gpointer object, const std::string name,
468     const std::list< Stroke<Pencil> >& value)
469     {
470     }
471 
472 
473 
474 class RawBuffer
475 {
476   std::string file_name;
477   int fd;
478   void* buf;
479   unsigned char* pxmask;
480 
481   // Requested image fields
482   unsigned int xsize;
483   unsigned int ysize;
484   unsigned int bands;
485   VipsBandFormat format;
486   VipsCoding coding;
487   VipsInterpretation interpretation;
488 
489   std::vector<float> bgd_color;
490 
491   VipsImage* image;
492 
493   ImagePyramid pyramid;
494 
495   std::vector< std::list< std::pair<unsigned int, unsigned int> > > stroke_ranges;
496 
497 public:
498   RawBuffer();
499   RawBuffer( std::string file_name );
500 
~RawBuffer()501   virtual ~RawBuffer()
502   {
503     std::cout<<"PF::RawBuffer::~RawBuffer(): deleting "<<(void*)this<<std::endl;
504     if( fd >= 0 ) {
505       close( fd );
506       unlink( file_name.c_str() );
507       std::cout<<"PF::RawBuffer::~RawBuffer(): "<<file_name<<" removed."<<std::endl;
508     }
509   }
510 
get_file_name()511   std::string get_file_name() { return file_name; }
get_fd()512   int get_fd() { return fd; }
513 
get_xsize()514   int get_xsize() { return xsize; }
get_ysize()515   int get_ysize() { return ysize; }
516 
set_xsize(int sz)517   void set_xsize(int sz) { xsize = sz; }
set_ysize(int sz)518   void set_ysize(int sz) { ysize = sz; }
519 
get_nbands()520   int get_nbands() { return bands; }
set_nbands(int n)521   void set_nbands( int n ) { bands = n; }
522 
get_interpretation()523   VipsInterpretation get_interpretation() { return interpretation; }
get_colorspace()524   colorspace_t get_colorspace() { return( PF::convert_colorspace( get_interpretation() ) ); }
set_interpretation(VipsInterpretation val)525   void set_interpretation( VipsInterpretation val ) { interpretation = val; }
526 
get_format()527   VipsBandFormat get_format() { return format; }
set_format(VipsBandFormat fmt)528   void set_format( VipsBandFormat fmt ) { format = fmt; }
529 
get_coding()530   VipsCoding get_coding() { return coding; }
set_coding(VipsCoding c)531   void set_coding( VipsCoding c ) { coding = c; }
532 
get_bgd_color()533   std::vector<float> get_bgd_color() { return bgd_color; }
534 
get_pyramid()535   ImagePyramid& get_pyramid() { return pyramid; }
536 
537   void init( const std::vector<float>& bgd_color );
538 
539   void draw_row( Pencil& pen, unsigned int row,
540       unsigned int startcol, unsigned int endcol );
541   void draw_point( Pencil& pen, unsigned int x, unsigned int y, VipsRect& update, bool update_pyramid );
542   void draw_segment( Pencil& pen, Segment& segment );
543 
544   void start_stroke();
545   void end_stroke();
546 
547   //void draw_stroke( Stroke& stroke );
548 };
549 
550 
551 };
552 
553 #endif
554