make CLI arg handling into vfuncs

add vfuncs to vipsobject for the CLI interface
This commit is contained in:
John Cupitt 2011-05-24 14:44:23 +01:00
parent 26c0ce8fde
commit 0b902bfbd4
7 changed files with 102 additions and 52 deletions

22
TODO
View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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.
*/

View File

@ -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 ) {

View File

@ -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.
*
* <itemizedlist>
@ -1524,7 +1542,7 @@ vips_image_new_array( VipsObject *parent, VipsImage **images, int n )
* <para>
* <emphasis>"r"</emphasis>
* 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 <emphasis>"r"</emphasis> 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 )
* <emphasis>"rd"</emphasis>
* 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 );

View File

@ -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 );
}