From babbb086f92a678b0aad87826d8ab738bce5570f Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Wed, 30 Dec 2020 14:14:08 +0000 Subject: [PATCH] add openslideload_source --- ChangeLog | 1 + libvips/foreign/foreign.c | 2 + libvips/foreign/openslideload.c | 281 ++++++++++++++++++++++++++++---- libvips/include/vips/foreign.h | 2 + 4 files changed, 258 insertions(+), 28 deletions(-) diff --git a/ChangeLog b/ChangeLog index cee2e141..45a4ef5d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -10,6 +10,7 @@ - add _source load support for pdfium - add "seed" param to perlin, worley and gaussnoise - add vips_source_g_input_stream_new() to load images from a GInputStream +- add openslideload_source() 22/12/20 start 8.10.6 - don't seek on bad file descriptors [kleisauke] diff --git a/libvips/foreign/foreign.c b/libvips/foreign/foreign.c index 2e6b29d2..d0722a33 100644 --- a/libvips/foreign/foreign.c +++ b/libvips/foreign/foreign.c @@ -2078,6 +2078,7 @@ vips_foreign_operation_init( void ) extern GType vips_foreign_load_openexr_get_type( void ); extern GType vips_foreign_load_openslide_get_type( void ); + extern GType vips_foreign_load_openslide_source_get_type( void ); extern GType vips_foreign_load_jpeg_file_get_type( void ); extern GType vips_foreign_load_jpeg_buffer_get_type( void ); @@ -2251,6 +2252,7 @@ vips_foreign_operation_init( void ) #ifdef HAVE_OPENSLIDE vips_foreign_load_openslide_get_type(); + vips_foreign_load_openslide_source_get_type(); #endif /*HAVE_OPENSLIDE*/ #ifdef ENABLE_MAGICKLOAD diff --git a/libvips/foreign/openslideload.c b/libvips/foreign/openslideload.c index 3aa8b41f..0d2b678e 100644 --- a/libvips/foreign/openslideload.c +++ b/libvips/foreign/openslideload.c @@ -64,9 +64,13 @@ typedef struct _VipsForeignLoadOpenslide { VipsForeignLoad parent_object; - /* Filename for load. + /* Source to load from (set by subclasses). */ - char *filename; + VipsSource *source; + + /* Filename from source. + */ + const char *filename; /* Load this level. */ @@ -88,13 +92,50 @@ typedef struct _VipsForeignLoadOpenslide { typedef VipsForeignLoadClass VipsForeignLoadOpenslideClass; -G_DEFINE_TYPE( VipsForeignLoadOpenslide, vips_foreign_load_openslide, +G_DEFINE_ABSTRACT_TYPE( VipsForeignLoadOpenslide, vips_foreign_load_openslide, VIPS_TYPE_FOREIGN_LOAD ); -static VipsForeignFlags -vips_foreign_load_openslide_get_flags_filename( const char *filename ) +static void +vips_foreign_load_openslide_dispose( GObject *gobject ) { - /* We can't tell from just the filename, we need to know what part of + VipsForeignLoadOpenslide *openslide = + (VipsForeignLoadOpenslide *) gobject; + + VIPS_UNREF( openslide->source ); + + G_OBJECT_CLASS( vips_foreign_load_openslide_parent_class )-> + dispose( gobject ); +} + +static int +vips_foreign_load_openslide_build( VipsObject *object ) +{ + VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object ); + VipsForeignLoadOpenslide *openslide = + (VipsForeignLoadOpenslide *) object; + + if( VIPS_OBJECT_CLASS( vips_foreign_load_openslide_parent_class )-> + build( object ) ) + return( -1 ); + + /* We can only open source which have an associated filename, since + * the openslide library works in terms of filenames. + */ + openslide->filename = vips_connection_filename( VIPS_CONNECTION( + openslide->source ) ); + if( !openslide->filename ) { + vips_error( class->nickname, "%s", + _( "no filename available" ) ); + return( -1 ); + } + + return( 0 ); +} + +static VipsForeignFlags +vips_foreign_load_openslide_get_flags_source( VipsSource *source ) +{ + /* We can't tell from just the source, we need to know what part of * the file the user wants. But it'll usually be partial. */ return( VIPS_FOREIGN_PARTIAL ); @@ -113,6 +154,20 @@ vips_foreign_load_openslide_get_flags( VipsForeignLoad *load ) return( flags ); } +static VipsForeignFlags +vips_foreign_load_openslide_get_flags_filename( const char *filename ) +{ + VipsSource *source; + VipsForeignFlags flags; + + if( !(source = vips_source_new_from_file( filename )) ) + return( 0 ); + flags = vips_foreign_load_openslide_get_flags_source( source ); + VIPS_UNREF( source ); + + return( flags ); +} + static int vips_foreign_load_openslide_header( VipsForeignLoad *load ) { @@ -148,17 +203,6 @@ vips_foreign_load_openslide_load( VipsForeignLoad *load ) return( 0 ); } -static const char *vips_foreign_openslide_suffs[] = { - ".svs", /* Aperio */ - ".vms", ".vmu", ".ndpi", /* Hamamatsu */ - ".scn", /* Leica */ - ".mrxs", /* MIRAX */ - ".svslide", /* Sakura */ - ".tif", /* Trestle */ - ".bif", /* Ventana */ - NULL -}; - static void vips_foreign_load_openslide_class_init( VipsForeignLoadOpenslideClass *class ) { @@ -167,11 +211,13 @@ vips_foreign_load_openslide_class_init( VipsForeignLoadOpenslideClass *class ) VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; + gobject_class->dispose = vips_foreign_load_openslide_dispose; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; - object_class->nickname = "openslideload"; - object_class->description = _( "load file with OpenSlide" ); + object_class->nickname = "openslideload_base"; + object_class->description = _( "load OpenSlide base class" ); + object_class->build = vips_foreign_load_openslide_build; /* We need to be ahead of the tiff sniffer since many OpenSlide * formats are tiff derivatives. If we see a tiff which would be @@ -181,22 +227,13 @@ vips_foreign_load_openslide_class_init( VipsForeignLoadOpenslideClass *class ) * JPEGs. */ foreign_class->priority = 100; - foreign_class->suffs = vips_foreign_openslide_suffs; - load_class->is_a = vips__openslide_isslide; load_class->get_flags_filename = vips_foreign_load_openslide_get_flags_filename; load_class->get_flags = vips_foreign_load_openslide_get_flags; load_class->header = vips_foreign_load_openslide_header; load_class->load = vips_foreign_load_openslide_load; - VIPS_ARG_STRING( class, "filename", 1, - _( "Filename" ), - _( "Filename to load from" ), - VIPS_ARGUMENT_REQUIRED_INPUT, - G_STRUCT_OFFSET( VipsForeignLoadOpenslide, filename ), - NULL ); - VIPS_ARG_INT( class, "level", 20, _( "Level" ), _( "Load this level from the file" ), @@ -232,6 +269,164 @@ vips_foreign_load_openslide_init( VipsForeignLoadOpenslide *openslide ) { } +typedef struct _VipsForeignLoadOpenslideFile { + VipsForeignLoadOpenslide parent_object; + + /* Filename for load. + */ + char *filename; + +} VipsForeignLoadOpenslideFile; + +typedef VipsForeignLoadOpenslideClass VipsForeignLoadOpenslideFileClass; + +G_DEFINE_TYPE( VipsForeignLoadOpenslideFile, vips_foreign_load_openslide_file, + vips_foreign_load_openslide_get_type() ); + +static int +vips_foreign_load_openslide_file_build( VipsObject *object ) +{ + VipsForeignLoadOpenslide *openslide = + (VipsForeignLoadOpenslide *) object; + VipsForeignLoadOpenslideFile *file = + (VipsForeignLoadOpenslideFile *) object; + + if( file->filename && + !(openslide->source = + vips_source_new_from_file( file->filename )) ) + return( -1 ); + + if( VIPS_OBJECT_CLASS( vips_foreign_load_openslide_file_parent_class )-> + build( object ) ) + return( -1 ); + + return( 0 ); +} + +static const char *vips_foreign_openslide_suffs[] = { + ".svs", /* Aperio */ + ".vms", ".vmu", ".ndpi", /* Hamamatsu */ + ".scn", /* Leica */ + ".mrxs", /* MIRAX */ + ".svslide", /* Sakura */ + ".tif", /* Trestle */ + ".bif", /* Ventana */ + NULL +}; + +static void +vips_foreign_load_openslide_file_class_init( + VipsForeignLoadOpenslideFileClass *class ) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS( class ); + VipsObjectClass *object_class = (VipsObjectClass *) class; + VipsForeignClass *foreign_class = (VipsForeignClass *) class; + VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; + + gobject_class->set_property = vips_object_set_property; + gobject_class->get_property = vips_object_get_property; + + object_class->nickname = "openslideload"; + object_class->description = _( "load file with OpenSlide" ); + object_class->build = vips_foreign_load_openslide_file_build; + + foreign_class->suffs = vips_foreign_openslide_suffs; + + load_class->is_a = vips__openslide_isslide; + + VIPS_ARG_STRING( class, "filename", 1, + _( "Filename" ), + _( "Filename to load from" ), + VIPS_ARGUMENT_REQUIRED_INPUT, + G_STRUCT_OFFSET( VipsForeignLoadOpenslideFile, filename ), + NULL ); + +} + +static void +vips_foreign_load_openslide_file_init( VipsForeignLoadOpenslideFile *openslide ) +{ +} + +typedef struct _VipsForeignLoadOpenslideSource { + VipsForeignLoadOpenslide parent_object; + + /* Load from a source. + */ + VipsSource *source; + +} VipsForeignLoadOpenslideSource; + +typedef VipsForeignLoadOpenslideClass VipsForeignLoadOpenslideSourceClass; + +G_DEFINE_TYPE( VipsForeignLoadOpenslideSource, + vips_foreign_load_openslide_source, + vips_foreign_load_openslide_get_type() ); + +static int +vips_foreign_load_openslide_source_build( VipsObject *object ) +{ + VipsForeignLoadOpenslide *openslide = + (VipsForeignLoadOpenslide *) object; + VipsForeignLoadOpenslideSource *source = + (VipsForeignLoadOpenslideSource *) object; + + if( source->source ) { + openslide->source = source->source; + g_object_ref( openslide->source ); + } + + if( VIPS_OBJECT_CLASS( + vips_foreign_load_openslide_source_parent_class )-> + build( object ) ) + return( -1 ); + + return( 0 ); +} + +static gboolean +vips_foreign_load_openslide_source_is_a_source( VipsSource *source ) +{ + const char *filename; + + return( (filename = + vips_connection_filename( VIPS_CONNECTION( source ) )) && + vips__openslide_isslide( filename ) ); +} + +static void +vips_foreign_load_openslide_source_class_init( + VipsForeignLoadOpenslideSourceClass *class ) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS( class ); + VipsObjectClass *object_class = (VipsObjectClass *) class; + VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; + + gobject_class->set_property = vips_object_set_property; + gobject_class->get_property = vips_object_get_property; + + object_class->nickname = "openslideload_source"; + object_class->description = _( "load source with OpenSlide" ); + object_class->build = vips_foreign_load_openslide_source_build; + + load_class->is_a_source = + vips_foreign_load_openslide_source_is_a_source; + + VIPS_ARG_OBJECT( class, "source", 1, + _( "Source" ), + _( "Source to load from" ), + VIPS_ARGUMENT_REQUIRED_INPUT, + G_STRUCT_OFFSET( VipsForeignLoadOpenslideSource, source ), + VIPS_TYPE_SOURCE ); + +} + +static void +vips_foreign_load_openslide_source_init( + VipsForeignLoadOpenslideSource *openslide ) +{ +} + #endif /*HAVE_OPENSLIDE*/ /** @@ -286,3 +481,33 @@ vips_openslideload( const char *filename, VipsImage **out, ... ) return( result ); } + +/** + * vips_openslideload_source: + * @source: source to load from + * @out: (out): decompressed image + * @...: %NULL-terminated list of optional named arguments + * + * Optional arguments: + * + * * @level: %gint, load this level + * * @associated: %gchararray, load this associated image + * * @attach_associated: %gboolean, attach all associated images as metadata + * * @autocrop: %gboolean, crop to image bounds + * + * Exactly as vips_openslideload(), but read from a source. + * + * Returns: 0 on success, -1 on error. + */ +int +vips_openslideload_source( VipsSource *source, VipsImage **out, ... ) +{ + va_list ap; + int result; + + va_start( ap, out ); + result = vips_call_split( "openslideload_source", ap, source, out ); + va_end( ap ); + + return( result ); +} diff --git a/libvips/include/vips/foreign.h b/libvips/include/vips/foreign.h index 6c70d21d..e8439f70 100644 --- a/libvips/include/vips/foreign.h +++ b/libvips/include/vips/foreign.h @@ -363,6 +363,8 @@ int vips_vipssave( VipsImage *in, const char *filename, ... ) int vips_openslideload( const char *filename, VipsImage **out, ... ) __attribute__((sentinel)); +int vips_openslideload_source( VipsSource *source, VipsImage **out, ... ) + __attribute__((sentinel)); /** * VipsForeignJpegSubsample: