diff --git a/TODO b/TODO index cd595f85..3f8542a4 100644 --- a/TODO +++ b/TODO @@ -14,6 +14,8 @@ copy_swap needs doing too, a separate class I guess + or add a "swap" prop and an enum like VIPS_SWAP8, VIPS_SWAP2 etc.? + - do clip/embed etc. in new style, good to get everything that VipsAdd uses in diff --git a/libvips/conversion/copy.c b/libvips/conversion/copy.c index c609a429..446bf585 100644 --- a/libvips/conversion/copy.c +++ b/libvips/conversion/copy.c @@ -73,6 +73,10 @@ */ +/* + */ +#define VIPS_DEBUG + #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ @@ -84,6 +88,7 @@ #include #include +#include #include "conversion.h" @@ -95,14 +100,20 @@ * Copy an image, optionally modifying the header. VIPS copies images by * copying pointers, so this operation is fast, even for very large images. * + * You can optionally set any or all header fields during the copy. Some + * header fields, such as "xres", the horizontal resolution, are safe to + * change in any way, others, such as "width" will cause immediate crashes if + * they are not set carefully. + * * Returns: 0 on success, -1 on error. */ /* Properties. + * + * Order important! Keep in sync with vips_copy_names[] below. */ enum { PROP_INPUT = 1, - PROP_INTERPRETATION, PROP_XRES, PROP_YRES, @@ -164,12 +175,31 @@ vips_copy_gen( VipsRegion *or, void *seq, void *a, void *b, gboolean *stop ) return( 0 ); } +/* The props we copy, if set, from the operation to the image. + */ +static const char *vips_copy_names[] = { + NULL, /* unused */ + NULL, /* PROP_INPUT = 1 */ + "interpretation", /* PROP_INTERPRETATION, */ + "xres", /* PROP_XRES, */ + "yres", /* PROP_YRES, */ + "xoffset", /* PROP_XOFFSET, */ + "xoffset", /* PROP_YOFFSET, */ + "bands", /* PROP_BANDS, */ + "format", /* PROP_FORMAT, */ + "coding", /* PROP_CODING, */ + "width", /* PROP_WIDTH, */ + "height" /* PROP_HEIGHT, */ +}; + static int vips_copy_build( VipsObject *object ) { VipsConversion *conversion = VIPS_CONVERSION( object ); VipsCopy *copy = (VipsCopy *) object; + int i; + if( VIPS_OBJECT_CLASS( vips_copy_parent_class )->build( object ) ) return( -1 ); @@ -177,12 +207,40 @@ vips_copy_build( VipsObject *object ) vips_image_pio_output( conversion->output ) ) return( -1 ); - /* Use props to adjust header fields. - */ - + if( vips_image_copy_fields( conversion->output, copy->input ) ) + return( -1 ); vips_demand_hint( conversion->output, VIPS_DEMAND_STYLE_THINSTRIP, copy->input, NULL ); + /* Use props to adjust header fields. + */ + for( i = 2; i < PROP_LAST; i++ ) { + const char *name = vips_copy_names[i]; + + GParamSpec *pspec; + VipsArgumentClass *argument_class; + VipsArgumentInstance *argument_instance; + + if( vips_object_get_argument( object, name, + &pspec, &argument_class, &argument_instance ) ) + return( -1 ); + + if( argument_instance->assigned ) { + GType type = G_PARAM_SPEC_VALUE_TYPE( pspec ); + GValue value = { 0, }; + + VIPS_DEBUG_MSG( "vips_copy_build: assigning %s\n", + name ); + + g_value_init( &value, type ); + g_object_get_property( G_OBJECT( object ), + name, &value ); + g_object_set_property( G_OBJECT( conversion->output ), + name, &value ); + g_value_unset( &value ); + } + } + if( vips_image_generate( conversion->output, vips_start_one, vips_copy_gen, vips_stop_one, copy->input, copy ) ) diff --git a/libvips/iofuncs/object.c b/libvips/iofuncs/object.c index bd06ae65..1a1a5818 100644 --- a/libvips/iofuncs/object.c +++ b/libvips/iofuncs/object.c @@ -1260,27 +1260,21 @@ vips_object_set_argument_from_string( VipsObject *object, gboolean 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; + VipsArgumentInstance *argument_instance; VipsObjectClass *oclass; #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 ); + 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_OUTPUT ); @@ -1316,11 +1310,10 @@ int vips_object_get_argument_to_string( VipsObject *object, const char *name, const char *arg ) { - VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object ); - GParamSpec *pspec; GType otype; VipsArgumentClass *argument_class; + VipsArgumentInstance *argument_instance; VipsObjectClass *oclass; #ifdef DEBUG @@ -1328,16 +1321,11 @@ vips_object_get_argument_to_string( VipsObject *object, 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 ); + 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_OUTPUT ); diff --git a/libvips/iofuncs/operation.c b/libvips/iofuncs/operation.c index 9d92c780..a777c12d 100644 --- a/libvips/iofuncs/operation.c +++ b/libvips/iofuncs/operation.c @@ -311,11 +311,6 @@ vips_operation_set_valist_required( VipsOperation *operation, va_list ap ) static int vips_operation_set_valist_optional( VipsOperation *operation, va_list ap ) { - VipsOperationClass *class = - VIPS_OPERATION_GET_CLASS( operation ); - VipsArgumentTable *argument_table = - VIPS_OBJECT_CLASS( class )->argument_table; - char *name; VIPS_DEBUG_MSG( "vips_operation_set_valist_optional:\n" ); @@ -325,29 +320,22 @@ vips_operation_set_valist_optional( VipsOperation *operation, va_list ap ) while( name ) { GParamSpec *pspec; VipsArgumentClass *argument_class; + VipsArgumentInstance *argument_instance; VIPS_DEBUG_MSG( "\tname = '%s' (%p)\n", name, name ); - 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'\n" ), - G_OBJECT_TYPE_NAME( operation ), name ); + if( vips_object_get_argument( VIPS_OBJECT( operation ), name, + &pspec, &argument_class, &argument_instance ) ) return( -1 ); - } - argument_class = (VipsArgumentClass *) - vips__argument_table_lookup( argument_table, pspec ); - if( argument_class ) { - VIPS_OPERATION_COLLECT_SET( pspec, argument_class, ap ); + VIPS_OPERATION_COLLECT_SET( pspec, argument_class, ap ); - g_object_set_property( G_OBJECT( operation ), - name, &value ); + g_object_set_property( G_OBJECT( operation ), + name, &value ); - VIPS_OPERATION_COLLECT_GET( pspec, argument_class, ap ); + VIPS_OPERATION_COLLECT_GET( pspec, argument_class, ap ); - VIPS_OPERATION_COLLECT_END - } + VIPS_OPERATION_COLLECT_END name = va_arg( ap, char * ); } @@ -402,11 +390,6 @@ vips_operation_get_valist_required( VipsOperation *operation, va_list ap ) static int vips_operation_get_valist_optional( VipsOperation *operation, va_list ap ) { - VipsOperationClass *class = - VIPS_OPERATION_GET_CLASS( operation ); - VipsArgumentTable *argument_table = - VIPS_OBJECT_CLASS( class )->argument_table; - char *name; VIPS_DEBUG_MSG( "vips_operation_get_valist_optional:\n" ); @@ -416,54 +399,47 @@ vips_operation_get_valist_optional( VipsOperation *operation, va_list ap ) while( name ) { GParamSpec *pspec; VipsArgumentClass *argument_class; + VipsArgumentInstance *argument_instance; VIPS_DEBUG_MSG( "\tname = '%s' (%p)\n", name, name ); - 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'\n" ), - G_OBJECT_TYPE_NAME( operation ), name ); + if( vips_object_get_argument( VIPS_OBJECT( operation ), name, + &pspec, &argument_class, &argument_instance ) ) return( -1 ); - } - argument_class = (VipsArgumentClass *) - vips__argument_table_lookup( argument_table, pspec ); - if( argument_class ) { - VIPS_OPERATION_COLLECT_SET( pspec, argument_class, ap ); + VIPS_OPERATION_COLLECT_SET( pspec, argument_class, ap ); - g_object_set_property( G_OBJECT( operation ), - name, &value ); + g_object_set_property( G_OBJECT( operation ), + name, &value ); - VIPS_OPERATION_COLLECT_GET( pspec, argument_class, ap ); + VIPS_OPERATION_COLLECT_GET( pspec, argument_class, ap ); #ifdef VIPS_DEBUG - printf( "\twriting %s to %p\n", - g_param_spec_get_name( pspec ), arg ); + printf( "\twriting %s to %p\n", + g_param_spec_get_name( pspec ), arg ); #endif /*VIPS_DEBUG */ - /* If the dest pointer is NULL, skip the read. + /* If the dest pointer is NULL, skip the read. + */ + if( arg ) { + g_object_get( G_OBJECT( operation ), + g_param_spec_get_name( pspec ), arg, + NULL ); + + /* If the pspec is an object, that will up + * the ref count. We want to hand over the + * ref, so we have to knock it down again. */ - if( arg ) { - g_object_get( G_OBJECT( operation ), - g_param_spec_get_name( pspec ), arg, - NULL ); + if( G_IS_PARAM_SPEC_OBJECT( pspec ) ) { + GObject *object; - /* If the pspec is an object, that will up - * the ref count. We want to hand over the - * ref, so we have to knock it down again. - */ - if( G_IS_PARAM_SPEC_OBJECT( pspec ) ) { - GObject *object; - - object = *((GObject **) arg); - g_object_unref( object ); - } + object = *((GObject **) arg); + g_object_unref( object ); } - - VIPS_OPERATION_COLLECT_END } + VIPS_OPERATION_COLLECT_END + name = va_arg( ap, char * ); }