1 /*
2 */
3
4 /*
5
6 Copyright (C) 2014 Ferrero Andrea
7
8 This program is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
20
21
22 */
23
24 /*
25
26 These files are distributed with PhotoFlow - http://aferrero2707.github.io/PhotoFlow/
27
28 */
29
30
31
32 /* Turn on ADDR() range checks.
33 #define DEBUG 1
34 */
35
36 //#ifdef HAVE_CONFIG_H
37 //#include <config.h>
38 //#endif /*HAVE_CONFIG_H*/
39 //#include <vips/intl.h>
40
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <limits.h>
45
46 #include <lcms2.h>
47
48 #include <iostream>
49
50
51 #include <vips/vips.h>
52 //#include <vips/dispatch.h>
53
54 #include "../base/processor.hh"
55 #include "../base/layer.hh"
56
57 #define PF_MAX_INPUT_IMAGES 10
58
59 static GObject* object_in;
60
61 /**/
62 #define VIPS_TYPE_LAYER (vips_layer_get_type())
63 #define VIPS_LAYER( obj ) \
64 (G_TYPE_CHECK_INSTANCE_CAST( (obj), \
65 VIPS_TYPE_LAYER, VipsLayer ))
66 #define VIPS_LAYER_CLASS( klass ) \
67 (G_TYPE_CHECK_CLASS_CAST( (klass), \
68 VIPS_TYPE_LAYER, VipsLayerClass))
69 #define VIPS_IS_LAYER( obj ) \
70 (G_TYPE_CHECK_INSTANCE_TYPE( (obj), VIPS_TYPE_LAYER ))
71 #define VIPS_IS_LAYER_CLASS( klass ) \
72 (G_TYPE_CHECK_CLASS_TYPE( (klass), VIPS_TYPE_LAYER ))
73 #define VIPS_LAYER_GET_CLASS( obj ) \
74 (G_TYPE_INSTANCE_GET_CLASS( (obj), \
75 VIPS_TYPE_LAYER, VipsLayerClass ))
76 /**/
77 typedef struct _VipsLayer {
78 VipsOperation parent_instance;
79
80 /* The vector of input images.
81 */
82 VipsImage* in[PF_MAX_INPUT_IMAGES];
83 int ninput;
84
85 /* The vector of input images.
86 */
87 VipsImage* out;
88
89 /* The index at which input images start
90 * in[0] always corresponds to the lower layer of the blending step,
91 * however it might not directly represent an input image for processing.
92 * This is for example the case for composed operations: the last step
93 * receives as input the result of the previous operation, but performs
94 * the blending with the initial input image.
95 */
96 int in_first;
97
98 /* Pointer to the object which does the actual image processing
99 */
100 PF::ProcessorBase* processor;
101
102 /* The (optional) intensity map
103 */
104 VipsImage *imap;
105
106 /* The (optional) opacity map
107 */
108 VipsImage *omap;
109
110 /* The preferred output style for this layer
111 */
112 VipsDemandStyle demand_hint;
113
114 int width;
115 int height;
116 int nbands;
117
118 int serial_id;
119
120 //int rand;
121
122 /* All the imput images, including the intensity
123 and opacity masks
124 */
125 VipsImage **in_all;
126
127 } VipsLayer;
128
129 /*
130 typedef struct _VipsLayerClass {
131 VipsOperationClass parent_class;
132 } VipsLayerClass;
133 */
134 typedef VipsOperationClass VipsLayerClass;
135
136 #ifdef __cplusplus
137 extern "C" {
138 #endif /*__cplusplus*/
139
140 G_DEFINE_TYPE( VipsLayer, vips_layer, VIPS_TYPE_OPERATION );
141
142 #ifdef __cplusplus
143 }
144 #endif /*__cplusplus*/
145
146
147
148 /* Run the PhotoFlow image editing code
149 */
150 static int
vips_layer_gen(VipsRegion * oreg,void * seq,void * a,void * b,gboolean * stop)151 vips_layer_gen( VipsRegion *oreg, void *seq, void *a, void *b, gboolean *stop )
152 {
153 VipsRegion **ir = (VipsRegion **) seq;
154 VipsLayer *layer = (VipsLayer *) b;
155
156 /* Do the actual processing
157 */
158
159 /* Output area we are building.
160 */
161 const VipsRect *r = &oreg->valid;
162 VipsRect s;
163 int i;
164 int x, y;
165 int ninput = layer->ninput;
166 bool verbose = false;
167 //if( layer->processor->get_par() &&
168 // layer->processor->get_par()->get_type() == "impulse_nr_RT" )
169 // verbose = true;
170 /**/
171 //#ifndef NDEBUG
172 if( verbose ) {
173 std::cout<<"vips_layer_gen(): "<<std::endl;
174 if( layer->processor->get_par() )
175 std::cout<<" type: "<<layer->processor->get_par()->get_type()<<std::endl;
176 if( layer->processor->get_par()->get_config_ui() )
177 std::cout<<" name: "<<layer->processor->get_par()->get_config_ui()->get_layer()->get_name()<<std::endl;
178 std::cout<<" output region: left="<<oreg->valid.left
179 <<" top="<<oreg->valid.top
180 <<" width="<<oreg->valid.width
181 <<" height="<<oreg->valid.height<<std::endl;
182 }
183 //#endif
184 /**/
185 /* Prepare the input images
186 */
187 if(ir) {
188 for( i = 0; ir[i]; i++ ) {
189 /**/
190 /* Area of input we need.
191 */
192 layer->processor->get_par()->transform_inv(r, &s, i);
193
194 VipsRect r_img = {0, 0, ir[i]->im->Xsize, ir[i]->im->Ysize};
195 vips_rect_intersectrect (&s, &r_img, &s);
196 //#ifndef NDEBUG
197 if( verbose ) {
198 if( layer->processor->get_par()->get_config_ui() )
199 std::cout<<"["<<layer->processor->get_par()->get_config_ui()->get_layer()->get_name()<<"]"<<std::endl;
200 if( layer->processor->get_par() )
201 std::cout<<"["<<layer->processor->get_par()->get_type()<<"]: ";
202 std::cout<<r->width<<"x"<<r->height<<"+"<<r->left<<"+"<<r->top;
203 std::cout<<" -> ["<<i<<"] "<<s.width<<"x"<<s.height<<"+"<<s.left<<"+"<<s.top<<std::endl
204 <<" ir["<<i<<"]->im="<<ir[i]->im<<" size="<<ir[i]->im->Xsize<<"x"<<ir[i]->im->Ysize
205 <<std::endl;
206 }
207 //#endif
208 if( vips_region_prepare( ir[i], &s ) ) {
209 printf("vips_layer_gen: %s vips_region_prepare failed.\n", layer->processor->get_par()->get_type().c_str());
210 std::cout<<r->width<<"x"<<r->height<<"+"<<r->left<<"+"<<r->top;
211 std::cout<<" -> ["<<i<<"] "<<s.width<<"x"<<s.height<<"+"<<s.left<<"+"<<s.top;
212 std::cout<<" img: "<<(void*)(ir[i]->im)<<" "<<r_img.width<<","<<r_img.height<<std::endl;
213 return( -1 );
214 }
215 /*
216 if( verbose ) {
217 if( layer->processor->get_par()->get_config_ui() )
218 std::cout<<"["<<layer->processor->get_par()->get_config_ui()->get_layer()->get_name()<<"]"<<std::endl;
219 if( layer->processor->get_par() )
220 std::cout<<"["<<layer->processor->get_par()->get_type()<<"]: ";
221 std::cout<<" region ir["<<i<<"]->valid: "
222 <<" top="<<ir[i]->valid.top
223 <<" left="<<ir[i]->valid.left
224 <<" width="<<ir[i]->valid.width
225 <<" height="<<ir[i]->valid.height<<std::endl;
226 }
227 */
228 }
229 }
230
231 /* Do the actual processing
232 */
233 /*
234 int line_size = r->width * layer->in_all[0]->Bands;
235 for( y = 0; y < r->height; y++ ) {
236 unsigned char *p = (unsigned char *)
237 VIPS_REGION_ADDR( ir[0], r->left, r->top + y );
238 unsigned char *q = (unsigned char *)
239 VIPS_REGION_ADDR( oreg, r->left, r->top + y );
240
241 for( x = 0; x < line_size; x++ ) {
242 q[x] = 255 - p[x];
243 //std::cout<<"x="<<x<<" p["<<x<<"]="<<(uint32_t)p[x]<<" pout["<<x<<"]="<<(uint32_t)q[x]<<std::endl;
244 }
245
246 }
247 */
248 /**/
249 //#ifndef NDEBUG
250 if(verbose)
251 std::cout<<"vips_layer_gen(): "<<std::endl
252 <<" bands = "<<oreg->im->Bands<<std::endl
253 <<" fmt = "<<oreg->im->BandFmt<<std::endl
254 <<" colorspace = "<<oreg->im->Type<<std::endl
255 <<" imap = "<<layer->imap<<" omap = "<<layer->omap<<std::endl;
256 //#endif
257 /**/
258
259 // Get pointers to imap and omap regions
260 VipsRegion* rimap = NULL;
261 VipsRegion* romap = NULL;
262 if(ir) {
263 for( i = 0; ir[i]; i++ ) {
264 //std::cout<<" array["<<i<<"]="<<array[i]<<" imap="<<layer->imap<<std::endl;
265 if(ir[i]->im == layer->imap) { rimap = ir[i]; }
266 if(ir[i]->im == layer->omap) { romap = ir[i]; }
267 //std::cout<<" rimap="<<rimap<<std::endl;
268 }
269 }
270
271 //pf_process(pflayer->processor,r,&s,pflayer);
272 //#ifndef NDEBUG
273 if(verbose)
274 std::cout<<"Calling processor function..."<<std::endl;
275 //#endif
276 layer->processor->process(ir, ninput, layer->in_first, rimap, romap, oreg);
277 //#ifndef NDEBUG
278 if(verbose)
279 std::cout<<"...done"<<std::endl;
280 //#endif
281 return( 0 );
282 }
283
284
285 static int
vips_layer_build(VipsObject * object)286 vips_layer_build( VipsObject *object )
287 {
288 VipsObjectClass *klass = VIPS_OBJECT_GET_CLASS( object );
289 VipsOperation *operation = VIPS_OPERATION( object );
290 VipsLayer *layer = (VipsLayer *) object;
291 int i;
292
293 if( VIPS_OBJECT_CLASS( vips_layer_parent_class )->build( object ) )
294 return( -1 );
295
296 //layer->rand = 0;/*random();*/
297
298 // Count total number of input images
299 int nimg = layer->ninput;
300 if(layer->imap) {
301 nimg++;
302 }
303 if(layer->omap) {
304 nimg++;
305 }
306
307 layer->in_all = (VipsImage**)vips_malloc( ((VipsObject *)(layer->out)), sizeof(VipsImage*)*(nimg+1) );
308 if( !layer->in_all ) return( -1 );
309
310 //std::cout<<"vips_layer_build: type="<<layer->processor->get_par()->get_type()<<std::endl;
311 for( i = 0; i < layer->ninput; i++ ) {
312 layer->in_all[i] = layer->in[i];
313 //std::cout<<" in["<<i<<"]="<<layer->in[i];
314 //if( layer->in[i] ) std::cout<<" size="<<layer->in[i]->Xsize<<"x"<<layer->in[i]->Ysize;
315 //std::cout<<std::endl;
316 }
317 if( layer->imap ) { layer->in_all[i] = layer->imap; i+= 1; }
318 if( layer->omap ) { layer->in_all[i] = layer->omap; i+= 1; }
319 layer->in_all[nimg] = NULL;
320
321 //if( layer->processor->identity() == 1 )
322 // return( vips_image_write( layer->in, conversion->out ) );
323
324 for( i = 0; i < nimg; i++ ) {
325 if( vips_image_pio_input( layer->in_all[i] ) ||
326 vips_check_coding_known( klass->nickname, layer->in_all[i] ) )
327 return( -1 );
328 }
329
330 /* Get ready to write to @out. @out must be set via g_object_set() so
331 * that vips can see the assignment. It'll complain that @out hasn't
332 * been set otherwise.
333 */
334 g_object_set( layer, "out", vips_image_new(), NULL );
335
336 /* Set demand hints.
337 */
338 if( vips_image_pipeline_array( layer->out,
339 layer->demand_hint,
340 layer->in_all ) )
341 return( -1 );
342
343 PF::OpParBase* par = layer->processor->get_par();
344
345 #ifndef NDEBUG
346 std::cout<<"vips_layer_build(): layer->ninput="<<layer->ninput<<std::endl;
347 #endif
348
349 #ifndef NDEBUG
350 std::cout<<"vips_layer_build(): output format = "<<par->get_format()<<std::endl;
351 std::cout<<"vips_layer_build(): output interpretation = "<<par->get_interpretation()<<std::endl;
352 std::cout<<"vips_layer_build(): output colorspace = "<<PF::convert_colorspace( par->get_interpretation() )<<std::endl;
353 std::cout<<"vips_layer_build(): number of channels = "<<par->get_nbands()<<std::endl;
354 #endif
355 vips_image_init_fields( layer->out,
356 par->get_xsize(), par->get_ysize(),
357 par->get_nbands(), par->get_format(),
358 par->get_coding(),
359 par->get_interpretation(),
360 1.0, 1.0);
361 if(nimg > 0) {
362 if( vips_image_generate( layer->out,
363 vips_start_many, vips_layer_gen, vips_stop_many,
364 layer->in_all, layer ) )
365 return( -1 );
366 } else {
367 if( vips_image_generate( layer->out,
368 NULL, vips_layer_gen, NULL, NULL, layer ) )
369 return( -1 );
370 }
371
372 return( 0 );
373 }
374
375
376 static void
vips_layer_dispose(GObject * gobject)377 vips_layer_dispose( GObject *gobject )
378 {
379 VipsLayer *layer = (VipsLayer*)gobject;
380 if( layer->in_all ) free(layer->in_all);
381 G_OBJECT_CLASS( vips_layer_parent_class )->dispose( gobject );
382 }
383
384
385
386 static void
vips_layer_class_init(VipsLayerClass * klass)387 vips_layer_class_init( VipsLayerClass *klass )
388 {
389 GObjectClass *gobject_class = G_OBJECT_CLASS( klass );
390 VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( klass );
391 VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( klass );
392
393 gobject_class->set_property = vips_object_set_property;
394 gobject_class->get_property = vips_object_get_property;
395 gobject_class->dispose = vips_layer_dispose;
396
397
398 vobject_class->nickname = "layer";
399 vobject_class->description = _( "Photoflow layer" );
400 vobject_class->build = vips_layer_build;
401
402 operation_class->flags = VIPS_OPERATION_SEQUENTIAL_UNBUFFERED/*+VIPS_OPERATION_NOCACHE*/;
403
404 int argid = 0;
405
406 VIPS_ARG_INT( klass, "ninput", argid,
407 _( "NInput" ),
408 _( "Number of input images" ),
409 VIPS_ARGUMENT_REQUIRED_INPUT,
410 G_STRUCT_OFFSET( VipsLayer, ninput ),
411 0, PF_MAX_INPUT_IMAGES, 0);
412 argid += 1;
413
414 VIPS_ARG_IMAGE( klass, "out", argid,
415 _( "Output" ),
416 _( "Output image" ),
417 VIPS_ARGUMENT_REQUIRED_OUTPUT,
418 G_STRUCT_OFFSET( VipsLayer, out ) );
419 argid += 1;
420
421 VIPS_ARG_POINTER( klass, "processor", argid,
422 _( "Processor" ),
423 _( "Image processing object" ),
424 VIPS_ARGUMENT_REQUIRED_INPUT,
425 G_STRUCT_OFFSET( VipsLayer, processor ) );
426 argid += 1;
427
428 VIPS_ARG_IMAGE( klass, "intensity_map", argid,
429 _( "IntensityMap" ),
430 _( "Intensity map" ),
431 VIPS_ARGUMENT_REQUIRED_INPUT,
432 G_STRUCT_OFFSET( VipsLayer, imap ) );
433 argid += 1;
434
435 VIPS_ARG_IMAGE( klass, "opacity_map", argid,
436 _( "OpacityMap" ),
437 _( "Opacity map" ),
438 VIPS_ARGUMENT_REQUIRED_INPUT,
439 G_STRUCT_OFFSET( VipsLayer, omap ) );
440 argid += 1;
441
442 VIPS_ARG_ENUM( klass, "demand_hint", argid,
443 _( "DemandHint" ),
444 _( "Preferred demand style" ),
445 VIPS_ARGUMENT_REQUIRED_INPUT,
446 G_STRUCT_OFFSET( VipsLayer, demand_hint ),
447 VIPS_TYPE_DEMAND_STYLE, VIPS_DEMAND_STYLE_THINSTRIP );
448 argid += 1;
449
450 VIPS_ARG_INT( klass, "width", argid,
451 _( "Width" ),
452 _( "Image width" ),
453 VIPS_ARGUMENT_REQUIRED_INPUT,
454 G_STRUCT_OFFSET( VipsLayer, width ),
455 0, 10000000, 0);
456 argid += 1;
457
458 VIPS_ARG_INT( klass, "height", argid,
459 _( "Height" ),
460 _( "Image height" ),
461 VIPS_ARGUMENT_REQUIRED_INPUT,
462 G_STRUCT_OFFSET( VipsLayer, height ),
463 0, 10000000, 0);
464 argid += 1;
465
466 VIPS_ARG_INT( klass, "nbands", argid,
467 _( "NBands" ),
468 _( "Number of channels" ),
469 VIPS_ARGUMENT_REQUIRED_INPUT,
470 G_STRUCT_OFFSET( VipsLayer, nbands ),
471 1, 1000, 3);
472 argid += 1;
473
474 VIPS_ARG_INT( klass, "serial", argid,
475 _( "SerialID" ),
476 _( "Serial ID" ),
477 VIPS_ARGUMENT_REQUIRED_INPUT,
478 G_STRUCT_OFFSET( VipsLayer, serial_id ),
479 0, 0xFFFFFFF, 0);
480 argid += 1;
481
482 char tstr[100];
483 char tstr2[100];
484 char tstr3[100];
485 for( int imgid = 0; imgid < PF_MAX_INPUT_IMAGES; imgid++ ) {
486 snprintf(tstr,99,"in%d",imgid);
487 snprintf(tstr2,99,"Input%d",imgid);
488 snprintf(tstr3,99,"Input image %d",imgid);
489 VIPS_ARG_IMAGE( klass, tstr, argid,
490 _( tstr2 ),
491 _( tstr3 ),
492 VIPS_ARGUMENT_OPTIONAL_INPUT,
493 G_STRUCT_OFFSET( VipsLayer, in )+sizeof(VipsImage*)*imgid );
494 argid += 1;
495 }
496 }
497
498 /**
499 * vips_layer:
500 * @in: input image
501 * @out: output image
502 * @...: %NULL-terminated list of optional named arguments
503 *
504 * Returns: 0 on success, -1 on error.
505 */
506 static void
vips_layer_init(VipsLayer * layer)507 vips_layer_init( VipsLayer *layer )
508 {
509 for(int i = 0; i < PF_MAX_INPUT_IMAGES; i++)
510 layer->in[i] = NULL;
511 layer->in_all = NULL;
512 }
513
514 int
vips_layer(int n,VipsImage ** out,PF::ProcessorBase * proc,VipsImage * imap,VipsImage * omap,VipsDemandStyle demand_hint,int width,int height,int nbands,int sid,...)515 vips_layer( int n, VipsImage **out, PF::ProcessorBase* proc,
516 VipsImage* imap, VipsImage* omap, VipsDemandStyle demand_hint,
517 int width, int height, int nbands, int sid, ...)
518 {
519 va_list ap;
520 int result;
521
522 va_start( ap, sid );
523 result = vips_call_split( "layer", ap, n, out, proc, imap, omap, demand_hint, width, height, nbands, sid );
524 va_end( ap );
525
526 return( result );
527 }
528
529 /*
530 VipsImage* in = image;
531 VipsImage* out;
532 VipsImage* imap;
533 VipsArea *area;
534 VipsImage **array;
535 const int N = 0;
536
537 if (vips_call("layer", NULL, &imap, 0, gradient, NULL, NULL, NULL))
538 verror ();
539 //g_object_unref( imap );
540
541 area = vips_area_new_array_object( 1 );
542 array = (VipsImage **) area->data;
543 array[0] = in;
544 g_object_ref( array[0] );
545 if (vips_call("layer", area, &out, 0, bc, imap, NULL, NULL))
546 verror ();
547 vips_area_unref( area );
548 g_object_unref( out );
549 in = out;
550
551 for(int i = 0; i < N; i++) {
552 area = vips_area_new_array_object( 1 );
553 array = (VipsImage **) area->data;
554 array[0] = in;
555 g_object_ref( array[0] );
556 if (vips_call("layer", area, &out, 0, invert, NULL, NULL, NULL))
557 verror ();
558 vips_area_unref( area );
559 */
560