load header done

This commit is contained in:
John Cupitt 2021-04-01 12:33:36 +01:00
parent c7f69718da
commit 2a249a3049
3 changed files with 97 additions and 511 deletions

View File

@ -1454,6 +1454,9 @@ EXIF metadata support with libexif: $with_libexif
## File format support
JPEG load/save with libjpeg: $with_jpeg
JXL load/save with libjxl: $with_libjxl
JPEG2000 load/save with libopenjp2: $with_libopenjp2
(requires libopenjp2 2.2 or later)
PNG load with libspng: $with_libspng
(requires libspng-0.6 or later)
PNG load/save with libpng: $with_png
@ -1464,7 +1467,6 @@ TIFF load/save with libtiff: $with_tiff
image pyramid save: $with_gsf
(requires libgsf-1 1.14.26 or later)
HEIC/AVIF load/save with libheif: $with_heif
JXL load/save with libjxl: $with_libjxl
WebP load/save with libwebp: $with_libwebp
(requires libwebp, libwebpmux, libwebpdemux 0.6.0 or later)
PDF load with PDFium: $with_pdfium
@ -1473,8 +1475,6 @@ PDF load with poppler-glib: $with_poppler
SVG load with librsvg-2.0: $with_rsvg
(requires librsvg-2.0 2.34.0 or later)
EXR load with OpenEXR: $with_OpenEXR
JPEG2000 load/save with libopenjp2: $with_libopenjp2
(requires libopenjp2 2.2 or later)
slide load with OpenSlide: $with_openslide
(requires openslide-3.3.0 or later)
Matlab load with matio: $with_matio

View File

@ -75,6 +75,8 @@ typedef struct _VipsForeignLoadJxl {
/* Base image properties.
*/
JxlBasicInfo info;
size_t icc_size;
uint8_t *icc_data;
/* Decompress state.
*/
@ -120,15 +122,25 @@ vips_foreign_load_jxl_dispose( GObject *gobject )
VIPS_FREEF( JxlThreadParallelRunnerDestroy, jxl->runner );
VIPS_FREEF( JxlDecoderDestroy, jxl->decoder );
VIPS_FREE( jxl->icc_data );
G_OBJECT_CLASS( vips_foreign_load_jxl_parent_class )->
dispose( gobject );
}
static void
vips_foreign_load_jxl_error( VipsForeignLoadJxl *jxl, const char *details )
{
VipsObjectClass *klass = VIPS_OBJECT_GET_CLASS( object );
/* TODO ... jxl has no way to get error messages at the moemnt.
*/
vips_error( klass->nickname, "%s", details );
}
static int
vips_foreign_load_jxl_build( VipsObject *object )
{
VipsObjectClass *klass = VIPS_OBJECT_GET_CLASS( object );
VipsForeignLoadJxl *jxl = (VipsForeignLoadJxl *) object;
JxlDecoderStatus status;
@ -141,18 +153,18 @@ vips_foreign_load_jxl_build( VipsObject *object )
vips_concurrency_get() );
jxl->decoder = JxlDecoderCreate( nullptr );
/* We are only interested in end of header and end of pixel data.
*/
if( JxlDecoderSubscribeEvents( jxl->decoder,
JXL_DEC_BASIC_INFO |
JXL_DEC_COLOR_ENCODING |
JXL_DEC_FULL_IMAGE ) != JXL_DEC_SUCCESS ) {
vips_error( klass->nickname,
"%s", _( "JxlDecoderSubscribeEvents failed" ) );
vips_foreign_load_jxl_error( jxl, "JxlDecoderSubscribeEvents" );
return( -1 );
}
if( JxlDecoderSetParallelRunner( jxl->decoder,
JxlThreadParallelRunner, jxl->runner ) != JXL_DEC_SUCCESS ) {
vips_error( klass->nickname,
"%s", _( "JxlDecoderSetParallelRunner failed" ) );
vips_foreign_load_jxl_error( jxl,
"JxlDecoderSetParallelRunner" );
return( -1 );
}
@ -163,115 +175,31 @@ vips_foreign_load_jxl_build( VipsObject *object )
return( 0 );
}
/* Always read as scRGBA.
*/
static JxlPixelFormat vips_foreign_load_jxl_format =
{ 4, JXL_TYPE_FLOAT, JXL_NATIVE_ENDIAN, 0 };
static int
vips_foreign_load_jxl_set_header( VipsForeignLoadJxl *jxl, VipsImage *out )
{
VipsObjectClass *klass = VIPS_OBJECT_GET_CLASS( jxl );
opj_image_comp_t *first = &jxl->image->comps[0];
VipsBandFormat format;
VipsInterpretation interpretation;
/* OpenJPEG only supports up to 31 bpp. Treat it as 32.
*/
if( first->prec <= 8 )
format = first->sgnd ? VIPS_FORMAT_CHAR : VIPS_FORMAT_UCHAR;
else if( first->prec <= 16 )
format = first->sgnd ? VIPS_FORMAT_SHORT : VIPS_FORMAT_USHORT;
else
format = first->sgnd ? VIPS_FORMAT_INT : VIPS_FORMAT_UINT;
switch( jxl->image->color_space ) {
case OPJ_CLRSPC_SYCC:
case OPJ_CLRSPC_EYCC:
/* Map these to RGB.
*/
interpretation = vips_format_sizeof( format ) == 1 ?
VIPS_INTERPRETATION_sRGB :
VIPS_INTERPRETATION_RGB16;
jxl->ycc_to_rgb = TRUE;
break;
case OPJ_CLRSPC_GRAY:
interpretation = vips_format_sizeof( format ) == 1 ?
VIPS_INTERPRETATION_B_W :
VIPS_INTERPRETATION_GREY16;
break;
case OPJ_CLRSPC_SRGB:
interpretation = vips_format_sizeof( format ) == 1 ?
VIPS_INTERPRETATION_sRGB :
VIPS_INTERPRETATION_RGB16;
break;
case OPJ_CLRSPC_CMYK:
interpretation = VIPS_INTERPRETATION_CMYK;
break;
case OPJ_CLRSPC_UNSPECIFIED:
/* Try to guess something sensible.
*/
if( jxl->image->numcomps < 3 )
interpretation = vips_format_sizeof( format ) == 1 ?
VIPS_INTERPRETATION_B_W :
VIPS_INTERPRETATION_GREY16;
else
interpretation = vips_format_sizeof( format ) == 1 ?
VIPS_INTERPRETATION_sRGB :
VIPS_INTERPRETATION_RGB16;
/* Unspecified with three bands and subsampling on bands 2 and
* 3 is usually YCC.
*/
if( jxl->image->numcomps == 3 &&
jxl->image->comps[0].dx == 1 &&
jxl->image->comps[0].dy == 1 &&
jxl->image->comps[1].dx > 1 &&
jxl->image->comps[1].dy > 1 &&
jxl->image->comps[2].dx > 1 &&
jxl->image->comps[2].dy > 1)
jxl->ycc_to_rgb = TRUE;
break;
default:
vips_error( klass->nickname,
_( "unsupported colourspace %d" ),
jxl->image->color_space );
return( -1 );
}
/* Even though this is a tiled reader, we hint thinstrip since with
* the cache we are quite happy serving that if anything downstream
/* Even though this is a full image reader, we hint thinstrip since
* we are quite happy serving that if anything downstream
* would like it.
*/
vips_image_pipelinev( out, VIPS_DEMAND_STYLE_THINSTRIP, NULL );
vips_image_init_fields( out,
first->w, first->h, jxl->image->numcomps, format,
VIPS_CODING_NONE, interpretation, 1.0, 1.0 );
jxl->info.width, jxl->info.height, 4, VIPS_FORMAT_FLOAT,
VIPS_CODING_NONE, VIPS_INTERPRETATION_scRGB, 1.0, 1.0 );
/* openjpeg allows left and top of the coordinate grid to be
* non-zero. These are always in unshrunk coordinates.
*/
out->Xoffset =
-VIPS_ROUND_INT( (double) jxl->image->x0 / jxl->shrink );
out->Yoffset =
-VIPS_ROUND_INT( (double) jxl->image->y0 / jxl->shrink );
if( jxl->image->icc_profile_buf &&
jxl->image->icc_profile_len > 0 )
vips_image_set_blob_copy( out, VIPS_META_ICC_NAME,
jxl->image->icc_profile_buf,
jxl->image->icc_profile_len );
/* Map number of layers in image to pages.
*/
if( jxl->info &&
jxl->info->m_default_tile_info.tccp_info )
vips_image_set_int( out, VIPS_META_N_PAGES,
jxl->info->m_default_tile_info.tccp_info->
numresolutions );
if( jxl->icc_data &&
jxl->icc_size > 0 ) {
vips_image_set_blob( out, VIPS_META_ICC_NAME, vips_free,
jxl->icc_data, jxl->icc_size );
jxl->icc_data = nullptr;
jxl->icc_size = 0;
}
return( 0 );
}
@ -371,10 +299,11 @@ vips_foreign_load_jxl_process( VipsForeignLoadJxl *jxl )
while( (status = JxlDecoderProcessInput( jx->decoder )) ==
JXL_DEC_NEED_MORE_INPUT ) {
size_t bytes_remaining;
size_t unused;
bytes_remaining = JxlDecoderReleaseInput( jxl->decoder );
if( vips_foreign_load_jxl_fill_input( jxl, bytes_remaining ) )
unused = JxlDecoderReleaseInput( jxl->decoder );
if( vips_foreign_load_jxl_fill_input( jxl, unused ) &&
unused == 0 )
return( JXL_DEC_ERROR );
JxlDecoderSetInput( jxl->decoder,
jxl->input_buffer, jxl->bytes_remaining );
@ -386,17 +315,28 @@ vips_foreign_load_jxl_process( VipsForeignLoadJxl *jxl )
return( status );
}
static int
vips_foreign_load_jxl_header( VipsForeignLoad *load )
{
VipsObjectClass *klass = VIPS_OBJECT_GET_CLASS( load );
VipsForeignLoadJxl *jxl = (VipsForeignLoadJxl *) load;
JxlDecoderStatus status;
#ifdef DEBUG
printf( "vips_foreign_load_jxl_header:\n" );
#endif /*DEBUG*/
/* Even though this is a full image reader, we hint thinstrip since
* we are quite happy serving that if anything downstream
* would like it.
*/
vips_image_pipelinev( out, VIPS_DEMAND_STYLE_THINSTRIP, NULL );
vips_image_init_fields( out,
jxl->info.width, first->h, jxl->image->numcomps, format,
VIPS_CODING_NONE, interpretation, 1.0, 1.0 );
if( vips_foreign_load_jxl_fill_input( jxl, 0 ) )
return( -1 );
JxlDecoderSetInput( jx->decoder,
@ -405,89 +345,48 @@ vips_foreign_load_jxl_header( VipsForeignLoad *load )
/* Read to the end of the header.
*/
do {
JxlDecoderStatus status;
status = vips_foreign_load_jxl_process( jxl );
if( status == JXL_DEC_ERROR )
switch( (status = vips_foreign_load_jxl_process( jxl )) ) {
case JXL_DEC_ERROR:
vips_foreign_load_jxl_error( jxl,
"JxlDecoderProcessInput" );
return( -1 );
case JXL_DEC_BASIC_INFO:
if( JxlDecoderGetBasicInfo( jxl->decoder,
&jxl->info ) ) {
vips_foreign_load_jxl_error( jxl,
"JxlDecoderGetBasicInfo" );
return( -1 );
}
break;
case JXL_DEC_COLOR_ENCODING:
if( JxlDecoderGetICCProfileSize( jxl->decoder,
&vips_foreign_load_jxl_format,
JXL_COLOR_PROFILE_TARGET_DATA,
&jxl->icc_size ) ) {
vips_foreign_load_jxl_error( jxl,
"JxlDecoderGetICCProfileSize" );
return( -1 );
}
if( !(jxl->icc_data = vips_malloc( nullptr,
jxl->icc_size )) )
return( -1 );
if( JxlDecoderGetColorAsICCProfile(
jxl->decoder,
JXL_COLOR_PROFILE_TARGET_DATA,
jxl->icc_data, jxl->icc_size ) ) {
vips_foreign_load_jxl_error( jxl,
"JxlDecoderGetColorAsICCProfile" );
return( -1 );
}
break;
default:
break;
}
} while( status != JXL_DEC_COLOR_ENCODING );
JxlDecoderGetBasicInfo( jxl->decoder, &jxl->info );
jxl->format = vips_foreign_load_jxl_get_format( jxl->source );
vips_source_rewind( jxl->source );
if( !(jxl->codec = opj_create_decompress( jxl->format )) )
return( -1 );
vips_foreign_load_jxl_attach_handlers( jxl, jxl->codec );
jxl->shrink = 1 << jxl->page;
jxl->parameters.cp_reduce = jxl->page;
if( !opj_setup_decoder( jxl->codec, &jxl->parameters ) )
return( -1 );
#ifdef HAVE_LIBJXL_THREADING
/* Use eg. VIPS_CONCURRENCY etc. to set n-cpus, if this openjpeg has
* stable support.
*/
opj_codec_set_threads( jxl->codec, vips_concurrency_get() );
#endif /*HAVE_LIBJXL_THREADING*/
if( !opj_read_header( jxl->stream, jxl->codec, &jxl->image ) )
return( -1 );
if( !(jxl->info = opj_get_cstr_info( jxl->codec )) )
return( -1 );
#ifdef DEBUG
vips_foreign_load_jxl_print( jxl );
#endif /*DEBUG*/
/* We only allow images where all components have the same format.
*/
if( jxl->image->numcomps > MAX_BANDS ) {
vips_error( klass->nickname,
"%s", _( "too many image bands" ) );
return( -1 );
}
if( jxl->image->numcomps == 0 ) {
vips_error( klass->nickname,
"%s", _( "no image components" ) );
return( -1 );
}
first = &jxl->image->comps[0];
for( i = 1; i < jxl->image->numcomps; i++ ) {
opj_image_comp_t *this = &jxl->image->comps[i];
if( this->x0 != first->x0 ||
this->y0 != first->y0 ||
this->w * this->dx != first->w * first->dx ||
this->h * this->dy != first->h * first->dy ||
this->resno_decoded != first->resno_decoded ||
this->factor != first->factor ) {
vips_error( klass->nickname,
"%s", _( "components differ in geometry" ) );
return( -1 );
}
if( this->prec != first->prec ||
this->bpp != first->bpp ||
this->sgnd != first->sgnd ) {
vips_error( klass->nickname,
"%s", _( "components differ in precision" ) );
return( -1 );
}
/* If dx/dy are not 1, we'll need to upsample components during
* tile packing.
*/
if( this->dx != first->dx ||
this->dy != first->dy ||
first->dx != 1 ||
first->dy != 1 )
jxl->upsample = TRUE;
}
if( vips_foreign_load_jxl_set_header( jxl, load->out ) )
return( -1 );
@ -497,281 +396,11 @@ vips_foreign_load_jxl_header( VipsForeignLoad *load )
return( 0 );
}
#define PACK( TYPE ) { \
TYPE *tq = (TYPE *) q; \
\
for( x = 0; x < length; x++ ) { \
for( i = 0; i < b; i++ ) \
tq[i] = planes[i][x]; \
\
tq += b; \
} \
}
#define PACK_UPSAMPLE( TYPE ) { \
TYPE *tq = (TYPE *) q; \
\
for( x = 0; x < length; x++ ) { \
for( i = 0; i < b; i++ ) { \
int dx = jxl->image->comps[i].dx; \
int pixel = planes[i][x / dx]; \
\
tq[i] = pixel; \
} \
\
tq += b; \
} \
}
/* Pack the set of openjpeg components into a libvips region. left/top are the
* offsets into the tile in pixel coordinates where we should start reading.
*/
static void
vips_foreign_load_jxl_pack( VipsForeignLoadJxl *jxl,
VipsImage *image, VipsPel *q,
int left, int top, int length )
{
int *planes[MAX_BANDS];
int b = jxl->image->numcomps;
int x, i;
for( i = 0; i < b; i++ ) {
opj_image_comp_t *comp = &jxl->image->comps[i];
planes[i] = comp->data + (top / comp->dy) * comp->w +
(left / comp->dx);
}
if( jxl->upsample )
switch( image->BandFmt ) {
case VIPS_FORMAT_CHAR:
case VIPS_FORMAT_UCHAR:
PACK_UPSAMPLE( unsigned char );
break;
case VIPS_FORMAT_SHORT:
case VIPS_FORMAT_USHORT:
PACK_UPSAMPLE( unsigned short );
break;
case VIPS_FORMAT_INT:
case VIPS_FORMAT_UINT:
PACK_UPSAMPLE( unsigned int );
break;
default:
g_assert_not_reached();
break;
}
else
/* Fast no-upsample path.
*/
switch( image->BandFmt ) {
case VIPS_FORMAT_CHAR:
case VIPS_FORMAT_UCHAR:
PACK( unsigned char );
break;
case VIPS_FORMAT_SHORT:
case VIPS_FORMAT_USHORT:
PACK( unsigned short );
break;
case VIPS_FORMAT_INT:
case VIPS_FORMAT_UINT:
PACK( unsigned int );
break;
default:
g_assert_not_reached();
break;
}
}
/* ycc->rgb coversion adapted from openjpeg src/bin/common/color.c
*
* See also https://en.wikipedia.org/wiki/YCbCr#JPEG_conversion
*/
#define YCC_TO_RGB( TYPE ) { \
TYPE *tq = (TYPE *) q; \
\
for( x = 0; x < length; x++ ) { \
int y = tq[0]; \
int cb = tq[1] - offset; \
int cr = tq[2] - offset; \
\
int r, g, b; \
\
r = y + (int)(1.402 * (float)cr); \
tq[0] = VIPS_CLIP( 0, r, upb ); \
\
g = y - (int)(0.344 * (float)cb + 0.714 * (float)cr); \
tq[1] = VIPS_CLIP( 0, g, upb ); \
\
b = y + (int)(1.772 * (float)cb); \
tq[2] = VIPS_CLIP( 0, b, upb ); \
\
tq += 3; \
} \
}
/* YCC->RGB for a line of pels.
*/
static void
vips_foreign_load_jxl_ycc_to_rgb( VipsForeignLoadJxl *jxl,
VipsPel *q, int length )
{
VipsForeignLoad *load = (VipsForeignLoad *) jxl;
int prec = jxl->image->comps[0].prec;
int offset = 1 << (prec - 1);
int upb = (1 << prec) - 1;
int x;
switch( load->out->BandFmt ) {
case VIPS_FORMAT_CHAR:
case VIPS_FORMAT_UCHAR:
YCC_TO_RGB( unsigned char );
break;
case VIPS_FORMAT_SHORT:
case VIPS_FORMAT_USHORT:
YCC_TO_RGB( unsigned short );
break;
case VIPS_FORMAT_INT:
case VIPS_FORMAT_UINT:
YCC_TO_RGB( unsigned int );
break;
default:
g_assert_not_reached();
break;
}
}
/* Loop over the output region, painting in tiles from the file.
*/
static int
vips_foreign_load_jxl_generate( VipsRegion *out,
void *seq, void *a, void *b, gboolean *stop )
{
VipsForeignLoad *load = (VipsForeignLoad *) a;
VipsForeignLoadJxl *jxl = (VipsForeignLoadJxl *) load;
VipsRect *r = &out->valid;
/* jxl get smaller with the layer size.
*/
int tile_width = VIPS_ROUND_UINT(
(double) jxl->info->tdx / jxl->shrink );
int tile_height = VIPS_ROUND_UINT(
(double) jxl->info->tdy / jxl->shrink );
/* ... so tiles_across is always the same.
*/
int tiles_across = jxl->info->tw;
int x, y, z;
#ifdef DEBUG_VERBOSE
printf( "vips_foreign_load_jxl_generate: "
"left = %d, top = %d, width = %d, height = %d\n",
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( jxl->n_errors )
return( 0 );
y = 0;
while( y < r->height ) {
VipsRect tile, hit;
/* Not necessary, but it stops static analyzers complaining
* about a used-before-set.
*/
hit.height = 0;
x = 0;
while( x < r->width ) {
/* Tile the xy falls in, in tile numbers.
*/
int tx = (r->left + x) / tile_width;
int ty = (r->top + y) / tile_height;
/* Pixel coordinates of the tile that xy falls in.
*/
int xs = tx * tile_width;
int ys = ty * tile_height;
int tile_index = ty * tiles_across + tx;
/* Fetch the tile.
*/
#ifdef DEBUG_VERBOSE
printf( " fetch tile %d\n", tile_index );
#endif /*DEBUG_VERBOSE*/
if( !opj_get_decoded_tile( jxl->codec,
jxl->stream, jxl->image, tile_index ) )
return( -1 );
/* Intersect tile with request to get pixels we need
* to copy out.
*/
tile.left = xs;
tile.top = ys;
tile.width = tile_width;
tile.height = tile_height;
vips_rect_intersectrect( &tile, r, &hit );
/* Unpack hit pixels to buffer in vips layout.
*/
for( z = 0; z < hit.height; z++ ) {
VipsPel *q = VIPS_REGION_ADDR( out,
hit.left, hit.top + z );
vips_foreign_load_jxl_pack( jxl,
out->im, q,
hit.left - tile.left,
hit.top - tile.top + z,
hit.width );
if( jxl->ycc_to_rgb )
vips_foreign_load_jxl_ycc_to_rgb( jxl,
q, hit.width );
}
x += hit.width;
}
/* This will be the same for all tiles in the row we've just
* done.
*/
y += hit.height;
}
if( load->fail &&
jxl->n_errors > 0 )
return( -1 );
return( 0 );
}
static int
vips_foreign_load_jxl_load( VipsForeignLoad *load )
{
VipsForeignLoadJxl *jxl = (VipsForeignLoadJxl *) load;
/* jxl tiles get smaller with the layer size, but we don't want tiny
* tiles for the libvips tile cache, so leave them at the base size.
*/
int tile_width = jxl->info->tdx;
int tile_height = jxl->info->tdy;
int tiles_across = jxl->info->tw;
VipsImage **t = (VipsImage **)
vips_object_local_array( VIPS_OBJECT( load ), 3 );
@ -783,20 +412,7 @@ vips_foreign_load_jxl_load( VipsForeignLoad *load )
if( vips_foreign_load_jxl_set_header( jxl, t[0] ) )
return( -1 );
if( vips_image_generate( t[0],
NULL, vips_foreign_load_jxl_generate, NULL, jxl, NULL ) )
return( -1 );
/* Copy to out, adding a cache. Enough tiles for two complete
* rows, plus 50%.
*/
if( vips_tilecache( t[0], &t[1],
"tile_width", tile_width,
"tile_height", tile_height,
"max_tiles", 3 * tiles_across,
NULL ) )
return( -1 );
if( vips_image_write( t[1], load->real ) )
if( vips_image_write( t[0], load->real ) )
return( -1 );
return( 0 );
@ -814,20 +430,13 @@ vips_foreign_load_jxl_class_init( VipsForeignLoadJxlClass *klass )
gobject_class->get_property = vips_object_get_property;
object_class->nickname = "jxlload_base";
object_class->description = _( "load JPEG2000 image" );
object_class->description = _( "load JPEG-XL image" );
object_class->build = vips_foreign_load_jxl_build;
load_class->get_flags = vips_foreign_load_jxl_get_flags;
load_class->header = vips_foreign_load_jxl_header;
load_class->load = vips_foreign_load_jxl_load;
VIPS_ARG_INT( klass, "page", 20,
_( "Page" ),
_( "Load this page from the image" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsForeignLoadJxl, page ),
0, 100000, 0 );
}
static void
@ -871,7 +480,7 @@ vips_foreign_load_jxl_file_build( VipsObject *object )
}
const char *vips__jxl_suffs[] =
{ ".j2k", ".jp2", ".jpt", ".j2c", ".jpc", NULL };
{ ".jxl", NULL };
static int
vips_foreign_load_jxl_is_a( const char *filename )
@ -1079,22 +688,7 @@ vips_foreign_load_jxl_source_init(
* @out: (out): decompressed image
* @...: %NULL-terminated list of optional named arguments
*
* Optional arguments:
*
* * @page: %gint, load this page
*
* Read a JPEG2000 image. The loader supports 8, 16 and 32-bit int pixel
* values, signed and unsigned.
* It supports greyscale, RGB, YCC, CMYK and
* multispectral colour spaces.
* It will read any ICC profile on
* the image.
*
* It will only load images where all channels are the same format.
*
* 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.
* Read a JPEG-XL image.
*
* See also: vips_image_new_from_file().
*
@ -1120,10 +714,6 @@ vips_jxlload( const char *filename, VipsImage **out, ... )
* @out: (out): image to write
* @...: %NULL-terminated list of optional named arguments
*
* Optional arguments:
*
* * @page: %gint, load this page
*
* Exactly as vips_jxlload(), but read from a source.
*
* Returns: 0 on success, -1 on error.
@ -1154,10 +744,6 @@ vips_jxlload_buffer( void *buf, size_t len, VipsImage **out, ... )
* @out: (out): decompressed image
* @...: %NULL-terminated list of optional named arguments
*
* Optional arguments:
*
* * @page: %gint, load this page
*
* Exactly as vips_jxlload(), but read from a source.
*
* Returns: 0 on success, -1 on error.

View File

@ -2,7 +2,7 @@ EXTRA_DIST = \
README-ns \
README.md \
patches \
update.sh \
update.sh \
utils
noinst_LTLIBRARIES = libnsgif.la