From 8036dda5b75a5b92448fdb6734708fa9c4632f80 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Mon, 23 May 2011 17:12:09 +0100 Subject: [PATCH] vips8 CLI works bugs fixed, leaks plugged, hooked up output write --- ChangeLog | 2 + TODO | 7 +- libvips/arithmetic/add.c | 2 +- libvips/arithmetic/arithmetic.c | 2 +- libvips/arithmetic/binary.c | 2 +- libvips/include/vips/object.h | 4 + libvips/iofuncs/image.c | 2 +- libvips/iofuncs/object.c | 144 ++++++++++++++++++++++++++------ libvips/iofuncs/operation.c | 63 +++++++++++--- libvips/iofuncs/region.c | 2 +- 10 files changed, 184 insertions(+), 46 deletions(-) diff --git a/ChangeLog b/ChangeLog index baf146ab..13a1426f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -59,6 +59,8 @@ - vips.c has new action syntax, knows about vips8 operations - add now has sizealike - vips7 binops all do sizealike too, also gbandjoin and ifthenelse +- new API is now functional +- vips.c generates GOption flags for vips8 operations 30/11/10 started 7.24.0 - bump for new stable diff --git a/TODO b/TODO index 875c3bbc..7bd9506d 100644 --- a/TODO +++ b/TODO @@ -1,6 +1,9 @@ -- nasty leakage for +- try + + $ vips im_add k2.v babe.v out.v + + egV - vips add k2.v babe.v out.v diff --git a/libvips/arithmetic/add.c b/libvips/arithmetic/add.c index bbe8bbd6..23e1ad3b 100644 --- a/libvips/arithmetic/add.c +++ b/libvips/arithmetic/add.c @@ -65,8 +65,8 @@ */ /* - */ #define DEBUG + */ #ifdef HAVE_CONFIG_H #include diff --git a/libvips/arithmetic/arithmetic.c b/libvips/arithmetic/arithmetic.c index 4117aff0..f0359323 100644 --- a/libvips/arithmetic/arithmetic.c +++ b/libvips/arithmetic/arithmetic.c @@ -37,8 +37,8 @@ */ /* - */ #define DEBUG + */ #ifdef HAVE_CONFIG_H #include diff --git a/libvips/arithmetic/binary.c b/libvips/arithmetic/binary.c index b1c588fc..1a675d98 100644 --- a/libvips/arithmetic/binary.c +++ b/libvips/arithmetic/binary.c @@ -33,8 +33,8 @@ */ /* - */ #define DEBUG + */ #ifdef HAVE_CONFIG_H #include diff --git a/libvips/include/vips/object.h b/libvips/include/vips/object.h index 1468922a..27e03ba9 100644 --- a/libvips/include/vips/object.h +++ b/libvips/include/vips/object.h @@ -297,6 +297,10 @@ void vips_object_class_install_argument( VipsObjectClass *, GParamSpec *pspec, VipsArgumentFlags flags, guint offset ); int vips_object_set_argument_from_string( VipsObject *object, const char *name, const char *value ); +gboolean vips_object_get_argument_needs_string( VipsObject *object, + const char *name ); +int vips_object_get_argument_to_string( VipsObject *object, + const char *name, const char *arg ); int vips_object_set_required( VipsObject *object, const char *value ); typedef void *(*VipsObjectSetArguments)( VipsObject *, void *, void * ); diff --git a/libvips/iofuncs/image.c b/libvips/iofuncs/image.c index d27028f6..fe52282a 100644 --- a/libvips/iofuncs/image.c +++ b/libvips/iofuncs/image.c @@ -31,8 +31,8 @@ */ /* - */ #define VIPS_DEBUG + */ #ifdef HAVE_CONFIG_H #include diff --git a/libvips/iofuncs/object.c b/libvips/iofuncs/object.c index c9122dbc..134d165e 100644 --- a/libvips/iofuncs/object.c +++ b/libvips/iofuncs/object.c @@ -30,10 +30,10 @@ */ /* - */ #define DEBUG #define VIPS_DEBUG #define DEBUG_REF + */ #ifdef HAVE_CONFIG_H #include @@ -463,7 +463,11 @@ vips_object_dispose( GObject *gobject ) vips_argument_free_all( object ); VIPS_FREEF( vips_argument_table_destroy, object->argument_table ); + vips_object_close( object ); + G_OBJECT_CLASS( vips_object_parent_class )->dispose( gobject ); + + vips_object_postclose( object ); } static void @@ -477,15 +481,15 @@ vips_object_finalize( GObject *gobject ) printf( "\n" ); #endif /*DEBUG*/ - vips_object_close( object ); + /* I'd like to have post-close in here, but you can't emit signals + * from finalize, sadly. + */ g_mutex_lock( vips__object_all_lock ); g_hash_table_remove( vips__object_all, object ); g_mutex_unlock( vips__object_all_lock ); G_OBJECT_CLASS( vips_object_parent_class )->finalize( gobject ); - - vips_object_postclose( object ); } static void @@ -1038,12 +1042,7 @@ vips_object_set_argument_from_string( VipsObject *object, argument_class = (VipsArgumentClass *) vips__argument_table_lookup( class->argument_table, pspec ); - if( argument_class->flags & VIPS_ARGUMENT_OUTPUT ) { - vips_error( "VipsObject", - _( "can't set output argument %s.%s from string" ), - G_OBJECT_TYPE_NAME( object ), name ); - return( -1 ); - } + g_assert( argument_class->flags & VIPS_ARGUMENT_INPUT ); if( G_IS_PARAM_SPEC_OBJECT( pspec ) && G_PARAM_SPEC_VALUE_TYPE( pspec ) == VIPS_TYPE_IMAGE ) { @@ -1081,6 +1080,114 @@ vips_object_set_argument_from_string( VipsObject *object, return( 0 ); } +/* Does a named output arg need an argument to write to? For example, an image + * output needs a filename, a double output just prints. + */ +gboolean +vips_object_get_argument_needs_string( VipsObject *object, const char *name ) +{ + VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object ); + + GParamSpec *pspec; + VipsArgumentClass *argument_class; + +#ifdef DEBUG + printf( "vips_object_get_argument_needs_string: %s\n", name ); +#endif /*DEBUG*/ + + pspec = g_object_class_find_property( G_OBJECT_CLASS( class ), name ); + if( !pspec ) { + vips_error( "VipsObject", _( "%s.%s does not exist" ), + G_OBJECT_TYPE_NAME( object ), name ); + return( -1 ); + } + + argument_class = (VipsArgumentClass *) + vips__argument_table_lookup( class->argument_table, pspec ); + + g_assert( argument_class->flags & VIPS_ARGUMENT_OUTPUT ); + + /* For now, we just support writing an image to a filename. + */ + if( G_IS_PARAM_SPEC_OBJECT( pspec ) && + G_PARAM_SPEC_VALUE_TYPE( pspec ) == VIPS_TYPE_IMAGE ) + return( TRUE ); + else + return( FALSE ); +} + +static void +vips_object_print_arg( VipsObject *object, GParamSpec *pspec, VipsBuf *buf ) +{ + GType type = G_PARAM_SPEC_VALUE_TYPE( pspec ); + const char *name = g_param_spec_get_name( pspec ); + GValue value = { 0 }; + char *str_value; + + g_value_init( &value, type ); + g_object_get_property( G_OBJECT( object ), name, &value ); + str_value = g_strdup_value_contents( &value ); + vips_buf_appends( buf, str_value ); + g_free( str_value ); + g_value_unset( &value ); +} + +/* Write a named arg to the string. If the arg does not need a string (see + * above), arg will be NULL. + */ +int +vips_object_get_argument_to_string( VipsObject *object, + const char *name, const char *arg ) +{ + VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object ); + + GParamSpec *pspec; + VipsArgumentClass *argument_class; + +#ifdef DEBUG + printf( "vips_object_get_argument_to_string: %s -> %s\n", + name, arg ); +#endif /*DEBUG*/ + + pspec = g_object_class_find_property( G_OBJECT_CLASS( class ), name ); + if( !pspec ) { + vips_error( "VipsObject", _( "%s.%s does not exist" ), + G_OBJECT_TYPE_NAME( object ), name ); + return( -1 ); + } + + argument_class = (VipsArgumentClass *) + vips__argument_table_lookup( class->argument_table, pspec ); + + g_assert( argument_class->flags & VIPS_ARGUMENT_OUTPUT ); + + if( G_IS_PARAM_SPEC_OBJECT( pspec ) && + G_PARAM_SPEC_VALUE_TYPE( pspec ) == VIPS_TYPE_IMAGE ) { + VipsImage *value; + VipsImage *image; + + if( !(image = vips_image_new_from_file( arg, "w" )) ) + return( -1 ); + g_object_get( object, name, &value, NULL ); + if( im_copy( value, image ) ) { + g_object_unref( value ); + g_object_unref( image ); + return( -1 ); + } + g_object_unref( value ); + g_object_unref( image ); + } + else { + char str[1000]; + VipsBuf buf = VIPS_BUF_STATIC( str ); + + vips_object_print_arg( object, pspec, &buf ); + printf( "%s", vips_buf_all( &buf ) ); + } + + return( 0 ); +} + static void * vips_argument_is_required( VipsObject *object, GParamSpec *pspec, @@ -1225,23 +1332,6 @@ vips_object_new_from_string( const char *basename, const char *p ) vips_object_new_from_string_set, (void *) p, NULL ) ); } -static void -vips_object_print_arg( VipsObject *object, GParamSpec *pspec, VipsBuf *buf ) -{ - GType type = G_PARAM_SPEC_VALUE_TYPE( pspec ); - const char *name = g_param_spec_get_name( pspec ); - GValue value = { 0 }; - char *str_value; - - g_value_init( &value, type ); - g_object_get_property( G_OBJECT( object ), name, &value ); - str_value = g_strdup_value_contents( &value ); - vips_buf_appends( buf, str_value ); - g_free( str_value ); - g_value_unset( &value ); - -} - static void * vips_object_to_string_required( VipsObject *object, GParamSpec *pspec, diff --git a/libvips/iofuncs/operation.c b/libvips/iofuncs/operation.c index 034801d3..e22ea4af 100644 --- a/libvips/iofuncs/operation.c +++ b/libvips/iofuncs/operation.c @@ -28,8 +28,8 @@ */ /* - */ #define VIPS_DEBUG + */ #ifdef HAVE_CONFIG_H #include @@ -551,14 +551,17 @@ vips_call_argv_input( VipsObject *object, */ if( (argument_class->flags & VIPS_ARGUMENT_REQUIRED) && (argument_class->flags & VIPS_ARGUMENT_CONSTRUCT) ) { - /* Input args get set from argv, we skip output args. - */ - if( (argument_class->flags & VIPS_ARGUMENT_INPUT) ) + if( (argument_class->flags & VIPS_ARGUMENT_INPUT) ) { if( vips_object_set_argument_from_string( object, g_param_spec_get_name( pspec ), argv[*i] ) ) return( pspec ); - - *i += 1; + *i += 1; + } + else if( (argument_class->flags & VIPS_ARGUMENT_OUTPUT) ) { + if( vips_object_get_argument_needs_string( object, + g_param_spec_get_name( pspec ) ) ) + *i += 1; + } } return( NULL ); @@ -578,13 +581,46 @@ vips_call_argv_output( VipsObject *object, */ if( (argument_class->flags & VIPS_ARGUMENT_REQUIRED) && (argument_class->flags & VIPS_ARGUMENT_CONSTRUCT) ) { - /* Output args get written to argv[*i]. - */ - if( (argument_class->flags & VIPS_ARGUMENT_OUTPUT) ) - printf( "** write %s to %s\n", - g_param_spec_get_name( pspec ), argv[*i] ); + if( (argument_class->flags & VIPS_ARGUMENT_INPUT) ) + *i += 1; + else if( (argument_class->flags & VIPS_ARGUMENT_OUTPUT) ) { + char *arg; - *i += 1; + arg = NULL; + if( vips_object_get_argument_needs_string( object, + g_param_spec_get_name( pspec ) ) ) { + arg = argv[*i]; + *i += 1; + } + + if( vips_object_get_argument_to_string( object, + g_param_spec_get_name( pspec ), arg ) ) + return( pspec ); + } + } + + return( NULL ); +} + +static void * +vips_call_argv_unref_output( VipsObject *object, + GParamSpec *pspec, + VipsArgumentClass *argument_class, + VipsArgumentInstance *argument_instance, + void *a, void *b ) +{ + if( (argument_class->flags & VIPS_ARGUMENT_OUTPUT) && + G_IS_PARAM_SPEC_OBJECT( pspec ) ) { + GObject *value; + + g_object_get( object, + g_param_spec_get_name( pspec ), &value, NULL ); + + /* Doing the get refs the object, so unref the get, then unref + * again since this an an output object of the operation. + */ + g_object_unref( value ); + g_object_unref( value ); } return( NULL ); @@ -622,6 +658,9 @@ vips_call_argv( VipsOperation *operation, int argc, char **argv ) (void) vips_argument_map( VIPS_OBJECT( operation ), vips_call_argv_output, argv, &i ); + (void) vips_argument_map( VIPS_OBJECT( operation ), + vips_call_argv_unref_output, NULL, NULL ); + return( 0 ); } diff --git a/libvips/iofuncs/region.c b/libvips/iofuncs/region.c index 284c5d9e..0eb144b4 100644 --- a/libvips/iofuncs/region.c +++ b/libvips/iofuncs/region.c @@ -70,11 +70,11 @@ */ /* - */ #define DEBUG_MOVE #define DEBUG_ENVIRONMENT 1 #define DEBUG_CREATE #define DEBUG + */ #ifdef HAVE_CONFIG_H #include