diff --git a/= b/= deleted file mode 100644 index 6b9249b0..00000000 --- a/= +++ /dev/null @@ -1 +0,0 @@ -libheif 1.3 found diff --git a/libvips/Makefile.am b/libvips/Makefile.am index 6288cf33..bc05c661 100644 --- a/libvips/Makefile.am +++ b/libvips/Makefile.am @@ -119,4 +119,5 @@ typelibdir = $(libdir)/girepository-1.0 typelib_DATA = $(INTROSPECTION_GIRS:.gir=.typelib) CLEANFILES += $(gir_DATA) $(typelib_DATA) + endif diff --git a/libvips/foreign/foreign.c b/libvips/foreign/foreign.c index 8ce247af..e9a8b31c 100644 --- a/libvips/foreign/foreign.c +++ b/libvips/foreign/foreign.c @@ -1806,19 +1806,26 @@ vips_foreign_find_save_sub( VipsForeignSaveClass *save_class, VipsObjectClass *object_class = VIPS_OBJECT_CLASS( save_class ); VipsForeignClass *class = VIPS_FOREIGN_CLASS( save_class ); - /* All concrete savers needs suffs, since we use the suff to pick the + const char **p; + + /* All savers needs suffs defined since we use the suff to pick the * saver. */ - if( !G_TYPE_IS_ABSTRACT( G_TYPE_FROM_CLASS( class ) ) && - !class->suffs ) + if( !class->suffs ) g_warning( "no suffix defined for %s", object_class->nickname ); - if( !G_TYPE_IS_ABSTRACT( G_TYPE_FROM_CLASS( class ) ) && - class->suffs && - !vips_ispostfix( object_class->nickname, "_buffer" ) && - !vips_ispostfix( object_class->nickname, "_target" ) && - vips_filename_suffix_match( filename, class->suffs ) ) - return( save_class ); + /* Skip non-file savers. + */ + if( vips_ispostfix( object_class->nickname, "_buffer" ) || + vips_ispostfix( object_class->nickname, "_target" ) ) + return( NULL ); + + /* vips_foreign_find_save() has already removed any options from the + * end of the filename, so we can test directly against the suffix. + */ + for( p = class->suffs; *p; p++ ) + if( vips_iscasepostfix( filename, *p ) ) + return( save_class ); return( NULL ); } @@ -2119,7 +2126,8 @@ vips_foreign_operation_init( void ) extern GType vips_foreign_load_vips_file_get_type( void ); extern GType vips_foreign_load_vips_source_get_type( void ); - extern GType vips_foreign_save_vips_get_type( void ); + extern GType vips_foreign_save_vips_file_get_type( void ); + extern GType vips_foreign_save_vips_target_get_type( void ); extern GType vips_foreign_load_jpeg_file_get_type( void ); extern GType vips_foreign_load_jpeg_buffer_get_type( void ); @@ -2192,7 +2200,8 @@ vips_foreign_operation_init( void ) vips_foreign_save_raw_fd_get_type(); vips_foreign_load_vips_file_get_type(); vips_foreign_load_vips_source_get_type(); - vips_foreign_save_vips_get_type(); + vips_foreign_save_vips_file_get_type(); + vips_foreign_save_vips_target_get_type(); #ifdef HAVE_ANALYZE vips_foreign_load_analyze_get_type(); diff --git a/libvips/foreign/vipsload.c b/libvips/foreign/vipsload.c index 081a8579..901bb8f2 100644 --- a/libvips/foreign/vipsload.c +++ b/libvips/foreign/vipsload.c @@ -121,12 +121,16 @@ vips_foreign_load_vips_header( VipsForeignLoad *load ) return( -1 ); } else { + VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( load ); + /* We could add load vips from memory, fd, via mmap etc. here. * We should perhaps move iofuncs/vips.c into this file. * * For now, just fail unless there's a filename associated * with this source. */ + vips_error( class->nickname, + "%s", _( "no filename associated with source" ) ); return( -1 ); } diff --git a/libvips/foreign/vipssave.c b/libvips/foreign/vipssave.c index 5a1e2040..4be75aa7 100644 --- a/libvips/foreign/vipssave.c +++ b/libvips/foreign/vipssave.c @@ -51,34 +51,70 @@ typedef struct _VipsForeignSaveVips { VipsForeignSave parent_object; - char *filename; + VipsTarget *target; } VipsForeignSaveVips; typedef VipsForeignSaveClass VipsForeignSaveVipsClass; -G_DEFINE_TYPE( VipsForeignSaveVips, vips_foreign_save_vips, +G_DEFINE_ABSTRACT_TYPE( VipsForeignSaveVips, vips_foreign_save_vips, VIPS_TYPE_FOREIGN_SAVE ); +static void +vips_foreign_save_vips_dispose( GObject *gobject ) +{ + VipsForeignSaveVips *vips = (VipsForeignSaveVips *) gobject; + + if( vips->target ) + vips_target_finish( vips->target ); + VIPS_UNREF( vips->target ); + + G_OBJECT_CLASS( vips_foreign_save_vips_parent_class )-> + dispose( gobject ); +} + static int vips_foreign_save_vips_build( VipsObject *object ) { - VipsForeignSave *save = (VipsForeignSave *) object; VipsForeignSaveVips *vips = (VipsForeignSaveVips *) object; - VipsImage *x; + const char *filename; if( VIPS_OBJECT_CLASS( vips_foreign_save_vips_parent_class )-> build( object ) ) return( -1 ); - if( !(x = vips_image_new_mode( vips->filename, "w" )) ) - return( -1 ); - if( vips_image_write( save->ready, x ) ) { + if( (filename = + vips_connection_filename( VIPS_CONNECTION( vips->target ) )) ) { + VipsForeignSave *save = (VipsForeignSave *) object; + + VipsImage *x; + + /* vips_image_build() has some magic for "w" + * preventing recursion and sending this directly to the + * saver built into iofuncs. + */ + if( !(x = vips_image_new_mode( filename, "w" )) ) + return( -1 ); + if( vips_image_write( save->ready, x ) ) { + g_object_unref( x ); + return( -1 ); + } g_object_unref( x ); - return( -1 ); } - g_object_unref( x ); + else { + VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object ); + + /* We could add load vips from memory, fd, via mmap etc. here. + * We should perhaps move iofuncs/vips.c into this file. + * + * For now, just fail unless there's a filename associated + * with this source. + */ + vips_error( class->nickname, + "%s", _( "no filename associated with target" ) ); + return( -1 ); + } return( 0 ); } @@ -97,11 +133,10 @@ vips_foreign_save_vips_class_init( VipsForeignSaveVipsClass *class ) VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignSaveClass *save_class = (VipsForeignSaveClass *) class; - gobject_class->set_property = vips_object_set_property; - gobject_class->get_property = vips_object_get_property; + gobject_class->dispose = vips_foreign_save_vips_dispose; - object_class->nickname = "vipssave"; - object_class->description = _( "save image to vips file" ); + object_class->nickname = "vipssave_base"; + object_class->description = _( "save vips base class" ); object_class->build = vips_foreign_save_vips_build; foreign_class->suffs = vips__suffs; @@ -109,17 +144,121 @@ vips_foreign_save_vips_class_init( VipsForeignSaveVipsClass *class ) save_class->saveable = VIPS_SAVEABLE_ANY; for( i = 0; i < VIPS_CODING_LAST; i++ ) save_class->coding[i] = TRUE; +} + +static void +vips_foreign_save_vips_init( VipsForeignSaveVips *vips ) +{ +} + +typedef struct _VipsForeignSaveVipsFile { + VipsForeignSave parent_object; + + char *filename; + +} VipsForeignSaveVipsFile; + +typedef VipsForeignSaveVipsClass VipsForeignSaveVipsFileClass; + +G_DEFINE_TYPE( VipsForeignSaveVipsFile, vips_foreign_save_vips_file, + vips_foreign_save_vips_get_type() ); + +static int +vips_foreign_save_vips_file_build( VipsObject *object ) +{ + VipsForeignSaveVips *vips = (VipsForeignSaveVips *) object; + VipsForeignSaveVipsFile *file = (VipsForeignSaveVipsFile *) object; + + if( !(vips->target = vips_target_new_to_file( file->filename )) ) + return( -1 ); + + if( VIPS_OBJECT_CLASS( vips_foreign_save_vips_file_parent_class )-> + build( object ) ) + return( -1 ); + + return( 0 ); +} + +static void +vips_foreign_save_vips_file_class_init( VipsForeignSaveVipsFileClass *class ) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS( class ); + VipsObjectClass *object_class = (VipsObjectClass *) class; + + gobject_class->set_property = vips_object_set_property; + gobject_class->get_property = vips_object_get_property; + + object_class->nickname = "vipssave"; + object_class->description = _( "save image to file in vips format" ); + object_class->build = vips_foreign_save_vips_file_build; VIPS_ARG_STRING( class, "filename", 1, _( "Filename" ), _( "Filename to save to" ), VIPS_ARGUMENT_REQUIRED_INPUT, - G_STRUCT_OFFSET( VipsForeignSaveVips, filename ), + G_STRUCT_OFFSET( VipsForeignSaveVipsFile, filename ), NULL ); } static void -vips_foreign_save_vips_init( VipsForeignSaveVips *vips ) +vips_foreign_save_vips_file_init( VipsForeignSaveVipsFile *file ) +{ +} + +typedef struct _VipsForeignSaveVipsTarget { + VipsForeignSave parent_object; + + VipsTarget *target; + +} VipsForeignSaveVipsTarget; + +typedef VipsForeignSaveVipsClass VipsForeignSaveVipsTargetClass; + +G_DEFINE_TYPE( VipsForeignSaveVipsTarget, vips_foreign_save_vips_target, + vips_foreign_save_vips_get_type() ); + +static int +vips_foreign_save_vips_target_build( VipsObject *object ) +{ + VipsForeignSaveVips *vips = (VipsForeignSaveVips *) object; + VipsForeignSaveVipsTarget *target = + (VipsForeignSaveVipsTarget *) object; + + vips->target = target->target; + g_object_ref( vips->target ); + + if( VIPS_OBJECT_CLASS( vips_foreign_save_vips_target_parent_class )-> + build( object ) ) + return( -1 ); + + return( 0 ); +} + +static void +vips_foreign_save_vips_target_class_init( + VipsForeignSaveVipsTargetClass *class ) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS( class ); + VipsObjectClass *object_class = (VipsObjectClass *) class; + + gobject_class->set_property = vips_object_set_property; + gobject_class->get_property = vips_object_get_property; + + object_class->nickname = "vipssave_target"; + object_class->description = _( "save image to target in vips format" ); + object_class->build = vips_foreign_save_vips_target_build; + + VIPS_ARG_OBJECT( class, "target", 1, + _( "Target" ), + _( "Target to save to" ), + VIPS_ARGUMENT_REQUIRED_INPUT, + G_STRUCT_OFFSET( VipsForeignSaveVipsTarget, target ), + VIPS_TYPE_TARGET ); + +} + +static void +vips_foreign_save_vips_target_init( VipsForeignSaveVipsTarget *target ) { } @@ -148,3 +287,25 @@ vips_vipssave( VipsImage *in, const char *filename, ... ) return( result ); } +/** + * vips_vipssave_target: (method) + * @in: image to save + * @target: save image to this target + * @...: %NULL-terminated list of optional named arguments + * + * As vips_vipssave(), but save to a target. + * + * Returns: 0 on success, -1 on error. + */ +int +vips_vipssave_target( VipsImage *in, VipsTarget *target, ... ) +{ + va_list ap; + int result; + + va_start( ap, target ); + result = vips_call_split( "vipssave_target", ap, in, target ); + va_end( ap ); + + return( result ); +} diff --git a/libvips/include/vips/foreign.h b/libvips/include/vips/foreign.h index 6dfc279e..c98fa99f 100644 --- a/libvips/include/vips/foreign.h +++ b/libvips/include/vips/foreign.h @@ -362,6 +362,8 @@ int vips_vipsload_source( VipsSource *source, VipsImage **out, ... ) __attribute__((sentinel)); int vips_vipssave( VipsImage *in, const char *filename, ... ) __attribute__((sentinel)); +int vips_vipssave_target( VipsImage *in, VipsTarget *target, ... ) + __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 ec8b6aad..3ea04a83 100644 --- a/libvips/iofuncs/image.c +++ b/libvips/iofuncs/image.c @@ -921,7 +921,7 @@ vips_image_build( VipsObject *object ) /* Make sure the vips saver is there ... strange things will * happen if this type is renamed or removed. */ - g_assert( g_type_from_name( "VipsForeignSaveVips" ) ); + g_assert( g_type_from_name( "VipsForeignSaveVipsFile" ) ); if( !(file_op = vips_foreign_find_save( filename )) ) return( -1 ); @@ -930,7 +930,7 @@ vips_image_build( VipsObject *object ) * Otherwise save with VipsForeign when the image has been * written to. */ - if( strcmp( file_op, "VipsForeignSaveVips" ) == 0 ) + if( strcmp( file_op, "VipsForeignSaveVipsFile" ) == 0 ) image->dtype = VIPS_IMAGE_OPENOUT; else { image->dtype = VIPS_IMAGE_PARTIAL; diff --git a/libvips/iofuncs/util.c b/libvips/iofuncs/util.c index b986e275..c3658893 100644 --- a/libvips/iofuncs/util.c +++ b/libvips/iofuncs/util.c @@ -1522,7 +1522,7 @@ vips__find_rightmost_brackets( const char *p ) /* Too many tokens? */ - if( n == MAX_TOKENS ) + if( n >= MAX_TOKENS ) return( NULL ); /* No rightmost close bracket? diff --git a/libvips/resample/thumbnail.c b/libvips/resample/thumbnail.c index 88b18d8a..aaee14fb 100644 --- a/libvips/resample/thumbnail.c +++ b/libvips/resample/thumbnail.c @@ -122,9 +122,7 @@ typedef struct _VipsThumbnail { int n_loaded_pages; /* Pages we've loaded from file */ int n_subifds; /* Number of subifds */ - /* For openslide, we need to read out the size of each level too. - * - * These are filled out for pyr tiffs as well. + /* For pyramidal formats, we need to read out the size of each level. */ int level_count; int level_width[MAX_LEVELS];