revert to sharing an openslide handle

openslide master now has locking around tiff access
This commit is contained in:
John Cupitt 2012-10-12 14:20:02 +01:00
parent 92366883cd
commit 2f6aceb32a
2 changed files with 35 additions and 104 deletions

View File

@ -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

View File

@ -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