diff --git a/TODO b/TODO index ca213115..33c010ba 100644 --- a/TODO +++ b/TODO @@ -1,22 +1,30 @@ -- output arrays need an extra * in +- test other arg types - body must be: + input int works + input double + input enum works + input image works + input doublevec + input imagevec + input blob - std::vector *out_array; + output int + output double works + output enum + output image works + output doublevec + output imagevec + output blob - call( "thing", options->set( "out-array", &out_array ) ); +- set of overloads - and call will new() a vector and place the pointer in out_array +- something to make an image matched to another image from a vector or a + single constant - alternative: - - std::vector out_array; - - call( "thing", options->set( "out-array", &out_array ) ); - - now the caller must pass in an empty vector (or not?) which we fill (or - empty?) ... seems odd, but makes lifetime management much simpler +- something to make an image from an array of constants, need to set + scale/offset too +- new_from_buffer(), new_from_memory(), write_to_memory() etc etc diff --git a/cplusplus/VImage.cc b/cplusplus/VImage.cc index f6eb56bc..6965e355 100644 --- a/cplusplus/VImage.cc +++ b/cplusplus/VImage.cc @@ -316,7 +316,7 @@ void VOption::get_operation( VipsOperation *operation ) else if( type == G_TYPE_BOOLEAN ) *((*i)->vbool) = g_value_get_boolean( value ); else if( type == G_TYPE_DOUBLE ) - *((*i)->vint) = g_value_get_double( value ); + *((*i)->vdouble) = g_value_get_double( value ); else if( type == VIPS_TYPE_ARRAY_DOUBLE ) { int length; double *array = @@ -439,4 +439,71 @@ void VImage::write_to_file( const char *name, VOption *options ) #include "vips-operators.cc" +VImage VImage::linear( double a, double b, VOption *options ) + throw( VError ) +{ + double av[1] = { a }; + std::vector avec( av, av + VIPS_NUMBER( av ) ); + + double bv[1] = { b }; + std::vector bvec( bv, bv + VIPS_NUMBER( bv ) ); + + VImage out; + + call( "linear", + (options ? options : VImage::option()) -> + set( "out", &out ) -> + set( "in", *this ) -> + set( "a", avec ) -> + set( "b", bvec ) ); + + return( out ); +} + +std::vector VImage::bandsplit( VOption *options ) + throw( VError ) +{ + std::vector bands; + + for( int i = 0; i < this->bands(); i++ ) + bands.push_back( this->extract_band( i ) ); + + return( bands ); +} + +VImage VImage::bandjoin( VImage other, VOption *options ) + throw( VError ) +{ + VImage v[2] = { *this, other }; + std::vector vec( v, v + VIPS_NUMBER( v ) ); + + return( bandjoin( vec, options ) ); +} + +std::complex VImage::minpos( VOption *options ) + throw( VError ) +{ + double x, y; + + (void) this->min( + (options ? options : VImage::option()) -> + set( "x", &x ) -> + set( "y", &y ) ); + + return( std::complex( x, y ) ); +} + +std::complex VImage::maxpos( VOption *options ) + throw( VError ) +{ + double x, y; + + (void) this->max( + (options ? options : VImage::option()) -> + set( "x", &x ) -> + set( "y", &y ) ); + + return( std::complex( x, y ) ); +} + VIPS_NAMESPACE_END diff --git a/cplusplus/examples/avg.cc b/cplusplus/examples/avg.cc new file mode 100644 index 00000000..152c1268 --- /dev/null +++ b/cplusplus/examples/avg.cc @@ -0,0 +1,53 @@ +/* + * compile with: + * + * g++ -g -Wall avg.cc `pkg-config vips-cc --cflags --libs` + * + */ + +#define DEBUG + +#include + +using namespace vips8; + +int +main( int argc, char **argv ) +{ + GOptionContext *context; + GOptionGroup *main_group; + GError *error = NULL; + + if( vips_init( argv[0] ) ) + vips_error_exit( NULL ); + + context = g_option_context_new( "" ); + + main_group = g_option_group_new( NULL, NULL, NULL, NULL, NULL ); + g_option_context_set_main_group( context, main_group ); + g_option_context_add_group( context, vips_get_option_group() ); + + if( !g_option_context_parse( context, &argc, &argv, &error ) ) { + if( error ) { + fprintf( stderr, "%s\n", error->message ); + g_error_free( error ); + } + + vips_error_exit( NULL ); + } + + +{ + VImage in = VImage::new_from_file( argv[1], + VImage::option()->set( "access", VIPS_ACCESS_SEQUENTIAL_UNBUFFERED ) ); + double avg; + + avg = in.avg(); + + printf( "avg = %g\n", avg ); +} + + vips_shutdown(); + + return( 0 ); +} diff --git a/cplusplus/examples/embed.cc b/cplusplus/examples/embed.cc new file mode 100644 index 00000000..4d93f0d2 --- /dev/null +++ b/cplusplus/examples/embed.cc @@ -0,0 +1,53 @@ +/* + * compile with: + * + * g++ -g -Wall embed.cc `pkg-config vips-cc --cflags --libs` + * + */ + +#define DEBUG + +#include + +using namespace vips8; + +int +main( int argc, char **argv ) +{ + GOptionContext *context; + GOptionGroup *main_group; + GError *error = NULL; + + if( vips_init( argv[0] ) ) + vips_error_exit( NULL ); + + context = g_option_context_new( "" ); + + main_group = g_option_group_new( NULL, NULL, NULL, NULL, NULL ); + g_option_context_set_main_group( context, main_group ); + g_option_context_add_group( context, vips_get_option_group() ); + + if( !g_option_context_parse( context, &argc, &argv, &error ) ) { + if( error ) { + fprintf( stderr, "%s\n", error->message ); + g_error_free( error ); + } + + vips_error_exit( NULL ); + } + + +{ + VImage in = VImage::new_from_file( argv[1], + VImage::option()->set( "access", VIPS_ACCESS_SEQUENTIAL_UNBUFFERED ) ); + + VImage out = in.embed( 10, 10, 1000, 1000, + VImage::option()->set( "extend", VIPS_EXTEND_COPY ) ); + + out.write_to_file( argv[2] ); +} + + vips_shutdown(); + + return( 0 ); +} diff --git a/cplusplus/examples/try.cc b/cplusplus/examples/try.cc new file mode 100644 index 00000000..4546398c --- /dev/null +++ b/cplusplus/examples/try.cc @@ -0,0 +1,85 @@ +/* + * compile with: + * + * g++ -g -Wall try.cc `pkg-config vips-cc --cflags --libs` + * + */ + +#define DEBUG + +#include + +using namespace vips8; + +int +main( int argc, char **argv ) +{ + GOptionContext *context; + GOptionGroup *main_group; + GError *error = NULL; + + if( vips_init( argv[0] ) ) + vips_error_exit( NULL ); + + context = g_option_context_new( "" ); + + main_group = g_option_group_new( NULL, NULL, NULL, NULL, NULL ); + g_option_context_set_main_group( context, main_group ); + g_option_context_add_group( context, vips_get_option_group() ); + + if( !g_option_context_parse( context, &argc, &argv, &error ) ) { + if( error ) { + fprintf( stderr, "%s\n", error->message ); + g_error_free( error ); + } + + vips_error_exit( NULL ); + } + + +{ + VImage in = VImage::new_from_file( argv[1], + VImage::option()->set( "access", VIPS_ACCESS_SEQUENTIAL_UNBUFFERED ) ); + double avg; + + avg = in.avg(); + + printf( "avg = %g\n", avg ); +} + +{ + VImage in = VImage::new_from_file( argv[1], + VImage::option()->set( "access", VIPS_ACCESS_SEQUENTIAL_UNBUFFERED ) ); + + VImage out = in.embed( 10, 10, 1000, 1000, + VImage::option()->set( "extend", VIPS_EXTEND_COPY ) ); + + out.write_to_file( "embed.jpg" ); +} + +{ + VImage in = VImage::new_from_file( argv[1], + VImage::option()->set( "access", VIPS_ACCESS_SEQUENTIAL_UNBUFFERED ) ); + double a[] = { 1.0, 2.0, 3.0 }; + double b[] = { 4.0, 5.0, 6.0 }; + + std::vector avec( a, a + VIPS_NUMBER( a ) ); + std::vector bvec( b, b + VIPS_NUMBER( b ) ); + + VImage out = in.linear( avec, bvec ); + + out.write_to_file( "linear.jpg" ); +} + +{ + VImage in = VImage::new_from_file( argv[1], + VImage::option()->set( "access", VIPS_ACCESS_SEQUENTIAL_UNBUFFERED ) ); + VImage out = in.linear( 1, 2 ); + + out.write_to_file( "linear1.jpg" ); +} + + vips_shutdown(); + + return( 0 ); +} diff --git a/cplusplus/include/vips/VImage8.h b/cplusplus/include/vips/VImage8.h index 2d08dd9d..0cf19e3c 100644 --- a/cplusplus/include/vips/VImage8.h +++ b/cplusplus/include/vips/VImage8.h @@ -249,6 +249,81 @@ public: return( (VipsImage *) VObject::get_object() ); } + int width() + { + return( vips_image_get_width( get_image() ) ); + } + + int height() + { + return( vips_image_get_height( get_image() ) ); + } + + int bands() + { + return( vips_image_get_bands( get_image() ) ); + } + + VipsBandFormat format() + { + return( vips_image_get_format( get_image() ) ); + } + + VipsCoding coding() + { + return( vips_image_get_coding( get_image() ) ); + } + + VipsInterpretation interpretation() + { + return( vips_image_get_interpretation( get_image() ) ); + } + + VipsInterpretation guess_interpretation() + { + return( vips_image_guess_interpretation( get_image() ) ); + } + + double xres() + { + return( vips_image_get_xres( get_image() ) ); + } + + double yres() + { + return( vips_image_get_yres( get_image() ) ); + } + + double xoffset() + { + return( vips_image_get_xoffset( get_image() ) ); + } + + double yoffset() + { + return( vips_image_get_yoffset( get_image() ) ); + } + + const char *filename() + { + return( vips_image_get_filename( get_image() ) ); + } + + double scale() + { + return( vips_image_get_scale( get_image() ) ); + } + + double offset() + { + return( vips_image_get_offset( get_image() ) ); + } + + const void *data() + { + return( vips_image_get_data( get_image() ) ); + } + static VOption *option() { return( new VOption() ); @@ -268,6 +343,150 @@ public: #include "vips-operators.h" + // a few useful things + + VImage linear( double a, double b, VOption *options = 0 ) + throw( VError ); + + std::vector bandsplit( VOption *options = 0 ) + throw( VError ); + + VImage bandjoin( VImage other, VOption *options = 0 ) + throw( VError ); + + std::complex minpos( VOption *options = 0 ) + throw( VError ); + + std::complex maxpos( VOption *options = 0 ) + throw( VError ); + + VImage floor( VOption *options = 0 ) + throw( VError ) + { + return( round( VIPS_OPERATION_ROUND_FLOOR, options ) ); + } + + VImage ceil( VOption *options = 0 ) + throw( VError ) + { + return( round( VIPS_OPERATION_ROUND_CEIL, options ) ); + } + + VImage rint( VOption *options = 0 ) + throw( VError ) + { + return( round( VIPS_OPERATION_ROUND_RINT, options ) ); + } + + VImage real( VOption *options = 0 ) + throw( VError ) + { + return( complexget( VIPS_OPERATION_COMPLEXGET_REAL, options ) ); + } + + VImage imag( VOption *options = 0 ) + throw( VError ) + { + return( complexget( VIPS_OPERATION_COMPLEXGET_IMAG, options ) ); + } + + VImage polar( VOption *options = 0 ) + throw( VError ) + { + return( complex( VIPS_OPERATION_COMPLEX_POLAR, options ) ); + } + + VImage rect( VOption *options = 0 ) + throw( VError ) + { + return( complex( VIPS_OPERATION_COMPLEX_RECT, options ) ); + } + + VImage conj( VOption *options = 0 ) + throw( VError ) + { + return( complex( VIPS_OPERATION_COMPLEX_CONJ, options ) ); + } + + VImage sin( VOption *options = 0 ) + throw( VError ) + { + return( math( VIPS_OPERATION_MATH_SIN, options ) ); + } + + VImage cos( VOption *options = 0 ) + throw( VError ) + { + return( math( VIPS_OPERATION_MATH_COS, options ) ); + } + + VImage tan( VOption *options = 0 ) + throw( VError ) + { + return( math( VIPS_OPERATION_MATH_TAN, options ) ); + } + + VImage asin( VOption *options = 0 ) + throw( VError ) + { + return( math( VIPS_OPERATION_MATH_ASIN, options ) ); + } + + VImage acos( VOption *options = 0 ) + throw( VError ) + { + return( math( VIPS_OPERATION_MATH_ACOS, options ) ); + } + + VImage atan( VOption *options = 0 ) + throw( VError ) + { + return( math( VIPS_OPERATION_MATH_ATAN, options ) ); + } + + VImage log( VOption *options = 0 ) + throw( VError ) + { + return( math( VIPS_OPERATION_MATH_LOG, options ) ); + } + + VImage log10( VOption *options = 0 ) + throw( VError ) + { + return( math( VIPS_OPERATION_MATH_LOG10, options ) ); + } + + VImage exp( VOption *options = 0 ) + throw( VError ) + { + return( math( VIPS_OPERATION_MATH_EXP, options ) ); + } + + VImage exp10( VOption *options = 0 ) + throw( VError ) + { + return( math( VIPS_OPERATION_MATH_EXP10, options ) ); + } + + /* + VImage ifthenelse( double th, VImage el, VOption *options = 0 ) + throw( VError ); + VImage ifthenelse( VImage th, double el, VOption *options = 0 ) + throw( VError ); + VImage ifthenelse( double th, double el, VOption *options = 0 ) + throw( VError ); + + VImage ifthenelse( std::vector th, VImage el, + VOption *options = 0 ) + throw( VError ); + VImage ifthenelse( VImage th, std::vector el, + VOption *options = 0 ) + throw( VError ); + VImage ifthenelse( std::vector th, std::vector el, + VOption *options = 0 ) + throw( VError ); + */ + }; VIPS_NAMESPACE_END diff --git a/libvips/iofuncs/type.c b/libvips/iofuncs/type.c index 6600572f..8a7011c1 100644 --- a/libvips/iofuncs/type.c +++ b/libvips/iofuncs/type.c @@ -1378,7 +1378,7 @@ vips_value_get_array_int( const GValue *value, int *n ) /** * vips_value_set_array_int: * @value: (out): %GValue to get from - * @array: (array length=n): array of ints + * @array: (array length=n) (allow_none): array of ints * @n: the number of elements * * Set @value to hold a copy of @array. Pass in the array length in @n. @@ -1388,12 +1388,15 @@ vips_value_get_array_int( const GValue *value, int *n ) void vips_value_set_array_int( GValue *value, const int *array, int n ) { - int *array_copy; - g_value_init( value, VIPS_TYPE_ARRAY_INT ); vips_value_set_array( value, n, G_TYPE_INT, sizeof( int ) ); - array_copy = vips_value_get_array_int( value, NULL ); - memcpy( array_copy, array, n * sizeof( int ) ); + + if( array ) { + int *array_copy; + + array_copy = vips_value_get_array_int( value, NULL ); + memcpy( array_copy, array, n * sizeof( int ) ); + } } /** @@ -1417,7 +1420,7 @@ vips_value_get_array_double( const GValue *value, int *n ) /** * vips_value_set_array_double: * @value: (out): %GValue to get from - * @array: (array length=n): array of doubles + * @array: (array length=n) (allow-none): array of doubles * @n: the number of elements * * Set @value to hold a copy of @array. Pass in the array length in @n. @@ -1427,12 +1430,15 @@ vips_value_get_array_double( const GValue *value, int *n ) void vips_value_set_array_double( GValue *value, const double *array, int n ) { - double *array_copy; - g_value_init( value, VIPS_TYPE_ARRAY_DOUBLE ); vips_value_set_array( value, n, G_TYPE_DOUBLE, sizeof( double ) ); - array_copy = vips_value_get_array_double( value, NULL ); - memcpy( array_copy, array, n * sizeof( double ) ); + + if( array ) { + double *array_copy; + + array_copy = vips_value_get_array_double( value, NULL ); + memcpy( array_copy, array, n * sizeof( double ) ); + } } /**