diff --git a/ChangeLog b/ChangeLog index 84e5ac5a..5af03869 100644 --- a/ChangeLog +++ b/ChangeLog @@ -11,6 +11,7 @@ - add :seq support to im_tiff2vips(), im_jpeg2vips() ... helps ruby-vips - better thread safety for vips8 operation dispatch - better thread safety for upstream / downstream image linking +- added "rs" open mode, removed "rd" 18/6/12 started 7.28.9 - slightly more memory debugging output diff --git a/TODO b/TODO index aea08dad..a1a19b70 100644 --- a/TODO +++ b/TODO @@ -1,26 +1,12 @@ -- have made vips_operation_set_valist_optional into a general thing on - vipsobject - vips_object_setv( VipsObject, va_list list ); +- test "rs" mode - needs docs + can't see the code for "rd" mode? + + or "rw" mode either? -- should - - vips_image_new_mode () - - have "rs" mode? ie. open for sequential read? - - it's a property of in VipsForeignLoad - - vips_foreign_load_options() needs to take a va_list of optional extra args, - use that to set seq - - look for analogues to vips_foreign_load_options() which need to be va_list'd - as well - - need a flag on operations for "is sequential" should be on the object, not the class, since it can change with params diff --git a/libvips/foreign/foreign.c b/libvips/foreign/foreign.c index 15a09d3b..1ca49054 100644 --- a/libvips/foreign/foreign.c +++ b/libvips/foreign/foreign.c @@ -1489,23 +1489,27 @@ vips_foreign_save( VipsImage *in, const char *filename, ... ) * vips_foreign_load_options: * @filename: file to load * @out: output image + * @...: %NULL-terminated list of optional named arguments * * Loads @filename into @out using the loader recommended by * vips_foreign_find_load(). * * Arguments to the loader may be embedded in the filename using the usual - * syntax. + * syntax. They may also be given as a set of NULL-terminated optional + * arguments. * * See also: vips_foreign_load(). * * Returns: 0 on success, -1 on error */ int -vips_foreign_load_options( const char *filename, VipsImage **out ) +vips_foreign_load_options( const char *filename, VipsImage **out, ... ) { VipsObjectClass *oclass = g_type_class_ref( VIPS_TYPE_FOREIGN_LOAD ); VipsObject *object; + va_list ap; + int result; /* This will use vips_foreign_load_new_from_string() to pick a loader, * then set options from the remains of the string. @@ -1513,6 +1517,14 @@ vips_foreign_load_options( const char *filename, VipsImage **out ) if( !(object = vips_object_new_from_string( oclass, filename )) ) return( -1 ); + /* Also set options from args. + */ + va_start( ap, out ); + result = vips_object_set_valist( object, ap ); + va_end( ap ); + if( result ) + return( -1 ); + if( vips_cache_operation_buildp( (VipsOperation **) &object ) ) { /* The build may have made some output objects before * failing. @@ -1540,22 +1552,27 @@ vips_foreign_load_options( const char *filename, VipsImage **out ) * vips_foreign_save_options: * @in: image to write * @filename: file to write to + * @...: %NULL-terminated list of optional named arguments * * Saves @in to @filename using the saver recommended by * vips_foreign_find_save(). * * Arguments to the saver may be embedded in the filename using the usual - * syntax. + * syntax. They may also be given as a set of NULL-terminated optional + * arguments. * * See also: vips_foreign_save(). * * Returns: 0 on success, -1 on error */ int -vips_foreign_save_options( VipsImage *in, const char *filename ) +vips_foreign_save_options( VipsImage *in, const char *filename, ... ) { VipsObjectClass *oclass = g_type_class_ref( VIPS_TYPE_FOREIGN_SAVE ); + VipsObject *object; + va_list ap; + int result; /* This will use vips_foreign_save_new_from_string() to pick a saver, * then set options from the tail of the filename. @@ -1565,6 +1582,14 @@ vips_foreign_save_options( VipsImage *in, const char *filename ) g_object_set( object, "in", in, NULL ); + /* Also set options from args. + */ + va_start( ap, filename ); + result = vips_object_set_valist( object, ap ); + va_end( ap ); + if( result ) + return( -1 ); + /* ... and running _build() should save it. */ if( vips_cache_operation_buildp( (VipsOperation **) &object ) ) { diff --git a/libvips/include/vips/foreign.h b/libvips/include/vips/foreign.h index e6829851..a1d42e40 100644 --- a/libvips/include/vips/foreign.h +++ b/libvips/include/vips/foreign.h @@ -294,8 +294,10 @@ int vips_foreign_load( const char *filename, VipsImage **out, ... ) int vips_foreign_save( VipsImage *in, const char *filename, ... ) __attribute__((sentinel)); -int vips_foreign_load_options( const char *filename, VipsImage **out ); -int vips_foreign_save_options( VipsImage *in, const char *filename ); +int vips_foreign_load_options( const char *filename, VipsImage **out, ... ) + __attribute__((sentinel)); +int vips_foreign_save_options( VipsImage *in, const char *filename, ... ) + __attribute__((sentinel)); int vips_openslideload( const char *filename, VipsImage **out, ... ) __attribute__((sentinel)); diff --git a/libvips/iofuncs/image.c b/libvips/iofuncs/image.c index accbdff8..20ec4395 100644 --- a/libvips/iofuncs/image.c +++ b/libvips/iofuncs/image.c @@ -308,7 +308,7 @@ vips_image_new_from_file_object( const char *string ) image = VIPS_IMAGE( g_object_new( VIPS_TYPE_IMAGE, NULL ) ); g_object_set( image, "filename", string, - "mode", "rd", + "mode", "r", NULL ); return( VIPS_OBJECT( image ) ); @@ -508,7 +508,7 @@ vips_image_rewind( VipsObject *object ) static void vips_image_save_cb( VipsImage *image, int *result ) { - if( vips_foreign_save_options( image, image->filename ) ) + if( vips_foreign_save_options( image, image->filename, NULL ) ) *result = -1; } @@ -655,8 +655,17 @@ vips_image_build( VipsObject *object ) else { VipsImage *t; - if( vips_foreign_load_options( filename, &t ) ) - return( -1 ); + if( mode[1] == 's' ) { + if( vips_foreign_load_options( filename, &t, + "sequential", TRUE, + NULL ) ) + return( -1 ); + } + else { + if( vips_foreign_load_options( filename, &t, + NULL ) ) + return( -1 ); + } image->dtype = VIPS_IMAGE_PARTIAL; if( vips_image_write( t, image ) ) { @@ -1370,28 +1379,20 @@ vips_image_new( void ) * VIPS format for your machine, vips_image_new_mode() * automatically converts the file for you. * - * For some large files (eg. TIFF) this may - * not be what you want, it can fill memory very quickly. Instead, you - * can either use "rd" mode (see below), or you can use the lower-level + * Some formats (eg. tiled tiff) are read directly. + * + * Some formats (eg. strip tiff) do not support random access and can't + * be processed directly. Small images are decompressed to memory and + * loaded from there, large images are decompressed to a disc file and + * processed from that. + * + * If the operations you intend to perform are sequential, that is, they + * operate in a strict top-to-bottom manner, you can use sequential mode + * instead, see "rs" below, + * or you can use the lower-level * API and control the loading process yourself. See * #VipsForeign. * - * 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 - * only actually read in pixels when you first access them. - * - * - * - * - * "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_mode() will - * uncompress to a temporary disc file. This file will be automatically - * deleted when the VipsImage is closed. - * * See im_system_image() for an explanation of how VIPS selects a * location for the temporary file. * @@ -1408,6 +1409,20 @@ vips_image_new( void ) * * will copy via disc if "fred.tif" is more than 500 Mbytes * uncompressed. The default threshold is 100 MB. + * + * Note that "r" mode works in at least two stages. + * It should return quickly and let you check header fields. It will + * only actually read in pixels when you first access them. + * + * + * + * + * "rs" + * opens the named file for reading sequentially. It reads the source + * image top-to-bottom and serves up pixels to the pipeline as required. + * Provided the operations that connect to the image all demand pixels +* only top-to-bottom as well, everything is fine and you avoid the +* separate decompress stage. * * * @@ -1479,7 +1494,7 @@ vips_image_new_buffer( void ) * vips_image_new_from_file: * @filename: file to open * - * vips_image_new_from_file() opens @filename for reading in mode "rd". See + * vips_image_new_from_file() opens @filename for reading in mode "r". See * vips_image_new_mode() for details. * * See also: vips_image_new_mode(). @@ -1489,7 +1504,7 @@ vips_image_new_buffer( void ) VipsImage * vips_image_new_from_file( const char *filename ) { - return( vips_image_new_mode( filename, "rd" ) ); + return( vips_image_new_mode( filename, "r" ) ); } /** diff --git a/libvips/iofuncs/object.c b/libvips/iofuncs/object.c index a438e777..d809fe48 100644 --- a/libvips/iofuncs/object.c +++ b/libvips/iofuncs/object.c @@ -1470,7 +1470,7 @@ vips_object_set_argument_from_string( VipsObject *object, /* Read the filename. vips_foreign_load_options() * handles embedded options. */ - if( vips_foreign_load_options( value, &out ) ) + if( vips_foreign_load_options( value, &out, NULL ) ) return( -1 ); g_value_init( &gvalue, VIPS_TYPE_IMAGE ); @@ -1684,7 +1684,7 @@ vips_object_get_argument_to_string( VipsObject *object, * vips_foreign_save_options() handles embedded options. */ g_object_get( object, name, &in, NULL ); - if( vips_foreign_save_options( in, arg ) ) { + if( vips_foreign_save_options( in, arg, NULL ) ) { g_object_unref( in ); return( -1 ); } @@ -1772,6 +1772,15 @@ vips_object_new( GType type, VipsObjectSetArguments set, void *a, void *b ) return( object ); } +/** + * vips_object_set_valist: + * @object: object to set arguments on + * @ap: %NULL-terminated list of argument/value pairs + * + * See vips_object_set(). + * + * Returns: 0 on success, -1 on error + */ int vips_object_set_valist( VipsObject *object, va_list ap ) { @@ -1807,6 +1816,27 @@ vips_object_set_valist( VipsObject *object, va_list ap ) return( 0 ); } +/** + * vips_object_set: + * @object: object to set arguments on + * @...: %NULL-terminated list of argument/value pairs + * + * Set a list of vips object arguments. For example: + * + * |[ + * vips_object_set (operation, + * "input", in, + * "output", &out, + * NULL); + * ]| + * + * Input arguments are given in-line, output arguments are given as pointers + * to where the output value should be written. + * + * See also: vips_object_set_valist(). + * + * Returns: 0 on success, -1 on error + */ int vips_object_set( VipsObject *object, ... ) { diff --git a/libvips/iofuncs/operation.c b/libvips/iofuncs/operation.c index 6f0e61e3..7c6cda0d 100644 --- a/libvips/iofuncs/operation.c +++ b/libvips/iofuncs/operation.c @@ -471,7 +471,7 @@ vips_call_required_optional( VipsOperation **operation, va_copy( a, required ); va_copy( b, optional ); result = vips_operation_set_valist_required( *operation, a ) || - vips_object_set_valist( *operation, b ); + vips_object_set_valist( VIPS_OBJECT( *operation ), b ); va_end( a ); va_end( b );