1 /*
2 
3  */
4 
5 /*
6 
7     Copyright (C) 2014 Ferrero Andrea
8 
9     This program is free software: you can redistribute it and/or modify
10     it under the terms of the GNU General Public License as published by
11     the Free Software Foundation, either version 3 of the License, or
12     (at your option) any later version.
13 
14     This program is distributed in the hope that it will be useful,
15     but WITHOUT ANY WARRANTY; without even the implied warranty of
16     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17     GNU General Public License for more details.
18 
19     You should have received a copy of the GNU General Public License
20     along with this program. If not, see <http://www.gnu.org/licenses/>.
21 
22 
23  */
24 
25 /*
26 
27     These files are distributed with PhotoFlow - http://aferrero2707.github.io/PhotoFlow/
28 
29  */
30 
31 #ifndef PF_IMAGE_HH
32 #define PF_IMAGE_HH
33 
34 #include <stdlib.h>
35 #include <sigc++/sigc++.h>
36 
37 //#include <gexiv2/gexiv2-metadata.h>
38 
39 #include "condition.hh"
40 
41 #include "layermanager.hh"
42 #include "pipeline.hh"
43 
44 #define CACHE_PIPELINE_ID 0
45 #define PREVIEW_PIPELINE_ID 1
46 #define HISTOGRAM_PIPELINE_ID 2
47 
48 
49 
50 
51 
52 namespace PF
53 {
54 
55 
56 enum export_format_t
57 {
58   EXPORT_FORMAT_JPEG,
59   EXPORT_FORMAT_TIFF_8,
60   EXPORT_FORMAT_TIFF_16,
61   EXPORT_FORMAT_TIFF_32f,
62   EXPORT_FORMAT_EXR_16f,
63   EXPORT_FORMAT_EXR_32f
64 };
65 
66 struct ImageBuffer
67 {
68   float* buf;
69   int width, height;
70   //GExiv2Metadata* exif_buf;
71   void* iccdata;
72   size_t iccsize;
73   TRC_type trc_type;
74 };
75 
76 
77 struct image_export_opt_t
78 {
79   int jpeg_quality;
80   bool jpeg_chroma_subsampling;
81   int jpeg_quant_table;
82   int tiff_format;
83   bool tiff_compress;
84   int exr_format;
85   export_size_t size;
86   int width, height;
87   scale_interpolation_t interpolator;
88   bool sharpen_enabled;
89   float sharpen_radius;
90   float sharpen_amount;
91   profile_type_t profile_type;
92   TRC_type trc_type;
93   cmsUInt32Number intent;
94   bool bpc;
95   Glib::ustring custom_profile_name;
96 };
97 
98 
99 class Image: public sigc::trackable
100 {
101   LayerManager layer_manager;
102   std::vector<Pipeline*> pipelines;
103 
104   // Flag indicating whether the update should be preformed asynchronously
105   bool async;
106 
107   // Flag indicating whether the pipelines have to be re-built
108   bool modified_flag;
109 
110   // Flag indicating whether there is a re-building ongoing
111   bool rebuilding;
112 
113   bool loaded;
114 
115   // Current file name associated to this image
116   // It corresponds to the file specified in the
117   // most recent "open" or "save" action
118   std::string file_name;
119 
120   // Name of the backup file used to save the current
121   // editing parameters so that they can be restored
122   // in case of a program crash
123   std::string backup_file_name;
124 
125   bool disable_update;
126 
127   GMutex* image_mutex;
128   //GCond* rebuild_done;
129   PF::Condition rebuild_cond;
130 
131   bool force_synced_update;
132 
133   //GMutex* export_mutex;
134   //GCond* export_done;
135   Condition export_cond;
136   bool export_ok;
137 
138   //GMutex* sample_mutex;
139   //GCond* sample_done;
140   PF::Condition sample_cond;
141 
142   PF::Condition destroy_cond;
143 
144   //GMutex* remove_layer_mutex;
145   //GCond* remove_layer_done;
146   PF::Condition remove_layer_cond;
147 
148   //ProcessorBase* convert2srgb;
149   ProcessorBase* convert_format;
150   ProcessorBase* resize;
151   ProcessorBase* sharpen;
152   ProcessorBase* convert2outprof;
153   ProcessorBase* convert2linear;
154 
155   void remove_from_inputs( PF::Layer* layer );
156   void remove_from_inputs( PF::Layer* layer, std::list<Layer*>& list );
157   void remove_layer( PF::Layer* layer, std::list<Layer*>& list );
158 
159   VipsImage* sampler_image;
160   std::vector<float> sampler_values;
161 
162   void update_async();
163 
164 public:
165   Image();
166 
167   ~Image();
168 
169   sigc::signal<void> signal_modified;
170 
171   sigc::signal<void> signal_updated;
172 
get_layer_manager()173   LayerManager& get_layer_manager() { return layer_manager; }
174 
175   void do_remove_layer( PF::Layer* layer );
176   void remove_layer( PF::Layer* layer );
177 
add_pipeline(VipsBandFormat fmt,int level,rendermode_t mode=PF_RENDER_PREVIEW)178   Pipeline* add_pipeline( VipsBandFormat fmt, int level, rendermode_t mode=PF_RENDER_PREVIEW )
179   {
180     Pipeline* pipeline = new Pipeline( this, fmt, level, mode );
181     pipelines.push_back( pipeline);
182     return pipeline;
183   }
184 
remove_pipeline(Pipeline * pipeline)185   void remove_pipeline( Pipeline* pipeline )
186   {
187     std::vector<Pipeline*>::iterator i;
188     for( i = pipelines.begin(); i != pipelines.end(); i++) {
189       if( *i == pipeline) {
190         pipelines.erase( i );
191         break;
192       }
193     }
194   }
195 
get_npipelines()196   unsigned int get_npipelines() { return pipelines.size(); }
197 
get_pipeline(unsigned int n)198   Pipeline* get_pipeline(unsigned int n)
199   {
200     if( n >= pipelines.size() ) return NULL;
201     return(pipelines[n]);
202   }
203 
204   PipelineNode* get_compatible_node(Layer* layer, Pipeline* pipeline, unsigned int level);
205 
is_async()206   bool is_async() { return async; }
set_async(bool flag)207   void set_async( bool flag ) { async = flag; }
208 
is_modified()209   bool is_modified() { return modified_flag; }
set_modified()210   void set_modified() { modified_flag = true; }
clear_modified()211   void clear_modified() { modified_flag = false; }
modified()212   void modified() {  set_modified(); signal_modified.emit(); }
213 
is_rebuilding()214   bool is_rebuilding() { return rebuilding; }
set_rebuilding(bool flag)215   void set_rebuilding( bool flag ) { rebuilding = flag; }
216 
get_force_synced_update()217   bool get_force_synced_update() { return force_synced_update; }
set_force_synced_update(bool flag)218   void set_force_synced_update( bool flag ) { force_synced_update = flag; }
219 
is_loaded()220   bool is_loaded() { return loaded; }
set_loaded(bool flag)221   void set_loaded( bool flag ) { loaded = flag; }
222 
223   //Glib::Threads::Mutex& get_rebuild_mutex() { return rebuild_mutex; }
224 
225   void lock();
226   void unlock();
227   //void export_lock();
228   //void export_unlock();
229   //void sample_lock();
230   //void sample_unlock();
231   //void destroy_lock();
232   //void destroy_unlock();
233   //void remove_layer_lock() { g_mutex_lock( remove_layer_mutex); }
234   //void remove_layer_unlock() { g_mutex_unlock( remove_layer_mutex); }
235   //void rebuild_lock() { /*g_cond_signal( rebuild_done );*/ rebuild_cond.lock(); }
236   //void rebuild_unlock() { /*g_cond_signal( rebuild_done );*/ rebuild_cond.unlock(); }
rebuild_done_reset()237   void rebuild_done_reset() { /*g_cond_signal( rebuild_done ); rebuild_cond.lock();*/ rebuild_cond.reset(); }
rebuild_done_signal()238   void rebuild_done_signal() { /*g_cond_signal( rebuild_done );*/ rebuild_cond.signal(); }
rebuild_done_wait(bool unlock=true)239   void rebuild_done_wait(bool unlock=true) { /*g_cond_signal( rebuild_done );*/ rebuild_cond.wait(); }
export_done_signal()240   void export_done_signal() { export_cond.signal(); }
sample_done_signal()241   void sample_done_signal() { /*g_cond_signal( sample_done );*/ sample_cond.signal(); }
destroy_done_signal()242   void destroy_done_signal() { /*g_cond_signal( sample_done );*/ destroy_cond.signal(); }
243   //void remove_layer_done_signal() { /*g_cond_signal( remove_layer_done );*/  }
remove_layer_reset()244   void remove_layer_reset() { /*g_cond_signal( rebuild_done ); remove_layer_cond.lock();*/ remove_layer_cond.reset(); }
remove_layer_signal()245   void remove_layer_signal() { /*g_cond_signal( rebuild_done );*/ remove_layer_cond.signal(); }
remove_layer_wait(bool unlock=true)246   void remove_layer_wait(bool unlock=true) { /*g_cond_signal( rebuild_done );*/ remove_layer_cond.wait(); }
247 
248   void set_pipeline_level( PF::Pipeline* pipeline, int level );
249 
250   void update( PF::Pipeline* pipeline=NULL, bool sync=false );
update_all()251   void update_all() { update( NULL ); }
252   void do_update( PF::Pipeline* pipeline=NULL, bool update_gui=true );
253 
254 
255   void sample( int layer_id, std::vector<VipsRect>& areas, bool weighted,
256       VipsImage** image, std::vector<float>& values );
257   void sample( int layer_id, int x, int y, int size,
258       VipsImage** image, std::vector<float>& values );
259   void do_sample( int layer_id, std::vector<VipsRect>& areas, bool weighted );
260 
261   void destroy();
262   void do_destroy();
263 
264   bool open( std::string filename, std::string bckname="" );
265 
set_filename(std::string name)266   void set_filename(std::string name) { file_name = name; }
get_filename()267   std::string get_filename() { return file_name; }
268 
set_backup_filename(std::string name)269   void set_backup_filename(std::string name) { backup_file_name = name; }
get_backup_filename()270   std::string get_backup_filename() { return backup_file_name; }
271   bool save_backup();
272 
273   bool save( std::string filename, bool do_clear=true, bool update_filename=true );
274   bool export_merged( std::string filename, image_export_opt_t* export_opt=NULL );
275   void do_export_merged( std::string filename, image_export_opt_t* export_opt=NULL );
276   void export_merged_to_mem( ImageBuffer* imgbuf, void* gimp_iccdata, size_t gimp_iccsize );
277   void export_merged_to_tiff( const std::string filename );
278 };
279 
280 gint image_rebuild_callback( gpointer data );
281 
282 }
283 
284 
285 #endif /*VIPS_PARITHMETIC_H*/
286 
287 
288