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   Changelog:
30 
31   - 2015/06/03
32     Fixed bug that prevented correct loading of presets with multiple layers into a layer mask.
33 
34 
35 */
36 
37 #include <libgen.h>
38 
39 #include <string>
40 #include <stack>
41 #include <vector>
42 #include <map>
43 
44 /*
45 #include "../operations/vips_operation.hh"
46 #include "../operations/image_reader.hh"
47 #include "../operations/brightness_contrast.hh"
48 #include "../operations/invert.hh"
49 #include "../operations/gradient.hh"
50 #include "../operations/convert2lab.hh"
51 #include "../operations/clone.hh"
52 #include "../operations/curves.hh"
53 */
54 /*
55 #include "../gui/operations/brightness_contrast_config.hh"
56 #include "../gui/operations/imageread_config.hh"
57 #include "../gui/operations/vips_operation_config.hh"
58 #include "../gui/operations/clone_config.hh"
59 #include "../gui/operations/curves_config.hh"
60 */
61 
62 #include "pf_file_loader.hh"
63 
64 //#define DEBUG_PF_LOAD 1
65 
66 static PF::Image* image = NULL;
67 static std::deque<PF::Layer*> layers_stack;
68 static std::deque< std::pair<std::list<PF::Layer*>*,bool> > containers_stack;
69 static PF::Layer* current_layer = NULL;
70 static std::list<PF::Layer*>* current_container = NULL;
71 static bool current_container_map_flag = false;
72 static PF::OpParBase* current_op = NULL;
73 
74 static int version = 1;
75 
76 static std::vector<PF::Layer*> layer_id_mapper;
77 
78 
append_layer(PF::Layer * layer,PF::Layer * previous,std::list<PF::Layer * > & list)79 void append_layer( PF::Layer* layer, PF::Layer* previous, std::list<PF::Layer*>& list )
80 {
81   if( !previous ) {
82     list.push_back( layer );
83     return;
84   }
85 
86   std::list<PF::Layer*>::iterator i;
87   for( i = list.begin(); i != list.end(); i++ ) {
88     PF::Layer* l = (*i);
89     if( !l ) continue;
90     if( l->get_id() != previous->get_id() ) continue;
91     break;
92   }
93 
94   if( i == list.end() ) {
95     list.push_back( layer );
96   } else {
97     i++;
98     list.insert( i, layer );
99   }
100 }
101 
102 /* The handler functions. */
103 
start_element(GMarkupParseContext * context,const gchar * element_name,const gchar ** attribute_names,const gchar ** attribute_values,gpointer user_data,GError ** error)104 static void start_element (GMarkupParseContext *context,
105                     const gchar         *element_name,
106                     const gchar        **attribute_names,
107                     const gchar        **attribute_values,
108                     gpointer             user_data,
109                     GError             **error) {
110 
111   const gchar **name_cursor = attribute_names;
112   const gchar **value_cursor = attribute_values;
113 
114 //#ifdef DEBUG_PF_LOAD
115 //      std::cout<<"PF::pf_file_loader(): element name = \""<<element_name<<"\""<<std::endl;
116 //#endif
117   if( strcmp (element_name, "image") == 0 ) {
118     while (*name_cursor) {
119       if (strcmp (*name_cursor, "version") == 0) {
120         version = atoi(*value_cursor);
121       }
122 
123       name_cursor++;
124       value_cursor++;
125     }
126 
127   } else if( strcmp (element_name, "preset") == 0 ) {
128     while (*name_cursor) {
129       if (strcmp (*name_cursor, "version") == 0) {
130         version = atoi(*value_cursor);
131       }
132 
133       name_cursor++;
134       value_cursor++;
135     }
136 
137   } else if( strcmp (element_name, "layer") == 0 ) {
138 
139     // Create a new layer
140     PF::Layer* layer = image->get_layer_manager().new_layer();
141     // The new layer is inserted in the current container, above the current one
142     // If the current one is NULL, then the new layer is simply inserted on the top of the list
143     // Useful when for example inserting the first layer or sublayer
144     append_layer( layer, current_layer, *current_container );
145 
146     // Now we can update the current_layer pointer and we can collect parameters
147     // The new layer is pushed on top of the layers stack
148     current_layer = layer;
149     layers_stack.push_back( layer );
150     int old_id = -1;
151     std::string name;
152     int visible = -1;
153     int expanded = -1;
154     int normal = -1;
155     std::vector<int> extra_inputs;
156 
157     while (*name_cursor) {
158       if (strcmp (*name_cursor, "id") == 0) {
159         old_id = atoi( *value_cursor );
160       } else if (strcmp (*name_cursor, "name") == 0) {
161         name = *value_cursor;
162       } else if (strcmp (*name_cursor, "visible") == 0) {
163         visible = atoi( *value_cursor );
164       } else if (strcmp (*name_cursor, "expanded") == 0) {
165         expanded = atoi( *value_cursor );
166       } else if (strcmp (*name_cursor, "normal") == 0) {
167         normal = atoi( *value_cursor );
168       } else if (
169           (strcmp (*name_cursor, "extra_inputs") == 0) ||
170           (strcmp (*name_cursor, "inputs") == 0) ) {
171         std::string idstr = *value_cursor;
172         std::istringstream idstream( idstr );
173         int ninput = 0;
174         while ( !idstream.eof() ) {
175           unsigned int id, imgid = 0;
176           idstream>>id;
177           if( !idstream )
178             break;
179           if( (version>=4) ) {
180             idstream>>imgid;
181             if( !idstream )
182               break;
183           }
184           bool blended = true;
185           if( (version>=3) ) {
186             idstream>>blended;
187             if( !idstream )
188               break;
189           }
190           if( id < layer_id_mapper.size() &&
191               layer_id_mapper[id] )
192             layer->set_input( ninput, layer_id_mapper[id]->get_id(), imgid, blended );
193           ninput++;
194         }
195       }
196 
197       name_cursor++;
198       value_cursor++;
199     }
200 
201     for(int i = layer_id_mapper.size(); i <= old_id; i++)
202       layer_id_mapper.push_back( NULL );
203     layer_id_mapper[old_id] = layer;
204 
205     layer->set_name( name );
206     layer->set_enabled( visible );
207     layer->set_expanded( expanded );
208     layer->set_normal( normal );
209 
210     if( (version<2) && (normal==0) ) {
211 #ifdef DEBUG_PF_LOAD
212       std::cout<<"PF::pf_file_loader(): setting group layer operation to \"buffer\""<<std::endl;
213 #endif
214       PF::ProcessorBase* processor = PF::PhotoFlow::Instance().new_operation( "buffer", current_layer );
215       if( processor ) {
216 #ifdef DEBUG_PF_LOAD
217         std::cout<<"PF::pf_file_loader(): operation created."<<std::endl;
218 #endif
219         current_op = processor->get_par();
220       }
221       if( current_op )
222         current_op->set_map_flag( current_container_map_flag );
223     }
224 
225 #ifdef DEBUG_PF_LOAD
226     std::cout<<"Layer \""<<layer->get_name()<<"\" extra inputs: ";
227     for(unsigned int i = 0; i < layer->get_extra_inputs().size(); i++)
228       std::cout<<layer->get_extra_inputs()[i].first.first<<","<<layer->get_extra_inputs()[i].first.second
229                <<" (blended="<<layer->get_extra_inputs()[i].second<<")";
230     std::cout<<std::endl;
231 #endif
232 
233   } else if( strcmp (element_name, "sublayers") == 0 ) {
234 
235     if( !current_layer ) return;
236 
237     std::string type;
238 
239     while (*name_cursor) {
240       if (strcmp (*name_cursor, "type") == 0) {
241         type = *value_cursor;
242       }
243 
244       name_cursor++;
245       value_cursor++;
246     }
247 
248 #ifdef DEBUG_PF_LOAD
249     std::cout<<"\""<<element_name<<"\" start: current_container_map_flag="<<current_container_map_flag<<std::endl;
250 #endif
251     if( type == "imap" ) {
252       current_container = &(current_layer->get_imap_layers());
253       current_container_map_flag = true;
254       containers_stack.push_back( make_pair(current_container,true) );
255     } else if( type == "omap" ) {
256       current_container = &(current_layer->get_omap_layers());
257       current_container_map_flag = true;
258       containers_stack.push_back( make_pair(current_container,true) );
259     } else if( type == "child" ) {
260       current_container = &(current_layer->get_sublayers());
261       // Child layers inherit the map flag of their parent
262       //current_container_map_flag = false;
263       containers_stack.push_back( make_pair(current_container,current_container_map_flag) );
264     }
265 
266     // At this point we set the current_layer pointer to NULL,
267     // since we are starting to build a new layers list
268     // The pointer will be restored from the layers stack
269     // when we will exit the "sublayers" element
270     current_layer = NULL;
271 
272   } else if( strcmp (element_name, "operation") == 0 ) {
273     std::string op_type;
274     while (*name_cursor) {
275       if (strcmp (*name_cursor, "type") == 0) {
276         op_type = *value_cursor;
277       }
278 
279       name_cursor++;
280       value_cursor++;
281     }
282 
283     if( !current_layer ) return;
284 
285     if( op_type == "blender" ) {
286 #ifdef DEBUG_PF_LOAD
287       std::cout<<"PF::pf_file_loader(): setting blender operation"<<std::endl;
288 #endif
289       current_op = NULL;
290       if( current_layer->get_blender() ) {
291         current_op = current_layer->get_blender()->get_par();
292 #ifdef DEBUG_PF_LOAD
293         std::cout<<"PF::pf_file_loader(): blender operation set to "<<current_op<<std::endl;
294 #endif
295       }
296     } else {
297 #ifdef DEBUG_PF_LOAD
298       std::cout<<"PF::pf_file_loader(): creating operation of type "<<op_type<<std::endl;
299 #endif
300       PF::ProcessorBase* processor = PF::PhotoFlow::Instance().new_operation( op_type, current_layer );
301       if( processor ) {
302 #ifdef DEBUG_PF_LOAD
303         std::cout<<"PF::pf_file_loader(): operation created."<<std::endl;
304 #endif
305         current_op = processor->get_par();
306         if( !PF::PhotoFlow::Instance().is_batch() && current_op->init_hidden() )
307           current_layer->set_enabled( false );
308       }
309     }
310 
311 #ifdef DEBUG_PF_LOAD
312     std::cout<<"PF::pf_file_loader(): current_container_map_flag="<<current_container_map_flag
313         <<"  current_op="<<current_op<<std::endl;
314 #endif
315     if( current_op )
316       current_op->set_map_flag( current_container_map_flag );
317 
318   } else if( strcmp (element_name, "property") == 0 ) {
319 
320     if( !current_op ) return;
321 
322     std::string pname;
323     std::string pvalue;
324     while (*name_cursor) {
325       if (strcmp (*name_cursor, "name") == 0) {
326         pname = *value_cursor;
327       } else if (strcmp (*name_cursor, "value") == 0) {
328         pvalue = *value_cursor;
329       }
330 
331       name_cursor++;
332       value_cursor++;
333     }
334 
335 #ifdef DEBUG_PF_LOAD
336     std::cout<<"PF::pf_file_loader(): setting property \""<<pname<<"\" to \""<<pvalue<<"\""<<std::endl;
337 #endif
338 
339     if( !pname.empty() && !pvalue.empty() ) {
340       if( version < 2 &&
341           ( (pname=="opacity") || (pname=="blend_mode") ) ) {
342         if( current_layer &&
343             current_layer->get_blender() &&
344             current_layer->get_blender()->get_par() ) {
345           PF::PropertyBase* p = current_layer->get_blender()->get_par()->get_property( pname );
346           if( p ) p->set_str( pvalue );
347         }
348       } else {
349         PF::PropertyBase* p = current_op->get_property( pname );
350         if( p && p->is_persistent() ) p->set_str( pvalue );
351       }
352     }
353 
354   }
355 }
356 
text(GMarkupParseContext * context,const gchar * text,gsize text_len,gpointer user_data,GError ** error)357 static void text(GMarkupParseContext *context,
358           const gchar         *text,
359           gsize                text_len,
360           gpointer             user_data,
361           GError             **error)
362 {
363   /* Note that "text" is not a regular C string: it is
364    * not null-terminated. This is the reason for the
365    * unusual %*s format below.
366    */
367 
368 }
369 
end_element(GMarkupParseContext * context,const gchar * element_name,gpointer user_data,GError ** error)370 static void end_element (GMarkupParseContext *context,
371                   const gchar         *element_name,
372                   gpointer             user_data,
373                   GError             **error)
374 {
375   // If element is a layer, pop it from the stack
376   if( strcmp (element_name, "layer") == 0 ) {
377 
378     if( current_layer && current_layer->get_processor() &&
379         current_layer->get_processor()->get_par() ) {
380       current_layer->get_processor()->get_par()->set_file_format_version( version );
381       current_layer->get_processor()->get_par()->finalize();
382     }
383     if( current_layer && current_layer->get_blender() &&
384         current_layer->get_blender()->get_par() ) {
385       current_layer->get_blender()->get_par()->set_file_format_version( version );
386       current_layer->get_blender()->get_par()->finalize();
387     }
388     if( current_layer && current_layer->get_processor() &&
389         current_layer->get_processor()->get_par() &&
390         current_layer->get_processor()->get_par()->get_config_ui() ) {
391       // Load initial values into config UI.
392       // Called after operation and blender have been loaded.
393       current_layer->get_processor()->get_par()->get_config_ui()->init();
394       //current_op->get_config_ui()->update();
395     }
396     // The current layer is removed from the stack, and the current_layer pointer
397     // is set to the top element of the stack if present, or to NULL otherwise
398     layers_stack.pop_back();
399     current_layer = NULL;
400 #ifdef DEBUG_PF_LOAD
401     std::cout<<"\""<<element_name<<"\" end: layers_stack.size()="<<layers_stack.size()<<std::endl;
402 #endif
403     if( !layers_stack.empty() )
404       current_layer = layers_stack.back();
405 #ifdef DEBUG_PF_LOAD
406     std::cout<<"\""<<element_name<<"\" end: current_container_map_flag="<<current_container_map_flag<<std::endl;
407 #endif
408   } else if( strcmp (element_name, "sublayers") == 0 ) {
409 
410     containers_stack.pop_back();
411     current_container = NULL;
412 #ifdef DEBUG_PF_LOAD
413     std::cout<<"\""<<element_name<<"\" end: containers_stack.size()="<<containers_stack.size()<<std::endl;
414 #endif
415     if( !containers_stack.empty() ) {
416       current_container = containers_stack.back().first;
417       current_container_map_flag = containers_stack.back().second;
418     }
419 #ifdef DEBUG_PF_LOAD
420     std::cout<<"\""<<element_name<<"\" end: current_container_map_flag="<<current_container_map_flag<<std::endl;
421 #endif
422 
423     // We also restore the current_layer pointer to the top element of the stack (if present)
424     current_layer = NULL;
425 #ifdef DEBUG_PF_LOAD
426     std::cout<<"\""<<element_name<<"\" end: layers_stack.size()="<<layers_stack.size()<<std::endl;
427 #endif
428     if( !layers_stack.empty() )
429       current_layer = layers_stack.back();
430 
431   } else if( strcmp (element_name, "operation") == 0 ) {
432 
433     current_op = NULL;
434 
435   }
436 }
437 
438 /* The list of what handler does what. */
439 static GMarkupParser parser = {
440   start_element,
441   end_element,
442   text,
443   NULL,
444   NULL
445 };
446 
447 
448 
load_pf_image(std::string filename,PF::Image * img)449 bool PF::load_pf_image( std::string filename, PF::Image* img ) {
450   char *text;
451   gsize length;
452   GMarkupParseContext *context = g_markup_parse_context_new (&parser,
453                                                              (GMarkupParseFlags)0,
454                                                              NULL,
455                                                              NULL);
456 
457   image = img;
458   current_layer = NULL;
459   current_container = NULL;
460   layers_stack.clear();
461   containers_stack.clear();
462   layer_id_mapper.clear();
463 
464   current_container = &(image->get_layer_manager().get_layers());
465   containers_stack.push_back( make_pair(current_container,false) );
466   current_container_map_flag = false;
467 
468   /* seriously crummy error checking */
469 
470   if (g_file_get_contents (filename.c_str(), &text, &length, NULL) == FALSE) {
471     printf("Couldn't load XML\n");
472     return false;
473   }
474 
475   char* fname = strdup(filename.c_str());
476   char* dname = dirname( fname );
477   if( dname ) {
478     PF::PhotoFlow::Instance().set_current_image_dir(dname);
479 //    if( chdir( dname ) != 0 )
480 //      std::cout<<"Cannot change current directory to \""<<dname<<"\""<<std::endl;
481   }
482   free( fname );
483 
484   if (g_markup_parse_context_parse (context, text, length, NULL) == FALSE) {
485     printf("Parse failed\n");
486     return false;
487   }
488 
489   g_free(text);
490   g_markup_parse_context_free (context);
491   return true;
492 }
493 
494 
495 
insert_pf_preset(std::string filename,PF::Image * img,PF::Layer * previous,std::list<PF::Layer * > * list,bool map_flag)496 void PF::insert_pf_preset( std::string filename, PF::Image* img, PF::Layer* previous, std::list<PF::Layer*>* list, bool map_flag ) {
497   char *text;
498   gsize length;
499   GMarkupParseContext *context = g_markup_parse_context_new (&parser,
500                                                              (GMarkupParseFlags)0,
501                                                              NULL,
502                                                              NULL);
503 
504   layers_stack.clear();
505   containers_stack.clear();
506   layer_id_mapper.clear();
507 
508   image = img;
509   current_layer = previous;
510   current_container = list;
511   if(current_container) containers_stack.push_back( make_pair(current_container,map_flag) );
512 
513   current_container_map_flag = map_flag;
514 
515   /* seriously crummy error checking */
516 
517   if (g_file_get_contents (filename.c_str(), &text, &length, NULL) == FALSE) {
518     printf("Couldn't load XML\n");
519     exit(255);
520   }
521 
522   /*
523   char* fname = strdup(filename.c_str());
524   char* dname = dirname( fname );
525   if( dname ) {
526     if( chdir( dname ) != 0 )
527       std::cout<<"Cannot change current directory to \""<<dname<<"\""<<std::endl;
528   }
529   free( fname );
530   */
531 
532   if (g_markup_parse_context_parse (context, text, length, NULL) == FALSE) {
533     printf("Parse failed\n");
534     exit(255);
535   }
536 
537   g_free(text);
538   g_markup_parse_context_free (context);
539 }
540