From 41915530a7c5351d321a25610fbc91e494471139 Mon Sep 17 00:00:00 2001 From: Benjamin Gilbert Date: Sun, 27 Nov 2011 18:15:24 -0500 Subject: [PATCH] support reading arbitrary slide layers --- libvips/format/openslide.c | 43 +++++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/libvips/format/openslide.c b/libvips/format/openslide.c index e659e644..62cdaaed 100644 --- a/libvips/format/openslide.c +++ b/libvips/format/openslide.c @@ -11,6 +11,7 @@ * - no need to set *stop on fill_region() error return * - add OpenSlide properties to image metadata * - consolidate setup into one function + * - support reading arbitrary layers */ /* @@ -50,6 +51,8 @@ typedef struct { openslide_t *osr; + int32_t layer; + double downsample; uint32_t background; } ReadSlide; @@ -63,7 +66,10 @@ static ReadSlide * readslide_new( const char *filename, VipsImage *out ) { ReadSlide *rslide; + char name[FILENAME_MAX]; + char mode[FILENAME_MAX]; const char *background; + char *endp; int64_t w, h; const char * const *properties; @@ -72,7 +78,8 @@ readslide_new( const char *filename, VipsImage *out ) g_signal_connect( out, "close", G_CALLBACK( readslide_destroy_cb ), rslide ); - rslide->osr = openslide_open( filename ); + vips_filename_split( filename, name, mode ); + rslide->osr = openslide_open( name ); if( rslide->osr == NULL ) { vips_error( "im_openslide2vips", _( "failure opening slide" )); return( NULL ); @@ -85,7 +92,25 @@ readslide_new( const char *filename, VipsImage *out ) else rslide->background = 0xffffff; - openslide_get_layer0_dimensions( rslide->osr, &w, &h ); + if( mode[0] != 0 ) { + rslide->layer = strtol( mode, &endp, 10 ); + if( *endp == 0 ) { + /* Mode specifies slide layer. + */ + if( rslide->layer < 0 || rslide->layer >= + openslide_get_layer_count( rslide->osr )) { + vips_error( "im_openslide2vips", + _( "invalid slide layer" )); + return( NULL ); + } + } else { + vips_error( "im_openslide2vips", + _( "invalid file mode" )); + return( NULL ); + } + } + + openslide_get_layer_dimensions( rslide->osr, rslide->layer, &w, &h ); if( w < 0 || h < 0 ) { vips_error( "im_openslide2vips", _( "getting dimensions: %s" ), openslide_get_error( rslide->osr )); @@ -96,6 +121,8 @@ readslide_new( const char *filename, VipsImage *out ) _( "image dimensions overflow int" )); return( NULL ); } + rslide->downsample = openslide_get_layer_downsample( rslide->osr, + rslide->layer ); vips_image_init_fields( out, (int) w, (int) h, 4, VIPS_FORMAT_UCHAR, VIPS_CODING_NONE, VIPS_INTERPRETATION_RGB, 1.0, 1.0 ); @@ -106,6 +133,8 @@ readslide_new( const char *filename, VipsImage *out ) openslide_get_property_value( rslide->osr, *properties )); + vips_image_set_int( out, "slide-layer", rslide->layer ); + return( rslide ); } @@ -123,8 +152,10 @@ fill_region( VipsRegion *out, void *seq, void *_rslide, void *unused, buf = vips_malloc( NULL, out->valid.width * out->valid.height * sizeof( *buf )); - openslide_read_region( rslide->osr, buf, out->valid.left, - out->valid.top, 0, out->valid.width, out->valid.height ); + openslide_read_region( rslide->osr, buf, + out->valid.left * rslide->downsample, + out->valid.top * rslide->downsample, rslide->layer, + out->valid.width, out->valid.height ); for( y = 0; y < out->valid.height; y++ ) { for( x = 0; x < out->valid.width; x++ ) { /* Convert from ARGB to RGBA and undo @@ -180,7 +211,9 @@ openslide2vips_header( const char *filename, VipsImage *out ) * and Trestle formats. It also supports generic tiled TIFF images, but * im_openslide2vips() does not. * - * Currently, only layer 0 (the highest-resolution slide layer) is used. + * By default, read the highest-resolution layer (layer 0). To read a + * different layer, specify the layer number as part of the filename + * (for example, "CMU-1.mrxs:3"). * * See also: #VipsFormat *