use "page" param for jp2k pyr layers

should make it easy for thumbnail etc.
This commit is contained in:
John Cupitt 2021-03-18 16:16:46 +00:00
parent 197239727d
commit 1bcaab00a6
1 changed files with 45 additions and 41 deletions

View File

@ -35,9 +35,9 @@
*/
/*
*/
#define DEBUG
#define DEBUG_VERBOSE
#define DEBUG
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
@ -59,12 +59,10 @@
#include "pforeign.h"
/* TODO:
*
* - we only support 8 and 16-bit images, is this OK?
*
* - we only support images where all components have the same numeric
* type, is this OK?
*
*/
/* Surely enough ... does anyone do multispectral imaging with jp2k?
@ -78,8 +76,9 @@ typedef struct _VipsForeignLoadJp2k {
*/
VipsSource *source;
/* Shrink on load factor.
/* Page set by user, then we translate that into shrink factor.
*/
int page;
int shrink;
/* Decompress state.
@ -151,11 +150,11 @@ vips_foreign_load_jp2k_skip_source( OPJ_OFF_T n_bytes, void *client )
{
VipsSource *source = VIPS_SOURCE( client );
if( vips_source_seek( source, n_bytes, SEEK_CUR ) )
if( vips_source_seek( source, n_bytes, SEEK_CUR ) == -1 )
/* openjpeg skip uses -1 for both end of stream and error.
*/
return( -1 );
/* openjpeg skip uses -1 for both end of stream and error.
*/
return( n_bytes );
}
@ -360,8 +359,8 @@ vips_foreign_load_jp2k_print( VipsForeignLoadJp2k *jp2k )
jp2k->info->tx0, jp2k->info->ty0,
jp2k->info->tdx, jp2k->info->tdy,
jp2k->info->tw, jp2k->info->th );
printf( "nbcomps = %u\n",
jp2k->info->nbcomps );
printf( "nbcomps = %u, tile_info = %p\n",
jp2k->info->nbcomps, jp2k->info->tile_info );
}
#endif /*DEBUG*/
@ -372,8 +371,6 @@ vips_foreign_load_jp2k_set_header( VipsForeignLoadJp2k *jp2k, VipsImage *out )
opj_image_comp_t *first;
int i;
int width;
int height;
VipsBandFormat format;
VipsInterpretation interpretation;
@ -410,18 +407,6 @@ vips_foreign_load_jp2k_set_header( VipsForeignLoadJp2k *jp2k, VipsImage *out )
}
}
/* Image size shrunk down should match components in size. jp2k uses
* round to nearest.
*/
width = VIPS_ROUND_UINT( (double) jp2k->image->x1 / jp2k->shrink );
height = VIPS_ROUND_UINT( (double) jp2k->image->y1 / jp2k->shrink );
if( width != first->w ||
height != first->h ) {
vips_error( class->nickname,
"%s", _( "components not same size as image" ) );
return( -1 );
}
switch( first->prec ) {
case 8:
format = VIPS_FORMAT_UCHAR;
@ -481,7 +466,7 @@ vips_foreign_load_jp2k_set_header( VipsForeignLoadJp2k *jp2k, VipsImage *out )
vips_image_pipelinev( out, VIPS_DEMAND_STYLE_THINSTRIP, NULL );
vips_image_init_fields( out,
width, height, jp2k->image->numcomps, format,
first->w, first->h, jp2k->image->numcomps, format,
VIPS_CODING_NONE, interpretation, 1.0, 1.0 );
/* openjpeg allows left and top of the coordinate grid to be
@ -498,6 +483,14 @@ vips_foreign_load_jp2k_set_header( VipsForeignLoadJp2k *jp2k, VipsImage *out )
jp2k->image->icc_profile_buf,
jp2k->image->icc_profile_len );
/* Map number of layers in image to pages.
*/
if( jp2k->info &&
jp2k->info->m_default_tile_info.tccp_info )
vips_image_set_int( out, VIPS_META_N_PAGES,
jp2k->info->m_default_tile_info.tccp_info->
numresolutions );
return( 0 );
}
@ -511,8 +504,6 @@ vips_foreign_load_jp2k_header( VipsForeignLoad *load )
printf( "vips_foreign_load_jp2k_header:\n" );
#endif /*DEBUG*/
int bits;
jp2k->format = vips_foreign_load_jp2k_get_format( jp2k->source );
vips_source_rewind( jp2k->source );
if( !(jp2k->codec = opj_create_decompress( jp2k->format )) ) {
@ -523,13 +514,8 @@ vips_foreign_load_jp2k_header( VipsForeignLoad *load )
vips_foreign_load_jp2k_attach_handlers( jp2k, jp2k->codec );
bits = vips_ispoweroftwo( jp2k->shrink );
if( !bits ) {
vips_error( class->nickname,
"%s", _( "shrink must be a power of two" ) );
return( -1 );
}
jp2k->parameters.cp_reduce = bits - 1;
jp2k->shrink = 1 << jp2k->page;
jp2k->parameters.cp_reduce = jp2k->page;
if( !opj_setup_decoder( jp2k->codec, &jp2k->parameters ) )
return( -1 );
@ -630,6 +616,12 @@ vips_foreign_load_jp2k_generate( VipsRegion *out,
r->left, r->top, r->width, r->height );
#endif /*DEBUG_VERBOSE*/
/* If openjpeg has flagged an error, the library is not in a known
* state and it's not safe to call again.
*/
if( jp2k->n_errors )
return( 0 );
y = 0;
while( y < r->height ) {
VipsRect tile, hit;
@ -765,18 +757,18 @@ vips_foreign_load_jp2k_class_init( VipsForeignLoadJp2kClass *class )
load_class->header = vips_foreign_load_jp2k_header;
load_class->load = vips_foreign_load_jp2k_load;
VIPS_ARG_INT( class, "shrink", 20,
_( "Shrink" ),
_( "Shrink factor on load" ),
VIPS_ARG_INT( class, "page", 20,
_( "Page" ),
_( "Load this page from the image" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsForeignLoadJp2k, shrink ),
1, 1000, 1 );
G_STRUCT_OFFSET( VipsForeignLoadJp2k, page ),
0, 100000, 0 );
}
static void
vips_foreign_load_jp2k_init( VipsForeignLoadJp2k *jp2k )
{
jp2k->shrink = 1;
}
typedef struct _VipsForeignLoadJp2kFile {
@ -934,7 +926,15 @@ vips_foreign_load_jp2k_source_init(
* @out: (out): decompressed image
* @...: %NULL-terminated list of optional named arguments
*
* Read a JP2k image file into a VIPS image.
* Optional arguments:
*
* * @page: %gint, load this page
*
* Read a JPEG2000 image.
*
* Use @page to set the page to load, where page 0 is the base resolution
* image, and higher-numbered pages are x2 reductions. Use the metadata item
* "n-pages" to find the number of pyramid layers.
*
* See also: vips_image_new_from_file().
*
@ -959,6 +959,10 @@ vips_jp2kload( const char *filename, VipsImage **out, ... )
* @out: (out): decompressed image
* @...: %NULL-terminated list of optional named arguments
*
* Optional arguments:
*
* * @page: %gint, load this page
*
* Exactly as vips_jp2kload(), but read from a source.
*
* Returns: 0 on success, -1 on error.