From 9ddca0e99ea9f42e2dca5c97ef2c4515f03d5042 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Thu, 31 Jul 2014 09:04:32 +0100 Subject: [PATCH] change @whole_slide to @autocrop on seconds thoughts, make openslide crop-on-load an option, not the default also, clip image bounds against image size --- ChangeLog | 2 +- libvips/foreign/foreign.c | 4 +-- libvips/foreign/openslide2vips.c | 48 +++++++++++++++++++++----------- libvips/foreign/openslide2vips.h | 4 +-- libvips/foreign/openslideload.c | 16 +++++------ 5 files changed, 45 insertions(+), 29 deletions(-) diff --git a/ChangeLog b/ChangeLog index 13d5d057..dc91dd1d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,7 +2,7 @@ - fix a race in im_maxpos_avg() - limit n_thr on tiny images - don't exit() on memleak detected, just warn -- add "whole_slide" option to openslide load +- add "autocrop" option to openslide load 4/7/14 started 7.40.4 - fix vips_rawsave_fd(), thanks aferrero2707 diff --git a/libvips/foreign/foreign.c b/libvips/foreign/foreign.c index aa3c02f2..b39f611e 100644 --- a/libvips/foreign/foreign.c +++ b/libvips/foreign/foreign.c @@ -2307,6 +2307,7 @@ vips_openexrload( const char *filename, VipsImage **out, ... ) * * @level: load this level * @associated: load this associated image + * @autocrop: crop to image bounds * * Read a virtual slide supported by the OpenSlide library into a VIPS image. * OpenSlide supports images in Aperio, Hamamatsu, MIRAX, Sakura, Trestle, @@ -2324,8 +2325,7 @@ vips_openexrload( const char *filename, VipsImage **out, ... ) * A slide's associated images are listed in the * "slide-associated-images" metadata item. * - * The output of this operator is in pre-multipled ARGB format. Use - * im_argb2rgba() to decode to png-style RGBA. + * The output of this operator is always RGBA. * * See also: vips_image_new_from_file(). * diff --git a/libvips/foreign/openslide2vips.c b/libvips/foreign/openslide2vips.c index 22486467..136c1339 100644 --- a/libvips/foreign/openslide2vips.c +++ b/libvips/foreign/openslide2vips.c @@ -42,7 +42,7 @@ * 25/1/14 * - use openslide_detect_vendor() on >= 3.4.0 * 30/7/14 - * - add whole_slide toggle + * - add autocrop toggle */ /* @@ -94,10 +94,9 @@ typedef struct { char *associated; - /* Normally we crop to image bounds, if set. @whole_slide means, get the - * whole image. + /* Crop to image bounds if @autocrop is set. */ - gboolean whole_slide; + gboolean autocrop; VipsRect bounds; /* Only valid if associated == NULL. @@ -218,7 +217,7 @@ get_bounds( openslide_t *osr, VipsRect *rect ) static ReadSlide * readslide_new( const char *filename, VipsImage *out, - int level, gboolean whole_slide, const char *associated ) + int level, gboolean autocrop, const char *associated ) { ReadSlide *rslide; int64_t w, h; @@ -240,7 +239,7 @@ readslide_new( const char *filename, VipsImage *out, rslide ); rslide->level = level; - rslide->whole_slide = whole_slide; + rslide->autocrop = autocrop; rslide->associated = g_strdup( associated ); /* Non-crazy defaults, override below if we can. @@ -305,18 +304,35 @@ readslide_new( const char *filename, VipsImage *out, if( value ) VIPS_DEBUG_MSG( "readslide_new: found tile-size\n" ); - /* Some images have a bounds in the header. Try to crop to - * that, unless whole_slide is set. + /* Some images have a bounds in the header. Crop to + * that if autocrop is set. */ - if( !rslide->whole_slide ) + if( rslide->autocrop ) if( !get_bounds( rslide->osr, &rslide->bounds ) ) - rslide->whole_slide = TRUE; - if( !rslide->whole_slide ) { + rslide->autocrop = FALSE; + if( rslide->autocrop ) { + VipsRect image; + rslide->bounds.left /= rslide->downsample; rslide->bounds.top /= rslide->downsample; rslide->bounds.width /= rslide->downsample; rslide->bounds.height /= rslide->downsample; + /* Clip against image size. + */ + image.left = 0; + image.top = 0; + image.width = w; + image.height = h; + vips_rect_intersectrect( &rslide->bounds, &image, + &rslide->bounds ); + + /* If we've clipped to nothing, ignore bounds. + */ + if( vips_rect_isempty( &rslide->bounds ) ) + rslide->autocrop = FALSE; + } + if( rslide->autocrop ) { w = rslide->bounds.width; h = rslide->bounds.height; } @@ -341,7 +357,7 @@ readslide_new( const char *filename, VipsImage *out, return( NULL ); } - if( rslide->whole_slide ) { + if( !rslide->autocrop ) { rslide->bounds.left = 0; rslide->bounds.top = 0; rslide->bounds.width = w; @@ -366,9 +382,9 @@ readslide_new( const char *filename, VipsImage *out, int vips__openslide_read_header( const char *filename, VipsImage *out, - int level, gboolean whole_slide, char *associated ) + int level, gboolean autocrop, char *associated ) { - if( !readslide_new( filename, out, level, whole_slide, associated ) ) + if( !readslide_new( filename, out, level, autocrop, associated ) ) return( -1 ); return( 0 ); @@ -457,7 +473,7 @@ vips__openslide_generate( VipsRegion *out, int vips__openslide_read( const char *filename, VipsImage *out, - int level, gboolean whole_slide ) + int level, gboolean autocrop ) { ReadSlide *rslide; VipsImage *raw; @@ -470,7 +486,7 @@ vips__openslide_read( const char *filename, VipsImage *out, vips_object_local( out, raw ); if( !(rslide = readslide_new( filename, raw, - level, whole_slide, NULL )) ) + level, autocrop, NULL )) ) return( -1 ); if( vips_image_generate( raw, diff --git a/libvips/foreign/openslide2vips.h b/libvips/foreign/openslide2vips.h index 06a8aa68..3b903a6b 100644 --- a/libvips/foreign/openslide2vips.h +++ b/libvips/foreign/openslide2vips.h @@ -37,9 +37,9 @@ extern "C" { int vips__openslide_isslide( const char *filename ); int vips__openslide_read_header( const char *filename, VipsImage *out, - int level, gboolean whole_slide, char *associated ); + int level, gboolean autocrop, char *associated ); int vips__openslide_read( const char *filename, VipsImage *out, - int level, gboolean whole_slide ); + int level, gboolean autocrop ); int vips__openslide_read_associated( const char *filename, VipsImage *out, const char *associated ); diff --git a/libvips/foreign/openslideload.c b/libvips/foreign/openslideload.c index 723f2692..fce856f8 100644 --- a/libvips/foreign/openslideload.c +++ b/libvips/foreign/openslideload.c @@ -70,9 +70,9 @@ typedef struct _VipsForeignLoadOpenslide { */ int level; - /* Don't crop to image bounds. + /* Crop to image bounds. */ - gboolean whole_slide; + gboolean autocrop; /* Load this associated image. */ @@ -113,7 +113,7 @@ vips_foreign_load_openslide_header( VipsForeignLoad *load ) VipsForeignLoadOpenslide *openslide = (VipsForeignLoadOpenslide *) load; if( vips__openslide_read_header( openslide->filename, load->out, - openslide->level, openslide->whole_slide, + openslide->level, openslide->autocrop, openslide->associated ) ) return( -1 ); @@ -129,7 +129,7 @@ vips_foreign_load_openslide_load( VipsForeignLoad *load ) if( !openslide->associated ) { if( vips__openslide_read( openslide->filename, load->real, - openslide->level, openslide->whole_slide ) ) + openslide->level, openslide->autocrop ) ) return( -1 ); } else { @@ -195,11 +195,11 @@ vips_foreign_load_openslide_class_init( VipsForeignLoadOpenslideClass *class ) G_STRUCT_OFFSET( VipsForeignLoadOpenslide, level ), 0, 100000, 0 ); - VIPS_ARG_BOOL( class, "whole_slide", 11, - _( "Whole slide" ), - _( "Output entire side area" ), + VIPS_ARG_BOOL( class, "autocrop", 11, + _( "Autocrop" ), + _( "Crop to image bounds" ), VIPS_ARGUMENT_OPTIONAL_INPUT, - G_STRUCT_OFFSET( VipsForeignLoadOpenslide, whole_slide ), + G_STRUCT_OFFSET( VipsForeignLoadOpenslide, autocrop ), FALSE ); VIPS_ARG_STRING( class, "associated", 12,