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