From 0b902bfbd4c4f5d6ff0a68612ab76ff56a5f4667 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Tue, 24 May 2011 14:44:23 +0100 Subject: [PATCH] make CLI arg handling into vfuncs add vfuncs to vipsobject for the CLI interface --- TODO | 22 ++---------- libvips/deprecated/vips7compat.c | 2 +- libvips/include/vips/image.h | 5 +-- libvips/include/vips/object.h | 20 +++++++++++ libvips/iofuncs/error.c | 4 +-- libvips/iofuncs/image.c | 57 ++++++++++++++++++++++++++------ libvips/iofuncs/object.c | 44 +++++++++++++++--------- 7 files changed, 102 insertions(+), 52 deletions(-) diff --git a/TODO b/TODO index c413b735..cb43c9ee 100644 --- a/TODO +++ b/TODO @@ -1,28 +1,10 @@ -- try +- test the vfunc system for CLI args - $ vips im_add k2.v babe.v out.v - VIPS:ERROR:image.c:300:vips_image_finalize: - assertion failed: (!image->regions) - - during the close of k2.v, triggered by destroy_args() in package.c as it - junks the argv ... there's one region there - - I suppose we are unreffing one time too many during cleanup after - im_run_command() - - should the wrapper for im_open() do sink_ref to make sure it returns a real - reference? + vips_object_new_from_string() is now very confusingly named -- vips_object_get_argument_to_string(), - vips_object_get_argument_needs_string(), - vips_object_set_argument_from_string() - - should all be vfuncs on object - - - make something for Python as well diff --git a/libvips/deprecated/vips7compat.c b/libvips/deprecated/vips7compat.c index b1b00ab4..ddd810ee 100644 --- a/libvips/deprecated/vips7compat.c +++ b/libvips/deprecated/vips7compat.c @@ -57,7 +57,7 @@ im_open( const char *filename, const char *mode ) { VipsImage *image; - if( !(image = vips_image_new_from_file( filename, mode )) ) + if( !(image = vips_image_new_mode( filename, mode )) ) return( NULL ); /* We have to refsink since the im_open() result is used like a hard diff --git a/libvips/include/vips/image.h b/libvips/include/vips/image.h index e696719f..5ef80d4a 100644 --- a/libvips/include/vips/image.h +++ b/libvips/include/vips/image.h @@ -285,7 +285,7 @@ typedef struct _VipsImageClass { void (*posteval)( VipsImage *image, VipsProgress *progress ); /* An image has been written to. - * Used by eg. vips_image_new_from_file("x.jpg", "w") to do the + * Used by eg. vips_image_new_mode("x.jpg", "w") to do the * final write to jpeg. * Set *result to non-zero to indicate an error on write. */ @@ -357,7 +357,8 @@ void vips_image_set_kill( VipsImage *image, gboolean kill ); VipsImage *vips_image_new( void ); int vips_image_new_array( VipsObject *parent, VipsImage **images, int n ); -VipsImage *vips_image_new_from_file( const char *filename, const char *mode ); +VipsImage *vips_image_new_mode( const char *filename, const char *mode ); +VipsImage *vips_image_new_from_file( const char *filename ); VipsImage *vips_image_new_from_file_raw( const char *filename, int xsize, int ysize, int bands, int offset ); VipsImage *vips_image_new_from_memory( void *buffer, diff --git a/libvips/include/vips/object.h b/libvips/include/vips/object.h index 27e03ba9..0a22948b 100644 --- a/libvips/include/vips/object.h +++ b/libvips/include/vips/object.h @@ -261,6 +261,26 @@ struct _VipsObjectClass { */ void (*postclose)( VipsObject * ); + /* The CLI interface. Implement these three to get CLI input and output + * for your object. + */ + + /* Given a command-line arg (eg. a filename), make an instance of the + * object. + */ + VipsObject *(*new_from_string)( const char *string ); + + /* Does this output arg need an arg from the command line? Image + * output, for example, needs a filename to write to. + */ + gboolean output_needs_arg; + + /* Write the object to the string. Return 0 for success, or -1 on + * error setting vips_error(). string is NULL if output_needs_arg() + * was FALSE. + */ + int (*output_to_arg)( VipsObject *object, const char *string ); + /* Class nickname, eg. "VipsInterpolateBicubic" has "bicubic" as a * nickname. Not internationalised. */ diff --git a/libvips/iofuncs/error.c b/libvips/iofuncs/error.c index 1e360da3..31c22f2c 100644 --- a/libvips/iofuncs/error.c +++ b/libvips/iofuncs/error.c @@ -93,8 +93,8 @@ * |[ * IMAGE *im; * - * if( !(im = vips_image_new_from_file( filename, "r" )) ) - * // vips_image_new_from_file() will set a mmessage, we don't need to + * if( !(im = vips_image_new_from_file( filename )) ) + * // vips_image_new_from_file() will set a message, we don't need to * return( -1 ); * * if( vips_image_get_width( im ) < 100 ) { diff --git a/libvips/iofuncs/image.c b/libvips/iofuncs/image.c index 45e3c6e7..c2ed17d1 100644 --- a/libvips/iofuncs/image.c +++ b/libvips/iofuncs/image.c @@ -388,6 +388,20 @@ vips_image_dispose( GObject *gobject ) G_OBJECT_CLASS( vips_image_parent_class )->dispose( gobject ); } + + +static VipsObject * +vips_image_new_from_file_object( const char *string ) +{ + return( VIPS_OBJECT( vips_image_new_from_file( string ) ) ); +} + +static int +vips_image_write_object( VipsObject *object, const char *string ) +{ + return( vips_image_write( VIPS_IMAGE( object ), string ) ); +} + static void * print_field_fn( VipsImage *image, const char *field, GValue *value, void *a ) { @@ -1047,6 +1061,10 @@ vips_image_class_init( VipsImageClass *class ) gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; + vobject_class->new_from_string = vips_image_new_from_file_object; + vobject_class->output_needs_arg = TRUE; + vobject_class->output_to_arg = vips_image_write_object; + vobject_class->nickname = "image"; vobject_class->description = _( "VIPS image class" ); @@ -1435,7 +1453,7 @@ vips_image_temp_name( void ) * vips_image_new() creates a "glue" descriptor you can use to join two image * processing operations together. * - * It is the equivalent of vips_image_new_from_file("xxx", "p"). + * It is the equivalent of vips_image_new_mode("xxx", "p"). * * Returns: the new #VipsImage, or %NULL on error. */ @@ -1499,11 +1517,11 @@ vips_image_new_array( VipsObject *parent, VipsImage **images, int n ) } /** - * vips_image_new_from_file: + * vips_image_new_mode: * @filename: file to open * @mode: mode to open with * - * vips_image_new_from_file() examines the mode string and creates an + * vips_image_new_mode() examines the mode string and creates an * appropriate #VipsImage. * * @@ -1524,7 +1542,7 @@ vips_image_new_array( VipsObject *parent, VipsImage **images, int n ) * * "r" * opens the named file for reading. If the file is not in the native - * VIPS format for your machine, vips_image_new_from_file() + * VIPS format for your machine, vips_image_new_mode() * automatically converts the file for you in memory. * * For some large files (eg. TIFF) this may @@ -1533,7 +1551,7 @@ vips_image_new_array( VipsObject *parent, VipsImage **images, int n ) * API and control the loading process yourself. See * #VipsBandFormat. * - * vips_image_new_from_file() can read files in most formats. + * vips_image_new_mode() can read files in most formats. * * Note that "r" mode works in at least two stages. * It should return quickly and let you check header fields. It will @@ -1545,7 +1563,7 @@ vips_image_new_array( VipsObject *parent, VipsImage **images, int n ) * "rd" * opens the named file for reading. If the uncompressed image is larger * than a threshold and the file format does not support random access, - * rather than uncompressing to memory, vips_image_new_from_file() will + * rather than uncompressing to memory, vips_image_new_mode() will * uncompress to a temporary disc file. This file will be automatically * deleted when the IMAGE is closed. * @@ -1574,7 +1592,7 @@ vips_image_new_array( VipsObject *parent, VipsImage **images, int n ) * suffix to determine the type to write -- for example: * * |[ - * vips_image_new_from_file( "fred.tif", "w" ) + * vips_image_new_mode( "fred.tif", "w" ) * ]| * * will write in TIFF format. @@ -1593,7 +1611,7 @@ vips_image_new_array( VipsObject *parent, VipsImage **images, int n ) * Returns: the new #VipsImage, or %NULL on error. */ VipsImage * -vips_image_new_from_file( const char *filename, const char *mode ) +vips_image_new_mode( const char *filename, const char *mode ) { VipsImage *image; @@ -1610,6 +1628,23 @@ vips_image_new_from_file( const char *filename, const char *mode ) return( image ); } +/** + * vips_image_new_from_file: + * @filename: file to open + * + * vips_image_new_from_file() opens @filename for reading. See + * vips_image_new_mode() for details. + * + * See also: vips_image_new_mode(). + * + * Returns: the new #VipsImage, or %NULL on error. + */ +VipsImage * +vips_image_new_from_file( const char *filename ) +{ + return( vips_image_new_mode( filename, "r" ) ); +} + /** * vips_image_new_from_file_raw: * @filename: filename to open @@ -1721,7 +1756,7 @@ vips_image_new_disc_temp( const char *format ) if( !(name = vips__temp_name( format )) ) return( NULL ); - if( !(image = vips_image_new_from_file( name, "w" )) ) { + if( !(image = vips_image_new_mode( name, "w" )) ) { g_free( name ); return( NULL ); } @@ -1750,7 +1785,7 @@ vips_image_write( VipsImage *image, const char *filename ) { VipsImage *out; - if( !(out = vips_image_new_from_file( filename, "w" )) ) + if( !(out = vips_image_new_mode( filename, "w" )) ) return( -1 ); if( im_copy( image, out ) ) { g_object_unref( out ); @@ -2029,7 +2064,7 @@ vips_image_wio_input( VipsImage *image ) /* Change to VIPS_IMAGE_SETBUF. First, make a memory * buffer and copy into that. */ - if( !(t1 = vips_image_new_from_file( "wio_input", "t" )) ) + if( !(t1 = vips_image_new_mode( "wio_input", "t" )) ) return( -1 ); if( im_copy( image, t1 ) ) { g_object_unref( t1 ); diff --git a/libvips/iofuncs/object.c b/libvips/iofuncs/object.c index 462b131c..4917cdd6 100644 --- a/libvips/iofuncs/object.c +++ b/libvips/iofuncs/object.c @@ -1024,7 +1024,9 @@ vips_object_set_argument_from_string( VipsObject *object, VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object ); GParamSpec *pspec; + GType otype; VipsArgumentClass *argument_class; + VipsObjectClass *oclass; GValue gvalue = { 0 }; #ifdef DEBUG @@ -1038,24 +1040,27 @@ vips_object_set_argument_from_string( VipsObject *object, G_OBJECT_TYPE_NAME( object ), name ); return( -1 ); } + otype = G_PARAM_SPEC_VALUE_TYPE( pspec ); argument_class = (VipsArgumentClass *) vips__argument_table_lookup( class->argument_table, pspec ); g_assert( argument_class->flags & VIPS_ARGUMENT_INPUT ); - if( G_IS_PARAM_SPEC_OBJECT( pspec ) && - G_PARAM_SPEC_VALUE_TYPE( pspec ) == VIPS_TYPE_IMAGE ) { - VipsImage *image; + if( g_type_is_a( otype, VIPS_TYPE_OBJECT ) && + (oclass = g_type_class_peek( otype )) && + oclass->new_from_string ) { + VipsObject *object; + + if( !(object = oclass->new_from_string( value )) ) + return( -1 ); g_value_init( &gvalue, G_TYPE_OBJECT ); - if( !(image = vips_image_new_from_file( value, "r" )) ) - return( -1 ); /* VipsObject is GInitiallyUnowned, so the gvalue now has a * ref count 1 image. */ - g_value_set_object( &gvalue, image ); + g_value_set_object( &gvalue, object ); } else if( G_IS_PARAM_SPEC_BOOLEAN( pspec ) ) { gboolean b; @@ -1089,7 +1094,9 @@ vips_object_get_argument_needs_string( VipsObject *object, const char *name ) VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object ); GParamSpec *pspec; + GType otype; VipsArgumentClass *argument_class; + VipsObjectClass *oclass; #ifdef DEBUG printf( "vips_object_get_argument_needs_string: %s\n", name ); @@ -1101,19 +1108,20 @@ vips_object_get_argument_needs_string( VipsObject *object, const char *name ) G_OBJECT_TYPE_NAME( object ), name ); return( -1 ); } + otype = G_PARAM_SPEC_VALUE_TYPE( pspec ); 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. + /* For now, only vipsobject subclasses can ask for args. */ - if( G_IS_PARAM_SPEC_OBJECT( pspec ) && - G_PARAM_SPEC_VALUE_TYPE( pspec ) == VIPS_TYPE_IMAGE ) - return( TRUE ); - else - return( FALSE ); + if( g_type_is_a( otype, VIPS_TYPE_OBJECT ) && + (oclass = g_type_class_peek( otype )) ) + return( oclass->output_needs_arg ); + + return( FALSE ); } static void @@ -1142,7 +1150,9 @@ vips_object_get_argument_to_string( VipsObject *object, VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object ); GParamSpec *pspec; + GType otype; VipsArgumentClass *argument_class; + VipsObjectClass *oclass; #ifdef DEBUG printf( "vips_object_get_argument_to_string: %s -> %s\n", @@ -1155,18 +1165,20 @@ vips_object_get_argument_to_string( VipsObject *object, G_OBJECT_TYPE_NAME( object ), name ); return( -1 ); } + otype = G_PARAM_SPEC_VALUE_TYPE( pspec ); 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; + if( g_type_is_a( otype, VIPS_TYPE_OBJECT ) && + (oclass = g_type_class_peek( otype )) && + oclass->output_to_arg ) { + VipsObject *value; g_object_get( object, name, &value, NULL ); - if( vips_image_write( value, arg ) ) { + if( oclass->output_to_arg( value, arg ) ) { g_object_unref( value ); return( -1 ); }