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
This commit is contained in:
John Cupitt 2014-07-31 09:04:32 +01:00
parent 639c22bf53
commit 9ddca0e99e
5 changed files with 45 additions and 29 deletions

View File

@ -2,7 +2,7 @@
- fix a race in im_maxpos_avg() - fix a race in im_maxpos_avg()
- limit n_thr on tiny images - limit n_thr on tiny images
- don't exit() on memleak detected, just warn - 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 4/7/14 started 7.40.4
- fix vips_rawsave_fd(), thanks aferrero2707 - fix vips_rawsave_fd(), thanks aferrero2707

View File

@ -2307,6 +2307,7 @@ vips_openexrload( const char *filename, VipsImage **out, ... )
* *
* @level: load this level * @level: load this level
* @associated: load this associated image * @associated: load this associated image
* @autocrop: crop to image bounds
* *
* Read a virtual slide supported by the OpenSlide library into a VIPS image. * Read a virtual slide supported by the OpenSlide library into a VIPS image.
* OpenSlide supports images in Aperio, Hamamatsu, MIRAX, Sakura, Trestle, * 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 * A slide's associated images are listed in the
* "slide-associated-images" metadata item. * "slide-associated-images" metadata item.
* *
* The output of this operator is in pre-multipled ARGB format. Use * The output of this operator is always RGBA.
* im_argb2rgba() to decode to png-style RGBA.
* *
* See also: vips_image_new_from_file(). * See also: vips_image_new_from_file().
* *

View File

@ -42,7 +42,7 @@
* 25/1/14 * 25/1/14
* - use openslide_detect_vendor() on >= 3.4.0 * - use openslide_detect_vendor() on >= 3.4.0
* 30/7/14 * 30/7/14
* - add whole_slide toggle * - add autocrop toggle
*/ */
/* /*
@ -94,10 +94,9 @@ typedef struct {
char *associated; char *associated;
/* Normally we crop to image bounds, if set. @whole_slide means, get the /* Crop to image bounds if @autocrop is set.
* whole image.
*/ */
gboolean whole_slide; gboolean autocrop;
VipsRect bounds; VipsRect bounds;
/* Only valid if associated == NULL. /* Only valid if associated == NULL.
@ -218,7 +217,7 @@ get_bounds( openslide_t *osr, VipsRect *rect )
static ReadSlide * static ReadSlide *
readslide_new( const char *filename, VipsImage *out, readslide_new( const char *filename, VipsImage *out,
int level, gboolean whole_slide, const char *associated ) int level, gboolean autocrop, const char *associated )
{ {
ReadSlide *rslide; ReadSlide *rslide;
int64_t w, h; int64_t w, h;
@ -240,7 +239,7 @@ readslide_new( const char *filename, VipsImage *out,
rslide ); rslide );
rslide->level = level; rslide->level = level;
rslide->whole_slide = whole_slide; rslide->autocrop = autocrop;
rslide->associated = g_strdup( associated ); rslide->associated = g_strdup( associated );
/* Non-crazy defaults, override below if we can. /* Non-crazy defaults, override below if we can.
@ -305,18 +304,35 @@ readslide_new( const char *filename, VipsImage *out,
if( value ) if( value )
VIPS_DEBUG_MSG( "readslide_new: found tile-size\n" ); VIPS_DEBUG_MSG( "readslide_new: found tile-size\n" );
/* Some images have a bounds in the header. Try to crop to /* Some images have a bounds in the header. Crop to
* that, unless whole_slide is set. * that if autocrop is set.
*/ */
if( !rslide->whole_slide ) if( rslide->autocrop )
if( !get_bounds( rslide->osr, &rslide->bounds ) ) if( !get_bounds( rslide->osr, &rslide->bounds ) )
rslide->whole_slide = TRUE; rslide->autocrop = FALSE;
if( !rslide->whole_slide ) { if( rslide->autocrop ) {
VipsRect image;
rslide->bounds.left /= rslide->downsample; rslide->bounds.left /= rslide->downsample;
rslide->bounds.top /= rslide->downsample; rslide->bounds.top /= rslide->downsample;
rslide->bounds.width /= rslide->downsample; rslide->bounds.width /= rslide->downsample;
rslide->bounds.height /= 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; w = rslide->bounds.width;
h = rslide->bounds.height; h = rslide->bounds.height;
} }
@ -341,7 +357,7 @@ readslide_new( const char *filename, VipsImage *out,
return( NULL ); return( NULL );
} }
if( rslide->whole_slide ) { if( !rslide->autocrop ) {
rslide->bounds.left = 0; rslide->bounds.left = 0;
rslide->bounds.top = 0; rslide->bounds.top = 0;
rslide->bounds.width = w; rslide->bounds.width = w;
@ -366,9 +382,9 @@ readslide_new( const char *filename, VipsImage *out,
int int
vips__openslide_read_header( const char *filename, VipsImage *out, 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( -1 );
return( 0 ); return( 0 );
@ -457,7 +473,7 @@ vips__openslide_generate( VipsRegion *out,
int int
vips__openslide_read( const char *filename, VipsImage *out, vips__openslide_read( const char *filename, VipsImage *out,
int level, gboolean whole_slide ) int level, gboolean autocrop )
{ {
ReadSlide *rslide; ReadSlide *rslide;
VipsImage *raw; VipsImage *raw;
@ -470,7 +486,7 @@ vips__openslide_read( const char *filename, VipsImage *out,
vips_object_local( out, raw ); vips_object_local( out, raw );
if( !(rslide = readslide_new( filename, raw, if( !(rslide = readslide_new( filename, raw,
level, whole_slide, NULL )) ) level, autocrop, NULL )) )
return( -1 ); return( -1 );
if( vips_image_generate( raw, if( vips_image_generate( raw,

View File

@ -37,9 +37,9 @@ extern "C" {
int vips__openslide_isslide( const char *filename ); int vips__openslide_isslide( const char *filename );
int vips__openslide_read_header( 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 );
int vips__openslide_read( const char *filename, VipsImage *out, 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, int vips__openslide_read_associated( const char *filename, VipsImage *out,
const char *associated ); const char *associated );

View File

@ -70,9 +70,9 @@ typedef struct _VipsForeignLoadOpenslide {
*/ */
int level; int level;
/* Don't crop to image bounds. /* Crop to image bounds.
*/ */
gboolean whole_slide; gboolean autocrop;
/* Load this associated image. /* Load this associated image.
*/ */
@ -113,7 +113,7 @@ vips_foreign_load_openslide_header( VipsForeignLoad *load )
VipsForeignLoadOpenslide *openslide = (VipsForeignLoadOpenslide *) load; VipsForeignLoadOpenslide *openslide = (VipsForeignLoadOpenslide *) load;
if( vips__openslide_read_header( openslide->filename, load->out, if( vips__openslide_read_header( openslide->filename, load->out,
openslide->level, openslide->whole_slide, openslide->level, openslide->autocrop,
openslide->associated ) ) openslide->associated ) )
return( -1 ); return( -1 );
@ -129,7 +129,7 @@ vips_foreign_load_openslide_load( VipsForeignLoad *load )
if( !openslide->associated ) { if( !openslide->associated ) {
if( vips__openslide_read( openslide->filename, load->real, if( vips__openslide_read( openslide->filename, load->real,
openslide->level, openslide->whole_slide ) ) openslide->level, openslide->autocrop ) )
return( -1 ); return( -1 );
} }
else { else {
@ -195,11 +195,11 @@ vips_foreign_load_openslide_class_init( VipsForeignLoadOpenslideClass *class )
G_STRUCT_OFFSET( VipsForeignLoadOpenslide, level ), G_STRUCT_OFFSET( VipsForeignLoadOpenslide, level ),
0, 100000, 0 ); 0, 100000, 0 );
VIPS_ARG_BOOL( class, "whole_slide", 11, VIPS_ARG_BOOL( class, "autocrop", 11,
_( "Whole slide" ), _( "Autocrop" ),
_( "Output entire side area" ), _( "Crop to image bounds" ),
VIPS_ARGUMENT_OPTIONAL_INPUT, VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsForeignLoadOpenslide, whole_slide ), G_STRUCT_OFFSET( VipsForeignLoadOpenslide, autocrop ),
FALSE ); FALSE );
VIPS_ARG_STRING( class, "associated", 12, VIPS_ARG_STRING( class, "associated", 12,