clean up options in image filenames

allow new-style options everywhere with the addition and use of
vips_foreign_write_options() and friends everywhere
This commit is contained in:
John Cupitt 2011-12-12 14:51:41 +00:00
parent 968c84e478
commit 5bc26b0b65
6 changed files with 132 additions and 99 deletions

View File

@ -58,6 +58,8 @@
- "header" is terse by default
- "header" outputs filenames if working on many files
- added openslide support (Benjamin Gilbert)
- allow new-style load/save options in filenames to
vips_image_new_from_file() etc.
12/10/11 started 7.26.6
- NOCACHE was not being set correctly on OS X causing performance

32
TODO
View File

@ -1,35 +1,3 @@
- we suffs on load as well for nip2's file-open dialog
- what should we do?
vips_image_new_from_file( "x.tif[page=12]" );
or maybe:
vips_image_new_from_file( "x.tif", "page", 12, NULL );
or maybe neither? we'd like this to work though:
header x.tif[page=12]
object_new_from_string()?
- "header fred.png" does not work, since header uses im_open() which uses
VipsForeign

View File

@ -645,7 +645,7 @@ vips_foreign_save_print_class( VipsObjectClass *object_class, VipsBuf *buf )
/* Can we write this filename with this file?
*/
static void *
vips_foreign_save_new_from_foreignname_sub( VipsForeignSaveClass *save_class,
vips_foreign_find_save_sub( VipsForeignSaveClass *save_class,
const char *filename )
{
VipsForeignClass *class = VIPS_FOREIGN_CLASS( save_class );
@ -674,7 +674,7 @@ vips_foreign_find_save( const char *filename )
if( !(save_class = (VipsForeignSaveClass *) vips_foreign_map(
"VipsForeignSave",
(VipsSListMap2Fn) vips_foreign_save_new_from_foreignname_sub,
(VipsSListMap2Fn) vips_foreign_find_save_sub,
(void *) filename, NULL )) ) {
vips_error( "VipsForeignSave",
_( "\"%s\" is not a supported image file." ),
@ -954,7 +954,7 @@ vips_foreign_save_init( VipsForeignSave *object )
* Loads @filename into @out using the loader recommended by
* vips_foreign_find_load().
*
* See also: vips_foreign_write().
* See also: vips_foreign_write(), vips_foreign_read_options().
*
* Returns: 0 on success, -1 on error
*/
@ -979,6 +979,7 @@ vips_foreign_read( const char *filename, VipsImage **out, ... )
* vips_foreign_write:
* @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().
@ -1004,6 +1005,95 @@ vips_foreign_write( VipsImage *in, const char *filename, ... )
return( result );
}
/**
* vips_foreign_read_options:
* @filename: file to load
* @out: output image
*
* 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.
*
* See also: vips_foreign_read().
*
* Returns: 0 on success, -1 on error
*/
int
vips_foreign_read_options( const char *filename, VipsImage **out )
{
VipsObjectClass *oclass = g_type_class_ref( VIPS_TYPE_FOREIGN_LOAD );
VipsObject *object;
/* This will use vips_foreign_load_new_from_string() to pick a loader,
* then set options from the remains of the string.
*/
if( !(object = vips_object_new_from_string( oclass, filename )) )
return( -1 );
if( vips_cache_operation_build( (VipsOperation **) &object ) ) {
/* The build may have made some output objects before
* failing.
*/
vips_object_unref_outputs( object );
g_object_unref( object );
return( -1 );
}
g_object_get( object, "out", out, NULL );
/* Getting @out will have upped its count so it'll be safe.
* We can junk all other outputs,
*/
vips_object_unref_outputs( object );
/* @out holds a ref to new_object, we can drop ours.
*/
g_object_unref( object );
return( 0 );
}
/**
* vips_foreign_write_options:
* @in: image to write
* @filename: file to write to
*
* Saves @in to @filename using the saver recommended by
* vips_foreign_find_save().
*
* See also: vips_foreign_write().
*
* Returns: 0 on success, -1 on error
*/
int
vips_foreign_write_options( VipsImage *in, const char *filename )
{
VipsObjectClass *oclass = g_type_class_ref( VIPS_TYPE_FOREIGN_SAVE );
VipsObject *object;
/* This will use vips_foreign_save_new_from_string() to pick a saver,
* then set options from the tail of the filename.
*/
if( !(object = vips_object_new_from_string( oclass, filename )) )
return( -1 );
g_object_set( object, "in", in, NULL );
/* ... and running _build() should save it.
*/
if( vips_cache_operation_build( (VipsOperation **) &object ) ) {
g_object_unref( object );
return( -1 );
}
g_object_unref( object );
return( 0 );
}
/* Called from iofuncs to init all operations in this dir. Use a plugin system
* instead?
*/

View File

@ -233,6 +233,9 @@ int vips_foreign_read( const char *filename, VipsImage **out, ... )
int vips_foreign_write( VipsImage *in, const char *filename, ... )
__attribute__((sentinel));
int vips_foreign_read_options( const char *filename, VipsImage **out );
int vips_foreign_write_options( VipsImage *in, const char *filename );
void vips_foreign_operation_init( void );
int vips_openslideload( const char *filename, VipsImage **out, ... )

View File

@ -466,23 +466,13 @@ vips_image_rewind( VipsObject *object )
* to a "p" and on "written" do im_vips2tiff() or whatever.
*/
/* From "written" callback: invoke a delayed save.
/* From "written" callback: invoke a delayed save by building the write object..
*/
static void
vips_image_save_cb( VipsImage *image, int *result, char *filename )
vips_image_save_cb( VipsImage *image, int *result, VipsObject *write )
{
if( vips_foreign_write( image, filename, NULL ) )
if( vips_object_build( write ) )
*result = -1;
g_free( filename );
}
static void
vips_attach_save( VipsImage *image, const char *filename )
{
g_signal_connect( image, "written",
G_CALLBACK( vips_image_save_cb ),
g_strdup( filename ) );
}
/* Progress feedback.
@ -627,7 +617,7 @@ vips_image_build( VipsObject *object )
else {
VipsImage *t;
if( vips_foreign_read( filename, &t, NULL ) )
if( vips_foreign_read_options( filename, &t ) )
return( -1 );
image->dtype = VIPS_IMAGE_PARTIAL;
@ -642,21 +632,36 @@ vips_image_build( VipsObject *object )
case 'w':
{
const char *file_op;
VipsObjectClass *oclass =
g_type_class_ref( VIPS_TYPE_FOREIGN_SAVE );
VipsObject *object;
if( !(file_op = vips_foreign_find_save( filename )) )
/* This will use vips_foreign_save_new_from_string() to pick a
* saver, then set options from the tail of the filename.
*/
if( !(object = vips_object_new_from_string( oclass,
filename )) )
return( -1 );
vips_object_local( image, object );
/* Make sure the vips saver is there ... strange things will
* happen if that type is renamed or removed.
*/
g_assert( g_type_from_name( "VipsForeignSaveVips" ) );
if( strcmp( file_op, "VipsForeignSaveVips" ) == 0 )
/* If this ia the vips saver, just save directly ourselves.
* Otherwise trigger a _build() and save when the image has
* been written to.
*/
if( G_TYPE_CHECK_INSTANCE_TYPE( object,
g_type_from_name( "VipsForeignSaveVips" ) ) ) {
image->dtype = VIPS_IMAGE_OPENOUT;
}
else {
image->dtype = VIPS_IMAGE_PARTIAL;
vips_attach_save( image, filename );
g_signal_connect( image, "written",
G_CALLBACK( vips_image_save_cb ),
object );
}
}
break;

View File

@ -1250,8 +1250,8 @@ vips_object_set_argument_from_string( VipsObject *object,
GParamSpec *pspec;
VipsArgumentClass *argument_class;
VipsArgumentInstance *argument_instance;
GType otype;
VipsObjectClass *oclass;
GType otype;
GValue gvalue = { 0 };
@ -1266,39 +1266,15 @@ vips_object_set_argument_from_string( VipsObject *object,
g_assert( argument_class->flags & VIPS_ARGUMENT_INPUT );
if( g_type_is_a( otype, VIPS_TYPE_IMAGE ) &&
(oclass = g_type_class_ref( VIPS_TYPE_FOREIGN_LOAD )) ) {
VipsObject *new_object;
if( g_type_is_a( otype, VIPS_TYPE_IMAGE ) ) {
VipsImage *out;
/* Use VipsForeign to build images, then pull @out from it and
* use that to set the value.
/* Read the filename. vips_foreign_read_options()
* handles embedded options.
*/
if( !(new_object =
vips_object_new_from_string( oclass, value )) )
if( vips_foreign_read_options( value, &out ) )
return( -1 );
if( vips_cache_operation_build(
(VipsOperation **) &new_object ) ) {
/* The build may have made some output objects before
* failing.
*/
vips_object_unref_outputs( new_object );
g_object_unref( new_object );
return( -1 );
}
g_object_get( new_object, "out", &out, NULL );
/* Getting @out will have upped its count so it'll be safe.
* We can junk all other outputs,
*/
vips_object_unref_outputs( new_object );
/* @out holds a ref to new_object, we can drop ours.
*/
g_object_unref( new_object );
g_value_init( &gvalue, VIPS_TYPE_IMAGE );
g_value_set_object( &gvalue, out );
@ -1460,29 +1436,18 @@ vips_object_get_argument_to_string( VipsObject *object,
g_assert( argument_class->flags & VIPS_ARGUMENT_OUTPUT );
if( g_type_is_a( otype, VIPS_TYPE_IMAGE ) &&
(oclass = g_type_class_ref( VIPS_TYPE_FOREIGN_SAVE )) ) {
VipsObject *new_object;
if( g_type_is_a( otype, VIPS_TYPE_IMAGE ) ) {
VipsImage *in;
/* Use VipsForeign to make a saver, set 'in' on that and run
* build to make it write.
/* Pull out the image and write it.
* vips_foreign_write_options() handles embedded options.
*/
if( !(new_object =
vips_object_new_from_string( oclass, arg )) )
return( -1 );
g_object_get( object, name, &in, NULL );
g_object_set( new_object, "in", in, NULL );
g_object_unref( in );
if( vips_cache_operation_build(
(VipsOperation **) &new_object ) ) {
g_object_unref( new_object );
if( vips_foreign_write_options( in, arg ) ) {
g_object_unref( in );
return( -1 );
}
g_object_unref( new_object );
g_object_unref( in );
}
else if( g_type_is_a( otype, VIPS_TYPE_OBJECT ) &&
(oclass = g_type_class_ref( otype )) &&