diff --git a/TODO b/TODO index 01c94397..323a00c9 100644 --- a/TODO +++ b/TODO @@ -1,8 +1,3 @@ -- google maps write needs a bg colour option - -- get more threading out of SVS read by opening multiple times? - - could work for PNG read as well? also very slow - see diff --git a/libvips/foreign/joined-openslide2vips.c b/libvips/foreign/joined-openslide2vips.c deleted file mode 100644 index aa85353b..00000000 --- a/libvips/foreign/joined-openslide2vips.c +++ /dev/null @@ -1,438 +0,0 @@ -/* Read a virtual microscope slide using OpenSlide. - * - * Benjamin Gilbert - * - * Copyright (c) 2011-2012 Carnegie Mellon University - * - * 26/11/11 - * - initial version - * 27/11/11 - * - fix black background in transparent areas - * - no need to set *stop on fill_region() error return - * - add OpenSlide properties to image metadata - * - consolidate setup into one function - * - support reading arbitrary layers - * - use VIPS_ARRAY() - * - add helper to copy a line of pixels - * - support reading associated images - * 7/12/11 - * - redirect OpenSlide error logging to vips_error() - * 8/12/11 - * - add more exposition to documentation - * 9/12/11 - * - unpack to a tile cache - * 11/12/11 - * - move argb->rgba into conversion - * - turn into a set of read fns ready to be called from a class - * 28/2/12 - * - convert "layer" to "level" where externally visible - * 9/4/12 - * - move argb2rgba back in here, we don't have a use for coded pixels - * - small cleanups - * 11/4/12 - * - fail if both level and associated image are specified - * 20/9/12 - * - update openslide_open error handling for 3.3.0 semantics - * - switch from deprecated _layer_ functions - * 11/10/12 - * - look for tile-width and tile-height properties - */ - -/* - - This file is part of VIPS. - - VIPS is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - */ - -/* -#define VIPS_DEBUG - */ - -#ifdef HAVE_CONFIG_H -#include -#endif /*HAVE_CONFIG_H*/ -#include - -#ifdef HAVE_OPENSLIDE - -#include -#include -#include -#include - -#include -#include - -#include - -#include "openslide2vips.h" - -typedef struct { - openslide_t *osr; - - char *associated; - - /* Only valid if associated == NULL. - */ - int32_t level; - double downsample; - uint32_t bg; - - /* Try to get these from openslide properties. - */ - int tile_width; - int tile_height; -} ReadSlide; - -int -vips__openslide_isslide( const char *filename ) -{ - openslide_t *osr; - const char *vendor; - int ok; - - ok = 0; - if( (osr = openslide_open( filename )) ) { - /* Generic tiled tiff images can be opened by openslide as - * well. Only offer to load this file if it's not a generic - * tiff since we want vips_tiffload() to handle these. - */ - vendor = openslide_get_property_value( osr, - OPENSLIDE_PROPERTY_NAME_VENDOR ); - - /* vendor will be NULL if osr is in error state. - */ - if( vendor && - strcmp( vendor, "generic-tiff" ) != 0 ) - ok = 1; - - openslide_close( osr ); - } - - VIPS_DEBUG_MSG( "vips__openslide_isslide: %s - %d\n", filename, ok ); - - return( ok ); -} - -static void -readslide_destroy_cb( VipsImage *image, ReadSlide *rslide ) -{ - VIPS_FREEF( openslide_close, rslide->osr ); - VIPS_FREE( rslide->associated ); -} - -static int -check_associated_image( openslide_t *osr, const char *name ) -{ - const char * const *associated; - - for( associated = openslide_get_associated_image_names( osr ); - *associated != NULL; associated++ ) - if( strcmp( *associated, name ) == 0 ) - return( 0 ); - - vips_error( "openslide2vips", - "%s", _( "invalid associated image name" ) ); - - return( -1 ); -} - -static ReadSlide * -readslide_new( const char *filename, VipsImage *out, - int level, const char *associated ) -{ - ReadSlide *rslide; - int64_t w, h; - const char *error; - const char *background; - const char * const *properties; - - if( level && associated ) { - vips_error( "openslide2vips", - "%s", _( "specify only one of level or associated " - "image" ) ); - return( NULL ); - } - - rslide = VIPS_NEW( out, ReadSlide ); - memset( rslide, 0, sizeof( *rslide ) ); - g_signal_connect( out, "close", G_CALLBACK( readslide_destroy_cb ), - rslide ); - - rslide->level = level; - rslide->associated = g_strdup( associated ); - - /* Non-crazy defaults, override below if we can. - */ - rslide->tile_width = 256; - rslide->tile_height = 256; - - rslide->osr = openslide_open( filename ); - if( rslide->osr == NULL ) { - vips_error( "openslide2vips", - "%s", _( "unsupported slide format" ) ); - return( NULL ); - } - - error = openslide_get_error( rslide->osr ); - if( error ) { - vips_error( "openslide2vips", - _( "opening slide: %s" ), error ); - return( NULL ); - } - - if( level < 0 || - level >= openslide_get_level_count( rslide->osr ) ) { - vips_error( "openslide2vips", - "%s", _( "invalid slide level" ) ); - return( NULL ); - } - - if( associated && - check_associated_image( rslide->osr, associated ) ) - return( NULL ); - - if( associated ) { - openslide_get_associated_image_dimensions( rslide->osr, - associated, &w, &h ); - vips_image_set_string( out, "slide-associated-image", - associated ); - vips_demand_hint( out, VIPS_DEMAND_STYLE_THINSTRIP, NULL ); - } - else { - char buf[256]; - const char *value; - - openslide_get_level_dimensions( rslide->osr, - level, &w, &h ); - rslide->downsample = openslide_get_level_downsample( - rslide->osr, level ); - vips_image_set_int( out, "slide-level", level ); - vips_demand_hint( out, VIPS_DEMAND_STYLE_SMALLTILE, NULL ); - - /* Try to get tile width/height. An undocumented, experimental - * feature. - */ - vips_snprintf( buf, 256, - "openslide.level[%d].tile-width", level ); - if( (value = openslide_get_property_value( rslide->osr, buf )) ) - rslide->tile_width = atoi( value ); - vips_snprintf( buf, 256, - "openslide.level[%d].tile-height", level ); - if( (value = openslide_get_property_value( rslide->osr, buf )) ) - rslide->tile_height = atoi( value ); - if( value ) - VIPS_DEBUG_MSG( "readslide_new: found tile-size\n" ); - } - - rslide->bg = 0xffffff; - if( (background = openslide_get_property_value( rslide->osr, - OPENSLIDE_PROPERTY_NAME_BACKGROUND_COLOR )) ) - rslide->bg = strtoul( background, NULL, 16 ); - - if( w < 0 || h < 0 || rslide->downsample < 0 ) { - vips_error( "openslide2vips", _( "getting dimensions: %s" ), - openslide_get_error( rslide->osr ) ); - return( NULL ); - } - if( w > INT_MAX || - h > INT_MAX ) { - vips_error( "openslide2vips", - "%s", _( "image dimensions overflow int" ) ); - return( NULL ); - } - - vips_image_init_fields( out, w, h, 4, VIPS_FORMAT_UCHAR, - VIPS_CODING_NONE, VIPS_INTERPRETATION_RGB, 1.0, 1.0 ); - - for( properties = openslide_get_property_names( rslide->osr ); - *properties != NULL; properties++ ) - vips_image_set_string( out, *properties, - openslide_get_property_value( rslide->osr, - *properties ) ); - - associated = g_strjoinv( ", ", (char **) - openslide_get_associated_image_names( rslide->osr ) ); - vips_image_set_string( out, "slide-associated-images", associated ); - - return( rslide ); -} - -int -vips__openslide_read_header( const char *filename, VipsImage *out, - int level, char *associated ) -{ - ReadSlide *rslide; - - if( !(rslide = readslide_new( filename, out, level, associated )) ) - return( -1 ); - - return( 0 ); -} - -static int -vips__openslide_generate( VipsRegion *out, - void *_seq, void *_rslide, void *unused, gboolean *stop ) -{ - ReadSlide *rslide = _rslide; - uint32_t bg = rslide->bg; - VipsRect *r = &out->valid; - int n = r->width * r->height; - uint32_t *buf = (uint32_t *) VIPS_REGION_ADDR( out, r->left, r->top ); - - const char *error; - int i; - - VIPS_DEBUG_MSG( "vips__openslide_generate: %dx%d @ %dx%d\n", - r->width, r->height, r->left, r->top ); - - /* - printf( "vips__openslide_generate: %p %dx%d @ %dx%d\n", - g_thread_self(), - r->width, r->height, r->left, r->top ); - */ - - /* 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 ); - - /* 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( rslide->osr ); - if( error ) { - vips_error( "openslide2vips", - _( "reading region: %s" ), error ); - - return( -1 ); - } - - /* Convert from ARGB to RGBA and undo premultiplication. Since we are - * inside a cache, we know buf must be continuous. - */ - for( i = 0; i < n; i++ ) { - uint32_t *p = buf + i; - uint32_t x = *p; - uint8_t a = x >> 24; - VipsPel *out = (VipsPel *) p; - - 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; - } - } - - 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 ); - - raw = vips_image_new(); - vips_object_local( out, raw ); - - if( !(rslide = readslide_new( filename, raw, level, NULL )) ) - return( -1 ); - - if( vips_image_generate( raw, - NULL, vips__openslide_generate, NULL, rslide, NULL ) ) - return( -1 ); - - /* Copy to out, adding a cache. Enough tiles for a complete row, plus - * 50%. - */ - if( vips_tilecache( raw, &t, - "tile_width", rslide->tile_width, - "tile_height", rslide->tile_height, - "max_tiles", - (int) (1.5 * (1 + raw->Xsize / rslide->tile_width)), - "threaded", TRUE, - NULL ) ) - return( -1 ); - if( vips_image_write( t, out ) ) { - g_object_unref( t ); - return( -1 ); - } - g_object_unref( t ); - - return( 0 ); -} - -int -vips__openslide_read_associated( const char *filename, VipsImage *out, - const char *associated ) -{ - ReadSlide *rslide; - VipsImage *raw; - const char *error; - - VIPS_DEBUG_MSG( "vips__openslide_read_associated: %s %s\n", - filename, associated ); - - /* Memory buffer. Get associated directly to this, then copy to out. - */ - raw = vips_image_new_buffer(); - vips_object_local( out, raw ); - - if( !(rslide = readslide_new( filename, raw, 0, associated )) || - vips_image_write_prepare( raw ) ) - return( -1 ); - openslide_read_associated_image( rslide->osr, rslide->associated, - (uint32_t *) VIPS_IMAGE_ADDR( raw, 0, 0 ) ); - error = openslide_get_error( rslide->osr ); - if( error ) { - vips_error( "openslide2vips", - _( "reading associated image: %s" ), error ); - return( -1 ); - } - - if( vips_image_write( raw, out ) ) - return( -1 ); - - return( 0 ); -} - -#endif /*HAVE_OPENSLIDE*/ diff --git a/libvips/foreign/openslide2vips.c b/libvips/foreign/openslide2vips.c index b95adcb6..7bdcc8c5 100644 --- a/libvips/foreign/openslide2vips.c +++ b/libvips/foreign/openslide2vips.c @@ -36,6 +36,7 @@ * - switch from deprecated _layer_ functions * 11/10/12 * - look for tile-width and tile-height properties + * - use threaded tile cache */ /* diff --git a/libvips/foreign/split-openslide2vips.c b/libvips/foreign/split-openslide2vips.c deleted file mode 100644 index 1997059c..00000000 --- a/libvips/foreign/split-openslide2vips.c +++ /dev/null @@ -1,500 +0,0 @@ -/* Read a virtual microscope slide using OpenSlide. - * - * Benjamin Gilbert - * - * Copyright (c) 2011-2012 Carnegie Mellon University - * - * 26/11/11 - * - initial version - * 27/11/11 - * - fix black background in transparent areas - * - no need to set *stop on fill_region() error return - * - add OpenSlide properties to image metadata - * - consolidate setup into one function - * - support reading arbitrary layers - * - use VIPS_ARRAY() - * - add helper to copy a line of pixels - * - support reading associated images - * 7/12/11 - * - redirect OpenSlide error logging to vips_error() - * 8/12/11 - * - add more exposition to documentation - * 9/12/11 - * - unpack to a tile cache - * 11/12/11 - * - move argb->rgba into conversion - * - turn into a set of read fns ready to be called from a class - * 28/2/12 - * - convert "layer" to "level" where externally visible - * 9/4/12 - * - move argb2rgba back in here, we don't have a use for coded pixels - * - small cleanups - * 11/4/12 - * - fail if both level and associated image are specified - * 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 - */ - -/* - - This file is part of VIPS. - - VIPS is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - */ - -/* -#define VIPS_DEBUG - */ - -#ifdef HAVE_CONFIG_H -#include -#endif /*HAVE_CONFIG_H*/ -#include - -#ifdef HAVE_OPENSLIDE - -#include -#include -#include -#include - -#include -#include - -#include - -#include "openslide2vips.h" - -typedef struct { - openslide_t *osr; - char *filename; - - char *associated; - - /* Only valid if associated == NULL. - */ - int32_t level; - double downsample; - uint32_t bg; - - /* Try to get these from openslide properties. - */ - int tile_width; - int tile_height; -} ReadSlide; - -int -vips__openslide_isslide( const char *filename ) -{ - openslide_t *osr; - const char *vendor; - int ok; - - ok = 0; - if( (osr = openslide_open( filename )) ) { - /* Generic tiled tiff images can be opened by openslide as - * well. Only offer to load this file if it's not a generic - * tiff since we want vips_tiffload() to handle these. - */ - vendor = openslide_get_property_value( osr, - OPENSLIDE_PROPERTY_NAME_VENDOR ); - - /* vendor will be NULL if osr is in error state. - */ - if( vendor && - strcmp( vendor, "generic-tiff" ) != 0 ) - ok = 1; - - openslide_close( osr ); - } - - VIPS_DEBUG_MSG( "vips__openslide_isslide: %s - %d\n", filename, ok ); - - return( ok ); -} - -static void -readslide_destroy_cb( VipsImage *image, ReadSlide *rslide ) -{ - VIPS_FREEF( openslide_close, rslide->osr ); - VIPS_FREE( rslide->associated ); -} - -static int -check_associated_image( openslide_t *osr, const char *name ) -{ - const char * const *associated; - - for( associated = openslide_get_associated_image_names( osr ); - *associated != NULL; associated++ ) - if( strcmp( *associated, name ) == 0 ) - return( 0 ); - - vips_error( "openslide2vips", - "%s", _( "invalid associated image name" ) ); - - return( -1 ); -} - -static ReadSlide * -readslide_new( const char *filename, VipsImage *out, - int level, const char *associated ) -{ - ReadSlide *rslide; - int64_t w, h; - const char *error; - const char *background; - const char * const *properties; - - if( level && associated ) { - vips_error( "openslide2vips", - "%s", _( "specify only one of level or associated " - "image" ) ); - return( NULL ); - } - - rslide = VIPS_NEW( out, ReadSlide ); - memset( rslide, 0, sizeof( *rslide ) ); - g_signal_connect( out, "close", G_CALLBACK( readslide_destroy_cb ), - rslide ); - - rslide->filename = g_strdup( filename ); - rslide->level = level; - rslide->associated = g_strdup( associated ); - - /* Non-crazy defaults, override below if we can. - */ - rslide->tile_width = 256; - rslide->tile_height = 256; - - rslide->osr = openslide_open( rslide->filename ); - if( rslide->osr == NULL ) { - vips_error( "openslide2vips", - "%s", _( "unsupported slide format" ) ); - return( NULL ); - } - - error = openslide_get_error( rslide->osr ); - if( error ) { - vips_error( "openslide2vips", - _( "opening slide: %s" ), error ); - return( NULL ); - } - - if( level < 0 || - level >= openslide_get_level_count( rslide->osr ) ) { - vips_error( "openslide2vips", - "%s", _( "invalid slide level" ) ); - return( NULL ); - } - - if( associated && - check_associated_image( rslide->osr, associated ) ) - return( NULL ); - - if( associated ) { - openslide_get_associated_image_dimensions( rslide->osr, - associated, &w, &h ); - vips_image_set_string( out, "slide-associated-image", - associated ); - vips_demand_hint( out, VIPS_DEMAND_STYLE_THINSTRIP, NULL ); - } - else { - char buf[256]; - const char *value; - - openslide_get_level_dimensions( rslide->osr, - level, &w, &h ); - rslide->downsample = openslide_get_level_downsample( - rslide->osr, level ); - vips_image_set_int( out, "slide-level", level ); - vips_demand_hint( out, VIPS_DEMAND_STYLE_SMALLTILE, NULL ); - - /* Try to get tile width/height. An undocumented, experimental - * feature. - */ - vips_snprintf( buf, 256, - "openslide.level[%d].tile-width", level ); - if( (value = openslide_get_property_value( rslide->osr, buf )) ) - rslide->tile_width = atoi( value ); - vips_snprintf( buf, 256, - "openslide.level[%d].tile-height", level ); - if( (value = openslide_get_property_value( rslide->osr, buf )) ) - rslide->tile_height = atoi( value ); - if( value ) - VIPS_DEBUG_MSG( "readslide_new: found tile-size\n" ); - } - - rslide->bg = 0xffffff; - if( (background = openslide_get_property_value( rslide->osr, - OPENSLIDE_PROPERTY_NAME_BACKGROUND_COLOR )) ) - rslide->bg = strtoul( background, NULL, 16 ); - - if( w < 0 || h < 0 || rslide->downsample < 0 ) { - vips_error( "openslide2vips", _( "getting dimensions: %s" ), - openslide_get_error( rslide->osr ) ); - return( NULL ); - } - if( w > INT_MAX || - h > INT_MAX ) { - vips_error( "openslide2vips", - "%s", _( "image dimensions overflow int" ) ); - return( NULL ); - } - - vips_image_init_fields( out, w, h, 4, VIPS_FORMAT_UCHAR, - VIPS_CODING_NONE, VIPS_INTERPRETATION_RGB, 1.0, 1.0 ); - - for( properties = openslide_get_property_names( rslide->osr ); - *properties != NULL; properties++ ) - vips_image_set_string( out, *properties, - openslide_get_property_value( rslide->osr, - *properties ) ); - - associated = g_strjoinv( ", ", (char **) - openslide_get_associated_image_names( rslide->osr ) ); - vips_image_set_string( out, "slide-associated-images", associated ); - - return( rslide ); -} - -int -vips__openslide_read_header( const char *filename, VipsImage *out, - int level, char *associated ) -{ - ReadSlide *rslide; - - if( !(rslide = readslide_new( filename, out, level, associated )) ) - return( -1 ); - - 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; - - const char *error; - int x, y; - - 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, - r->left * rslide->downsample, - r->top * rslide->downsample, - rslide->level, - r->width, r->height ); - - error = openslide_get_error( seq->osr ); - if( error ) { - vips_error( "openslide2vips", - _( "reading region: %s" ), error ); - - return( -1 ); - } - - /* Convert from ARGB to RGBA and undo premultiplication. - */ - p = seq->buf; - for( y = 0; y < r->height; y++ ) { - VipsPel *q = (VipsPel *) - VIPS_REGION_ADDR( out, r->left, r->top + y ); - - 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; - } - - 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; - - 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 ); - - if( !(rslide = readslide_new( filename, raw, level, NULL )) ) - return( -1 ); - - if( vips_image_generate( raw, - vips__openslide_start, - vips__openslide_generate, - vips__openslide_stop, - rslide, NULL ) ) - return( -1 ); - - /* Copy to out, adding a cache. Enough tiles for a complete row, plus - * 50%. - */ - if( vips_tilecache( raw, &t, - "tile_width", rslide->tile_width, - "tile_height", rslide->tile_height, - "max_tiles", - (int) (1.5 * (1 + raw->Xsize / rslide->tile_width)), - "threaded", TRUE, - NULL ) ) - return( -1 ); - if( vips_image_write( t, out ) ) { - g_object_unref( t ); - return( -1 ); - } - g_object_unref( t ); - - return( 0 ); -} - -int -vips__openslide_read_associated( const char *filename, VipsImage *out, - const char *associated ) -{ - ReadSlide *rslide; - VipsImage *raw; - const char *error; - - VIPS_DEBUG_MSG( "vips__openslide_read_associated: %s %s\n", - filename, associated ); - - /* Memory buffer. Get associated directly to this, then copy to out. - */ - raw = vips_image_new_buffer(); - vips_object_local( out, raw ); - - if( !(rslide = readslide_new( filename, raw, 0, associated )) || - vips_image_write_prepare( raw ) ) - return( -1 ); - openslide_read_associated_image( rslide->osr, rslide->associated, - (uint32_t *) VIPS_IMAGE_ADDR( raw, 0, 0 ) ); - error = openslide_get_error( rslide->osr ); - if( error ) { - vips_error( "openslide2vips", - _( "reading associated image: %s" ), error ); - return( -1 ); - } - - if( vips_image_write( raw, out ) ) - return( -1 ); - - return( 0 ); -} - -#endif /*HAVE_OPENSLIDE*/