diff --git a/TODO b/TODO index 39e6461e..cd595f85 100644 --- a/TODO +++ b/TODO @@ -1,5 +1,15 @@ - VipsCopy needs optional params for all header fields it can change + need a vips_argument_lookup(), see vips_argument_map(), since we need to + be able to find out if an optional arg has been set + + added vips_object_get_argument(), look for use of + g_object_class_find_property() and swap for new thing, then back to copy.c + + operation.c could use it too in places + + copy.c things to set interpretation etc. could go into image.c + how would we do meta sets? copy_swap needs doing too, a separate class I guess diff --git a/libvips/conversion/copy.c b/libvips/conversion/copy.c index c7f0cf18..c609a429 100644 --- a/libvips/conversion/copy.c +++ b/libvips/conversion/copy.c @@ -89,8 +89,8 @@ /** * VipsCopy: - * @in: input image - * @out: output image + * @input: input image + * @output: output image * * Copy an image, optionally modifying the header. VIPS copies images by * copying pointers, so this operation is fast, even for very large images. @@ -102,6 +102,18 @@ */ enum { PROP_INPUT = 1, + + PROP_INTERPRETATION, + PROP_XRES, + PROP_YRES, + PROP_XOFFSET, + PROP_YOFFSET, + PROP_BANDS, + PROP_FORMAT, + PROP_CODING, + PROP_WIDTH, + PROP_HEIGHT, + PROP_LAST }; @@ -111,6 +123,20 @@ typedef struct _VipsCopy { /* The input image. */ VipsImage *input; + + /* Fields we can optionally set on the way through. + */ + VipsInterpretation interpretation; + double xres; + double yres; + int xoffset; + int yoffset; + int bands; + VipsBandFormat format; + VipsCoding coding; + int width; + int height; + } VipsCopy; typedef VipsConversionClass VipsCopyClass; @@ -180,8 +206,6 @@ vips_copy_class_init( VipsCopyClass *class ) vobject_class->description = _( "copy an image" ); vobject_class->build = vips_copy_build; - /* Create properties. - */ pspec = g_param_spec_object( "input", "Input", "Input image argument", VIPS_TYPE_IMAGE, @@ -192,6 +216,97 @@ vips_copy_class_init( VipsCopyClass *class ) VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET( VipsCopy, input ) ); + pspec = g_param_spec_enum( "interpretation", "Interpretation", + _( "Pixel interpretation" ), + VIPS_TYPE_INTERPRETATION, VIPS_INTERPRETATION_MULTIBAND, + G_PARAM_READWRITE ); + g_object_class_install_property( gobject_class, + PROP_INTERPRETATION, pspec ); + vips_object_class_install_argument( vobject_class, pspec, + VIPS_ARGUMENT_SET_ONCE, + G_STRUCT_OFFSET( VipsCopy, interpretation ) ); + + pspec = g_param_spec_double( "xres", "XRes", + _( "Horizontal resolution in pixels/mm" ), + 0, 1000000, 0, + G_PARAM_READWRITE ); + g_object_class_install_property( gobject_class, PROP_XRES, pspec ); + vips_object_class_install_argument( vobject_class, pspec, + VIPS_ARGUMENT_SET_ONCE, + G_STRUCT_OFFSET( VipsCopy, xres ) ); + + pspec = g_param_spec_double( "yres", "YRes", + _( "Vertical resolution in pixels/mm" ), + 0, 1000000, 0, + G_PARAM_READWRITE ); + g_object_class_install_property( gobject_class, PROP_YRES, pspec ); + vips_object_class_install_argument( vobject_class, pspec, + VIPS_ARGUMENT_SET_ONCE, + G_STRUCT_OFFSET( VipsCopy, yres ) ); + + pspec = g_param_spec_int( "xoffset", "XOffset", + _( "Horizontal offset of origin" ), + -10000000, 1000000, 0, + G_PARAM_READWRITE ); + g_object_class_install_property( gobject_class, PROP_XOFFSET, pspec ); + vips_object_class_install_argument( vobject_class, pspec, + VIPS_ARGUMENT_SET_ONCE, + G_STRUCT_OFFSET( VipsCopy, xoffset ) ); + + pspec = g_param_spec_int( "yoffset", "YOffset", + _( "Vertical offset of origin" ), + -10000000, 1000000, 0, + G_PARAM_READWRITE ); + g_object_class_install_property( gobject_class, PROP_YOFFSET, pspec ); + vips_object_class_install_argument( vobject_class, pspec, + VIPS_ARGUMENT_SET_ONCE, + G_STRUCT_OFFSET( VipsCopy, yoffset ) ); + + pspec = g_param_spec_int( "bands", "Bands", + _( "Number of bands in image" ), + 0, 1000000, 0, + G_PARAM_READWRITE ); + g_object_class_install_property( gobject_class, PROP_BANDS, pspec ); + vips_object_class_install_argument( vobject_class, pspec, + VIPS_ARGUMENT_SET_ONCE, + G_STRUCT_OFFSET( VipsCopy, bands ) ); + + pspec = g_param_spec_enum( "format", "Format", + _( "Pixel format in image" ), + VIPS_TYPE_BAND_FORMAT, VIPS_FORMAT_UCHAR, + G_PARAM_READWRITE ); + g_object_class_install_property( gobject_class, PROP_FORMAT, pspec ); + vips_object_class_install_argument( vobject_class, pspec, + VIPS_ARGUMENT_SET_ONCE, + G_STRUCT_OFFSET( VipsCopy, format ) ); + + pspec = g_param_spec_enum( "coding", "Coding", + _( "Pixel coding" ), + VIPS_TYPE_CODING, VIPS_CODING_NONE, + G_PARAM_READWRITE ); + g_object_class_install_property( gobject_class, PROP_FORMAT, pspec ); + vips_object_class_install_argument( vobject_class, pspec, + VIPS_ARGUMENT_SET_ONCE, + G_STRUCT_OFFSET( VipsCopy, coding ) ); + + pspec = g_param_spec_int( "width", "Width", + _( "Image width in pixels" ), + 0, 1000000, 0, + G_PARAM_READWRITE ); + g_object_class_install_property( gobject_class, PROP_WIDTH, pspec ); + vips_object_class_install_argument( vobject_class, pspec, + VIPS_ARGUMENT_SET_ONCE, + G_STRUCT_OFFSET( VipsCopy, width ) ); + + pspec = g_param_spec_int( "height", "Height", + _( "Image height in pixels" ), + 0, 1000000, 0, + G_PARAM_READWRITE ); + g_object_class_install_property( gobject_class, PROP_HEIGHT, pspec ); + vips_object_class_install_argument( vobject_class, pspec, + VIPS_ARGUMENT_SET_ONCE, + G_STRUCT_OFFSET( VipsCopy, height ) ); + } static void diff --git a/libvips/include/vips/object.h b/libvips/include/vips/object.h index 89e6b746..5607a0d2 100644 --- a/libvips/include/vips/object.h +++ b/libvips/include/vips/object.h @@ -168,6 +168,10 @@ typedef void *(*VipsArgumentMapFn)( VipsObject *, GParamSpec *, void *vips_argument_map( VipsObject *object, VipsArgumentMapFn fn, void *a, void *b ); void vips_argument_dispose_all( VipsObject *object ); +int vips_object_get_argument( VipsObject *object, const char *name, + GParamSpec **pspec, + VipsArgumentClass **argument_class, + VipsArgumentInstance **argument_instance ); /* We have to loop over an objects args in several places, and we can't always * use vips_argument_map(), the preferred looper. Have the loop code as a diff --git a/libvips/iofuncs/object.c b/libvips/iofuncs/object.c index ec8ebe30..bd06ae65 100644 --- a/libvips/iofuncs/object.c +++ b/libvips/iofuncs/object.c @@ -388,6 +388,44 @@ vips__argument_get_instance( VipsArgumentClass *argument_class, ((VipsArgument *) argument_class)->pspec ) ); } +/* Look up the three things you need to work with a vips argument. + */ +int +vips_object_get_argument( VipsObject *object, const char *name, + GParamSpec **pspec, + VipsArgumentClass **argument_class, + VipsArgumentInstance **argument_instance ) +{ + VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object ); + + if( !(*pspec = g_object_class_find_property( + G_OBJECT_CLASS( class ), name )) ) { + vips_error( VIPS_OBJECT_CLASS( class )->description, + _( "class `%s' has no property named `%s'" ), + G_OBJECT_TYPE_NAME( object ), name ); + return( -1 ); + } + + if( !(*argument_class = (VipsArgumentClass *) + vips__argument_table_lookup( class->argument_table, + *pspec )) ) { + vips_error( VIPS_OBJECT_CLASS( class )->description, + _( "class `%s' has no vips argument named `%s'" ), + G_OBJECT_TYPE_NAME( object ), name ); + return( -1 ); + } + if( argument_class && + !(*argument_instance = vips__argument_get_instance( + *argument_class, object )) ) { + vips_error( VIPS_OBJECT_CLASS( class )->description, + _( "vips argument `%s' has no instance" ), + G_OBJECT_TYPE_NAME( object ), name ); + return( -1 ); + } + + return( 0 ); +} + static void vips_object_clear_member( VipsObject *object, GParamSpec *pspec, GObject **member ) @@ -1158,12 +1196,12 @@ int vips_object_set_argument_from_string( VipsObject *object, const char *name, const char *value ) { - VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object ); - GParamSpec *pspec; - GType otype; VipsArgumentClass *argument_class; + VipsArgumentInstance *argument_instance; + GType otype; VipsObjectClass *oclass; + GValue gvalue = { 0 }; #ifdef DEBUG @@ -1171,16 +1209,11 @@ vips_object_set_argument_from_string( VipsObject *object, name, value ); #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 ); + if( vips_object_get_argument( object, name, + &pspec, &argument_class, &argument_instance ) ) return( -1 ); - } - otype = G_PARAM_SPEC_VALUE_TYPE( pspec ); - argument_class = (VipsArgumentClass *) - vips__argument_table_lookup( class->argument_table, pspec ); + otype = G_PARAM_SPEC_VALUE_TYPE( pspec ); g_assert( argument_class->flags & VIPS_ARGUMENT_INPUT );