diff --git a/ChangeLog b/ChangeLog index d8b296bd..d66013f5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,5 @@ 3/10/12 started 7.31.0 - dzsave can write zoomify and google maps layout as well -- openslide2vips now opens the input once for each thread - tilecache supports threaded access - openslide2vips gets underlying tile size from openslide - embed has 'background' option diff --git a/libvips/foreign/openslide2vips.c b/libvips/foreign/openslide2vips.c index 1997059c..4883c206 100644 --- a/libvips/foreign/openslide2vips.c +++ b/libvips/foreign/openslide2vips.c @@ -34,9 +34,6 @@ * 20/9/12 * - update openslide_open error handling for 3.3.0 semantics * - switch from deprecated _layer_ functions - * 4/10/12 - * - open the image once for each thread, so we get some parallelism on - * decode * 11/10/12 * - look for tile-width and tile-height properties */ @@ -86,7 +83,6 @@ typedef struct { openslide_t *osr; - char *filename; char *associated; @@ -177,7 +173,6 @@ readslide_new( const char *filename, VipsImage *out, g_signal_connect( out, "close", G_CALLBACK( readslide_destroy_cb ), rslide ); - rslide->filename = g_strdup( filename ); rslide->level = level; rslide->associated = g_strdup( associated ); @@ -186,7 +181,7 @@ readslide_new( const char *filename, VipsImage *out, rslide->tile_width = 256; rslide->tile_height = 256; - rslide->osr = openslide_open( rslide->filename ); + rslide->osr = openslide_open( filename ); if( rslide->osr == NULL ) { vips_error( "openslide2vips", "%s", _( "unsupported slide format" ) ); @@ -289,79 +284,42 @@ vips__openslide_read_header( const char *filename, VipsImage *out, return( 0 ); } -/* One of these for each thread. - */ -typedef struct { - openslide_t *osr; - - /* A mem buffer we can read to. This must be continuous. - */ - uint32_t *buf; - size_t size; - -} Seq; - -static void * -vips__openslide_start( VipsImage *out, void *_rslide, void *unused ) -{ - ReadSlide *rslide = _rslide; - Seq *seq; - - if( !(seq = VIPS_NEW( out, Seq )) ) - return( NULL ); - seq->buf = NULL; - if( !(seq->osr = openslide_open( rslide->filename )) ) { - vips_error( "openslide2vips", - "%s", _( "unsupported slide format" ) ); - return( NULL ); - } - - return( (void *) seq ); -} - static int vips__openslide_generate( VipsRegion *out, void *_seq, void *_rslide, void *unused, gboolean *stop ) { - Seq *seq = (Seq *) _seq; ReadSlide *rslide = _rslide; uint32_t bg = rslide->bg; VipsRect *r = &out->valid; - uint32_t *p; + int n = r->width * r->height; + uint32_t *buf = (uint32_t *) VIPS_REGION_ADDR( out, r->left, r->top ); const char *error; - int x, y; + int i; VIPS_DEBUG_MSG( "vips__openslide_generate: %dx%d @ %dx%d\n", r->width, r->height, r->left, r->top ); - /* Make sure our buffer is large enough. - */ - if( !seq->buf || - (size_t) r->width * r->height > seq->size ) { - seq->size = (size_t) r->width * r->height; - VIPS_FREE( seq->buf ); - if( !(seq->buf = (uint32_t *) VIPS_ARRAY( NULL, seq->size, - uint32_t )) ) - return( -1 ); - } - /* We're inside a cache, so requests should always be * tile_width by tile_height pixels and on a tile boundary. */ g_assert( (r->left % rslide->tile_width) == 0 ); g_assert( (r->top % rslide->tile_height) == 0 ); g_assert( r->width <= rslide->tile_width ); - g_assert( r->height <= rslide->tile_height ); - openslide_read_region( seq->osr, - seq->buf, + /* The memory on the region should be contiguous for our ARGB->RGBA + * loop below. + */ + g_assert( VIPS_REGION_LSKIP( out ) == r->width * 4 ); + + openslide_read_region( rslide->osr, + buf, r->left * rslide->downsample, r->top * rslide->downsample, rslide->level, r->width, r->height ); - error = openslide_get_error( seq->osr ); + error = openslide_get_error( rslide->osr ); if( error ) { vips_error( "openslide2vips", _( "reading region: %s" ), error ); @@ -369,67 +327,44 @@ vips__openslide_generate( VipsRegion *out, return( -1 ); } - /* Convert from ARGB to RGBA and undo premultiplication. + /* Convert from ARGB to RGBA and undo premultiplication. Since we are + * inside a cache, we know buf must be continuous. */ - p = seq->buf; - for( y = 0; y < r->height; y++ ) { - VipsPel *q = (VipsPel *) - VIPS_REGION_ADDR( out, r->left, r->top + y ); + for( i = 0; i < n; i++ ) { + uint32_t *p = buf + i; + uint32_t x = *p; + uint8_t a = x >> 24; + VipsPel *out = (VipsPel *) p; - for( x = 0; x < r->width; x++ ) { - uint32_t b = p[x]; - uint8_t a = b >> 24; - - if( a != 0 ) { - q[0] = 255 * ((b >> 16) & 255) / a; - q[1] = 255 * ((b >> 8) & 255) / a; - q[2] = 255 * (b & 255) / a; - q[3] = b; - } - else { - /* Use background color. - */ - q[0] = (bg >> 16) & 255; - q[1] = (bg >> 8) & 255; - q[2] = bg & 255; - q[3] = 0; - } - - q += 4; + if( a != 0 ) { + out[0] = 255 * ((x >> 16) & 255) / a; + out[1] = 255 * ((x >> 8) & 255) / a; + out[2] = 255 * (x & 255) / a; + out[3] = a; + } + else { + /* Use background color. + */ + out[0] = (bg >> 16) & 255; + out[1] = (bg >> 8) & 255; + out[2] = bg & 255; + out[3] = 0; } - - p += r->width; } return( 0 ); } -static int -vips__openslide_stop( void *_seq, void *a, void *b ) -{ - Seq *seq = (Seq *) _seq; - - VIPS_FREEF( openslide_close, seq->osr ); - VIPS_FREE( seq->buf ); - - return( 0 ); -} - int vips__openslide_read( const char *filename, VipsImage *out, int level ) { ReadSlide *rslide; + VipsImage *raw; + VipsImage *t; VIPS_DEBUG_MSG( "vips__openslide_read: %s %d\n", filename, level ); - /* Tile cache: keep enough for two complete rows of tiles. OpenSlide - * has its own tile cache, but it's not large enough for a complete - * scan line. - */ - VipsImage *raw; - VipsImage *t; - raw = vips_image_new(); vips_object_local( out, raw ); @@ -437,10 +372,7 @@ vips__openslide_read( const char *filename, VipsImage *out, int level ) return( -1 ); if( vips_image_generate( raw, - vips__openslide_start, - vips__openslide_generate, - vips__openslide_stop, - rslide, NULL ) ) + NULL, vips__openslide_generate, NULL, rslide, NULL ) ) return( -1 ); /* Copy to out, adding a cache. Enough tiles for a complete row, plus