1 #include <string.h>
2 #include <vips/vips.h>
3 #include <gtkmm/main.h>
4 
5 #include "../base/image.hh"
6 
7 #include "../operations/image_reader.hh"
8 #include "../operations/invert.hh"
9 //#include "../operations/brightness_contrast.hh"
10 //#include "../operations/gradient.hh"
11 
12 //#include "../gui/operations/brightness_contrast_config.hh"
13 
14 /* Create a tiny VipsOperator ... photographic negative of a uchar image.
15  */
16 
17 typedef struct _Negative {
18 	VipsOperation parent_instance;
19 
20 	VipsImage *in;
21 	VipsImage *out;
22 
23 	int image_max;
24 
25 } Negative;
26 
27 typedef struct _NegativeClass {
28 	VipsOperationClass parent_class;
29 
30 	/* No new class members needed for this op.
31 	 */
32 
33 } NegativeClass;
34 
35 /* This defines a function called negative_get_type() which adds the new
36  * operation to the class hierarchy, and negative_parent_class, our
37  * superclass.
38  *
39  * You must define negative_class_init() to init a new class struct and
40  * negative_init() to init a new instance struct.
41  */
42 
43 G_DEFINE_TYPE( Negative, negative, VIPS_TYPE_OPERATION );
44 
45 static int
negative_generate(VipsRegion * oreg,void * vseq,void * a,void * b,gboolean * stop)46 negative_generate( VipsRegion *oreg,
47 	void *vseq, void *a, void *b, gboolean *stop )
48 {
49 	/* The area of the output region we have neen asked to make.
50 	 */
51 	VipsRect *r = &oreg->valid;
52 
53 	/* The sequence value ... the thing returned by start_one.
54 	 */
55 	VipsRegion *ir = (VipsRegion *) vseq;
56 
57 	Negative *negative = (Negative *) b;
58 	int line_size = r->width * negative->in->Bands;
59 
60 	int x, y;
61 	int max = negative->image_max;
62 
63 	/* Request matching part of input region.
64 	 */
65 	if( vips_region_prepare( ir, r ) )
66 		return( -1 );
67 
68 	for( y = 0; y < r->height; y++ ) {
69 		unsigned char *p = (unsigned char *)
70 			VIPS_REGION_ADDR( ir, r->left, r->top + y );
71 		unsigned char *q = (unsigned char *)
72 			VIPS_REGION_ADDR( oreg, r->left, r->top + y );
73 
74 		for( x = 0; x < line_size; x++ )
75 			q[x] = max - p[x];
76 	}
77 
78 	return( 0 );
79 }
80 
81 static int
negative_build(VipsObject * object)82 negative_build( VipsObject *object )
83 {
84 	VipsObjectClass *klass = VIPS_OBJECT_GET_CLASS( object );
85 	Negative *negative = (Negative *) object;
86 
87 	/* Build all the superclasses. This will set @in and
88 	 * @image_max.
89 	 */
90 	if( VIPS_OBJECT_CLASS( negative_parent_class )->build( object ) )
91 		return( -1 );
92 
93 	/* We only work for uchar images.
94 	 */
95 	if( vips_check_uncoded( klass->nickname, negative->in ) ||
96 		vips_check_format( klass->nickname,
97 			negative->in, VIPS_FORMAT_UCHAR ) )
98 		return( -1 );
99 
100 	/* Get ready to write to @out. @out must be set via g_object_set() so
101 	 * that vips can see the assignment. It'll complain that @out hasn't
102 	 * been set otherwise.
103 	 */
104 	g_object_set( object, "out", vips_image_new(), NULL );
105 
106 	/* Tell vips that @out depends on @in and prefers to work in
107 	 * scanlines.
108 	 */
109 	if( vips_image_pipelinev( negative->out,
110 		VIPS_DEMAND_STYLE_THINSTRIP, negative->in, NULL ) )
111 		return( -1 );
112 
113 	/* This attaches callbacks to @out to calculate pixels on request.
114 	 * start_one and stop_one are a pair of start and stop functions which
115 	 * create a single input region on extra argument 1, handy for 1-ary
116 	 * operations.
117 	 */
118 	if( vips_image_generate( negative->out,
119 		vips_start_one,
120 		negative_generate,
121 		vips_stop_one,
122 		negative->in, negative ) )
123 		return( -1 );
124 
125 	return( 0 );
126 }
127 
128 static void
negative_class_init(NegativeClass * klass)129 negative_class_init( NegativeClass *klass )
130 {
131 	GObjectClass *gobject_class = G_OBJECT_CLASS( klass );
132 	VipsObjectClass *object_class = (VipsObjectClass *) klass;
133 
134 	gobject_class->set_property = vips_object_set_property;
135 	gobject_class->get_property = vips_object_get_property;
136 
137 	object_class->nickname = "negative";
138 	object_class->description = "photographic negative";
139 	object_class->build = negative_build;
140 
141 	VIPS_ARG_IMAGE( klass, "in", 1,
142 		"Input",
143 		"Input image",
144 		VIPS_ARGUMENT_REQUIRED_INPUT,
145 		G_STRUCT_OFFSET( Negative, in ) );
146 
147 	VIPS_ARG_IMAGE( klass, "out", 2,
148 		"Output",
149 		"Output image",
150 		VIPS_ARGUMENT_REQUIRED_OUTPUT,
151 		G_STRUCT_OFFSET( Negative, out ) );
152 
153 	VIPS_ARG_INT( klass, "image_max", 4,
154 		"Image maximum",
155 		"Maximum value in image: pivot about this",
156 		VIPS_ARGUMENT_OPTIONAL_INPUT,
157 		G_STRUCT_OFFSET( Negative, image_max ),
158 		0, 255, 255 );
159 
160 }
161 
162 static void
negative_init(Negative * negative)163 negative_init( Negative *negative )
164 {
165 	negative->image_max = 255;
166 }
167 
168 /* A type-safe way to call nagative from C.
169  *
170  * You can also use
171  *
172  * 	vips_call( "negative", in, &out, "image_max", 128, NULL )
173  *
174  * but that won't have any compile-time checks, of course.
175  */
176 static int
negative(VipsImage * in,VipsImage ** out,...)177 negative( VipsImage *in, VipsImage **out, ... )
178 {
179 	va_list ap;
180 	int result;
181 
182 	va_start( ap, out );
183 	result = vips_call_split( "negative", ap, in, out );
184 	va_end( ap );
185 
186 	return( result );
187 }
188 
189 /* We need C linkage for this.
190  */
191 #ifdef __cplusplus
192 extern "C" {
193 #endif /*__cplusplus*/
194 
195   extern GType vips_layer_get_type( void );
196 
197 #ifdef __cplusplus
198 }
199 #endif /*__cplusplus*/
200 
201 int
main(int argc,char ** argv)202 main( int argc, char **argv )
203 {
204   //Gtk::Main kit(argc, argv);
205 
206   VipsImage *in;
207   VipsImage *out;
208   VipsImage *temp;
209 
210 
211   if( vips_init( argv[0] ) )
212     vips_error_exit( "unable to init" );
213 
214   im_concurrency_set( 1 );
215 
216   /* Add negative to the class hierarchy. You'll now be able to use it
217    * exactly like any built-in vips operation and it'll appear in
218    * Python, nip2, C, C++ etc etc.
219    */
220   negative_get_type();
221   vips_layer_get_type();
222 
223   if( argc != 4 )
224     vips_error_exit( "usage: %s vips/pf infile outfile", argv[0] );
225 
226   bool check_vips = true;
227   if(!strcmp(argv[1],"pf")) check_vips = false;
228 
229   if( check_vips ) {
230     if( !(in = vips_image_new_from_file( argv[2], NULL )) )
231       vips_error_exit( "unable to open" );
232 
233     std::cout<<"in refcount after new_from_file:  "<<G_OBJECT(in)->ref_count<<std::endl;
234 
235     temp = in;
236 
237     for(int i = 0; i < 1000; i++) {
238 
239       std::cout<<std::endl;
240       std::cout<<"refcount before negative("<<i<<"): in("<<temp<<")="<<G_OBJECT(temp)->ref_count<<std::endl;
241       if( negative( temp, &out, "image_max", 128, NULL ) ) {
242 	g_object_unref( temp );
243 	vips_error_exit( "unable to invert" );
244       }
245       std::cout<<"refcount after negative("<<i<<"):  in("<<temp<<")="<<G_OBJECT(temp)->ref_count
246 	       <<"  out("<<out<<")="<<G_OBJECT(out)->ref_count<<std::endl;
247 
248       /* We have a ref to out, out holds a ref to the negative operation,
249        * and the operation holds a ref to in. We can safely unref in and
250        * it'll be unreffed when we unref out.
251        */
252       g_object_unref( temp );
253       std::cout<<std::endl;
254       std::cout<<"refcount after unref(in):  in("<<temp<<")="<<G_OBJECT(temp)->ref_count
255 	       <<"  out("<<out<<")="<<G_OBJECT(out)->ref_count<<std::endl;
256       std::cout<<"-----------------------------------"<<std::endl;
257       temp = out;
258 
259     }
260 
261     printf("Writing output image...\n");
262 
263     std::cout<<"refcount before write_to_file:  in("<<in<<")="<<G_OBJECT(in)->ref_count
264 	       <<"  out("<<out<<")="<<G_OBJECT(out)->ref_count<<std::endl;
265     if( vips_image_write_to_file( out, argv[3], NULL ) ) {
266       g_object_unref( out );
267       vips_error_exit( "unable to write" );
268     }
269 
270     printf("...done\n");
271 
272     std::cout<<"refcount after write_to_file:  in("<<in<<")="<<G_OBJECT(in)->ref_count
273 	       <<"  out("<<out<<")="<<G_OBJECT(out)->ref_count<<std::endl;
274     g_object_unref( out );
275     std::cout<<"refcount after unref(out):  in("<<in<<")="<<G_OBJECT(in)->ref_count
276 	       <<"  out("<<out<<")="<<G_OBJECT(out)->ref_count<<std::endl;
277   } else {
278 
279     std::vector<VipsImage*> in;
280 
281     PF::Processor<PF::ImageReaderPar,PF::ImageReader>* imgread =
282       new PF::Processor<PF::ImageReaderPar,PF::ImageReader>();
283     imgread->get_par()->set_file_name( argv[2] );
284 
285     PF::Image* pf_image = new PF::Image();
286     PF::LayerManager& layer_manager = pf_image->get_layer_manager();
287 
288     PF::Layer* limg = layer_manager.new_layer();
289     limg->set_processor( imgread );
290     limg->set_name( "input image" );
291     layer_manager.get_layers().push_back( limg );
292 
293     for(int i = 0; i < 4; i++) {
294       PF::Layer* linv1 = layer_manager.new_layer();
295       linv1->set_processor( new PF::Processor<PF::InvertPar,PF::Invert>() );
296       linv1->set_name( "invert" );
297       layer_manager.get_layers().push_back( linv1 );
298     }
299 
300     pf_image->add_pipeline( VIPS_FORMAT_UCHAR, 0 );
301     pf_image->do_update(NULL);
302 
303     PF::Pipeline* pipeline = pf_image->get_pipeline( 0 );
304 
305     VipsImage* image = pipeline->get_output();
306 
307     printf("Writing output image...\n");
308 
309     if( vips_image_write_to_file( pipeline->get_output(), argv[3], NULL ) ) {
310       //g_object_unref( out );
311       vips_error_exit( "unable to write" );
312     }
313 
314     printf("...done\n");
315 
316     delete pf_image;
317 
318   }
319 
320   return( 0 );
321 }
322