From ee1874c5cab0b78cc8ea2fee8b5bdd82820f5c7d Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Sat, 27 Feb 2016 20:37:20 +0000 Subject: [PATCH] much better handling of arrayimage cli args we were not setting the access hint on arrayimage args, so arrayjoin "$(echo *.jpg)" x.tif[bigtiff] --across 10 would open all the jpg images to memory, usually, in random mode now arrayimage args see the operation's access hint (seq in this case), for much better behaviour also, we allow any whitespace as an arg separator in arrayimage from string --- ChangeLog | 1 + libvips/conversion/arrayjoin.c | 7 +++ libvips/include/vips/image.h | 2 + libvips/iofuncs/object.c | 48 +++++++++++++-- libvips/iofuncs/type.c | 108 ++++++++++++++++++++++----------- 5 files changed, 124 insertions(+), 42 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9d063433..e7518ec3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -10,6 +10,7 @@ - sharpen has a new @sigma param, @radius is deprecated - sharpen allows a much greater range of parameters - better handling of deprecated args in python +- much better handling of arrayimage command-line args 27/1/16 started 8.2.3 - fix a crash with SPARC byte-order labq vips images diff --git a/libvips/conversion/arrayjoin.c b/libvips/conversion/arrayjoin.c index 91de3995..712791c2 100644 --- a/libvips/conversion/arrayjoin.c +++ b/libvips/conversion/arrayjoin.c @@ -134,6 +134,10 @@ vips_arrayjoin_build( VipsObject *object ) return( -1 ); in = vips_array_image_get( join->in, &n ); + /* Array length zero means error. + */ + if( n == 0 ) + return( -1 ); /* Move all input images to a common format and number of bands. */ @@ -291,6 +295,7 @@ vips_arrayjoin_class_init( VipsArrayjoinClass *class ) { GObjectClass *gobject_class = G_OBJECT_CLASS( class ); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class ); + VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class ); VIPS_DEBUG_MSG( "vips_arrayjoin_class_init\n" ); @@ -301,6 +306,8 @@ vips_arrayjoin_class_init( VipsArrayjoinClass *class ) vobject_class->description = _( "join an array of images" ); vobject_class->build = vips_arrayjoin_build; + operation_class->flags = VIPS_OPERATION_SEQUENTIAL_UNBUFFERED; + VIPS_ARG_BOXED( class, "in", -1, _( "Input" ), _( "Array of input images" ), diff --git a/libvips/include/vips/image.h b/libvips/include/vips/image.h index 1c354757..ee8d7a6b 100644 --- a/libvips/include/vips/image.h +++ b/libvips/include/vips/image.h @@ -493,6 +493,8 @@ int vips_system( const char *cmd_format, ... ) */ VipsArrayImage *vips_array_image_new( VipsImage **array, int n ); VipsArrayImage *vips_array_image_newv( int n, ... ); +VipsArrayImage *vips_array_image_new_from_string( const char *string, + VipsAccess flags ); VipsArrayImage *vips_array_image_empty( void ); VipsArrayImage *vips_array_image_append( VipsArrayImage *array, VipsImage *image ); diff --git a/libvips/iofuncs/object.c b/libvips/iofuncs/object.c index c7412e2a..6e311381 100644 --- a/libvips/iofuncs/object.c +++ b/libvips/iofuncs/object.c @@ -1818,16 +1818,16 @@ vips_object_set_argument_from_string( VipsObject *object, VipsOperationFlags flags; VipsAccess access; - flags = 0; - if( VIPS_IS_OPERATION( object ) ) - flags = vips_operation_get_flags( - VIPS_OPERATION( object ) ); - if( !value ) { vips_object_no_value( object, name ); return( -1 ); } + flags = 0; + if( VIPS_IS_OPERATION( object ) ) + flags = vips_operation_get_flags( + VIPS_OPERATION( object ) ); + /* Read the filename. */ if( flags & VIPS_OPERATION_SEQUENTIAL_UNBUFFERED ) @@ -1850,6 +1850,44 @@ vips_object_set_argument_from_string( VipsObject *object, */ g_object_unref( out ); } + else if( g_type_is_a( otype, VIPS_TYPE_ARRAY_IMAGE ) ) { + /* We have to have a special case for this, we can't just rely + * on transform_g_string_array_image(), since we need to be + * able to set the access hint on the image. + */ + VipsArrayImage *array_image; + VipsOperationFlags flags; + VipsAccess access; + + if( !value ) { + vips_object_no_value( object, name ); + return( -1 ); + } + + flags = 0; + if( VIPS_IS_OPERATION( object ) ) + flags = vips_operation_get_flags( + VIPS_OPERATION( object ) ); + + if( flags & VIPS_OPERATION_SEQUENTIAL_UNBUFFERED ) + access = VIPS_ACCESS_SEQUENTIAL_UNBUFFERED; + else if( flags & VIPS_OPERATION_SEQUENTIAL ) + access = VIPS_ACCESS_SEQUENTIAL; + else + access = VIPS_ACCESS_RANDOM; + + if( !(array_image = + vips_array_image_new_from_string( value, access )) ) + return( -1 ); + + g_value_init( &gvalue, VIPS_TYPE_ARRAY_IMAGE ); + g_value_set_boxed( &gvalue, array_image ); + + /* Setting gvalue will have upped @array_image's count again, + * go back to 1 so that gvalue has the only ref. + */ + vips_area_unref( (VipsArea *) array_image ); + } else if( g_type_is_a( otype, VIPS_TYPE_OBJECT ) && (oclass = g_type_class_ref( otype )) ) { VipsObject *new_object; diff --git a/libvips/iofuncs/type.c b/libvips/iofuncs/type.c index 192e86ea..23ca5919 100644 --- a/libvips/iofuncs/type.c +++ b/libvips/iofuncs/type.c @@ -1089,43 +1089,6 @@ vips_array_double_get_type( void ) return( type ); } -static void -transform_g_string_array_image( const GValue *src_value, GValue *dest_value ) -{ - char *str; - int n; - char *p, *q; - int i; - VipsImage **array; - - /* We need a copy of the string, since we insert \0 during - * scan. - */ - str = g_value_dup_string( src_value ); - - n = 0; - for( p = str; (q = vips_break_token( p, " " )); p = q ) - n += 1; - - g_free( str ); - - vips_value_set_array_image( dest_value, n ); - array = vips_value_get_array_image( dest_value, NULL ); - - str = g_value_dup_string( src_value ); - - for( i = 0, p = str; (q = vips_break_token( p, " " )); i++, p = q ) - if( !(array[i] = vips_image_new_from_file( p, NULL )) ) { - /* Set the dest to length zero to indicate error. - */ - vips_value_set_array_image( dest_value, 0 ); - g_free( str ); - return; - } - - g_free( str ); -} - /** * vips_array_image_new: * @array: (array length=n): array of #VipsImage @@ -1205,6 +1168,52 @@ vips_array_image_newv( int n, ... ) return( (VipsArrayImage *) area ); } +VipsArrayImage * +vips_array_image_new_from_string( const char *string, VipsAccess access ) +{ + char *str; + int n; + VipsArea *area; + VipsImage **array; + char *p, *q; + int i; + + /* We need a copy of the string, since we insert \0 during + * scan. + */ + str = g_strdup( string ); + + n = 0; + for( p = str; (q = vips_break_token( p, " \n\t\r" )); p = q ) + n += 1; + + g_free( str ); + + area = vips_area_new_array_object( n ); + area->type = VIPS_TYPE_IMAGE; + + array = vips_area_get_data( area, NULL, NULL, NULL, NULL ); + + str = g_strdup( string ); + + i = 0; + for( p = str; (q = vips_break_token( p, " \n\t\r" )); p = q ) { + if( !(array[i] = vips_image_new_from_file( p, + "access", access, + NULL )) ) { + vips_area_unref( area ); + g_free( str ); + return( NULL ); + } + + i += 1; + } + + g_free( str ); + + return( (VipsArrayImage *) area ); +} + /** * vips_array_image_empty: * @@ -1284,6 +1293,31 @@ vips_array_image_get( VipsArrayImage *array, int *n ) return( (VipsImage **) VIPS_ARRAY_ADDR( array, 0 ) ); } +static void +transform_g_string_array_image( const GValue *src_value, GValue *dest_value ) +{ + char *str; + VipsArrayImage *array_image; + + str = g_value_dup_string( src_value ); + + /* We can't get access here, just assume nothing. See the special case + * in vips_object_new_from_string() for how we usually get this right. + */ + if( !(array_image = vips_array_image_new_from_string( str, 0 )) ) { + /* Set the dest to length zero to indicate error. + */ + vips_value_set_array_image( dest_value, 0 ); + g_free( str ); + return; + } + + g_free( str ); + + g_value_set_boxed( dest_value, array_image ); + vips_area_unref( (VipsArea *) array_image ); +} + GType vips_array_image_get_type( void ) {