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