1 /* Object part of VImage class
2  *
3  * 30/12/14
4  * 	- allow set enum value from string
5  * 10/6/16
6  * 	- missing implementation of VImage::write()
7  * 11/6/16
8  * 	- added arithmetic assignment overloads, += etc.
9  */
10 
11 /*
12 
13     Copyright (C) 1991-2001 The National Gallery
14 
15     This program is free software; you can redistribute it and/or modify
16     it under the terms of the GNU Lesser General Public License as published by
17     the Free Software Foundation; either version 2 of the License, or
18     (at your option) any later version.
19 
20     This program is distributed in the hope that it will be useful,
21     but WITHOUT ANY WARRANTY; without even the implied warranty of
22     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23     GNU Lesser General Public License for more details.
24 
25     You should have received a copy of the GNU Lesser General Public License
26     along with this program; if not, write to the Free Software
27     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
28     02110-1301  USA
29 
30  */
31 
32 /*
33 
34     These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
35 
36  */
37 
38 #ifdef HAVE_CONFIG_H
39 #include <config.h>
40 #endif /*HAVE_CONFIG_H*/
41 #include <vips/intl.h>
42 
43 #include <vips/vips8>
44 
45 #include <vips/debug.h>
46 
47 /*
48 #define VIPS_DEBUG
49 #define VIPS_DEBUG_VERBOSE
50  */
51 
52 VIPS_NAMESPACE_START
53 
54 /**
55  * \namespace vips
56  *
57  * General docs for the vips namespace.
58  */
59 
60 std::vector<double>
to_vectorv(int n,...)61 to_vectorv( int n, ... )
62 {
63 	std::vector<double> vector( n );
64 	va_list ap;
65 
66 	va_start( ap, n );
67 	for( int i = 0; i < n; i++ )
68 		vector[i] = va_arg( ap, double );
69 	va_end( ap );
70 
71 	return( vector );
72 }
73 
74 std::vector<double>
to_vector(double value)75 to_vector( double value )
76 {
77 	return( to_vectorv( 1, value ) );
78 }
79 
80 std::vector<double>
to_vector(int n,double array[])81 to_vector( int n, double array[] )
82 {
83 	std::vector<double> vector( n );
84 
85 	for( int i = 0; i < n; i++ )
86 		vector[i] = array[i];
87 
88 	return( vector );
89 }
90 
91 std::vector<double>
negate(std::vector<double> vector)92 negate( std::vector<double> vector )
93 {
94 	std::vector<double> new_vector( vector.size() );
95 
96 	for( std::vector<double>::size_type i = 0; i < vector.size(); i++ )
97 		new_vector[i] = vector[i] * -1;
98 
99 	return( new_vector );
100 }
101 
102 std::vector<double>
invert(std::vector<double> vector)103 invert( std::vector<double> vector )
104 {
105 	std::vector<double> new_vector( vector.size() );
106 
107 	for( std::vector<double>::size_type i = 0; i < vector.size(); i++ )
108 		new_vector[i] = 1.0 / vector[i];
109 
110 	return( new_vector );
111 }
112 
~VOption()113 VOption::~VOption()
114 {
115 	std::list<Pair *>::iterator i;
116 
117 	for( i = options.begin(); i != options.end(); ++i )
118 		delete *i;
119 }
120 
121 // input bool
122 VOption *
set(const char * name,bool value)123 VOption::set( const char *name, bool value )
124 {
125 	Pair *pair = new Pair( name );
126 
127 	pair->input = true;
128 	g_value_init( &pair->value, G_TYPE_BOOLEAN );
129 	g_value_set_boolean( &pair->value, value );
130 	options.push_back( pair );
131 
132 	return( this );
133 }
134 
135 // input int ... this path is used for enums as well
136 VOption *
set(const char * name,int value)137 VOption::set( const char *name, int value )
138 {
139 	Pair *pair = new Pair( name );
140 
141 	pair->input = true;
142 	g_value_init( &pair->value, G_TYPE_INT );
143 	g_value_set_int( &pair->value, value );
144 	options.push_back( pair );
145 
146 	return( this );
147 }
148 
149 // input guint64
150 VOption *
set(const char * name,guint64 value)151 VOption::set( const char *name, guint64 value )
152 {
153 	Pair *pair = new Pair( name );
154 
155 	pair->input = true;
156 	g_value_init( &pair->value, G_TYPE_UINT64 );
157 	g_value_set_uint64( &pair->value, value );
158 	options.push_back( pair );
159 
160 	return( this );
161 }
162 
163 // input double
164 VOption *
set(const char * name,double value)165 VOption::set( const char *name, double value )
166 {
167 	Pair *pair = new Pair( name );
168 
169 	pair->input = true;
170 	g_value_init( &pair->value, G_TYPE_DOUBLE );
171 	g_value_set_double( &pair->value, value );
172 	options.push_back( pair );
173 
174 	return( this );
175 }
176 
177 VOption *
set(const char * name,const char * value)178 VOption::set( const char *name, const char *value )
179 {
180 	Pair *pair = new Pair( name );
181 
182 	pair->input = true;
183 	g_value_init( &pair->value, G_TYPE_STRING );
184 	g_value_set_string( &pair->value, value );
185 	options.push_back( pair );
186 
187 	return( this );
188 }
189 
190 // input vips object (image, source, target, etc. etc.)
191 VOption *
set(const char * name,const VObject value)192 VOption::set( const char *name, const VObject value )
193 {
194 	Pair *pair = new Pair( name );
195 	VipsObject *object = value.get_object();
196 	GType type = G_OBJECT_TYPE( object );
197 
198 	pair->input = true;
199 	g_value_init( &pair->value, type );
200 	g_value_set_object( &pair->value, object );
201 	options.push_back( pair );
202 
203 	return( this );
204 }
205 
206 // input int array
207 VOption *
set(const char * name,std::vector<int> value)208 VOption::set( const char *name, std::vector<int> value )
209 {
210 	Pair *pair = new Pair( name );
211 
212 	int *array;
213 
214 	pair->input = true;
215 
216 	g_value_init( &pair->value, VIPS_TYPE_ARRAY_INT );
217 	vips_value_set_array_int( &pair->value, NULL,
218 		static_cast< int >( value.size() ) );
219 	array = vips_value_get_array_int( &pair->value, NULL );
220 
221 	for( std::vector<double>::size_type i = 0; i < value.size(); i++ )
222 		array[i] = value[i];
223 
224 	options.push_back( pair );
225 
226 	return( this );
227 }
228 
229 // input double array
230 VOption *
set(const char * name,std::vector<double> value)231 VOption::set( const char *name, std::vector<double> value )
232 {
233 	Pair *pair = new Pair( name );
234 
235 	double *array;
236 
237 	pair->input = true;
238 
239 	g_value_init( &pair->value, VIPS_TYPE_ARRAY_DOUBLE );
240 	vips_value_set_array_double( &pair->value, NULL,
241 		static_cast< int >( value.size() ) );
242 	array = vips_value_get_array_double( &pair->value, NULL );
243 
244 	for( std::vector<double>::size_type i = 0; i < value.size(); i++ )
245 		array[i] = value[i];
246 
247 	options.push_back( pair );
248 
249 	return( this );
250 }
251 
252 // input image array
253 VOption *
set(const char * name,std::vector<VImage> value)254 VOption::set( const char *name, std::vector<VImage> value )
255 {
256 	Pair *pair = new Pair( name );
257 
258 	VipsImage **array;
259 
260 	pair->input = true;
261 
262 	g_value_init( &pair->value, VIPS_TYPE_ARRAY_IMAGE );
263 	vips_value_set_array_image( &pair->value,
264 		static_cast< int >( value.size() ) );
265 	array = vips_value_get_array_image( &pair->value, NULL );
266 
267 	for( std::vector<double>::size_type i = 0; i < value.size(); i++ ) {
268 		VipsImage *vips_image = value[i].get_image();
269 
270 		array[i] = vips_image;
271 		g_object_ref( vips_image );
272 	}
273 
274 	options.push_back( pair );
275 
276 	return( this );
277 }
278 
279 // input blob
280 VOption *
set(const char * name,VipsBlob * value)281 VOption::set( const char *name, VipsBlob *value )
282 {
283 	Pair *pair = new Pair( name );
284 
285 	pair->input = true;
286 	g_value_init( &pair->value, VIPS_TYPE_BLOB );
287 	g_value_set_boxed( &pair->value, value );
288 	options.push_back( pair );
289 
290 	return( this );
291 }
292 
293 // output bool
294 VOption *
set(const char * name,bool * value)295 VOption::set( const char *name, bool *value )
296 {
297 	Pair *pair = new Pair( name );
298 
299 	pair->input = false;
300 	pair->vbool = value;
301 	g_value_init( &pair->value, G_TYPE_BOOLEAN );
302 
303 	options.push_back( pair );
304 
305 	return( this );
306 }
307 
308 // output int
309 VOption *
set(const char * name,int * value)310 VOption::set( const char *name, int *value )
311 {
312 	Pair *pair = new Pair( name );
313 
314 	pair->input = false;
315 	pair->vint = value;
316 	g_value_init( &pair->value, G_TYPE_INT );
317 
318 	options.push_back( pair );
319 
320 	return( this );
321 }
322 
323 // output double
324 VOption *
set(const char * name,double * value)325 VOption::set( const char *name, double *value )
326 {
327 	Pair *pair = new Pair( name );
328 
329 	pair->input = false;
330 	pair->vdouble = value;
331 	g_value_init( &pair->value, G_TYPE_DOUBLE );
332 
333 	options.push_back( pair );
334 
335 	return( this );
336 }
337 
338 // output image
339 VOption *
set(const char * name,VImage * value)340 VOption::set( const char *name, VImage *value )
341 {
342 	Pair *pair = new Pair( name );
343 
344 	pair->input = false;
345 	pair->vimage = value;
346 	g_value_init( &pair->value, VIPS_TYPE_IMAGE );
347 
348 	options.push_back( pair );
349 
350 	return( this );
351 }
352 
353 // output doublearray
354 VOption *
set(const char * name,std::vector<double> * value)355 VOption::set( const char *name, std::vector<double> *value )
356 {
357 	Pair *pair = new Pair( name );
358 
359 	pair->input = false;
360 	pair->vvector = value;
361 	g_value_init( &pair->value, VIPS_TYPE_ARRAY_DOUBLE );
362 
363 	options.push_back( pair );
364 
365 	return( this );
366 }
367 
368 // output blob
369 VOption *
set(const char * name,VipsBlob ** value)370 VOption::set( const char *name, VipsBlob **value )
371 {
372 	Pair *pair = new Pair( name );
373 
374 	pair->input = false;
375 	pair->vblob = value;
376 	g_value_init( &pair->value, VIPS_TYPE_BLOB );
377 
378 	options.push_back( pair );
379 
380 	return( this );
381 }
382 
383 // just g_object_set_property(), except we allow set enum from string
384 static void
set_property(VipsObject * object,const char * name,const GValue * value)385 set_property( VipsObject *object, const char *name, const GValue *value )
386 {
387 	VipsObjectClass *object_class = VIPS_OBJECT_GET_CLASS( object );
388 	GType type = G_VALUE_TYPE( value );
389 
390 	GParamSpec *pspec;
391 	VipsArgumentClass *argument_class;
392 	VipsArgumentInstance *argument_instance;
393 
394 	if( vips_object_get_argument( object, name,
395 		&pspec, &argument_class, &argument_instance ) ) {
396 		g_warning( "%s", vips_error_buffer() );
397 		vips_error_clear();
398 		return;
399 	}
400 
401 	if( G_IS_PARAM_SPEC_ENUM( pspec ) &&
402 		type == G_TYPE_STRING ) {
403 		GType pspec_type = G_PARAM_SPEC_VALUE_TYPE( pspec );
404 
405 		int enum_value;
406 		GValue value2 = { 0 };
407 
408 		if( (enum_value = vips_enum_from_nick( object_class->nickname,
409 			pspec_type, g_value_get_string( value ) )) < 0 ) {
410 			g_warning( "%s", vips_error_buffer() );
411 			vips_error_clear();
412 			return;
413 		}
414 
415 		g_value_init( &value2, pspec_type );
416 		g_value_set_enum( &value2, enum_value );
417 		g_object_set_property( G_OBJECT( object ), name, &value2 );
418 		g_value_unset( &value2 );
419 	}
420 	else
421 		g_object_set_property( G_OBJECT( object ), name, value );
422 }
423 
424 // walk the options and set props on the operation
425 void
set_operation(VipsOperation * operation)426 VOption::set_operation( VipsOperation *operation )
427 {
428 	std::list<Pair *>::iterator i;
429 
430 	for( i = options.begin(); i != options.end(); ++i )
431 		if( (*i)->input ) {
432 #ifdef VIPS_DEBUG_VERBOSE
433 			printf( "set_operation: " );
434 			vips_object_print_name( VIPS_OBJECT( operation ) );
435 			char *str_value =
436 				g_strdup_value_contents( &(*i)->value );
437 			printf( ".%s = %s\n", (*i)->name, str_value );
438 			g_free( str_value );
439 #endif /*VIPS_DEBUG_VERBOSE*/
440 
441 			set_property( VIPS_OBJECT( operation ),
442 				(*i)->name, &(*i)->value );
443 		}
444 }
445 
446 // walk the options and fetch any requested outputs
447 void
get_operation(VipsOperation * operation)448 VOption::get_operation( VipsOperation *operation )
449 {
450 	std::list<Pair *>::iterator i;
451 
452 	for( i = options.begin(); i != options.end(); ++i )
453 		if( ! (*i)->input ) {
454 			const char *name = (*i)->name;
455 
456 			g_object_get_property( G_OBJECT( operation ),
457 				name, &(*i)->value );
458 
459 #ifdef VIPS_DEBUG_VERBOSE
460 			printf( "get_operation: " );
461 			vips_object_print_name( VIPS_OBJECT( operation ) );
462 			char *str_value = g_strdup_value_contents(
463 				&(*i)->value );
464 			printf( ".%s = %s\n", name, str_value );
465 			g_free( str_value );
466 #endif /*VIPS_DEBUG_VERBOSE*/
467 
468 			GValue *value = &(*i)->value;
469 			GType type = G_VALUE_TYPE( value );
470 
471 			if( type == VIPS_TYPE_IMAGE ) {
472 				// rebox object
473 				VipsImage *image = VIPS_IMAGE(
474 					g_value_get_object( value ) );
475 				*((*i)->vimage) = VImage( image );
476 			}
477 			else if( type == G_TYPE_INT )
478 				*((*i)->vint) = g_value_get_int( value );
479 			else if( type == G_TYPE_BOOLEAN )
480 				*((*i)->vbool) = g_value_get_boolean( value );
481 			else if( type == G_TYPE_DOUBLE )
482 				*((*i)->vdouble) = g_value_get_double( value );
483 			else if( type == VIPS_TYPE_ARRAY_DOUBLE ) {
484 				int length;
485 				double *array =
486 					vips_value_get_array_double( value,
487 					&length );
488 
489 				((*i)->vvector)->resize( length );
490 				for( int j = 0; j < length; j++ )
491 					(*((*i)->vvector))[j] = array[j];
492 			}
493 			else if( type == VIPS_TYPE_BLOB ) {
494 				// our caller gets a reference
495 				*((*i)->vblob) =
496 					(VipsBlob *) g_value_dup_boxed( value );
497 			}
498 		}
499 }
500 
501 void
call_option_string(const char * operation_name,const char * option_string,VOption * options)502 VImage::call_option_string( const char *operation_name,
503 	const char *option_string, VOption *options )
504 {
505 	VipsOperation *operation;
506 
507 	VIPS_DEBUG_MSG( "call_option_string: starting for %s ...\n",
508 		operation_name );
509 
510 	if( !(operation = vips_operation_new( operation_name )) ) {
511 		delete options;
512 		throw( VError() );
513 	}
514 
515 	/* Set str options before vargs options, so the user can't
516 	 * override things we set deliberately.
517 	 */
518 	if( option_string &&
519 		vips_object_set_from_string( VIPS_OBJECT( operation ),
520 			option_string ) ) {
521 		vips_object_unref_outputs( VIPS_OBJECT( operation ) );
522 		g_object_unref( operation );
523 		delete options;
524 		throw( VError() );
525 	}
526 
527 	if( options )
528 		options->set_operation( operation );
529 
530 	/* Build from cache.
531 	 */
532 	if( vips_cache_operation_buildp( &operation ) ) {
533 		vips_object_unref_outputs( VIPS_OBJECT( operation ) );
534 		g_object_unref( operation );
535 		delete options;
536 		throw( VError() );
537 	}
538 
539 	/* Walk args again, writing output.
540 	 */
541 	if( options )
542 		options->get_operation( operation );
543 
544 	/* We're done with options!
545 	 */
546 	delete options;
547 
548 	/* The operation we have built should now have been reffed by
549 	 * one of its arguments or have finished its work. Either
550 	 * way, we can unref.
551 	 */
552 	g_object_unref( operation );
553 }
554 
555 void
call(const char * operation_name,VOption * options)556 VImage::call( const char *operation_name, VOption *options )
557 {
558 	call_option_string( operation_name, NULL, options );
559 }
560 
561 VImage
new_from_file(const char * name,VOption * options)562 VImage::new_from_file( const char *name, VOption *options )
563 {
564 	char filename[VIPS_PATH_MAX];
565 	char option_string[VIPS_PATH_MAX];
566 	const char *operation_name;
567 
568 	VImage out;
569 
570 	vips__filename_split8( name, filename, option_string );
571 	if( !(operation_name = vips_foreign_find_load( filename )) ) {
572 		delete options;
573 		throw VError();
574 	}
575 
576 	call_option_string( operation_name, option_string,
577 		(options ? options : VImage::option())->
578 			set( "filename", filename )->
579 			set( "out", &out ) );
580 
581 	return( out );
582 }
583 
584 VImage
new_from_buffer(const void * buf,size_t len,const char * option_string,VOption * options)585 VImage::new_from_buffer( const void *buf, size_t len, const char *option_string,
586 	VOption *options )
587 {
588 	const char *operation_name;
589 	VipsBlob *blob;
590 	VImage out;
591 
592 	if( !(operation_name = vips_foreign_find_load_buffer( buf, len )) ) {
593 		delete options;
594 		throw( VError() );
595 	}
596 
597 	/* We don't take a copy of the data or free it.
598 	 */
599 	blob = vips_blob_new( NULL, buf, len );
600 	options = (options ? options : VImage::option())->
601 		set( "buffer", blob )->
602 		set( "out", &out );
603 	vips_area_unref( VIPS_AREA( blob ) );
604 
605 	call_option_string( operation_name, option_string, options );
606 
607 	return( out );
608 }
609 
610 VImage
new_from_buffer(const std::string & buf,const char * option_string,VOption * options)611 VImage::new_from_buffer( const std::string &buf, const char *option_string,
612 	VOption *options )
613 {
614 	return( new_from_buffer( buf.c_str(), buf.size(),
615 		option_string, options ) );
616 }
617 
618 VImage
new_from_source(VSource source,const char * option_string,VOption * options)619 VImage::new_from_source( VSource source, const char *option_string,
620 	VOption *options )
621 {
622 	const char *operation_name;
623 	VImage out;
624 
625 	if( !(operation_name = vips_foreign_find_load_source(
626 		source.get_source() )) ) {
627 		delete options;
628 		throw( VError() );
629 	}
630 
631 	options = (options ? options : VImage::option())->
632 		set( "source", source )->
633 		set( "out", &out );
634 
635 	call_option_string( operation_name, option_string, options );
636 
637 	return( out );
638 }
639 
640 VImage
new_from_memory_steal(void * data,size_t size,int width,int height,int bands,VipsBandFormat format)641 VImage::new_from_memory_steal( void *data, size_t size,
642 	int width, int height, int bands, VipsBandFormat format )
643 {
644 	VipsImage *image;
645 
646 	if( !(image = vips_image_new_from_memory( data, size,
647 		width, height, bands, format )) )
648 		throw( VError() );
649 
650 	g_signal_connect( image, "postclose",
651 		G_CALLBACK( vips_image_free_buffer ), data);
652 
653 	return( VImage( image ) );
654 }
655 
656 VImage
new_matrix(int width,int height)657 VImage::new_matrix( int width, int height )
658 {
659 	return( VImage( vips_image_new_matrix( width, height ) ) );
660 }
661 
662 VImage
new_matrixv(int width,int height,...)663 VImage::new_matrixv( int width, int height, ... )
664 {
665 	VImage matrix = new_matrix( width, height );
666 	VipsImage *vips_matrix = matrix.get_image();
667 
668 	va_list ap;
669 
670 	va_start( ap, height );
671 	for( int y = 0; y < height; y++ )
672 		for( int x = 0; x < width; x++ )
673 			*VIPS_MATRIX( vips_matrix, x, y ) =
674 				va_arg( ap, double );
675 	va_end( ap );
676 
677 	return( matrix );
678 }
679 
680 VImage
write(VImage out) const681 VImage::write( VImage out ) const
682 {
683 	if( vips_image_write( this->get_image(), out.get_image() ) )
684 		throw VError();
685 
686 	return( out );
687 }
688 
689 void
write_to_file(const char * name,VOption * options) const690 VImage::write_to_file( const char *name, VOption *options ) const
691 {
692 	char filename[VIPS_PATH_MAX];
693 	char option_string[VIPS_PATH_MAX];
694 	const char *operation_name;
695 
696 	vips__filename_split8( name, filename, option_string );
697 	if( !(operation_name = vips_foreign_find_save( filename )) ) {
698 		delete options;
699 		throw VError();
700 	}
701 
702 	call_option_string( operation_name, option_string,
703 		(options ? options : VImage::option())->
704 			set( "in", *this )->
705 			set( "filename", filename ) );
706 }
707 
708 void
write_to_buffer(const char * suffix,void ** buf,size_t * size,VOption * options) const709 VImage::write_to_buffer( const char *suffix, void **buf, size_t *size,
710 	VOption *options ) const
711 {
712 	char filename[VIPS_PATH_MAX];
713 	char option_string[VIPS_PATH_MAX];
714 	const char *operation_name;
715 	VipsBlob *blob;
716 
717 	/* Save with the new target API if we can. Fall back to the older
718 	 * mechanism in case the saver we need has not been converted yet.
719 	 *
720 	 * We need to hide any errors from this first phase.
721 	 */
722 	vips__filename_split8( suffix, filename, option_string );
723 
724 	vips_error_freeze();
725 	operation_name = vips_foreign_find_save_target( filename );
726 	vips_error_thaw();
727 
728 	if( operation_name ) {
729 		VTarget target = VTarget::new_to_memory();
730 
731 		call_option_string( operation_name, option_string,
732 			(options ? options : VImage::option())->
733 				set( "in", *this )->
734 				set( "target", target ) );
735 
736 		g_object_get( target.get_target(), "blob", &blob, NULL );
737 	}
738 	else if( (operation_name = vips_foreign_find_save_buffer( filename )) ) {
739 		call_option_string( operation_name, option_string,
740 			(options ? options : VImage::option())->
741 				set( "in", *this )->
742 				set( "buffer", &blob ) );
743 	}
744 	else {
745 		delete options;
746 		throw VError();
747 	}
748 
749 	if( blob ) {
750 		if( buf ) {
751 			*buf = VIPS_AREA( blob )->data;
752 			VIPS_AREA( blob )->free_fn = NULL;
753 		}
754 		if( size )
755 			*size = VIPS_AREA( blob )->length;
756 
757 		vips_area_unref( VIPS_AREA( blob ) );
758 	}
759 }
760 
761 void
write_to_target(const char * suffix,VTarget target,VOption * options) const762 VImage::write_to_target( const char *suffix, VTarget target,
763 	VOption *options ) const
764 {
765 	char filename[VIPS_PATH_MAX];
766 	char option_string[VIPS_PATH_MAX];
767 	const char *operation_name;
768 
769 	vips__filename_split8( suffix, filename, option_string );
770 	if( !(operation_name = vips_foreign_find_save_target( filename )) ) {
771 		delete options;
772 		throw VError();
773 	}
774 
775 	call_option_string( operation_name, option_string,
776 		(options ? options : VImage::option())->
777 			set( "in", *this )->
778 			set( "target", target ) );
779 }
780 
781 #include "vips-operators.cpp"
782 
783 std::vector<VImage>
bandsplit(VOption * options) const784 VImage::bandsplit( VOption *options ) const
785 {
786 	std::vector<VImage> b;
787 	b.reserve(bands());
788 
789 	for( int i = 0; i < bands(); i++ )
790 		b.push_back( extract_band( i ) );
791 
792 	return( b );
793 }
794 
795 VImage
bandjoin(VImage other,VOption * options) const796 VImage::bandjoin( VImage other, VOption *options ) const
797 {
798 	VImage v[2] = { *this, other };
799 	std::vector<VImage> vec( v, v + VIPS_NUMBER( v ) );
800 
801 	return( bandjoin( vec, options ) );
802 }
803 
804 VImage
composite(VImage other,VipsBlendMode mode,VOption * options) const805 VImage::composite( VImage other, VipsBlendMode mode, VOption *options ) const
806 {
807 	VImage v[2] = { *this, other };
808 	std::vector<VImage> ivec( v, v + VIPS_NUMBER( v ) );
809 	int m[1] = { static_cast<int>( mode ) };
810 	std::vector<int> mvec( m, m + VIPS_NUMBER( m ) );
811 
812 	return( composite( ivec, mvec, options ) );
813 }
814 
815 std::complex<double>
minpos(VOption * options) const816 VImage::minpos( VOption *options ) const
817 {
818 	double x, y;
819 
820 	(void) min(
821 		(options ? options : VImage::option()) ->
822 			set( "x", &x ) ->
823 			set( "y", &y ) );
824 
825 	return( std::complex<double>( x, y ) );
826 }
827 
828 std::complex<double>
maxpos(VOption * options) const829 VImage::maxpos( VOption *options ) const
830 {
831 	double x, y;
832 
833 	(void) max(
834 		(options ? options : VImage::option()) ->
835 			set( "x", &x ) ->
836 			set( "y", &y ) );
837 
838 	return( std::complex<double>( x, y ) );
839 }
840 
841 // Operator overloads
842 
843 VImage
operator [](int index) const844 VImage::operator[]( int index ) const
845 {
846 	return( this->extract_band( index ) );
847 }
848 
849 std::vector<double>
operator ()(int x,int y) const850 VImage::operator()( int x, int y ) const
851 {
852 	return( this->getpoint( x, y ) );
853 }
854 
855 VImage
operator +(const VImage a,const VImage b)856 operator+( const VImage a, const VImage b )
857 {
858 	return( a.add( b ) );
859 }
860 
861 VImage
operator +(double a,const VImage b)862 operator+( double a, const VImage b )
863 {
864 	return( b.linear( 1.0, a ) );
865 }
866 
867 VImage
operator +(const VImage a,double b)868 operator+( const VImage a, double b )
869 {
870 	return( a.linear( 1.0, b ) );
871 }
872 
873 VImage
operator +(const std::vector<double> a,const VImage b)874 operator+( const std::vector<double> a, const VImage b )
875 {
876 	return( b.linear( 1.0, a ) );
877 }
878 
879 VImage
operator +(const VImage a,const std::vector<double> b)880 operator+( const VImage a, const std::vector<double> b )
881 {
882 	return( a.linear( 1.0, b ) );
883 }
884 
885 VImage &
operator +=(VImage & a,const VImage b)886 operator+=( VImage &a, const VImage b )
887 {
888 	return( a = a + b );
889 }
890 
891 VImage &
operator +=(VImage & a,const double b)892 operator+=( VImage &a, const double b )
893 {
894 	return( a = a + b );
895 }
896 
897 VImage &
operator +=(VImage & a,const std::vector<double> b)898 operator+=( VImage &a, const std::vector<double> b )
899 {
900 	return( a = a + b );
901 }
902 
903 VImage
operator -(const VImage a,const VImage b)904 operator-( const VImage a, const VImage b )
905 {
906 	return( a.subtract( b ) );
907 }
908 
909 VImage
operator -(double a,const VImage b)910 operator-( double a, const VImage b )
911 {
912 	return( b.linear( -1.0, a ) );
913 }
914 
915 VImage
operator -(const VImage a,double b)916 operator-( const VImage a, double b )
917 {
918 	return( a.linear( 1.0, -b ) );
919 }
920 
921 VImage
operator -(const std::vector<double> a,const VImage b)922 operator-( const std::vector<double> a, const VImage b )
923 {
924 	return( b.linear( -1.0, a ) );
925 }
926 
927 VImage
operator -(const VImage a,const std::vector<double> b)928 operator-( const VImage a, const std::vector<double> b )
929 {
930 	return( a.linear( 1.0, vips::negate( b ) ) );
931 }
932 
933 VImage &
operator -=(VImage & a,const VImage b)934 operator-=( VImage &a, const VImage b )
935 {
936 	return( a = a - b );
937 }
938 
939 VImage &
operator -=(VImage & a,const double b)940 operator-=( VImage &a, const double b )
941 {
942 	return( a = a - b );
943 }
944 
945 VImage &
operator -=(VImage & a,const std::vector<double> b)946 operator-=( VImage &a, const std::vector<double> b )
947 {
948 	return( a = a - b );
949 }
950 
951 VImage
operator -(const VImage a)952 operator-( const VImage a )
953 {
954 	return( a * -1 );
955 }
956 
957 VImage
operator *(const VImage a,const VImage b)958 operator*( const VImage a, const VImage b )
959 {
960 	return( a.multiply( b ) );
961 }
962 
963 VImage
operator *(double a,const VImage b)964 operator*( double a, const VImage b )
965 {
966 	return( b.linear( a, 0.0 ) );
967 }
968 
969 VImage
operator *(const VImage a,double b)970 operator*( const VImage a, double b )
971 {
972 	return( a.linear( b, 0.0 ) );
973 }
974 
975 VImage
operator *(const std::vector<double> a,const VImage b)976 operator*( const std::vector<double> a, const VImage b )
977 {
978 	return( b.linear( a, 0.0 ) );
979 }
980 
981 VImage
operator *(const VImage a,const std::vector<double> b)982 operator*( const VImage a, const std::vector<double> b )
983 {
984 	return( a.linear( b, 0.0 ) );
985 }
986 
987 VImage &
operator *=(VImage & a,const VImage b)988 operator*=( VImage &a, const VImage b )
989 {
990 	return( a = a * b );
991 }
992 
993 VImage &
operator *=(VImage & a,const double b)994 operator*=( VImage &a, const double b )
995 {
996 	return( a = a * b );
997 }
998 
999 VImage &
operator *=(VImage & a,const std::vector<double> b)1000 operator*=( VImage &a, const std::vector<double> b )
1001 {
1002 	return( a = a * b );
1003 }
1004 
1005 VImage
operator /(const VImage a,const VImage b)1006 operator/( const VImage a, const VImage b )
1007 {
1008 	return( a.divide( b ) );
1009 }
1010 
1011 VImage
operator /(double a,const VImage b)1012 operator/( double a, const VImage b )
1013 {
1014 	return( b.pow( -1.0 ).linear( a, 0.0 ) );
1015 }
1016 
1017 VImage
operator /(const VImage a,double b)1018 operator/( const VImage a, double b )
1019 {
1020 	return( a.linear( 1.0 / b, 0.0 ) );
1021 }
1022 
1023 VImage
operator /(const std::vector<double> a,const VImage b)1024 operator/( const std::vector<double> a, const VImage b )
1025 {
1026 	return( b.pow( -1.0 ).linear( a, 0.0 ) );
1027 }
1028 
1029 VImage
operator /(const VImage a,const std::vector<double> b)1030 operator/( const VImage a, const std::vector<double> b )
1031 {
1032 	return( a.linear( vips::invert( b ), 0.0 ) );
1033 }
1034 
1035 VImage &
operator /=(VImage & a,const VImage b)1036 operator/=( VImage &a, const VImage b )
1037 {
1038 	return( a = a / b );
1039 }
1040 
1041 VImage &
operator /=(VImage & a,const double b)1042 operator/=( VImage &a, const double b )
1043 {
1044 	return( a = a / b );
1045 }
1046 
1047 VImage &
operator /=(VImage & a,const std::vector<double> b)1048 operator/=( VImage &a, const std::vector<double> b )
1049 {
1050 	return( a = a / b );
1051 }
1052 
1053 VImage
operator %(const VImage a,const VImage b)1054 operator%( const VImage a, const VImage b )
1055 {
1056 	return( a.remainder( b ) );
1057 }
1058 
1059 VImage
operator %(const VImage a,const double b)1060 operator%( const VImage a, const double b )
1061 {
1062 	return( a.remainder_const( to_vector( b ) ) );
1063 }
1064 
1065 VImage
operator %(const VImage a,const std::vector<double> b)1066 operator%( const VImage a, const std::vector<double> b )
1067 {
1068 	return( a.remainder_const( b ) );
1069 }
1070 
1071 VImage &
operator %=(VImage & a,const VImage b)1072 operator%=( VImage &a, const VImage b )
1073 {
1074 	return( a = a % b );
1075 }
1076 
1077 VImage &
operator %=(VImage & a,const double b)1078 operator%=( VImage &a, const double b )
1079 {
1080 	return( a = a % b );
1081 }
1082 
1083 VImage &
operator %=(VImage & a,const std::vector<double> b)1084 operator%=( VImage &a, const std::vector<double> b )
1085 {
1086 	return( a = a % b );
1087 }
1088 
1089 VImage
operator <(const VImage a,const VImage b)1090 operator<( const VImage a, const VImage b )
1091 {
1092 	return( a.relational( b, VIPS_OPERATION_RELATIONAL_LESS ) );
1093 }
1094 
1095 VImage
operator <(const double a,const VImage b)1096 operator<( const double a, const VImage b )
1097 {
1098 	return( b.relational_const( VIPS_OPERATION_RELATIONAL_MORE,
1099 		to_vector( a ) ) );
1100 }
1101 
1102 VImage
operator <(const VImage a,const double b)1103 operator<( const VImage a, const double b )
1104 {
1105 	return( a.relational_const( VIPS_OPERATION_RELATIONAL_LESS,
1106 		to_vector( b ) ) );
1107 }
1108 
1109 VImage
operator <(const std::vector<double> a,const VImage b)1110 operator<( const std::vector<double> a, const VImage b )
1111 {
1112 	return( b.relational_const( VIPS_OPERATION_RELATIONAL_MORE,
1113 		a ) );
1114 }
1115 
1116 VImage
operator <(const VImage a,const std::vector<double> b)1117 operator<( const VImage a, const std::vector<double> b )
1118 {
1119 	return( a.relational_const( VIPS_OPERATION_RELATIONAL_LESS,
1120 		b ) );
1121 }
1122 
1123 VImage
operator <=(const VImage a,const VImage b)1124 operator<=( const VImage a, const VImage b )
1125 {
1126 	return( a.relational( b, VIPS_OPERATION_RELATIONAL_LESSEQ ) );
1127 }
1128 
1129 VImage
operator <=(const double a,const VImage b)1130 operator<=( const double a, const VImage b )
1131 {
1132 	return( b.relational_const( VIPS_OPERATION_RELATIONAL_MOREEQ,
1133 		to_vector( a ) ) );
1134 }
1135 
1136 VImage
operator <=(const VImage a,const double b)1137 operator<=( const VImage a, const double b )
1138 {
1139 	return( a.relational_const( VIPS_OPERATION_RELATIONAL_LESSEQ,
1140 		to_vector( b ) ) );
1141 }
1142 
1143 VImage
operator <=(const std::vector<double> a,const VImage b)1144 operator<=( const std::vector<double> a, const VImage b )
1145 {
1146 	return( b.relational_const( VIPS_OPERATION_RELATIONAL_MOREEQ,
1147 		a ) );
1148 }
1149 
1150 VImage
operator <=(const VImage a,const std::vector<double> b)1151 operator<=( const VImage a, const std::vector<double> b )
1152 {
1153 	return( a.relational_const( VIPS_OPERATION_RELATIONAL_LESSEQ,
1154 		b ) );
1155 }
1156 
1157 VImage
operator >(const VImage a,const VImage b)1158 operator>( const VImage a, const VImage b )
1159 {
1160 	return( a.relational( b, VIPS_OPERATION_RELATIONAL_MORE ) );
1161 }
1162 
1163 VImage
operator >(const double a,const VImage b)1164 operator>( const double a, const VImage b )
1165 {
1166 	return( b.relational_const( VIPS_OPERATION_RELATIONAL_LESS,
1167 		to_vector( a ) ) );
1168 }
1169 
1170 VImage
operator >(const VImage a,const double b)1171 operator>( const VImage a, const double b )
1172 {
1173 	return( a.relational_const( VIPS_OPERATION_RELATIONAL_MORE,
1174 		to_vector( b ) ) );
1175 }
1176 
1177 VImage
operator >(const std::vector<double> a,const VImage b)1178 operator>( const std::vector<double> a, const VImage b )
1179 {
1180 	return( b.relational_const( VIPS_OPERATION_RELATIONAL_LESS,
1181 		a ) );
1182 }
1183 
1184 VImage
operator >(const VImage a,const std::vector<double> b)1185 operator>( const VImage a, const std::vector<double> b )
1186 {
1187 	return( a.relational_const( VIPS_OPERATION_RELATIONAL_MORE,
1188 		b ) );
1189 }
1190 
1191 VImage
operator >=(const VImage a,const VImage b)1192 operator>=( const VImage a, const VImage b )
1193 {
1194 	return( a.relational( b, VIPS_OPERATION_RELATIONAL_MOREEQ ) );
1195 }
1196 
1197 VImage
operator >=(const double a,const VImage b)1198 operator>=( const double a, const VImage b )
1199 {
1200 	return( b.relational_const( VIPS_OPERATION_RELATIONAL_LESSEQ,
1201 		to_vector( a ) ) );
1202 }
1203 
1204 VImage
operator >=(const VImage a,const double b)1205 operator>=( const VImage a, const double b )
1206 {
1207 	return( a.relational_const( VIPS_OPERATION_RELATIONAL_MOREEQ,
1208 		to_vector( b ) ) );
1209 }
1210 
1211 VImage
operator >=(const std::vector<double> a,const VImage b)1212 operator>=( const std::vector<double> a, const VImage b )
1213 {
1214 	return( b.relational_const( VIPS_OPERATION_RELATIONAL_LESSEQ,
1215 		a ) );
1216 }
1217 
1218 VImage
operator >=(const VImage a,const std::vector<double> b)1219 operator>=( const VImage a, const std::vector<double> b )
1220 {
1221 	return( a.relational_const( VIPS_OPERATION_RELATIONAL_MOREEQ,
1222 		b ) );
1223 }
1224 
1225 VImage
operator ==(const VImage a,const VImage b)1226 operator==( const VImage a, const VImage b )
1227 {
1228 	return( a.relational( b, VIPS_OPERATION_RELATIONAL_EQUAL ) );
1229 }
1230 
1231 VImage
operator ==(const double a,const VImage b)1232 operator==( const double a, const VImage b )
1233 {
1234 	return( b.relational_const( VIPS_OPERATION_RELATIONAL_EQUAL,
1235 		to_vector( a ) ) );
1236 }
1237 
1238 VImage
operator ==(const VImage a,const double b)1239 operator==( const VImage a, const double b )
1240 {
1241 	return( a.relational_const( VIPS_OPERATION_RELATIONAL_EQUAL,
1242 		to_vector( b ) ) );
1243 }
1244 
1245 VImage
operator ==(const std::vector<double> a,const VImage b)1246 operator==( const std::vector<double> a, const VImage b )
1247 {
1248 	return( b.relational_const( VIPS_OPERATION_RELATIONAL_EQUAL,
1249 		a ) );
1250 }
1251 
1252 VImage
operator ==(const VImage a,const std::vector<double> b)1253 operator==( const VImage a, const std::vector<double> b )
1254 {
1255 	return( a.relational_const( VIPS_OPERATION_RELATIONAL_EQUAL,
1256 		b ) );
1257 }
1258 
1259 VImage
operator !=(const VImage a,const VImage b)1260 operator!=( const VImage a, const VImage b )
1261 {
1262 	return( a.relational( b, VIPS_OPERATION_RELATIONAL_NOTEQ ) );
1263 }
1264 
1265 VImage
operator !=(const double a,const VImage b)1266 operator!=( const double a, const VImage b )
1267 {
1268 	return( b.relational_const( VIPS_OPERATION_RELATIONAL_NOTEQ,
1269 		to_vector( a ) ) );
1270 }
1271 
1272 VImage
operator !=(const VImage a,const double b)1273 operator!=( const VImage a, const double b )
1274 {
1275 	return( a.relational_const( VIPS_OPERATION_RELATIONAL_NOTEQ,
1276 		to_vector( b ) ) );
1277 }
1278 
1279 VImage
operator !=(const std::vector<double> a,const VImage b)1280 operator!=( const std::vector<double> a, const VImage b )
1281 {
1282 	return( b.relational_const( VIPS_OPERATION_RELATIONAL_NOTEQ,
1283 		a ) );
1284 }
1285 
1286 VImage
operator !=(const VImage a,const std::vector<double> b)1287 operator!=( const VImage a, const std::vector<double> b )
1288 {
1289 	return( a.relational_const( VIPS_OPERATION_RELATIONAL_NOTEQ,
1290 		b ) );
1291 }
1292 
1293 VImage
operator &(const VImage a,const VImage b)1294 operator&( const VImage a, const VImage b )
1295 {
1296 	return( a.boolean( b, VIPS_OPERATION_BOOLEAN_AND ) );
1297 }
1298 
1299 VImage
operator &(const double a,const VImage b)1300 operator&( const double a, const VImage b )
1301 {
1302 	return( b.boolean_const( VIPS_OPERATION_BOOLEAN_AND,
1303 		to_vector( a ) ) );
1304 }
1305 
1306 VImage
operator &(const VImage a,const double b)1307 operator&( const VImage a, const double b )
1308 {
1309 	return( a.boolean_const( VIPS_OPERATION_BOOLEAN_AND,
1310 		to_vector( b ) ) );
1311 }
1312 
1313 VImage
operator &(const std::vector<double> a,const VImage b)1314 operator&( const std::vector<double> a, const VImage b )
1315 {
1316 	return( b.boolean_const( VIPS_OPERATION_BOOLEAN_AND, a ) );
1317 }
1318 
1319 VImage
operator &(const VImage a,const std::vector<double> b)1320 operator&( const VImage a, const std::vector<double> b )
1321 {
1322 	return( a.boolean_const( VIPS_OPERATION_BOOLEAN_AND, b ) );
1323 }
1324 
1325 VImage &
operator &=(VImage & a,const VImage b)1326 operator&=( VImage &a, const VImage b )
1327 {
1328 	return( a = a & b );
1329 }
1330 
1331 VImage &
operator &=(VImage & a,const double b)1332 operator&=( VImage &a, const double b )
1333 {
1334 	return( a = a & b );
1335 }
1336 
1337 VImage &
operator &=(VImage & a,const std::vector<double> b)1338 operator&=( VImage &a, const std::vector<double> b )
1339 {
1340 	return( a = a & b );
1341 }
1342 
1343 VImage
operator |(const VImage a,const VImage b)1344 operator|( const VImage a, const VImage b )
1345 {
1346 	return( a.boolean( b, VIPS_OPERATION_BOOLEAN_OR ) );
1347 }
1348 
1349 VImage
operator |(const double a,const VImage b)1350 operator|( const double a, const VImage b )
1351 {
1352 	return( b.boolean_const( VIPS_OPERATION_BOOLEAN_OR,
1353 		to_vector( a ) ) );
1354 }
1355 
1356 VImage
operator |(const VImage a,const double b)1357 operator|( const VImage a, const double b )
1358 {
1359 	return( a.boolean_const( VIPS_OPERATION_BOOLEAN_OR,
1360 		to_vector( b ) ) );
1361 }
1362 
1363 VImage
operator |(const std::vector<double> a,const VImage b)1364 operator|( const std::vector<double> a, const VImage b )
1365 {
1366 	return( b.boolean_const( VIPS_OPERATION_BOOLEAN_OR,
1367 		a ) );
1368 }
1369 
1370 VImage
operator |(const VImage a,const std::vector<double> b)1371 operator|( const VImage a, const std::vector<double> b )
1372 {
1373 	return( a.boolean_const( VIPS_OPERATION_BOOLEAN_OR,
1374 		b ) );
1375 }
1376 
1377 VImage &
operator |=(VImage & a,const VImage b)1378 operator|=( VImage &a, const VImage b )
1379 {
1380 	return( a = a | b );
1381 }
1382 
1383 VImage &
operator |=(VImage & a,const double b)1384 operator|=( VImage &a, const double b )
1385 {
1386 	return( a = a | b );
1387 }
1388 
1389 VImage &
operator |=(VImage & a,const std::vector<double> b)1390 operator|=( VImage &a, const std::vector<double> b )
1391 {
1392 	return( a = a | b );
1393 }
1394 
1395 VImage
operator ^(const VImage a,const VImage b)1396 operator^( const VImage a, const VImage b )
1397 {
1398 	return( a.boolean( b, VIPS_OPERATION_BOOLEAN_EOR ) );
1399 }
1400 
1401 VImage
operator ^(const double a,const VImage b)1402 operator^( const double a, const VImage b )
1403 {
1404 	return( b.boolean_const( VIPS_OPERATION_BOOLEAN_EOR,
1405 		to_vector( a ) ) );
1406 }
1407 
1408 VImage
operator ^(const VImage a,const double b)1409 operator^( const VImage a, const double b )
1410 {
1411 	return( a.boolean_const( VIPS_OPERATION_BOOLEAN_EOR,
1412 		to_vector( b ) ) );
1413 }
1414 
1415 VImage
operator ^(const std::vector<double> a,const VImage b)1416 operator^( const std::vector<double> a, const VImage b )
1417 {
1418 	return( b.boolean_const( VIPS_OPERATION_BOOLEAN_EOR,
1419 		a ) );
1420 }
1421 
1422 VImage
operator ^(const VImage a,const std::vector<double> b)1423 operator^( const VImage a, const std::vector<double> b )
1424 {
1425 	return( a.boolean_const( VIPS_OPERATION_BOOLEAN_EOR,
1426 		b ) );
1427 }
1428 
1429 VImage &
operator ^=(VImage & a,const VImage b)1430 operator^=( VImage &a, const VImage b )
1431 {
1432 	return( a = a ^ b );
1433 }
1434 
1435 VImage &
operator ^=(VImage & a,const double b)1436 operator^=( VImage &a, const double b )
1437 {
1438 	return( a = a ^ b );
1439 }
1440 
1441 VImage &
operator ^=(VImage & a,const std::vector<double> b)1442 operator^=( VImage &a, const std::vector<double> b )
1443 {
1444 	return( a = a ^ b );
1445 }
1446 
1447 VImage
operator <<(const VImage a,const VImage b)1448 operator<<( const VImage a, const VImage b )
1449 {
1450 	return( a.boolean( b, VIPS_OPERATION_BOOLEAN_LSHIFT ) );
1451 }
1452 
1453 VImage
operator <<(const VImage a,const double b)1454 operator<<( const VImage a, const double b )
1455 {
1456 	return( a.boolean_const( VIPS_OPERATION_BOOLEAN_LSHIFT,
1457 		to_vector( b ) ) );
1458 }
1459 
1460 VImage
operator <<(const VImage a,const std::vector<double> b)1461 operator<<( const VImage a, const std::vector<double> b )
1462 {
1463 	return( a.boolean_const( VIPS_OPERATION_BOOLEAN_LSHIFT,
1464 		b ) );
1465 }
1466 
1467 VImage &
operator <<=(VImage & a,const VImage b)1468 operator<<=( VImage &a, const VImage b )
1469 {
1470 	return( a = a << b );
1471 }
1472 
1473 VImage &
operator <<=(VImage & a,const double b)1474 operator<<=( VImage &a, const double b )
1475 {
1476 	return( a = a << b );
1477 }
1478 
1479 VImage &
operator <<=(VImage & a,const std::vector<double> b)1480 operator<<=( VImage &a, const std::vector<double> b )
1481 {
1482 	return( a = a << b );
1483 }
1484 
1485 VImage
operator >>(const VImage a,const VImage b)1486 operator>>( const VImage a, const VImage b )
1487 {
1488 	return( a.boolean( b, VIPS_OPERATION_BOOLEAN_RSHIFT ) );
1489 }
1490 
1491 VImage
operator >>(const VImage a,const double b)1492 operator>>( const VImage a, const double b )
1493 {
1494 	return( a.boolean_const( VIPS_OPERATION_BOOLEAN_RSHIFT,
1495 		to_vector( b ) ) );
1496 }
1497 
1498 VImage
operator >>(const VImage a,const std::vector<double> b)1499 operator>>( const VImage a, const std::vector<double> b )
1500 {
1501 	return( a.boolean_const( VIPS_OPERATION_BOOLEAN_RSHIFT,
1502 		b ) );
1503 }
1504 
1505 VImage &
operator >>=(VImage & a,const VImage b)1506 operator>>=( VImage &a, const VImage b )
1507 {
1508 	return( a = a << b );
1509 }
1510 
1511 VImage &
operator >>=(VImage & a,const double b)1512 operator>>=( VImage &a, const double b )
1513 {
1514 	return( a = a << b );
1515 }
1516 
1517 VImage &
operator >>=(VImage & a,const std::vector<double> b)1518 operator>>=( VImage &a, const std::vector<double> b )
1519 {
1520 	return( a = a << b );
1521 }
1522 
1523 VIPS_NAMESPACE_END
1524