add subifd pyr support to thumbnail
thumbnail can spot subifd pyramids and load lower levels if necessary
This commit is contained in:
parent
460e1d0bf5
commit
cff84f4606
@ -15,13 +15,15 @@
|
||||
- add subsample_mode, deprecate no_subsample in jpegsave [Elad-Laufer]
|
||||
- add vips_isdirf()
|
||||
- add PAGENUMBER support to tiff write [jclavoie-jive]
|
||||
- add all to smartcrop
|
||||
- add "all" mode to smartcrop
|
||||
- flood fill could stop half-way for some very complex shapes
|
||||
- better handling of unaligned reads in multipage tiffs [petoor]
|
||||
- mark old --delete option to vipsthumbnail as deprecated [UweOhse]
|
||||
- png save with a bad ICC profile just gives a warning
|
||||
- add "premultipled" option to vips_affine(), clarified vips_resize()
|
||||
behaviour with alpha channels
|
||||
- improve bioformats support with read and write of tiff subifd pyramids
|
||||
- thumbnail exploits subifd pyramids
|
||||
|
||||
24/4/20 started 8.9.3
|
||||
- better iiif tile naming [IllyaMoskvin]
|
||||
|
@ -178,6 +178,7 @@ double vips_image_get_scale( const VipsImage *image );
|
||||
double vips_image_get_offset( const VipsImage *image );
|
||||
int vips_image_get_page_height( VipsImage *image );
|
||||
int vips_image_get_n_pages( VipsImage *image );
|
||||
int vips_image_get_n_subifds( VipsImage *image );
|
||||
const void *vips_image_get_data( VipsImage *image );
|
||||
|
||||
void vips_image_init_fields( VipsImage *image,
|
||||
|
@ -818,7 +818,7 @@ vips_image_get_page_height( VipsImage *image )
|
||||
* vips_image_get_n_pages: (method)
|
||||
* @image: image to get from
|
||||
*
|
||||
* Fetch and sanity-check VIPS_META_N_PAGES. Default to 1 if not present or
|
||||
* Fetch and sanity-check #VIPS_META_N_PAGES. Default to 1 if not present or
|
||||
* crazy.
|
||||
*
|
||||
* This is the number of pages in the image file, not the number of pages that
|
||||
@ -840,6 +840,29 @@ vips_image_get_n_pages( VipsImage *image )
|
||||
return( 1 );
|
||||
}
|
||||
|
||||
/**
|
||||
* vips_image_get_n_subifds: (method)
|
||||
* @image: image to get from
|
||||
*
|
||||
* Fetch and sanity-check #VIPS_META_N_SUBIFDS. Default to 0 if not present or
|
||||
* crazy.
|
||||
*
|
||||
* Returns: the number of subifds in the image file
|
||||
*/
|
||||
int
|
||||
vips_image_get_n_subifds( VipsImage *image )
|
||||
{
|
||||
int n_subifds;
|
||||
|
||||
if( vips_image_get_typeof( image, VIPS_META_N_SUBIFDS ) &&
|
||||
!vips_image_get_int( image, VIPS_META_N_SUBIFDS, &n_subifds ) &&
|
||||
n_subifds > 1 &&
|
||||
n_subifds < 1000 )
|
||||
return( n_subifds );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* vips_image_get_data: (method)
|
||||
* @image: image to get data for
|
||||
|
@ -28,6 +28,8 @@
|
||||
* - smarter heif thumbnail selection
|
||||
* 12/10/19
|
||||
* - add thumbnail_source
|
||||
* 2/6/20
|
||||
* - add subifd pyr support
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -117,6 +119,7 @@ typedef struct _VipsThumbnail {
|
||||
VipsAngle angle; /* From vips_autorot_get_angle() */
|
||||
int n_pages; /* Pages in file */
|
||||
int n_loaded_pages; /* Pages we've loaded from file */
|
||||
int n_subifds; /* Number of subifds */
|
||||
|
||||
/* For openslide, we need to read out the size of each level too.
|
||||
*
|
||||
@ -131,6 +134,10 @@ typedef struct _VipsThumbnail {
|
||||
int heif_thumbnail_width;
|
||||
int heif_thumbnail_height;
|
||||
|
||||
/* For TIFF sources, open subifds rather than pages to get pyr layers.
|
||||
*/
|
||||
gboolean subifd_pyramid;
|
||||
|
||||
} VipsThumbnail;
|
||||
|
||||
typedef struct _VipsThumbnailClass {
|
||||
@ -199,6 +206,7 @@ vips_thumbnail_read_header( VipsThumbnail *thumbnail, VipsImage *image )
|
||||
thumbnail->angle = vips_autorot_get_angle( image );
|
||||
thumbnail->page_height = vips_image_get_page_height( image );
|
||||
thumbnail->n_pages = vips_image_get_n_pages( image );
|
||||
thumbnail->n_subifds = vips_image_get_n_subifds( image );
|
||||
|
||||
/* VIPS_META_N_PAGES is the number of pages in the document,
|
||||
* not the number we've read out into this image. We calculate
|
||||
@ -235,15 +243,20 @@ vips_thumbnail_read_header( VipsThumbnail *thumbnail, VipsImage *image )
|
||||
}
|
||||
}
|
||||
|
||||
/* This may not be a pyr tiff, so no error if we can't find the layers.
|
||||
* We just look for two or more pages following roughly /2 shrinks.
|
||||
/* Detect a TIFF pyramid made of pages following a roughly /2 shrink.
|
||||
*
|
||||
* This may not be a pyr tiff, so no error if we can't find the layers.
|
||||
*/
|
||||
static void
|
||||
vips_thumbnail_get_tiff_pyramid( VipsThumbnail *thumbnail )
|
||||
static gboolean
|
||||
vips_thumbnail_get_tiff_pyramid_page( VipsThumbnail *thumbnail )
|
||||
{
|
||||
VipsThumbnailClass *class = VIPS_THUMBNAIL_GET_CLASS( thumbnail );
|
||||
int i;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "vips_thumbnail_get_tiff_pyramid_page:\n" );
|
||||
#endif /*DEBUG*/
|
||||
|
||||
for( i = 0; i < thumbnail->n_pages; i++ ) {
|
||||
VipsImage *page;
|
||||
int level_width;
|
||||
@ -252,7 +265,7 @@ vips_thumbnail_get_tiff_pyramid( VipsThumbnail *thumbnail )
|
||||
int expected_level_height;
|
||||
|
||||
if( !(page = class->open( thumbnail, i )) )
|
||||
return;
|
||||
return( FALSE );
|
||||
level_width = page->Xsize;
|
||||
level_height = page->Ysize;
|
||||
VIPS_UNREF( page );
|
||||
@ -264,10 +277,10 @@ vips_thumbnail_get_tiff_pyramid( VipsThumbnail *thumbnail )
|
||||
*/
|
||||
if( abs( level_width - expected_level_width ) > 5 ||
|
||||
level_width < 2 )
|
||||
return;
|
||||
return( FALSE );
|
||||
if( abs( level_height - expected_level_height ) > 5 ||
|
||||
level_height < 2 )
|
||||
return;
|
||||
return( FALSE );
|
||||
|
||||
thumbnail->level_width[i] = level_width;
|
||||
thumbnail->level_height[i] = level_height;
|
||||
@ -276,10 +289,74 @@ vips_thumbnail_get_tiff_pyramid( VipsThumbnail *thumbnail )
|
||||
/* Now set level_count. This signals that we've found a pyramid.
|
||||
*/
|
||||
#ifdef DEBUG
|
||||
printf( "vips_thumbnail_get_tiff_pyramid: %d layer pyramid detected\n",
|
||||
thumbnail->n_pages );
|
||||
printf( "vips_thumbnail_get_tiff_pyramid_page: "
|
||||
"%d layer pyramid detected\n",
|
||||
thumbnail->n_pages );
|
||||
#endif /*DEBUG*/
|
||||
thumbnail->level_count = thumbnail->n_pages;
|
||||
|
||||
return( thumbnail->n_pages > 1 );
|
||||
}
|
||||
|
||||
/* Detect a TIFF pyramid made of subifds following a roughly /2 shrink.
|
||||
*
|
||||
* This may not be a pyr tiff, so no error if we can't find the layers.
|
||||
*/
|
||||
static gboolean
|
||||
vips_thumbnail_get_tiff_pyramid_subifd( VipsThumbnail *thumbnail )
|
||||
{
|
||||
VipsThumbnailClass *class = VIPS_THUMBNAIL_GET_CLASS( thumbnail );
|
||||
int i;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "vips_thumbnail_get_tiff_pyramid_subifd:\n" );
|
||||
#endif /*DEBUG*/
|
||||
|
||||
/* Tell open() that we want to open subifds rather than pages.
|
||||
*/
|
||||
thumbnail->subifd_pyramid = TRUE;
|
||||
|
||||
for( i = 0; i < thumbnail->n_subifds; i++ ) {
|
||||
VipsImage *page;
|
||||
int level_width;
|
||||
int level_height;
|
||||
int expected_level_width;
|
||||
int expected_level_height;
|
||||
|
||||
if( !(page = class->open( thumbnail, i )) )
|
||||
return( FALSE );
|
||||
level_width = page->Xsize;
|
||||
level_height = page->Ysize;
|
||||
VIPS_UNREF( page );
|
||||
|
||||
/* The main image is size 1, subifd 0 is half that.
|
||||
*/
|
||||
expected_level_width = thumbnail->input_width / (2 << i);
|
||||
expected_level_height = thumbnail->input_height / (2 << i);
|
||||
|
||||
/* This won't be exact due to rounding etc.
|
||||
*/
|
||||
if( abs( level_width - expected_level_width ) > 5 ||
|
||||
level_width < 2 )
|
||||
return( FALSE );
|
||||
if( abs( level_height - expected_level_height ) > 5 ||
|
||||
level_height < 2 )
|
||||
return( FALSE );
|
||||
|
||||
thumbnail->level_width[i] = level_width;
|
||||
thumbnail->level_height[i] = level_height;
|
||||
}
|
||||
|
||||
/* Now set level_count. This signals that we've found a pyramid.
|
||||
*/
|
||||
#ifdef DEBUG
|
||||
printf( "vips_thumbnail_get_tiff_pyramid_subifd: "
|
||||
"%d layer pyramid detected\n",
|
||||
thumbnail->n_pages );
|
||||
#endif /*DEBUG*/
|
||||
thumbnail->level_count = thumbnail->n_pages;
|
||||
|
||||
return( TRUE );
|
||||
}
|
||||
|
||||
static int
|
||||
@ -459,11 +536,13 @@ vips_thumbnail_open( VipsThumbnail *thumbnail )
|
||||
g_info( "input size is %d x %d",
|
||||
thumbnail->input_width, thumbnail->input_height );
|
||||
|
||||
/* For tiff, we need a separate ->open() for each page to
|
||||
* get all the pyramid levels.
|
||||
/* For tiff, scan the image and try to spot page-based and ifd-based
|
||||
* pyramids.
|
||||
*/
|
||||
if( vips_isprefix( "VipsForeignLoadTiff", thumbnail->loader ) )
|
||||
vips_thumbnail_get_tiff_pyramid( thumbnail );
|
||||
if( vips_isprefix( "VipsForeignLoadTiff", thumbnail->loader ) ) {
|
||||
if( !vips_thumbnail_get_tiff_pyramid_page( thumbnail ) )
|
||||
vips_thumbnail_get_tiff_pyramid_subifd( thumbnail );
|
||||
}
|
||||
|
||||
/* For heif, we need to fetch the thumbnail size, in case we can use
|
||||
* that as the source.
|
||||
@ -967,10 +1046,16 @@ vips_thumbnail_file_open( VipsThumbnail *thumbnail, double factor )
|
||||
NULL ) );
|
||||
}
|
||||
else if( vips_isprefix( "VipsForeignLoadTiff", thumbnail->loader ) ) {
|
||||
return( vips_image_new_from_file( file->filename,
|
||||
"access", VIPS_ACCESS_SEQUENTIAL,
|
||||
"page", (int) factor,
|
||||
NULL ) );
|
||||
if( thumbnail->subifd_pyramid )
|
||||
return( vips_image_new_from_file( file->filename,
|
||||
"access", VIPS_ACCESS_SEQUENTIAL,
|
||||
"subifd", (int) factor,
|
||||
NULL ) );
|
||||
else
|
||||
return( vips_image_new_from_file( file->filename,
|
||||
"access", VIPS_ACCESS_SEQUENTIAL,
|
||||
"page", (int) factor,
|
||||
NULL ) );
|
||||
}
|
||||
else if( vips_isprefix( "VipsForeignLoadHeif", thumbnail->loader ) ) {
|
||||
return( vips_image_new_from_file( file->filename,
|
||||
|
Loading…
Reference in New Issue
Block a user