add "whole_slide" toggle
openslideload now crops to image bounds (if set) ... use @whole_slide to stop this autocrop
This commit is contained in:
parent
0bb8a218bb
commit
639c22bf53
@ -2,6 +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
|
||||
|
||||
4/7/14 started 7.40.4
|
||||
- fix vips_rawsave_fd(), thanks aferrero2707
|
||||
|
2
TODO
2
TODO
@ -1,7 +1,5 @@
|
||||
- affine makes black lines with interp window_offset > 1, see nohalo
|
||||
|
||||
- get rid of libexif, try exiv2
|
||||
|
||||
- experiment with size down to two sizes above in vipsthumbnail
|
||||
|
||||
how does this affect speed and sharpness?
|
||||
|
@ -41,6 +41,8 @@
|
||||
* - always output solid (not transparent) pixels
|
||||
* 25/1/14
|
||||
* - use openslide_detect_vendor() on >= 3.4.0
|
||||
* 30/7/14
|
||||
* - add whole_slide toggle
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -92,6 +94,12 @@ typedef struct {
|
||||
|
||||
char *associated;
|
||||
|
||||
/* Normally we crop to image bounds, if set. @whole_slide means, get the
|
||||
* whole image.
|
||||
*/
|
||||
gboolean whole_slide;
|
||||
VipsRect bounds;
|
||||
|
||||
/* Only valid if associated == NULL.
|
||||
*/
|
||||
int32_t level;
|
||||
@ -178,9 +186,39 @@ check_associated_image( openslide_t *osr, const char *name )
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
static gboolean
|
||||
get_bounds( openslide_t *osr, VipsRect *rect )
|
||||
{
|
||||
static const char *openslide_names[] = {
|
||||
"openslide.bounds-x",
|
||||
"openslide.bounds-y",
|
||||
"openslide.bounds-width",
|
||||
"openslide.bounds-height"
|
||||
};
|
||||
static int vips_offsets[] = {
|
||||
G_STRUCT_OFFSET( VipsRect, left ),
|
||||
G_STRUCT_OFFSET( VipsRect, top ),
|
||||
G_STRUCT_OFFSET( VipsRect, width ),
|
||||
G_STRUCT_OFFSET( VipsRect, height )
|
||||
};
|
||||
|
||||
const char *value;
|
||||
int i;
|
||||
|
||||
for( i = 0; i < 4; i++ ) {
|
||||
if( !(value = openslide_get_property_value( osr,
|
||||
openslide_names[i] )) )
|
||||
return( FALSE );
|
||||
G_STRUCT_MEMBER( int, rect, vips_offsets[i] ) =
|
||||
atoi( value );
|
||||
}
|
||||
|
||||
return( TRUE );
|
||||
}
|
||||
|
||||
static ReadSlide *
|
||||
readslide_new( const char *filename, VipsImage *out,
|
||||
int level, const char *associated )
|
||||
int level, gboolean whole_slide, const char *associated )
|
||||
{
|
||||
ReadSlide *rslide;
|
||||
int64_t w, h;
|
||||
@ -188,7 +226,8 @@ readslide_new( const char *filename, VipsImage *out,
|
||||
const char *background;
|
||||
const char * const *properties;
|
||||
|
||||
if( level && associated ) {
|
||||
if( level &&
|
||||
associated ) {
|
||||
vips_error( "openslide2vips",
|
||||
"%s", _( "specify only one of level or associated "
|
||||
"image" ) );
|
||||
@ -201,6 +240,7 @@ readslide_new( const char *filename, VipsImage *out,
|
||||
rslide );
|
||||
|
||||
rslide->level = level;
|
||||
rslide->whole_slide = whole_slide;
|
||||
rslide->associated = g_strdup( associated );
|
||||
|
||||
/* Non-crazy defaults, override below if we can.
|
||||
@ -264,6 +304,22 @@ readslide_new( const char *filename, VipsImage *out,
|
||||
rslide->tile_height = atoi( value );
|
||||
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.
|
||||
*/
|
||||
if( !rslide->whole_slide )
|
||||
if( !get_bounds( rslide->osr, &rslide->bounds ) )
|
||||
rslide->whole_slide = TRUE;
|
||||
if( !rslide->whole_slide ) {
|
||||
rslide->bounds.left /= rslide->downsample;
|
||||
rslide->bounds.top /= rslide->downsample;
|
||||
rslide->bounds.width /= rslide->downsample;
|
||||
rslide->bounds.height /= rslide->downsample;
|
||||
|
||||
w = rslide->bounds.width;
|
||||
h = rslide->bounds.height;
|
||||
}
|
||||
}
|
||||
|
||||
rslide->bg = 0xffffff;
|
||||
@ -271,7 +327,9 @@ readslide_new( const char *filename, VipsImage *out,
|
||||
OPENSLIDE_PROPERTY_NAME_BACKGROUND_COLOR )) )
|
||||
rslide->bg = strtoul( background, NULL, 16 );
|
||||
|
||||
if( w < 0 || h < 0 || rslide->downsample < 0 ) {
|
||||
if( w <= 0 ||
|
||||
h <= 0 ||
|
||||
rslide->downsample < 0 ) {
|
||||
vips_error( "openslide2vips", _( "getting dimensions: %s" ),
|
||||
openslide_get_error( rslide->osr ) );
|
||||
return( NULL );
|
||||
@ -283,6 +341,13 @@ readslide_new( const char *filename, VipsImage *out,
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
if( rslide->whole_slide ) {
|
||||
rslide->bounds.left = 0;
|
||||
rslide->bounds.top = 0;
|
||||
rslide->bounds.width = w;
|
||||
rslide->bounds.height = h;
|
||||
}
|
||||
|
||||
vips_image_init_fields( out, w, h, 4, VIPS_FORMAT_UCHAR,
|
||||
VIPS_CODING_NONE, VIPS_INTERPRETATION_RGB, 1.0, 1.0 );
|
||||
|
||||
@ -301,9 +366,9 @@ readslide_new( const char *filename, VipsImage *out,
|
||||
|
||||
int
|
||||
vips__openslide_read_header( const char *filename, VipsImage *out,
|
||||
int level, char *associated )
|
||||
int level, gboolean whole_slide, char *associated )
|
||||
{
|
||||
if( !readslide_new( filename, out, level, associated ) )
|
||||
if( !readslide_new( filename, out, level, whole_slide, associated ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
@ -340,8 +405,8 @@ vips__openslide_generate( VipsRegion *out,
|
||||
|
||||
openslide_read_region( rslide->osr,
|
||||
buf,
|
||||
r->left * rslide->downsample,
|
||||
r->top * rslide->downsample,
|
||||
(r->left + rslide->bounds.left) * rslide->downsample,
|
||||
(r->top + rslide->bounds.top) * rslide->downsample,
|
||||
rslide->level,
|
||||
r->width, r->height );
|
||||
|
||||
@ -391,7 +456,8 @@ vips__openslide_generate( VipsRegion *out,
|
||||
}
|
||||
|
||||
int
|
||||
vips__openslide_read( const char *filename, VipsImage *out, int level )
|
||||
vips__openslide_read( const char *filename, VipsImage *out,
|
||||
int level, gboolean whole_slide )
|
||||
{
|
||||
ReadSlide *rslide;
|
||||
VipsImage *raw;
|
||||
@ -403,7 +469,8 @@ vips__openslide_read( const char *filename, VipsImage *out, int level )
|
||||
raw = vips_image_new();
|
||||
vips_object_local( out, raw );
|
||||
|
||||
if( !(rslide = readslide_new( filename, raw, level, NULL )) )
|
||||
if( !(rslide = readslide_new( filename, raw,
|
||||
level, whole_slide, NULL )) )
|
||||
return( -1 );
|
||||
|
||||
if( vips_image_generate( raw,
|
||||
@ -446,7 +513,7 @@ vips__openslide_read_associated( const char *filename, VipsImage *out,
|
||||
raw = vips_image_new_memory();
|
||||
vips_object_local( out, raw );
|
||||
|
||||
if( !(rslide = readslide_new( filename, raw, 0, associated )) ||
|
||||
if( !(rslide = readslide_new( filename, raw, 0, FALSE, associated )) ||
|
||||
vips_image_write_prepare( raw ) )
|
||||
return( -1 );
|
||||
openslide_read_associated_image( rslide->osr, rslide->associated,
|
||||
|
@ -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, char *associated );
|
||||
int level, gboolean whole_slide, char *associated );
|
||||
int vips__openslide_read( const char *filename, VipsImage *out,
|
||||
int level );
|
||||
int level, gboolean whole_slide );
|
||||
int vips__openslide_read_associated( const char *filename, VipsImage *out,
|
||||
const char *associated );
|
||||
|
||||
|
@ -70,6 +70,10 @@ typedef struct _VipsForeignLoadOpenslide {
|
||||
*/
|
||||
int level;
|
||||
|
||||
/* Don't crop to image bounds.
|
||||
*/
|
||||
gboolean whole_slide;
|
||||
|
||||
/* Load this associated image.
|
||||
*/
|
||||
char *associated;
|
||||
@ -109,7 +113,8 @@ vips_foreign_load_openslide_header( VipsForeignLoad *load )
|
||||
VipsForeignLoadOpenslide *openslide = (VipsForeignLoadOpenslide *) load;
|
||||
|
||||
if( vips__openslide_read_header( openslide->filename, load->out,
|
||||
openslide->level, openslide->associated ) )
|
||||
openslide->level, openslide->whole_slide,
|
||||
openslide->associated ) )
|
||||
return( -1 );
|
||||
|
||||
VIPS_SETSTR( load->out->filename, openslide->filename );
|
||||
@ -124,7 +129,7 @@ vips_foreign_load_openslide_load( VipsForeignLoad *load )
|
||||
|
||||
if( !openslide->associated ) {
|
||||
if( vips__openslide_read( openslide->filename, load->real,
|
||||
openslide->level ) )
|
||||
openslide->level, openslide->whole_slide ) )
|
||||
return( -1 );
|
||||
}
|
||||
else {
|
||||
@ -190,7 +195,14 @@ vips_foreign_load_openslide_class_init( VipsForeignLoadOpenslideClass *class )
|
||||
G_STRUCT_OFFSET( VipsForeignLoadOpenslide, level ),
|
||||
0, 100000, 0 );
|
||||
|
||||
VIPS_ARG_STRING( class, "associated", 11,
|
||||
VIPS_ARG_BOOL( class, "whole_slide", 11,
|
||||
_( "Whole slide" ),
|
||||
_( "Output entire side area" ),
|
||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||
G_STRUCT_OFFSET( VipsForeignLoadOpenslide, whole_slide ),
|
||||
FALSE );
|
||||
|
||||
VIPS_ARG_STRING( class, "associated", 12,
|
||||
_( "Associated" ),
|
||||
_( "Load this associated image" ),
|
||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||
|
Loading…
Reference in New Issue
Block a user