diff --git a/libvips/foreign/heifload.c b/libvips/foreign/heifload.c index 37685c26..1c05dd2a 100644 --- a/libvips/foreign/heifload.c +++ b/libvips/foreign/heifload.c @@ -32,9 +32,9 @@ */ /* -#define DEBUG #define VIPS_DEBUG */ +#define DEBUG #ifdef HAVE_CONFIG_H #include @@ -68,6 +68,11 @@ typedef struct _VipsForeignLoadHeif { */ gboolean autorotate; + /* Fetch the thumbnail instead of the image. If there is no thumbnail, + * just fetch the image. + */ + gboolean thumbnail; + /* Context for this image. */ struct heif_context *ctx; @@ -90,6 +95,11 @@ typedef struct _VipsForeignLoadHeif { */ int page_no; + /* TRUE if @handle has selected the thumbnail rather than the main + * image. + */ + gboolean thumbnail_set; + /* The page number of the primary image. */ int primary_page; @@ -180,16 +190,22 @@ vips_foreign_load_heif_get_flags( VipsForeignLoad *load ) return( VIPS_FOREIGN_SEQUENTIAL ); } +/* Select a page. If thumbnail is set, select the thumbnail for that page, if + * there is one. + */ static int -vips_foreign_load_heif_set_page( VipsForeignLoadHeif *heif, int page_no ) +vips_foreign_load_heif_set_page( VipsForeignLoadHeif *heif, + int page_no, gboolean thumbnail ) { if( !heif->handle || - page_no != heif->page_no ) { + page_no != heif->page_no || + thumbnail != heif->thumbnail_set ) { struct heif_error error; VIPS_FREEF( heif_image_handle_release, heif->handle ); VIPS_FREEF( heif_image_release, heif->img ); heif->data = NULL; + heif->thumbnail_set = FALSE; error = heif_context_get_image_handle( heif->ctx, heif->id[page_no], &heif->handle ); @@ -198,6 +214,30 @@ vips_foreign_load_heif_set_page( VipsForeignLoadHeif *heif, int page_no ) return( -1 ); } + if( thumbnail ) { + heif_item_id thumb_ids[1]; + int n_thumbs; + struct heif_image_handle *thumb_handle; + + n_thumbs = heif_image_handle_get_list_of_thumbnail_IDs( + heif->handle, thumb_ids, 1 ); + + if( n_thumbs > 0 ) { + error = heif_image_handle_get_thumbnail( + heif->handle, + thumb_ids[0], &thumb_handle ); + if( error.code ) { + vips__heif_error( &error ); + return( -1 ); + } + + VIPS_FREEF( heif_image_handle_release, + heif->handle ); + heif->handle = thumb_handle; + heif->thumbnail_set = TRUE; + } + } + heif->page_no = page_no; } @@ -387,14 +427,53 @@ vips_foreign_load_heif_header( VipsForeignLoad *load ) return( -1 ); } +#ifdef DEBUG + for( i = heif->page; i < heif->page + heif->n; i++ ) { + heif_item_id thumb_ids[1]; + int n_items; + int n_thumbs; + int j; + + if( vips_foreign_load_heif_set_page( heif, i, FALSE ) ) + return( -1 ); + + n_thumbs = heif_image_handle_get_number_of_thumbnails( + heif->handle ); + n_items = heif_image_handle_get_list_of_thumbnail_IDs( + heif->handle, thumb_ids, 1 ); + + printf( "page = %d\n", i ); + printf( "n_thumbs = %d\n", n_thumbs ); + printf( "n_items = %d\n", n_items ); + + for( j = 0; j < n_items; j++ ) { + struct heif_image_handle *thumb_handle; + + error = heif_image_handle_get_thumbnail( heif->handle, + thumb_ids[j], &thumb_handle ); + if( error.code ) { + vips__heif_error( &error ); + return( -1 ); + } + + printf( " thumb %d\n", j ); + printf( " width = %d\n", + heif_image_handle_get_width( thumb_handle ) ); + printf( " height = %d\n", + heif_image_handle_get_height( thumb_handle ) ); + } + } +#endif /*DEBUG*/ + /* All pages must be the same size for libvips toilet roll images. */ - if( vips_foreign_load_heif_set_page( heif, heif->page ) ) + if( vips_foreign_load_heif_set_page( heif, heif->page, heif->thumbnail ) ) return( -1 ); heif->page_width = heif_image_handle_get_width( heif->handle ); heif->page_height = heif_image_handle_get_height( heif->handle ); for( i = heif->page + 1; i < heif->page + heif->n; i++ ) { - if( vips_foreign_load_heif_set_page( heif, i ) ) + if( vips_foreign_load_heif_set_page( heif, + i, heif->thumbnail ) ) return( -1 ); if( heif_image_handle_get_width( heif->handle ) != heif->page_width || @@ -410,7 +489,7 @@ vips_foreign_load_heif_header( VipsForeignLoad *load ) printf( "n_top = %d\n", heif->n_top ); for( i = 0; i < heif->n_top; i++ ) { printf( " id[%d] = %d\n", i, heif->id[i] ); - if( vips_foreign_load_heif_set_page( heif, i ) ) + if( vips_foreign_load_heif_set_page( heif, i, FALSE ) ) return( -1 ); printf( " width = %d\n", heif_image_handle_get_width( heif->handle ) ); @@ -450,7 +529,7 @@ vips_foreign_load_heif_generate( VipsRegion *or, g_assert( r->height == 1 ); - if( vips_foreign_load_heif_set_page( heif, page ) ) + if( vips_foreign_load_heif_set_page( heif, page, heif->thumbnail ) ) return( -1 ); if( !heif->img ) { @@ -552,6 +631,13 @@ vips_foreign_load_heif_class_init( VipsForeignLoadHeifClass *class ) G_STRUCT_OFFSET( VipsForeignLoadHeif, autorotate ), FALSE ); + VIPS_ARG_BOOL( class, "thumbnail", 4, + _( "Thumbnail" ), + _( "Fetch thumbnail image" ), + VIPS_ARGUMENT_OPTIONAL_INPUT, + G_STRUCT_OFFSET( VipsForeignLoadHeif, thumbnail ), + FALSE ); + } static void