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 <string.h>
31
32 #include "layermanager.hh"
33 #include "image.hh"
34
35
36 //#undef NDEBUG
37
LayerManager(PF::Image * img)38 PF::LayerManager::LayerManager( PF::Image* img ): image( img )
39 {
40 }
41
42
~LayerManager()43 PF::LayerManager::~LayerManager()
44 {
45 for(unsigned int i = 0; i < layers_pool.size(); i++) {
46 if(layers_pool[i] == NULL)
47 continue;
48 delete layers_pool[i];
49 }
50 }
51
52
new_layer()53 PF::Layer* PF::LayerManager::new_layer()
54 {
55 uint32_t i;
56 for(i = 0; i < layers_pool.size(); i++) {
57 if(layers_pool[i] == NULL) {
58 PF::Layer* l = new PF::Layer(i);
59 l->set_image( image );
60 layers_pool[i] = l;
61 return l;
62 }
63 }
64 PF::Layer* l = new PF::Layer(layers_pool.size());
65 l->set_image( image );
66 layers_pool.push_back(l);
67 return l;
68 }
69
70
delete_layer(PF::Layer * layer)71 void PF::LayerManager::delete_layer( PF::Layer* layer )
72 {
73 // if( layer->get_id() < 0 ) {
74 // std::cout<<"ERROR: LayerManager::delete_layer(): layer->get_id() < 0"<<std::endl;
75 // return;
76 // }
77 if( layer->get_id() >= layers_pool.size() ) {
78 std::cout<<"ERROR: LayerManager::delete_layer(): layer->get_id() >= layers_pool.size()"<<std::endl;
79 return;
80 }
81 layers_pool[layer->get_id()] = NULL;
82 #ifndef NDEBUG
83 std::cout<<"LayerManager::delete_layer(): deleting layer"<<layer<<std::endl;
84 #endif
85 delete layer;
86 }
87
88
get_layer(int id)89 PF::Layer* PF::LayerManager::get_layer(int id)
90 {
91 if(id < 0 || id >= (int)layers_pool.size()) return NULL;
92 return ( layers_pool[id] );
93 }
94
95
96
97 // Fills a list with the current layer and all its children
expand_layer(PF::Layer * layer,std::list<PF::Layer * > & list)98 void PF::LayerManager::expand_layer( PF::Layer* layer, std::list<PF::Layer*>& list )
99 {
100 if( !layer ) return;
101 // Sublayers
102 #ifndef NDEBUG
103 std::cout<<"LayerManager::expand_layer: collecting sub-layers of \""<<layer->get_name()<<"\"("<<layer->get_id()<<")"<<std::endl;
104 #endif
105 for( std::list<PF::Layer*>::iterator li = layer->get_sublayers().begin();
106 li != layer->get_sublayers().end(); li++ ) {
107 expand_layer( *li, list);
108 }
109 // Intensity map layers
110 #ifndef NDEBUG
111 std::cout<<"LayerManager::expand_layer: collecting IMAP layers of \""<<layer->get_name()<<"\"("<<layer->get_id()<<")"<<std::endl;
112 #endif
113 for( std::list<PF::Layer*>::iterator li = layer->get_imap_layers().begin();
114 li != layer->get_imap_layers().end(); li++ ) {
115 expand_layer( *li, list);
116 }
117 // Opacity map layers
118 #ifndef NDEBUG
119 std::cout<<"LayerManager::expand_layer: collecting OMAP layers of \""<<layer->get_name()<<"\"("<<layer->get_id()<<")"<<std::endl;
120 #endif
121 for( std::list<PF::Layer*>::iterator li = layer->get_omap_layers().begin();
122 li != layer->get_omap_layers().end(); li++ ) {
123 expand_layer( *li, list);
124 }
125 // the layer itself
126 #ifndef NDEBUG
127 std::cout<<"LayerManager::expand_layer: adding layer \""<<layer->get_name()<<"\"("<<layer->get_id()<<")"<<std::endl;
128 #endif
129 list.push_back( layer );
130 }
131
132
get_input_layers(Layer * layer,std::list<PF::Layer * > & container,std::list<Layer * > & inputs)133 void PF::LayerManager::get_input_layers( Layer* layer, std::list<PF::Layer*>& container,
134 std::list<Layer*>& inputs )
135 {
136 #ifndef NDEBUG
137 std::cout<<"Collecting inputs of layer \""<<layer->get_name()<<"\"("<<layer->get_id()<<")"<<std::endl;
138 #endif
139 std::list<PF::Layer*>::iterator li;
140 for(li = container.begin(); li != container.end(); ++li) {
141 PF::Layer* l = *li;
142 #ifndef NDEBUG
143 std::cout<<" checking layer \""<<l->get_name()<<"\"("<<l->get_id()<<")"<<std::endl;
144 #endif
145 if( l->get_id() == layer->get_id() ) {
146 #ifndef NDEBUG
147 std::cout<<" reached initial layer, stopping."<<std::endl;
148 #endif
149 break;
150 }
151 // Add layer and all its children to the inputs list
152 expand_layer( l, inputs );
153 #ifndef NDEBUG
154 std::cout<<" added."<<std::endl;
155 #endif
156 }
157
158 PF::Layer* container_layer = get_container_layer( layer );
159 if( !container_layer ) return;
160 std::list<PF::Layer*>* clist = get_list( container_layer );
161 if( !clist ) return;
162 get_input_layers( container_layer, *clist, inputs );
163 }
164
165
get_input_layers(Layer * layer,std::list<Layer * > & inputs)166 void PF::LayerManager::get_input_layers( Layer* layer, std::list<Layer*>& inputs )
167 {
168 if( !layer ) return;
169 std::list<PF::Layer*>* clist = get_list( layer );
170 if( !clist ) return;
171 get_input_layers( layer, *clist, inputs );
172 }
173
174
get_flattened_layers_tree(std::list<Layer * > & inputs)175 void PF::LayerManager::get_flattened_layers_tree( std::list<Layer*>& inputs )
176 {
177 if( layers.empty() ) return;
178 PF::Layer* top_layer = layers.back();
179 if( !top_layer ) return;
180 get_input_layers( top_layer, layers, inputs );
181 //inputs.push_back(top_layer);
182 expand_layer( top_layer, inputs );
183 }
184
185
get_child_layers(Layer * layer,std::list<PF::Layer * > & container,std::list<Layer * > & children)186 void PF::LayerManager::get_child_layers( Layer* layer, std::list<PF::Layer*>& container,
187 std::list<Layer*>& children )
188 {
189 PF::Layer* container_layer = get_container_layer( layer );
190 #ifndef NDEBUG
191 std::cout<<"get_child_layers: contaner_layer: \""
192 <<(container_layer ? container_layer->get_name() : "NULL")<<"\""<<std::endl;
193 #endif
194
195 #ifndef NDEBUG
196 std::cout<<"Collecting children of layer \""<<layer->get_name()<<"\"("<<layer->get_id()<<")"<<std::endl;
197 #endif
198 std::list<PF::Layer*> tmplist, inputs;
199 std::list<PF::Layer*>::reverse_iterator li;
200 // Loop over layers in reverse order and fill a temporary list,
201 // until either the target layer is found or the end of the
202 // container list is reached
203 for(li = container.rbegin(); li != container.rend(); ++li) {
204 PF::Layer* l = *li;
205 #ifndef NDEBUG
206 std::cout<<" checking layer \""<<l->get_name()<<"\"("<<l->get_id()<<")"<<std::endl;
207 #endif
208 if( l->get_id() == layer->get_id() ) break;
209 // Add layer and all its children to the inputs list,
210 // but only if it is not the container of the target layer.
211 // Otherwise simply add the container layer itself
212 if( l != container_layer) {
213 expand_layer( l, inputs );
214 tmplist.insert( tmplist.begin(), inputs.begin(), inputs.end() );
215 } else {
216 tmplist.push_front( l );
217 }
218 #ifndef NDEBUG
219 std::cout<<" added."<<std::endl;
220 #endif
221 }
222
223 // Append the temporary list to the childrens one
224 children.insert( children.end(), tmplist.begin(), tmplist.end() );
225
226 if( !container_layer ) return;
227
228 // Add the container layer to the list of children
229 children.push_back( container_layer );
230
231 std::list<PF::Layer*>* clist = get_list( container_layer );
232 #ifndef NDEBUG
233 std::cout<<"get_child_layers: clist="<<clist<<std::endl;
234 #endif
235 if( !clist ) return;
236
237 // Add all the children of the container layer to the children list
238 get_child_layers( container_layer, *clist, children );
239 }
240
241
get_child_layers(Layer * layer,std::list<Layer * > & children)242 void PF::LayerManager::get_child_layers( Layer* layer, std::list<Layer*>& children )
243 {
244 if( !layer ) return;
245 std::list<PF::Layer*>* clist = get_list( layer );
246 if( !clist ) return;
247 get_child_layers( layer, *clist, children );
248 }
249
250 /*
251 * Fill the list of layers that are parent of a target layer, i.e. the list of layers
252 * that contribute to the input of the target layer (excluding the mask associated
253 * to the target layer itself)
254 */
get_parent_layers(Layer * layer,std::list<std::pair<std::string,Layer * >> & plist,std::string parent_name,std::list<Layer * > & list)255 bool PF::LayerManager::get_parent_layers(Layer* layer,
256 std::list< std::pair<std::string,Layer*> >& plist,
257 std::string parent_name, std::list<Layer*>& list)
258 {
259 #ifndef NDEBUG
260 std::cout<<"Collecting parents of layer \""<<layer->get_name()
261 <<"\"("<<layer->get_id()<<"), parent_name=\""<<parent_name<<"\""<<std::endl;
262 #endif
263 std::list<PF::Layer*>::iterator li = list.begin();
264 for(li = list.begin(); li != list.end(); ++li) {
265 PF::Layer* l = *li;
266
267 if( l->get_id() == layer->get_id() )
268 return true;
269
270 std::string name;
271 if( !parent_name.empty() ) name = parent_name + "/";
272 name = name + l->get_name();
273 #ifndef NDEBUG
274 std::cout<<" checking layer \""<<l->get_name()<<"\"("<<l->get_id()<<")"<<std::endl;
275 #endif
276
277 if( get_parent_layers( layer, plist, name, l->sublayers ) )
278 return true;
279
280 if( l->get_id() != layer->get_id() ) {
281 plist.push_back( make_pair( name, l ) );
282 #ifndef NDEBUG
283 std::cout<<" added."<<std::endl;
284 #endif
285 }
286
287 if( layer->is_map() ) {
288 if( get_parent_layers( layer, plist, name+"/IMap/", l->imap_layers ) )
289 return true;
290
291 if( get_parent_layers( layer, plist, name+"/", l->omap_layers ) )
292 return true;
293 }
294 }
295 return false;
296 }
297
298
get_parent_layers(PF::Layer * layer,std::list<std::pair<std::string,PF::Layer * >> & plist)299 void PF::LayerManager::get_parent_layers(PF::Layer* layer,
300 std::list< std::pair<std::string,PF::Layer*> >& plist)
301 {
302 get_parent_layers( layer, plist, std::string(""), layers );
303 }
304
305
get_default_input_layer(PF::Layer * layer)306 std::pair< std::pair<int32_t,int32_t>,bool> PF::LayerManager::get_default_input_layer(PF::Layer* layer)
307 {
308 std::pair< std::pair<int32_t,int32_t>,bool> result;
309 result.first.first = -1;
310 result.first.second = 0;
311 result.second = false;
312
313 if( !image ) return result;
314 PF::Pipeline* pipeline = image->get_pipeline(0);
315 if( !pipeline ) return result;
316 PF::PipelineNode* node = pipeline->get_node(layer);
317 if( !node ) return result;
318 PF::ProcessorBase* proc = node->processor;
319 if( !proc ) return result;
320 PF::OpParBase* par = proc->get_par();
321 if( !par ) return result;
322
323 std::list< std::pair<std::string,PF::Layer*> > plist;
324 get_parent_layers( layer, plist );
325
326 PF::Layer* container = get_container_layer(layer);
327 bool is_map = false;
328 if( layer && layer->get_processor() &&
329 layer->get_processor()->get_par() )
330 is_map = layer->get_processor()->get_par()->is_map();
331
332 std::list< std::pair<std::string,Layer*> >::reverse_iterator iter;
333 for( iter = plist.rbegin(); iter != plist.rend(); iter++ ) {
334 PF::Layer* l = iter->second;
335 if( l == NULL ) continue;
336 if( ! l->is_visible() ) continue;
337 PF::PipelineNode* pnode = pipeline->get_node(l);
338 if( !pnode ) continue;
339 PF::ProcessorBase* pproc = pnode->processor;
340 if( !pproc ) continue;
341 PF::OpParBase* ppar = pproc->get_par();
342 if( !ppar ) continue;
343 colorspace_t cs = ppar->get_colorspace();
344
345 if( ! par->accepts_colorspace(cs) ) continue;
346
347 bool is_map2 = false;
348 if( l->get_processor() &&
349 l->get_processor()->get_par() )
350 is_map2 = l->get_processor()->get_par()->is_map();
351
352 if( is_map ) {
353 std::cout<<"get_default_input_layer: l->get_name()="<<l->get_name()<<" is_map2="<<is_map2;
354 if( container ) std::cout<<" container->get_name()="<<container->get_name();
355 else std::cout<<" container=NULL";
356 std::cout<<std::endl;
357 }
358
359 if( (container != NULL) && is_map && (!is_map2) ) {
360 // new behavior:
361 // the target is a map layer, while the current layer is not.
362 // In this case we take the output of the container layer before blending as the
363 // input for the mask layer
364 //result.first.first = container->get_id();
365 //result.first.second = 0;
366 //result.second = false;
367 //break;
368
369 // the target is a map layer, while the current layer is not.
370 // if the container layer has a user-defined input, we take it as default input for the mask.
371 // Otherwise the default input of the container is taken instead.
372 std::cout<<"get_default_input_layer: container->get_inputs().empty()="<<container->get_inputs().empty()<<std::endl;
373 if( !container->get_inputs().empty() )
374 std::cout<<"get_default_input_layer: container->get_inputs()[0].first.first="<<container->get_inputs()[0].first.first<<std::endl;
375 if( container->get_inputs().empty() || (container->get_inputs()[0].first.first < 0) ) {
376 result = get_default_input_layer( container );
377 PF::Layer* rl = get_layer(result.first.first);
378 std::cout<<"get_default_input_layer: result->get_name()="<<(rl?rl->get_name():"")<<std::endl;
379 } else {
380 result = container->get_inputs()[0];
381 PF::Layer* rl = get_layer(result.first.first);
382 std::cout<<"get_default_input_layer: result->get_name()="<<(rl?rl->get_name():"")<<" blended="<<result.second<<std::endl;
383 }
384 break;
385 }
386
387 result.first.first = l->get_id();
388 result.first.second = 0;
389 result.second = true;
390 break;
391 }
392
393 return result;
394 }
395
396
397
get_container_layer(Layer * layer,std::list<Layer * > & list)398 PF::Layer* PF::LayerManager::get_container_layer( Layer* layer, std::list<Layer*>& list )
399 {
400 if( !layer )
401 return NULL;
402
403 bool is_map = false;
404 if( layer && layer->get_processor() &&
405 layer->get_processor()->get_par() )
406 is_map = layer->get_processor()->get_par()->is_map();
407
408 // Walk through the list and, for each layer in the list, search for the target layer in the
409 // lists (imaps, omaps and sublayers)
410 std::list<PF::Layer*>::iterator li;
411 for(li = list.begin(); li != list.end(); ++li) {
412 PF::Layer* l = *li;
413 // We first look in the sublayers list
414 std::list<PF::Layer*>::iterator lj;
415 for( lj = l->get_sublayers().begin();
416 lj != l->get_sublayers().end(); ++lj ) {
417 int id1 = layer->get_id();
418 int id2 = ( (*lj)!=NULL ) ? (*lj)->get_id() : -1;
419 if( (*lj) && ((*lj)->get_id() == layer->get_id()) ) {
420 // We found it, no need to continue...
421 return( l );
422 }
423 }
424 if( is_map ) {
425 // If the target layer is a layer map, then we also look into the
426 // intensity and opacity maps
427 std::list<PF::Layer*>::iterator lj;
428 for( lj = l->get_imap_layers().begin();
429 lj != l->get_imap_layers().end(); ++lj ) {
430 int id1 = layer->get_id();
431 int id2 = ( (*lj)!=NULL ) ? (*lj)->get_id() : -1;
432 if( (*lj) && ((*lj)->get_id() == layer->get_id()) ) {
433 // We found it, no need to continue...
434 return( l );
435 }
436 }
437 for( lj = l->get_omap_layers().begin();
438 lj != l->get_omap_layers().end(); ++lj ) {
439 int id1 = layer->get_id();
440 int id2 = ( (*lj)!=NULL ) ? (*lj)->get_id() : -1;
441 if( (*lj) && ((*lj)->get_id() == layer->get_id()) ) {
442 // We found it, no need to continue...
443 return( l );
444 }
445 }
446 }
447 }
448
449 // If we got here it means that the layer was not found yet, so we
450 // recursively search it in all the sub-layers in the list
451 for(li = list.begin(); li != list.end(); ++li) {
452 PF::Layer* l = *li;
453 PF::Layer* result;
454 result = get_container_layer( layer, l->get_imap_layers() );
455 if( result )
456 return( result );
457 result = get_container_layer( layer, l->get_omap_layers() );
458 if( result )
459 return( result );
460 result = get_container_layer( layer, l->get_sublayers() );
461 if( result )
462 return( result );
463 }
464
465 // If we reach this point, it means that the layer could not be found...
466 return( NULL );
467 }
468
get_container_layer(Layer * layer)469 PF::Layer* PF::LayerManager::get_container_layer( Layer* layer )
470 {
471 if( !layer )
472 return( NULL );
473 return( get_container_layer( layer, layers ) );
474 }
475
get_container_layer(int id)476 PF::Layer* PF::LayerManager::get_container_layer( int id )
477 {
478 PF::Layer* layer = get_layer( id );
479 if( !layer )
480 return( NULL );
481 return( get_container_layer( layer ) );
482 }
483
484
485
get_list(PF::Layer * layer,std::list<PF::Layer * > & list)486 std::list<PF::Layer*>* PF::LayerManager::get_list( PF::Layer* layer, std::list<PF::Layer*>& list)
487 {
488 std::list<PF::Layer*>::iterator li = list.begin();
489 for(li = list.begin(); li != list.end(); ++li) {
490 PF::Layer* l = *li;
491 if( l->get_id() == layer->get_id() ) {
492 return( &list );
493 }
494 }
495
496 // The layer is not contained in the current list, then we look into sub-lists
497 for(li = list.begin(); li != list.end(); ++li) {
498 PF::Layer* l = *li;
499 std::list<PF::Layer*>* result;
500 result = get_list( layer, l->sublayers );
501 if( result )
502 return result;
503 result = get_list( layer, l->imap_layers );
504 if( result )
505 return result;
506 result = get_list( layer, l->omap_layers );
507 if( result )
508 return result;
509 }
510
511 return NULL;
512 }
513
get_list(PF::Layer * layer)514 std::list<PF::Layer*>* PF::LayerManager::get_list(PF::Layer* layer)
515 {
516 return get_list( layer, layers );
517 }
518
519
520
521
get_cache_buffer()522 PF::CacheBuffer* PF::LayerManager::get_cache_buffer()
523 {
524 return( get_cache_buffer(layers) );
525 }
526
527
get_cache_buffer(std::list<Layer * > & list)528 PF::CacheBuffer* PF::LayerManager::get_cache_buffer( std::list<Layer*>& list )
529 {
530 std::list<PF::Layer*>::iterator li = list.begin();
531 for(li = list.begin(); li != list.end(); ++li) {
532 PF::Layer* l = *li;
533
534 if( !l ) continue;
535 if( !l->is_enabled() ) continue;
536 //std::cout<<"LayerManager::get_cache_buffer(): checking layer "<<l->get_name()<<std::endl;
537
538 PF::CacheBuffer* buf = NULL;
539 /*
540 for( unsigned int i = 0; i < l->inputs.size(); i++ ) {
541 Layer* lextra = get_layer( l->inputs[i].first );
542 if( lextra && lextra->is_enabled() && lextra->is_cached() && lextra->get_cache_buffer(mode) &&
543 !lextra->get_cache_buffer(mode)->is_completed() ) {
544 buf = lextra->get_cache_buffer( mode );
545 #ifndef NDEBUG
546 std::cout<<"Extra layer #"<<i<<"(\""<<lextra->get_name()<<"\"): pending cache buffer "<<buf<<std::endl;
547 #endif
548 break;
549 }
550 }
551 if( buf ) {
552 std::cout<<"Found pending cache buffer for layer "<<l->get_name<<std::endl;
553 return buf;
554 }
555 */
556
557 // Now we walk through the intensity and opacity maps to see if they contain a pending buffer
558 buf = get_cache_buffer( l->imap_layers );
559 if( buf ) return buf;
560
561 buf = get_cache_buffer( l->omap_layers );
562 if( buf ) return buf;
563
564 // Finally we walk through the sub-layers; again, if re-building is needed
565 // we mark this layer "dirty" as well
566 buf = get_cache_buffer( l->sublayers );
567 if( buf ) return buf;
568
569 // If the current layer is cached and the cache buffer is not completed, we return it.
570 if( l->get_image() && l->is_cached() && l->get_cache_buffer() &&
571 !l->get_cache_buffer()->is_completed() && l->get_image()->get_npipelines()>CACHE_PIPELINE_ID) {
572 buf = l->get_cache_buffer();
573 #ifndef NDEBUG
574 std::cout<<"Layer \""<<l->get_name()<<"\": pending cache buffer "<<buf<<std::endl;
575 std::cout<<" l->get_image()->get_npipelines()="<<l->get_image()->get_npipelines()<<std::endl;
576 #endif
577 PF::Pipeline* pipeline = l->get_image()->get_pipeline( CACHE_PIPELINE_ID );
578 //std::cout<<" l->get_image()->get_pipeline("<<pi<<")->get_render_mode()="
579 // <<pipeline->get_render_mode()<<std::endl;
580 if( pipeline && pipeline->get_node(l->get_id()) ) {
581 PF::PipelineNode* node = pipeline->get_node(l->get_id());
582 buf->set_image( node->image );
583 #ifndef NDEBUG
584 std::cout<<"Caching layer \""<<l->get_name()<<"\" image="<<node->image<<std::endl;
585 #endif
586 return( buf );
587 }
588 }
589 }
590 return NULL;
591 }
592
593
594
595
reset_cache_buffers(bool reinit)596 void PF::LayerManager::reset_cache_buffers( bool reinit )
597 {
598 for(unsigned int i = 0; i < layers_pool.size(); i++) {
599 if(layers_pool[i] == NULL)
600 continue;
601 PF::CacheBuffer* buf = layers_pool[i]->get_cache_buffer();
602 if( buf ) buf->reset( reinit );
603 }
604 }
605
606
607
608
update_visible(std::list<Layer * > & list,bool parent_visible)609 void PF::LayerManager::update_visible( std::list<Layer*>& list, bool parent_visible )
610 {
611 bool visible;
612 std::list<PF::Layer*>::reverse_iterator li;
613 for(li = list.rbegin(); li != list.rend(); ++li) {
614 PF::Layer* l = *li;
615 if(!l) continue;
616
617 // Set visible flag to parent value first
618 visible = parent_visible;
619 // Check if current layer is enabled
620 // If not, this and all subsequent and/or child layers
621 // will be marked as invisible
622 if( !l->is_enabled() ) {
623 //std::cout<<"Layer \""<<l->get_name()<<"\" disabled, setting visible flag to false"<<std::endl;
624 visible = false;
625 }
626 l->set_visible( visible );
627 //std::cout<<"Layer \""<<l->get_name()<<"\" visible flag set to "<<visible<<std::endl;
628
629 // Now we walk through the intensity and opacity maps.
630 update_visible( l->imap_layers, visible );
631
632 update_visible( l->omap_layers, visible );
633
634 // Finally we walk through the sub-layers.
635 update_visible( l->sublayers, visible );
636 }
637 }
638
639
640
update_dirty(std::list<Layer * > & list,bool & dirty)641 void PF::LayerManager::update_dirty( std::list<Layer*>& list, bool& dirty )
642 {
643 //if( !list.empty() ) std::cout<<"LayerManager::update_dirty("<<dirty<<")"<<std::endl;
644 std::list<PF::Layer*>::iterator li = list.begin();
645 for(li = list.begin(); li != list.end(); ++li) {
646 PF::Layer* l = *li;
647
648 bool input_dirty = dirty;
649 bool filter_dirty = false;
650 bool blender_dirty = false;
651
652 // If the operation associated to the current layer has been modified,
653 // the dirty flag is set to true.
654 // This will also qualify as "dirty" all the subsequent layers in the list
655 #ifndef NDEBUG
656 if( l->get_processor() &&
657 l->get_processor()->get_par() )
658 std::cout<<" Layer \""<<l->get_name()<<"\": par->is_modified()="
659 <<l->get_processor()->get_par()->is_modified()<<std::endl;
660 if( l->get_blender() &&
661 l->get_blender()->get_par() )
662 std::cout<<" Layer \""<<l->get_name()<<"\": blender->is_modified()="
663 <<l->get_blender()->get_par()->is_modified()<<std::endl;
664 #endif
665 if( l->get_processor() &&
666 l->get_processor()->get_par() &&
667 l->get_processor()->get_par()->is_modified() )
668 filter_dirty = true;
669
670 if( l->get_blender() &&
671 l->get_blender()->get_par() &&
672 l->get_blender()->get_par()->is_modified() )
673 blender_dirty = true;
674
675 // if the current layer is not qualified as "dirty", but one of the extra input layers is,
676 // then we set the dirty flag to true as well
677 for( unsigned int i = 0; i < l->inputs.size(); i++ ) {
678 Layer* lextra = get_layer( l->inputs[i].first.first );
679 if( lextra && lextra->is_dirty() ) {
680 input_dirty = true;
681 break;
682 }
683 }
684
685 // Now we walk through the intensity and opacity maps to see what needs to be re-built.
686 // If either one or the other has to be re-built, then we mark this layer "dirty" as well
687 bool imap_dirty = false;
688 update_dirty( l->imap_layers, imap_dirty );
689
690 bool omap_dirty = false;
691 update_dirty( l->omap_layers, omap_dirty );
692
693 //std::cout<<" Layer \""<<l->get_name()<<"\": filter_dirty="<<filter_dirty<<" blender_dirty="<<blender_dirty<<" input_dirty="<<input_dirty<<" imap_dirty="<<imap_dirty<<" omap_dirty="<<omap_dirty<<std::endl;
694
695 if( imap_dirty )
696 input_dirty = true;
697
698 if( omap_dirty )
699 blender_dirty = true;
700
701 // Finally we walk through the sub-layers; again, if re-building is needed
702 // we mark this layer "dirty" as well
703 bool sub_dirty = dirty;
704 update_dirty( l->sublayers, sub_dirty );
705
706 //std::cout<<" Layer \""<<l->get_name()<<"\": sub_dirty="<<sub_dirty<<std::endl;
707
708 if( sub_dirty )
709 input_dirty = true;
710
711 //std::cout<<" Layer \""<<l->get_name()<<"\": dirty="<<dirty
712 // <<" l->is_dirty()="<<l->is_dirty()<<std::endl;
713 // if the current layer is dirty the dirty flag is set to true
714 // this will also qualify as "dirty" all the subsequent layers in the list
715 // It probably means that the visibility of the layer has been toggled
716 if( l->is_dirty() )
717 dirty = true;
718
719 dirty = dirty || input_dirty || blender_dirty || filter_dirty;
720
721 // Now we have finished walking through all the subchains and extra inputs,
722 // and we can set the dirty flag for the current layer
723 //if( dirty ) {
724 // std::cout<<" Layer \""<<l->get_name()<<"\"->is_dirty()="<<l->is_dirty()<<std::endl;
725 // std::cout<<" Layer \""<<l->get_name()<<"\"->set_dirty("<<dirty<<")"<<std::endl;
726 //}
727 l->set_dirty( dirty );
728
729 // we mark the operations as "modified" if their input data
730 // has changed, so that they will be re-built
731 if( input_dirty && l->get_processor() &&
732 l->get_processor()->get_par() ) {
733 l->get_processor()->get_par()->set_modified();
734 }
735 if( (input_dirty || blender_dirty || filter_dirty) &&
736 l->get_blender() && l->get_blender()->get_par() ) {
737 l->get_blender()->get_par()->set_modified();
738 }
739
740 // If the current layer is cached, we reset the corresponding cache buffer
741 // so that the computation will restart from scratch at the next idle loop
742 if( /*l->is_dirty() ||*/ input_dirty || filter_dirty ) {
743 if( l->is_cached() )
744 l->reset_cache_buffers();
745 //if( l->is_cached() && l->get_cache_buffer() ) l->get_cache_buffer()->reset();
746 }
747 }
748 }
749
750
751
752
set_layers_dirty_flag(std::list<Layer * > & list)753 void PF::LayerManager::set_layers_dirty_flag( std::list<Layer*>& list )
754 {
755 std::list<PF::Layer*>::iterator li = list.begin();
756 for(li = list.begin(); li != list.end(); ++li) {
757 PF::Layer* l = *li;
758
759 if( l->get_processor() &&
760 l->get_processor()->get_par() )
761 l->get_processor()->get_par()->clear_modified();
762 if( l->get_blender() &&
763 l->get_blender()->get_par() )
764 l->get_blender()->get_par()->clear_modified();
765
766 l->set_dirty(true);
767
768 set_layers_dirty_flag( l->imap_layers );
769 set_layers_dirty_flag( l->omap_layers );
770 set_layers_dirty_flag( l->sublayers );
771 }
772 }
773
774
775
776
reset_layers_dirty_flag(std::list<Layer * > & list)777 void PF::LayerManager::reset_layers_dirty_flag( std::list<Layer*>& list )
778 {
779 std::list<PF::Layer*>::iterator li = list.begin();
780 for(li = list.begin(); li != list.end(); ++li) {
781 PF::Layer* l = *li;
782
783 if( l->get_processor() &&
784 l->get_processor()->get_par() )
785 l->get_processor()->get_par()->clear_modified();
786 if( l->get_blender() &&
787 l->get_blender()->get_par() )
788 l->get_blender()->get_par()->clear_modified();
789
790 l->clear_dirty();
791
792 reset_layers_dirty_flag( l->imap_layers );
793 reset_layers_dirty_flag( l->omap_layers );
794 reset_layers_dirty_flag( l->sublayers );
795 }
796 }
797
798
799
800
init_pipeline(PF::Pipeline * pipeline,std::list<Layer * > & list,PF::Layer * previous_layer)801 void PF::LayerManager::init_pipeline( PF::Pipeline* pipeline, std::list<Layer*>& list, PF::Layer* previous_layer )
802 {
803 std::list<PF::Layer*>::iterator li = list.begin();
804 for(li = list.begin(); li != list.end(); ++li) {
805 PF::Layer* l = *li;
806
807 if( !l ) continue;
808 #ifndef NDEBUG
809 std::cout<<"LayerManager::init_pipeline(): adding layer \""
810 <<l->get_name()<<"\""<<std::endl;
811 #endif
812 // Detect "pathological" conditions
813 g_assert( l->get_processor() != NULL );
814 g_assert( l->get_processor()->get_par() != NULL );
815 g_assert( l->get_blender() != NULL );
816 g_assert( l->get_blender()->get_par() != NULL );
817
818 // Create the node if it does not yet exist, and copy the parameters
819 // from the operation associated with the layer to the
820 // operation associated with the node
821 PF::PipelineNode* node = pipeline->set_node( l, previous_layer );
822 g_assert( node != NULL );
823 g_assert( node->processor != NULL );
824 g_assert( node->processor->get_par() != NULL );
825 g_assert( node->blender != NULL );
826 g_assert( node->blender->get_par() != NULL );
827
828 PF::OpParBase* par = l->get_processor()->get_par();
829 PF::OpParBase* pipelinepar = node->processor->get_par();
830 PF::OpParBase* blender = l->get_blender()->get_par();
831 PF::OpParBase* pipelineblender = node->blender->get_par();
832
833 // Run pre-build phase
834 #ifndef NDEBUG
835 std::cout<<"LayerManager::init_pipeline(): calling pre_build() for layer \""
836 <<l->get_name()<<"\""<<std::endl;
837 #endif
838 par->pre_build( pipeline->get_render_mode() );
839
840 // We import the parameters from the "master" operation associated to the layer,
841 // and which is directly connected with the GUI controls
842 //std::cout<<"LayerManager::init_pipeline(): calling import_settings() for layer \""
843 // <<l->get_name()<<"\""<<std::endl;
844 pipelinepar->import_settings( par );
845 pipelineblender->import_settings( blender );
846 //std::cout<<" settings imported."<<std::endl;
847
848 pipelinepar->set_output_caching( pipeline->get_op_caching_enabled() );
849 pipelineblender->set_output_caching( pipeline->get_op_caching_enabled() );
850
851 init_pipeline( pipeline, l->imap_layers, NULL );
852 init_pipeline( pipeline, l->omap_layers, NULL );
853 init_pipeline( pipeline, l->sublayers, previous_layer );
854
855 previous_layer = l;
856 }
857 }
858
859
860
861
update_ui(std::list<Layer * > & list)862 void PF::LayerManager::update_ui( std::list<Layer*>& list )
863 {
864 std::list<PF::Layer*>::iterator li = list.begin();
865 for(li = list.begin(); li != list.end(); ++li) {
866 PF::Layer* l = *li;
867
868 if( l->get_processor() &&
869 l->get_processor()->get_par() &&
870 l->get_processor()->get_par()->get_config_ui() ) {
871 l->get_processor()->get_par()->get_config_ui()->update();
872 }
873 update_ui( l->imap_layers );
874 update_ui( l->omap_layers );
875 update_ui( l->sublayers );
876 }
877 }
878
879
880
881
update_ui()882 void PF::LayerManager::update_ui()
883 {
884 update_ui( layers );
885 }
886
887
888
889
reset_op_caching(PF::Pipeline * pipeline)890 void PF::LayerManager::reset_op_caching( PF::Pipeline* pipeline )
891 {
892 if( !pipeline || !(pipeline->get_op_caching_enabled()) ) return;
893 reset_op_caching(pipeline, layers);
894 }
895
896
reset_op_caching(PF::Pipeline * pipeline,std::list<Layer * > & list)897 void PF::LayerManager::reset_op_caching( PF::Pipeline* pipeline, std::list<Layer*>& list )
898 {
899 std::list<PF::Layer*>::iterator li = list.begin();
900 for(li = list.begin(); li != list.end(); ++li) {
901 PF::Layer* l = *li;
902
903 if( !l ) continue;
904 if( !l->is_enabled() ) continue;
905 //std::cout<<"LayerManager::get_cache_buffer(): checking layer "<<l->get_name()<<std::endl;
906
907 reset_op_caching( pipeline, l->imap_layers );
908
909 reset_op_caching( pipeline, l->omap_layers );
910
911 // Finally we walk through the sub-layers
912 reset_op_caching( pipeline, l->sublayers );
913
914 //for( unsigned int pi = 0; pi < l->get_image()->get_npipelines(); pi++ ) {
915 // PF::Pipeline* pipeline = l->get_image()->get_pipeline( pi );
916 // if( !pipeline || !(pipeline->get_op_caching_enabled()) ) continue;
917
918 PF::PipelineNode* node = pipeline->get_node(l->get_id());
919 if( !node ) continue;
920 if( !node->processor ) continue;
921 if( !node->processor->get_par() ) continue;
922 node->processor->get_par()->reset_output_padding();
923 if( !node->blender ) continue;
924 if( !node->blender->get_par() ) continue;
925 node->blender->get_par()->reset_output_padding();
926 //}
927 }
928 }
929
930
931
932
update_op_caching(PF::Pipeline * pipeline)933 void PF::LayerManager::update_op_caching( PF::Pipeline* pipeline )
934 {
935 //if( !pipeline || !(pipeline->get_op_caching_enabled()) ) return;
936 if( !pipeline ) return;
937
938 reset_op_caching( pipeline );
939
940 //std::cout<<std::endl<<"LayerManager::update_op_caching():"<<std::endl;
941 update_op_caching( pipeline, layers, NULL );
942 }
943
944
945
946
update_op_caching(PF::Pipeline * pipeline,std::list<Layer * > & list,PF::Layer * input)947 void PF::LayerManager::update_op_caching( PF::Pipeline* pipeline, std::list<Layer*>& list, PF::Layer* input )
948 {
949 PF::Pipeline* pipeline0 = get_image()->get_pipeline( 0 );
950 //if( pipeline == pipeline0 ) return;
951
952 //std::cout<<"LayerManager::update_op_caching() called for layer \""
953 // <<(input ? input->get_name() : "NULL")<<"\""<<std::endl;
954
955 std::list<PF::Layer*>::reverse_iterator li;
956 for(li = list.rbegin(); li != list.rend(); ++li) {
957 PF::Layer* l = *li;
958 if(!l) continue;
959 if(!l->is_visible()) continue;
960
961 PF::PipelineNode* node0 = pipeline0->get_node(l->get_id());
962 if( !node0 ) continue;
963 if( !node0->image ) continue;
964
965 PF::PipelineNode* node = pipeline->get_node(l->get_id());
966 if( !node ) continue;
967 if( !node->processor ) continue;
968 if( !node->processor->get_par() ) continue;
969 PF::OpParBase* par = node->processor->get_par();
970
971 //std::cout<<" calling compute_padding() for layer: \""<<l->get_name()<<std::endl;
972 par->compute_padding( node0->image, 0, pipeline->get_level() );
973 int padding = par->get_padding(0);
974
975 //std::cout<<" current layer: \""<<l->get_name()<<"\", padding="<<padding<<std::endl;
976
977 PF::PipelineNode* pnode0 = NULL;
978 PF::PipelineNode* pnode = NULL;
979 PF::OpParBase* ppar = NULL;
980 std::list<PF::Layer*>::reverse_iterator lj = li; ++lj;
981 PF::Layer* lprev = NULL;
982 for( ; lj != list.rend(); ++lj ) {
983 lprev = *lj;
984 if(!lprev) continue;
985 if(!lprev->is_visible()) continue;
986
987 pnode0 = pipeline0->get_node(lprev->get_id());
988 if( !pnode0 ) continue;
989
990 pnode = pipeline->get_node(lprev->get_id());
991 if( !pnode ) continue;
992 if( !pnode->processor ) continue;
993 if( !pnode->blender ) continue;
994 if( !pnode->processor->get_par() ) continue;
995 if( !pnode->blender->get_par() ) continue;
996 ppar = pnode->processor->get_par();
997
998 // for the moment we keep the logic simple:
999 // if the operation allows opacity blending, we cache the blender
1000 // output instead of the operation output
1001 if( ppar->has_opacity() ) {
1002 ppar = pnode->blender->get_par();
1003 }
1004
1005 // check if the current operation is a mere transfer of images
1006 // currently only buffer layers fall under this category
1007 // in the NoOp case we walk one step more down the hierarchy
1008 bool is_noop = ppar->is_noop( pnode0->image, 0, pipeline->get_level() );
1009 //std::cout<<" layer: \""<<lprev->get_name()<<"\", is_noop="<<is_noop<<std::endl;
1010 if( !is_noop ) break;
1011 }
1012 if( !lprev ) {
1013 lprev = input;
1014 if( lprev ) {
1015 pnode0 = pipeline0->get_node(lprev->get_id());
1016 if( !pnode0 ) continue;
1017
1018 pnode = pipeline->get_node(lprev->get_id());
1019 if( !pnode ) continue;
1020 if( !pnode->processor ) continue;
1021 if( !pnode->blender ) continue;
1022 if( !pnode->processor->get_par() ) continue;
1023 if( !pnode->blender->get_par() ) continue;
1024 ppar = pnode->processor->get_par();
1025
1026 // for the moment we keep the logic simple:
1027 // if the operation allows opacity blending, we cache the blender
1028 // output instead of the operation output
1029 if( ppar->has_opacity() ) {
1030 ppar = pnode->blender->get_par();
1031 }
1032
1033 // check if the current operation is a mere transfer of images
1034 // currently only buffer layers fall under this category
1035 // in the NoOp case we walk one step more down the hierarchy
1036 bool is_noop = ppar->is_noop( pnode0->image, 0, pipeline->get_level() );
1037 if( is_noop ) { lprev = NULL; ppar = NULL; }
1038 }
1039 }
1040
1041 //if( lprev ) std::cout<<" previous layer: \""<<(lprev ? lprev->get_name() : "NULL")<<"\""<<std::endl;
1042
1043
1044 // Once more, we keep this preliminary implementation simple, and we ignore
1045 // the case where an operation oututs more than one image
1046 // currently only the wavelet decomposition tool does it
1047 if( padding > 0 && lprev && ppar ) {
1048 ppar->set_output_padding( padding, 0 );
1049 #ifndef NDEBUG
1050 std::cout<<" ppar->get_output_padding(0)="<<ppar->get_output_padding(0)
1051 <<" ppar->get_output_caching()="<<ppar->get_output_caching()<<std::endl;
1052 #endif
1053 }
1054
1055 if( !(l->get_sublayers().empty()) ) {
1056 //std::cout<<" updating sub-layers of layer \""<<l->get_name()<<"\""<<std::endl;
1057 update_op_caching( pipeline, l->get_sublayers(), lprev );
1058 }
1059
1060 if( !(l->get_imap_layers().empty()) ) {
1061 update_op_caching( pipeline, l->get_imap_layers(), NULL );
1062 }
1063
1064 if( !(l->get_omap_layers().empty()) ) {
1065 //std::cout<<" updating mask layers of layer \""<<l->get_name()<<"\""<<std::endl;
1066 update_op_caching( pipeline, l->get_omap_layers(), NULL );
1067 }
1068 }
1069 }
1070
1071
1072
1073
insert_layer(std::list<Layer * > & layers,Layer * layer,int32_t lid)1074 bool PF::insert_layer( std::list<Layer*>& layers, Layer* layer, int32_t lid )
1075 {
1076 if( lid < 0 ) {
1077 layers.push_back( layer );
1078 return true;
1079 }
1080
1081 std::list<Layer*>::iterator it;
1082 for( it = layers.begin(); it != layers.end(); ++it )
1083 if( (int32_t)(*it)->get_id() == lid ) break;
1084
1085 if( it == layers.end() ) return false;
1086 it++;
1087 layers.insert( it, layer );
1088
1089 return true;
1090 }
1091
1092
1093
insert_layer(Layer * layer,int32_t lid)1094 bool PF::LayerManager::insert_layer( Layer* layer, int32_t lid )
1095 {
1096 return PF::insert_layer( layers, layer, lid );
1097 }
1098
1099
remove_layer(PF::Layer * layer)1100 bool PF::LayerManager::remove_layer( PF::Layer* layer )
1101 {
1102 if( layer == NULL ) return false;
1103
1104 // Get the container list
1105 std::list<Layer*>* list = get_list( layer );
1106 if( list == NULL ) return false;
1107
1108 // Iterate over the list to find the good one
1109 std::list<Layer*>::iterator it;
1110 for( it = list->begin(); it != list->end(); ++it ) {
1111 if( (*it) == layer ) {
1112 list->erase( it );
1113 return true;
1114 }
1115 }
1116
1117 return false;
1118 }
1119
1120
1121
1122
rebuild_chain(PF::Pipeline * pipeline,colorspace_t cs,int width,int height,std::list<PF::Layer * > & list,PF::Layer * previous_layer)1123 VipsImage* PF::LayerManager::rebuild_chain( PF::Pipeline* pipeline, colorspace_t cs,
1124 int width, int height,
1125 std::list<PF::Layer*>& list,
1126 PF::Layer* previous_layer )
1127 {
1128 PipelineNode* previous_node = NULL;
1129 VipsImage* previous = NULL;
1130
1131 VipsImage* out = NULL;
1132 std::list<PF::Layer*>::iterator li = list.begin();
1133 for(li = list.begin(); li != list.end(); ++li) {
1134 PF::Layer* l = *li;
1135
1136 // Detect "pathological" conditions
1137 g_assert( l->get_processor() != NULL );
1138 g_assert( l->get_processor()->get_par() != NULL );
1139 g_assert( l->get_blender() != NULL );
1140 g_assert( l->get_blender()->get_par() != NULL );
1141
1142 char* name = (char*)l->get_name().c_str();
1143 if( !l->is_enabled() ) continue;
1144
1145 #ifndef NDEBUG
1146 std::cout<<"PF::LayerManager::rebuild_chain(): processing layer \""<<name<<"\""<<std::endl;
1147 std::cout<<" is_modified: "<<l->is_modified()<<std::endl;
1148 std::cout<<" is_dirty: "<<l->is_dirty()<<std::endl;
1149 #endif
1150 if( previous_layer ) {
1151 previous_node = pipeline->get_node( previous_layer->get_id() );
1152 //if( previous_node ) previous = previous_node->image;
1153 if( previous_node ) previous = previous_node->blended;
1154 #ifndef NDEBUG
1155 std::cout<<" Previous layer: \""<<previous_layer->get_name()<<"\""<<std::endl;
1156 #endif
1157 }
1158
1159 // Create the node if it does not yet exist, and copy the parameters
1160 // from the operation associated with the layer to the
1161 // operation associated with the node
1162 PF::PipelineNode* node = pipeline->set_node( l, previous_layer );
1163 g_assert( node != NULL );
1164 g_assert( node->processor != NULL );
1165 g_assert( node->processor->get_par() != NULL );
1166 g_assert( node->blender != NULL );
1167 g_assert( node->blender->get_par() != NULL );
1168
1169 PF::OpParBase* par = l->get_processor()->get_par();
1170 PF::OpParBase* pipelinepar = node->processor->get_par();
1171 PF::OpParBase* blender = l->get_blender()->get_par();
1172 PF::OpParBase* pipelineblender = node->blender->get_par();
1173
1174 //l->set_cached( par->needs_caching() );
1175
1176 #ifndef NDEBUG
1177 std::cout<<"PF::LayerManager::rebuild_chain(): setting format for layer "<<l->get_name()
1178 <<" to "<<pipeline->get_format()<<std::endl;
1179 std::cout<<" pipelinepar->set_render_mode( "<<pipeline->get_render_mode()<<" );"<<std::endl;
1180 #endif
1181 pipelinepar->set_format( pipeline->get_format() );
1182 pipelinepar->set_render_mode( pipeline->get_render_mode() );
1183
1184 #ifndef NDEBUG
1185 std::cout<<"PF::LayerManager::rebuild_chain(): par->is_modified()="<<par->is_modified()
1186 <<" blender->is_modified()="<<blender->is_modified()
1187 <<" node->image="<<node->image<<" pipeline->get_force_rebuild()="<<pipeline->get_force_rebuild()<<std::endl;
1188 #endif
1189 if( true && !pipeline->get_force_rebuild() && !par->is_modified() && (node->image != NULL) ) {
1190 // If the current operation is not modified, we check if the blender was modified
1191 #ifndef NDEBUG
1192 std::cout<<"LayerManager::rebuild_chain(): reusing existing layer \""<<l->get_name()
1193 <<"\" node->image="<<node->image<<std::endl;
1194 #endif
1195 VipsImage* blendedimg = node->blended;
1196 if( node->image && blender->is_modified() ) {
1197 // if the blender was modified we rebuild the blended image using the existing
1198 // output of the current operation
1199 if( par->has_opacity() && blender && pipelineblender) {
1200 #ifndef NDEBUG
1201 std::cout<<"LayerManager::rebuild_chain(): rebuilding blender output for layer \""<<l->get_name()
1202 <<"\""<<std::endl;
1203 #endif
1204 if( node->blended ) {
1205 std::cout<<"LayerManager::rebuild_chain(): vips_image_invalidate_all() called on node->blended"<< std::endl;
1206 vips_image_invalidate_all( node->blended );
1207 }
1208
1209 unsigned int level = pipeline->get_level();
1210 //pipelineblender->import_settings( blender );
1211
1212 VipsImage* omap = NULL;
1213 if( previous && !l->omap_layers.empty() && pipelineblender->get_mask_enabled()==true ) {
1214 omap = rebuild_chain( pipeline, PF_COLORSPACE_GRAYSCALE,
1215 previous->Xsize, previous->Ysize,
1216 l->omap_layers, NULL );
1217 }
1218
1219 std::vector<VipsImage*> in;
1220 // we add the previous image to the list of inputs, even if it is NULL
1221 in.push_back( previous );
1222 in.push_back( node->image );
1223 blendedimg = pipelineblender->build( in, 0, NULL, omap, level );
1224 #ifndef NDEBUG
1225 if(blendedimg)
1226 std::cout<<"rebuild_chain(): Layer \""<<l->get_name()<<"\" level="<<level
1227 <<" blended size: "<<blendedimg->Xsize<<","<<blendedimg->Ysize<<std::endl;
1228 #endif
1229 } else {
1230 blendedimg = node->image;
1231 PF_REF(blendedimg,"LayerManager::rebuild_chain(): blendedimg ref");
1232 }
1233 #ifndef NDEBUG
1234 std::cout<<"rebuild_chain(): Layer \""<<l->get_name()<<"\" blended: "<<blendedimg<<std::endl;
1235 #endif
1236 pipeline->set_blended( blendedimg, l->get_id() );
1237 }
1238 out = blendedimg;
1239 //previous = newimg;
1240 previous_layer = l;
1241 if(pipelineblender) pipelineblender->clear_modified();
1242 continue;
1243 }
1244
1245 #ifndef NDEBUG
1246 std::cout<<"LayerManager::rebuild_chain(): rebuilding output for layer \""<<l->get_name()
1247 <<"\""<<std::endl;
1248 #endif
1249 if( node->image ) {
1250 #ifndef NDEBUG
1251 std::cout<<"LayerManager::rebuild_chain(): vips_image_invalidate_all() called on node->image"<< std::endl;
1252 #endif
1253 vips_image_invalidate_all( node->image );
1254 }
1255 //if( node->blended ) vips_image_invalidate_all( node->blended );
1256
1257 // Run pre-build phase
1258 //par->pre_build( pipeline->get_render_mode() );
1259
1260 PF::PropertyBase* p_rgb_target_ch = blender->get_property( "rgb_target_channel" );
1261 if( p_rgb_target_ch )
1262 p_rgb_target_ch->set_enum_value( par->get_rgb_target_channel() );
1263 PF::PropertyBase* p_lab_target_ch = blender->get_property( "lab_target_channel" );
1264 if( p_lab_target_ch )
1265 p_lab_target_ch->set_enum_value( par->get_lab_target_channel() );
1266 PF::PropertyBase* p_cmyk_target_ch = blender->get_property( "cmyk_target_channel" );
1267 if( p_cmyk_target_ch )
1268 p_cmyk_target_ch->set_enum_value( par->get_cmyk_target_channel() );
1269
1270 #ifndef NDEBUG
1271 std::cout<<"PF::LayerManager::rebuild_chain(): setting format for layer "<<l->get_name()
1272 <<" to "<<pipeline->get_format()<<std::endl;
1273 #endif
1274 pipelineblender->set_format( pipeline->get_format() );
1275 pipelineblender->set_render_mode( pipeline->get_render_mode() );
1276
1277 // If the layer is at the beginning of the chain, we set hints about the desired
1278 // colorspace and pixel format using default values.
1279 // The size and colorspace hints might be ignored by
1280 // the operation (for example in the case of an image from a file, where the
1281 // size and colorspace are dictated by the file content).
1282 // On the other hand, the pixel format hint should be strictly respected by all
1283 // operators, as it defined the accuracy at which the final image is rendered.
1284 // If a previous image has been created already, hints are copied from it.
1285 //if( li == list.begin() || !previous )
1286 if( !previous ) {
1287 pipelinepar->set_image_hints( width, height, cs );
1288 pipelineblender->set_image_hints( width, height, cs );
1289 } else {
1290 pipelinepar->set_image_hints( previous );
1291 pipelineblender->set_image_hints( previous );
1292 }
1293 //PF::colorspace_t cs = PF::convert_colorspace( pipelinepar->get_interpretation() );
1294 //std::cout<<" par: "<<pipelinepar<<std::endl;
1295 //std::cout<<" cs after set_image_hints: "<<cs<<std::endl;
1296
1297 /* At this point there are two possibilities:
1298 1. the layer has no sub-layers, in which case it is combined with the output
1299 of the previous layer plus any extra inputs it might have
1300 2. the layer has sub-layers, in which case we first build the sub-layers chain
1301 and then we combine it with the output of the previous layer
1302 */
1303 VipsImage* newimg = NULL;
1304 std::vector<VipsImage*> newimgvec;
1305 VipsImage* imap = NULL;
1306 VipsImage* omap = NULL;
1307 if( l->sublayers.empty() ) {
1308 std::vector<VipsImage*> in;
1309 #ifndef NDEBUG
1310 std::cout<<"Layer \""<<l->get_name()<<"\""
1311 <<" par->needs_input()="<<par->needs_input()
1312 <<" previous="<<previous
1313 <<" get_previous_layer_is_input="<<par->get_previous_layer_is_input()
1314 <<" l->inputs.size()="<<l->inputs.size()
1315 <<std::endl;
1316 #endif
1317 if( false && par->needs_input() && !previous && l->inputs.empty() ) {
1318 // Here we have a problem: the operation we are trying to insert in the chain requires
1319 // a primary input image, but there is no previous image available... we give up
1320 std::cout<<"LayerManager::rebuild_chain(): missing input data for layer \""<<l->get_name()<<"\""<<std::endl;
1321 return NULL;
1322 }
1323
1324 // We build the chains for the intensity and opacity maps
1325 #ifndef NDEBUG
1326 std::cout<<"Layer \""<<l->get_name()<<"\""
1327 <<" imap_layers.size()="<<l->imap_layers.size()
1328 <<" omap_layers.size()="<<l->omap_layers.size()
1329 <<std::endl;
1330 #endif
1331 if( previous && !l->imap_layers.empty() && pipelinepar->get_mask_enabled()==true ) {
1332 imap = rebuild_chain( pipeline, PF_COLORSPACE_GRAYSCALE,
1333 previous->Xsize, previous->Ysize,
1334 l->imap_layers, NULL );
1335 }
1336
1337 if( previous && !l->omap_layers.empty() && pipelineblender->get_mask_enabled()==true ) {
1338 omap = rebuild_chain( pipeline, PF_COLORSPACE_GRAYSCALE,
1339 previous->Xsize, previous->Ysize,
1340 l->omap_layers, NULL );
1341 }
1342
1343 int iextra_min = 0;
1344 std::cout<<"Layer \""<<l->get_name()<<"\": inputs size: "<<l->inputs.size()<<std::endl;
1345 if( l->inputs.empty() || l->inputs[0].first.first < 0 ) {
1346 // input layer is not specified, we grab the default input
1347 std::pair< std::pair<int32_t,int32_t>,bool> input = get_default_input_layer(l);
1348 PF::Layer* ldef = get_layer(input.first.first);
1349 VipsImage* imdef = NULL;
1350 int imgid = input.first.second;
1351 PF::PipelineNode* ndef = pipeline->get_node(ldef);
1352 if( ndef ) {
1353 if( input.second == true ) {
1354 imdef = ndef->blended;
1355 } else {
1356 if( (imgid>=0) && (imgid<(int)ndef->images.size()) ) {
1357 imdef = ndef->images[imgid];
1358 //std::cout<<" extra_node->images[imgid]="<<extra_node->images[imgid]<<std::endl;
1359 }
1360 }
1361 }
1362 in.push_back(imdef);
1363 //#ifndef NDEBUG
1364 if( ldef && imdef )
1365 std::cout<<"Layer \""<<l->get_name()<<"\": added \""<<ldef->get_name()<<"\"("<<imdef<<") as default input"<<std::endl;
1366 else
1367 std::cout<<"Layer \""<<l->get_name()<<"\": added "<<imdef<<" as default input"<<std::endl;
1368 //#endif
1369 iextra_min = 1;
1370 }
1371
1372 // Now we loop on the vector of extra inputs, and we include the corresponding
1373 // images in the input vector
1374 for(uint32_t iextra = iextra_min; iextra < l->inputs.size(); iextra++) {
1375 #ifndef NDEBUG
1376 std::cout<<"Layer \""<<l->get_name()<<"\": adding extra input layer id="<<l->inputs[iextra].first.first
1377 <<" (blended="<<l->inputs[iextra].second<<")..."<<std::endl;
1378 #endif
1379 PF::Layer* lextra = get_layer( l->inputs[iextra].first.first );
1380 int imgid = l->inputs[iextra].first.second;
1381 // If the extra input layer is not found we have a problem, better to give up
1382 // with an error.
1383 //g_assert( lextra != NULL );
1384 if( !lextra ) {
1385 std::cout<<"Layer \""<<l->get_name()<<"\": extra input layer id="<<l->inputs[iextra].first.first
1386 <<" (blended="<<l->inputs[iextra].second<<") not found (NULL layer pointer)"<<std::endl;
1387 in.push_back( NULL );
1388 continue;
1389 }
1390 // If the layer is not visible (either bcause it is disabled,
1391 // or one of its parents is disabled) we ignore the associated image
1392 if( !(lextra->is_visible()) ) {
1393 std::cout<<"Layer \""<<l->get_name()<<"\": extra input layer id="<<l->inputs[iextra].first.first
1394 <<" (blended="<<l->inputs[iextra].second<<") not visible"<<std::endl;
1395 in.push_back( NULL );
1396 continue;
1397 }
1398 PF::PipelineNode* extra_node = pipeline->get_node( lextra->get_id() );
1399 //g_assert( extra_node != NULL );
1400 if( extra_node == NULL ) {
1401 std::cout<<"Layer \""<<l->get_name()<<"\": extra input layer id="<<l->inputs[iextra].first.first
1402 <<" (blended="<<l->inputs[iextra].second<<") node not found"<<std::endl;
1403 in.push_back( NULL );
1404 continue;
1405 }
1406 VipsImage* extra_img = NULL;
1407 #ifndef NDEBUG
1408 std::cout<<" imgid="<<imgid<<" extra_node->images.size()="<<extra_node->images.size()<<std::endl;
1409 #endif
1410 if( l->inputs[iextra].second == true ) {
1411 extra_img = extra_node->blended;
1412 } else {
1413 if( (imgid>=0) && (imgid<(int)extra_node->images.size()) ) {
1414 extra_img = extra_node->images[imgid];
1415 //std::cout<<" extra_node->images[imgid]="<<extra_node->images[imgid]<<std::endl;
1416 }
1417 }
1418 // Similarly, if the extra input layer has no valid image associated to it
1419 // we have a problem and we gve up
1420 //g_assert( extra_img != NULL );
1421 if( extra_img == NULL ) {
1422 std::cout<<"Layer \""<<l->get_name()<<"\": extra input layer id="<<l->inputs[iextra].first.first
1423 <<" (blended="<<l->inputs[iextra].second<<") NULL image"<<std::endl;
1424 in.push_back( NULL );
1425 continue;
1426 }
1427 in.push_back( extra_img );
1428
1429 // We inherit the image properties (size, colorspace, ...) from the last extra input
1430 pipelinepar->set_image_hints( extra_img );
1431 pipelineblender->set_image_hints( extra_img );
1432 if( par->is_map() ) {
1433 // If the layer is a mask, we force the output image colorspace to grayscale
1434 pipelinepar->grayscale_image( pipelinepar->get_xsize(), pipelinepar->get_ysize() );
1435 pipelineblender->grayscale_image( pipelinepar->get_xsize(), pipelinepar->get_ysize() );
1436 }
1437 #ifndef NDEBUG
1438 std::cout<<" ...added."<<std::endl;
1439 #endif
1440 }
1441
1442 //if( par->get_config_ui() ) {
1443 // par->get_config_ui()->update_properties();
1444 //}
1445 #ifndef NDEBUG
1446 std::cout<<"Building layer \""<<l->get_name()<<"\"..."<<std::endl;
1447 #endif
1448
1449 // We import the parameters from the "master" operation associated to the layer,
1450 // and which is directly connected with the GUI controls
1451 //pipelinepar->import_settings( par );
1452
1453 unsigned int level = pipeline->get_level();
1454
1455 PF::PipelineNode* node_compat =
1456 image->get_compatible_node(l, pipeline, par->get_real_level(level));
1457
1458 if( node_compat ) {
1459 newimgvec = node_compat->images;
1460 for(unsigned int ii = 0; ii < newimgvec.size(); ii++) {
1461 if( newimgvec[ii] ) PF_REF(newimgvec[ii], "rebuild_chain: newimgvec[ii] ref");
1462 }
1463 newimg = node_compat->image;
1464 //#ifndef NDEBUG
1465 std::cout<<"[rebuild_chain]: reusing existing node for layer \""<<l->get_name()<<"\"."<<std::endl;
1466 //#endif
1467 } else {
1468 newimgvec = pipelinepar->build_many_internal( in, 0, imap, omap, level );
1469 newimg = (newimgvec.empty()) ? NULL : newimgvec[0];
1470 }
1471 //cs = PF::convert_colorspace( pipelinepar->get_interpretation() );
1472 //std::cout<<" par: "<<pipelinepar<<std::endl;
1473 //std::cout<<" cs after build: "<<cs<<std::endl;
1474 //cs = PF::convert_colorspace( newimg->Type );
1475 //std::cout<<" cs from newimg: "<<cs<<std::endl;
1476 #ifndef NDEBUG
1477 std::cout<<"... layer \""<<l->get_name()<<"\" finished"<<std::endl;
1478 #endif
1479
1480 pipelinepar->clear_modified();
1481 pipeline->set_level( level );
1482 #ifndef NDEBUG
1483 if( newimg ) {
1484 std::cout<<"rebuild_chain(): Layer \""<<l->get_name()<<"\" level="<<level
1485 <<" image size: "<<newimg->Xsize<<","<<newimg->Ysize<<std::endl
1486 <<" inputs:";
1487 for(int i_in = 0; i_in < in.size(); i_in++)
1488 std::cout<<" 0x"<<in[i_in];
1489 std::cout<<std::endl<<" output: 0x"<<newimg<<std::endl;
1490 }
1491 //#endif
1492 //#ifndef NDEBUG
1493 if( !newimg ) {
1494 std::cout<<"WARNING: NULL image from layer \""<<name<<"\""<<std::endl;
1495 } else {
1496 void *data;
1497 size_t data_length;
1498 if( vips_image_get_blob( newimg, VIPS_META_ICC_NAME,
1499 &data, &data_length ) ) {
1500 std::cout<<"WARNING: missing ICC profile from layer \""<<name<<"\""<<std::endl;
1501 } else {
1502 cmsHPROFILE profile_in = cmsOpenProfileFromMem( data, data_length );
1503 if( profile_in ) {
1504 char tstr[1024];
1505 cmsGetProfileInfoASCII(profile_in, cmsInfoDescription, "en", "US", tstr, 1024);
1506 std::cout<<" Embedded profile found in layer \""<<name<<"\": "<<tstr<<std::endl;
1507 }
1508 }
1509 }
1510 std::cout<<"... done."<<std::endl;
1511 #endif
1512 //if( par->get_config_ui() ) par->get_config_ui()->update();
1513 } else {// if( l->sublayers.empty() )
1514 std::vector<VipsImage*> in;
1515
1516 // we add the previous image to the list of inputs, even if it is NULL
1517 //in.push_back( previous );
1518
1519 // Then we build the chain for the sub-layers, passing the previous image as the
1520 // initial input
1521 VipsImage* isub = NULL;
1522 if( previous )
1523 isub = rebuild_chain( pipeline, cs,
1524 previous->Xsize, previous->Ysize,
1525 l->sublayers, previous_layer );
1526 else
1527 isub = rebuild_chain( pipeline, cs,
1528 width, height,
1529 l->sublayers, NULL );
1530
1531 // we add the output of the sub-layers chain to the list of inputs, even if it is NULL
1532 in.push_back( isub );
1533
1534 // Then we build the chains for the intensity and opacity maps
1535 #ifndef NDEBUG
1536 std::cout<<"Layer \""<<l->get_name()<<"\""
1537 <<" imap_layers.size()="<<l->imap_layers.size()
1538 <<" omap_layers.size()="<<l->omap_layers.size()
1539 <<std::endl;
1540 #endif
1541 if( previous && !l->imap_layers.empty() && pipelinepar->get_mask_enabled()==true ) {
1542 imap = rebuild_chain( pipeline, PF_COLORSPACE_GRAYSCALE,
1543 previous->Xsize, previous->Ysize,
1544 l->imap_layers, NULL );
1545 //if( !imap ) return false;
1546 //std::list<PF::Layer*>::reverse_iterator map_i = l->imap_layers.rbegin();
1547 //if(map_i != l->imap_layers.rend())
1548 //imap = (*map_i)->get_processor()->get_par()->get_image();
1549 }
1550 if( previous && !l->omap_layers.empty() && pipelineblender->get_mask_enabled()==true ) {
1551 omap = rebuild_chain( pipeline, PF_COLORSPACE_GRAYSCALE,
1552 previous->Xsize, previous->Ysize,
1553 l->omap_layers, NULL );
1554 //if( !omap ) return false;
1555 //std::list<PF::Layer*>::reverse_iterator map_i = l->omap_layers.rbegin();
1556 //if(map_i != l->omap_layers.rend())
1557 //omap = (*map_i)->get_processor()->get_par()->get_image();
1558 }
1559
1560 //if( par->get_config_ui() ) par->get_config_ui()->update_properties();
1561 #ifndef NDEBUG
1562 std::cout<<"Building layer \""<<l->get_name()<<"\"..."<<std::endl;
1563 #endif
1564 unsigned int level = pipeline->get_level();
1565 //pipelinepar->import_settings( par );
1566 newimgvec = pipelinepar->build_many_internal( in, 0, imap, omap, level );
1567 newimg = (newimgvec.empty()) ? NULL : newimgvec[0];
1568 #ifndef NDEBUG
1569 std::cout<<"... layer \""<<l->get_name()<<"\" finished"<<std::endl;
1570 #endif
1571
1572 if( false && (newimg != NULL) && (newimgvec.size() == 1) && !image->is_loaded() && l->is_cached() &&
1573 (l->get_cache_buffer() != NULL) &&
1574 (l->get_cache_buffer()->is_completed() == false) ) {
1575 // The image is being loaded, and the current layer needs to be cached
1576 // In this case we cache the data immediately and we use the cached
1577 // image instead of the newly built one
1578 PF::CacheBuffer* buf = l->get_cache_buffer();
1579 buf->set_image( newimg );
1580 #ifndef NDEBUG
1581 std::cout<<"Writing cache buffer for layer "<<l->get_name()<<std::endl;
1582 #endif
1583 gint64 time1 = g_get_real_time();
1584 buf->write();
1585 gint64 time2 = g_get_real_time();
1586 #ifndef NDEBUG
1587 std::cout<<"Buffer saved in "<<(time2-time1)/1000000<<" seconds."<<std::endl;
1588 #endif
1589 PF_UNREF( newimg, "rebuild_chain(): newimg unref after cache buffer filling" );
1590
1591 PF::PyramidLevel* pl = buf->get_pyramid().get_level( level );
1592 if( pl && pl->image ) {
1593 pipeline->set_level( level );
1594 newimg = pl->image;
1595 newimgvec[0] = pl->image;
1596 }
1597 }
1598
1599 pipelinepar->clear_modified();
1600 pipeline->set_level( level );
1601 #ifndef NDEBUG
1602 if( newimg ) {
1603 std::cout<<"rebuild_chain(): Layer \""<<l->get_name()<<"\" level="<<level
1604 <<" image size: "<<newimg->Xsize<<","<<newimg->Ysize<<std::endl
1605 <<" inputs:";
1606 for(int i_in = 0; i_in < in.size(); i_in++)
1607 std::cout<<" 0x"<<in[i_in];
1608 std::cout<<std::endl<<" output: 0x"<<newimg<<std::endl;
1609 }
1610 #endif
1611 #ifndef NDEBUG
1612 if( !newimg ) {
1613 std::cout<<"WARNING: NULL image from layer \""<<name<<"\""<<std::endl;
1614 } else {
1615 void *data;
1616 size_t data_length;
1617 if( vips_image_get_blob( newimg, VIPS_META_ICC_NAME,
1618 &data, &data_length ) ) {
1619 std::cout<<"WARNING: missing ICC profile from layer \""<<name<<"\""<<std::endl;
1620 } else {
1621 cmsHPROFILE profile_in = cmsOpenProfileFromMem( data, data_length );
1622 if( profile_in ) {
1623 char tstr[1024];
1624 cmsGetProfileInfoASCII(profile_in, cmsInfoDescription, "en", "US", tstr, 1024);
1625 std::cout<<" Embedded profile found in layer \""<<name<<"\": "<<tstr<<std::endl;
1626 }
1627 }
1628 }
1629 std::cout<<"... done."<<std::endl;
1630 #endif
1631 //if( par->get_config_ui() ) par->get_config_ui()->update();
1632 }// if( l->sublayers.empty() )
1633
1634 if( newimg ) {
1635 VipsImage* blendedimg;
1636 #ifndef NDEBUG
1637 std::cout<<"rebuild_chain(): Layer \""<<l->get_name()<<"\" newimgvec.size()="<<newimgvec.size()<<std::endl;
1638 #endif
1639 unsigned int level = pipeline->get_level();
1640 unsigned int level_real = par->get_real_level(level);
1641 pipeline->set_images( newimgvec, l->get_id(), level_real );
1642
1643 bool needs_shrinking = (level_real != level) && par->do_shirnk_on_blend();
1644 if( needs_shrinking ) {
1645 float scale = 1;
1646 for(unsigned int l = 0; l < level; l++) scale /= 2;
1647 std::cout<<"rebuild_chain(): scaling layer \""<<l->get_name()<<"\" by "<<scale<<std::endl;
1648 VipsKernel kernel = VIPS_KERNEL_CUBIC;
1649 VipsImage* scaled;
1650 if( vips_resize(newimg, &scaled, scale, "kernel", kernel, NULL) ) {
1651 std::cout<<"rebuild_chain(): vips_resize() failed."<<std::endl;
1652 //PF_UNREF( interpolate, "ScalePar::build(): interpolate unref" );
1653 } else {
1654 newimg = scaled;
1655 }
1656
1657 if( scaled && scale < 0.5 ) {
1658 VipsAccess acc = VIPS_ACCESS_RANDOM;
1659 int threaded = 1, persistent = 1;
1660 VipsImage* cached;
1661 if( !phf_tilecache(scaled, &cached,
1662 "access", acc, "threaded", threaded,
1663 "persistent", persistent, NULL) ) {
1664 PF_UNREF(scaled, "rebuild_chan: scaled unref");
1665 newimg = cached;
1666 std::cout<<"rebuild_chain(): added tilecache after scaling layer \""<<l->get_name()<<"\" by "<<scale<<std::endl;
1667 }
1668 }
1669 } else {
1670 PF_REF(newimg,"LayerManager::rebuild_chain(): newimg ref");
1671 }
1672
1673 if( par->has_opacity() && blender && pipelineblender) {
1674 //pipelineblender->import_settings( blender );
1675
1676 //std::cout<<"rebuild_chain(): blending images for layer \""<<l->get_name()<<"\""<<std::endl;
1677 std::vector<VipsImage*> in;
1678 // we add the previous image to the list of inputs, even if it is NULL
1679 in.push_back( previous );
1680 in.push_back( newimg );
1681 blendedimg = pipelineblender->build( in, 0, NULL, omap, level );
1682 PF_UNREF(newimg,"LayerManager::rebuild_chain(): newimg unref");
1683 #ifndef NDEBUG
1684 if(blendedimg)
1685 std::cout<<"rebuild_chain(): Layer \""<<l->get_name()<<"\" level="<<level
1686 <<" blended size: "<<blendedimg->Xsize<<","<<blendedimg->Ysize<<std::endl;
1687 #endif
1688 } else {
1689 blendedimg = newimg;
1690 //PF_REF(blendedimg,"LayerManager::rebuild_chain(): blendedimg ref");
1691 }
1692 #ifndef NDEBUG
1693 std::cout<<"rebuild_chain(): Layer \""<<l->get_name()<<"\" blended: "<<blendedimg<<std::endl;
1694 #endif
1695 pipeline->set_blended( blendedimg, l->get_id() );
1696 out = blendedimg;
1697 //previous = newimg;
1698 previous_layer = l;
1699 }
1700 if(pipelineblender) pipelineblender->clear_modified();
1701 }
1702 return out;
1703 }
1704
1705
rebuild_prepare()1706 bool PF::LayerManager::rebuild_prepare()
1707 {
1708 #ifndef NDEBUG
1709 std::cout<<"PF::LayerManager::rebuild_prepare(): layers.size()="<<layers.size()<<std::endl;
1710 #endif
1711 bool visible = true;
1712 update_visible( layers, visible );
1713
1714 bool dirty = false;
1715 update_dirty( layers, dirty );
1716
1717 #ifndef NDEBUG
1718 std::cout<<"PF::LayerManager::rebuild_prepare(): finished"<<std::endl;
1719 #endif
1720 if( !dirty ) {
1721 return false;
1722 }
1723 return true;
1724 }
1725
1726
rebuild(Pipeline * pipeline,colorspace_t cs,int width,int height,VipsRect * area)1727 bool PF::LayerManager::rebuild( Pipeline* pipeline, colorspace_t cs, int width, int height, VipsRect* area )
1728 {
1729 //Glib::Threads::Mutex::Lock lock( pipeline->get_mutex() );
1730
1731 #ifndef NDEBUG
1732 std::cout<<"LayerManager::rebuild(): started."<<std::endl;
1733 #endif
1734 init_pipeline( pipeline, layers, NULL );
1735 #ifndef NDEBUG
1736 std::cout<<"LayerManager::rebuild(): after init_pipeline()"<<std::endl;
1737 #endif
1738
1739 update_op_caching( pipeline );
1740 #ifndef NDEBUG
1741 std::cout<<"LayerManager::rebuild(): after update_op_caching()"<<std::endl;
1742 #endif
1743
1744 if( pipeline && pipeline->get_output() ) {
1745 //vips_image_invalidate_all( pipeline->get_output() );
1746 }
1747 VipsImage* output = rebuild_chain( pipeline, cs, width, height, layers, NULL );
1748 #ifndef NDEBUG
1749 std::cout<<"LayerManager::rebuild(): chain rebuild finished."<<std::endl;
1750 #endif
1751 pipeline->set_output( output );
1752 pipeline->update( area );
1753 pipeline->clear_force_rebuild();
1754 //std::cout<<"LayerManager::rebuild(): pipeline updated."<<std::endl;
1755 return true;
1756 }
1757
1758
rebuild_finalize(bool ui_update)1759 bool PF::LayerManager::rebuild_finalize( bool ui_update )
1760 {
1761 reset_layers_dirty_flag( layers );
1762 //if( ui_update ) update_ui( layers );
1763 return true;
1764 }
1765
1766
1767
1768
rebuild_all(Pipeline * pipeline,colorspace_t cs,int width,int height)1769 bool PF::LayerManager::rebuild_all(Pipeline* pipeline, colorspace_t cs, int width, int height)
1770 {
1771 /*
1772 if( layers.empty() )
1773 return true;
1774 PF::Layer* l = *(layers.begin());
1775 l->set_dirty( true );
1776
1777 if( !l->imap_layers.empty() ) {
1778 PF::Layer* ll = *(l->imap_layers.begin());
1779 ll->set_dirty( true );
1780 }
1781 if( !l->omap_layers.empty() ) {
1782 PF::Layer* ll = *(l->omap_layers.begin());
1783 ll->set_dirty( true );
1784 }
1785 if( !l->sublayers.empty() ) {
1786 PF::Layer* ll = *(l->sublayers.begin());
1787 ll->set_dirty( true );
1788 }
1789
1790 bool dirty = false;
1791 update_dirty( layers, dirty );
1792
1793 if( !dirty ) {
1794 return false;
1795 }
1796 */
1797
1798 set_layers_dirty_flag( layers );
1799
1800 VipsImage* output = rebuild_chain( pipeline, cs, width, height, layers, NULL );
1801 pipeline->set_output( output );
1802
1803 reset_layers_dirty_flag( layers );
1804
1805
1806
1807 return true;
1808 }
1809
1810
1811
save(std::ostream & ostr)1812 bool PF::LayerManager::save( std::ostream& ostr )
1813 {
1814 int level = 1;
1815 std::list<PF::Layer*>::iterator li;
1816 for(li = layers.begin(); li != layers.end(); ++li) {
1817 PF::Layer* l = *li;
1818 if( !l->save( ostr, level ) ) return false;
1819 }
1820 return true;
1821 }
1822