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