libvips/libvips/foreign/jxlload.c

939 lines
22 KiB
C

/* load jpeg-xl
*
* 18/3/20
* - from jxlload.c
*/
/*
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., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
/*
These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
*/
/*
#define DEBUG_VERBOSE
#define DEBUG
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <vips/vips.h>
#include <vips/debug.h>
#include <vips/internal.h>
#ifdef HAVE_LIBJXL
#include <jxl/decode.h>
#include <jxl/thread_parallel_runner.h>
#include "pforeign.h"
/* TODO:
*
* - libjxl seems to only work in one shot mode, so there's no way to read in
* chunks
*
* - preview image? EXIF? XMP?
*
* - check scRGB encoding
*
* - add "shrink" option to read out 8x shrunk image?
*
* - add animation support
*/
#define INPUT_BUFFER_SIZE (4096)
typedef struct _VipsForeignLoadJxl {
VipsForeignLoad parent_object;
/* Source to load from (set by subclasses).
*/
VipsSource *source;
/* Page set by user, then we translate that into shrink factor.
*/
int page;
int shrink;
/* Base image properties.
*/
JxlBasicInfo info;
JxlPixelFormat format;
size_t icc_size;
uint8_t *icc_data;
/* Decompress state.
*/
void *runner;
JxlDecoder *decoder;
/* Our input buffer.
*/
uint8_t input_buffer[INPUT_BUFFER_SIZE];
size_t bytes_in_buffer;
/* Number of errors reported during load -- use this to block load of
* corrupted images.
*/
int n_errors;
/* If we need to upsample tiles read from opj.
*/
gboolean upsample;
/* If we need to do ycc->rgb conversion on load.
*/
gboolean ycc_to_rgb;
} VipsForeignLoadJxl;
typedef VipsForeignLoadClass VipsForeignLoadJxlClass;
G_DEFINE_ABSTRACT_TYPE( VipsForeignLoadJxl, vips_foreign_load_jxl,
VIPS_TYPE_FOREIGN_LOAD );
static void
vips_foreign_load_jxl_dispose( GObject *gobject )
{
VipsForeignLoadJxl *jxl = (VipsForeignLoadJxl *) gobject;
#ifdef DEBUG
printf( "vips_foreign_load_jxl_dispose:\n" );
#endif /*DEBUG*/
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 *class = VIPS_OBJECT_GET_CLASS( jxl );
/* TODO ... jxl has no way to get error messages at the moemnt.
*/
vips_error( class->nickname, "%s", details );
}
static int
vips_foreign_load_jxl_build( VipsObject *object )
{
VipsForeignLoadJxl *jxl = (VipsForeignLoadJxl *) object;
#ifdef DEBUG
printf( "vips_foreign_load_jxl_build:\n" );
#endif /*DEBUG*/
jxl->runner = JxlThreadParallelRunnerCreate( NULL,
vips_concurrency_get() );
jxl->decoder = JxlDecoderCreate( NULL );
if( JxlDecoderSubscribeEvents( jxl->decoder,
JXL_DEC_COLOR_ENCODING |
JXL_DEC_BASIC_INFO |
JXL_DEC_FULL_IMAGE ) ) {
vips_foreign_load_jxl_error( jxl, "JxlDecoderSubscribeEvents" );
return( -1 );
}
if( JxlDecoderSetParallelRunner( jxl->decoder,
JxlThreadParallelRunner, jxl->runner ) ) {
vips_foreign_load_jxl_error( jxl,
"JxlDecoderSetParallelRunner" );
return( -1 );
}
if( VIPS_OBJECT_CLASS( vips_foreign_load_jxl_parent_class )->
build( object ) )
return( -1 );
return( 0 );
}
static gboolean
vips_foreign_load_jxl_is_a_source( VipsSource *source )
{
const unsigned char *p;
JxlSignature sig;
return( (p = vips_source_sniff( source, 12 )) &&
(sig = JxlSignatureCheck( p, 12 )) == JXL_SIG_CODESTREAM );
}
static VipsForeignFlags
vips_foreign_load_jxl_get_flags( VipsForeignLoad *load )
{
return( VIPS_FOREIGN_PARTIAL );
}
static int
vips_foreign_load_jxl_fill_input( VipsForeignLoadJxl *jxl,
size_t bytes_remaining )
{
gint64 bytes_read;
memcpy( jxl->input_buffer,
jxl->input_buffer + jxl->bytes_in_buffer - bytes_remaining,
bytes_remaining );
bytes_read = vips_source_read( jxl->source,
jxl->input_buffer + bytes_remaining,
INPUT_BUFFER_SIZE - bytes_remaining );
if( bytes_read < 0 )
return( -1 );
jxl->bytes_in_buffer = bytes_read + bytes_remaining;
return( 0 );
}
#ifdef DEBUG
static void
vips_foreign_load_jxl_print_status( JxlDecoderStatus status )
{
switch( status ) {
case JXL_DEC_SUCCESS:
printf( "JXL_DEC_SUCCESS\n" );
break;
case JXL_DEC_ERROR:
printf( "JXL_DEC_ERROR\n" );
break;
case JXL_DEC_NEED_MORE_INPUT:
printf( "JXL_DEC_NEED_MORE_INPUT\n" );
break;
case JXL_DEC_NEED_PREVIEW_OUT_BUFFER:
printf( "JXL_DEC_NEED_PREVIEW_OUT_BUFFER\n" );
break;
case JXL_DEC_NEED_DC_OUT_BUFFER:
printf( "JXL_DEC_NEED_DC_OUT_BUFFER\n" );
break;
case JXL_DEC_NEED_IMAGE_OUT_BUFFER:
printf( "JXL_DEC_NEED_IMAGE_OUT_BUFFER\n" );
break;
case JXL_DEC_JPEG_NEED_MORE_OUTPUT:
printf( "JXL_DEC_JPEG_NEED_MORE_OUTPUT\n" );
break;
case JXL_DEC_BASIC_INFO:
printf( "JXL_DEC_BASIC_INFO\n" );
break;
case JXL_DEC_EXTENSIONS:
printf( "JXL_DEC_EXTENSIONS\n" );
break;
case JXL_DEC_COLOR_ENCODING:
printf( "JXL_DEC_COLOR_ENCODING\n" );
break;
case JXL_DEC_PREVIEW_IMAGE:
printf( "JXL_DEC_PREVIEW_IMAGE\n" );
break;
case JXL_DEC_FRAME:
printf( "JXL_DEC_FRAME\n" );
break;
case JXL_DEC_DC_IMAGE:
printf( "JXL_DEC_DC_IMAGE\n" );
break;
case JXL_DEC_FULL_IMAGE:
printf( "JXL_DEC_FULL_IMAGE\n" );
break;
case JXL_DEC_JPEG_RECONSTRUCTION:
printf( "JXL_DEC_JPEG_RECONSTRUCTION\n" );
break;
default:
g_assert_not_reached();
}
}
#endif /*DEBUG*/
static JxlDecoderStatus
vips_foreign_load_jxl_process( VipsForeignLoadJxl *jxl )
{
JxlDecoderStatus status;
while( (status = JxlDecoderProcessInput( jxl->decoder )) ==
JXL_DEC_NEED_MORE_INPUT ) {
size_t unused;
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_in_buffer );
}
#ifdef DEBUG
printf( "vips_foreign_load_jxl_process: seen " );
vips_foreign_load_jxl_print_status( status );
#endif /*DEBUG*/
return( status );
}
#ifdef DEBUG
static void
vips_foreign_load_jxl_print_info( VipsForeignLoadJxl *jxl )
{
printf( "vips_foreign_load_jxl_print_info:\n" );
printf( " have_container = %d\n", jxl->info.have_container );
printf( " xsize = %d\n", jxl->info.xsize );
printf( " ysize = %d\n", jxl->info.ysize );
printf( " bits_per_sample = %d\n", jxl->info.bits_per_sample );
printf( " exponent_bits_per_sample = %d\n",
jxl->info.exponent_bits_per_sample );
printf( " intensity_target = %g\n", jxl->info.intensity_target );
printf( " min_nits = %g\n", jxl->info.min_nits );
printf( " relative_to_max_display = %d\n",
jxl->info.relative_to_max_display );
printf( " linear_below = %g\n", jxl->info.linear_below );
printf( " uses_original_profile = %d\n",
jxl->info.uses_original_profile );
printf( " have_preview = %d\n", jxl->info.have_preview );
printf( " have_animation = %d\n", jxl->info.have_animation );
printf( " orientation = %d\n", jxl->info.orientation );
printf( " num_color_channels = %d\n", jxl->info.num_color_channels );
printf( " num_extra_channels = %d\n", jxl->info.num_extra_channels );
printf( " alpha_bits = %d\n", jxl->info.alpha_bits );
printf( " alpha_exponent_bits = %d\n", jxl->info.alpha_exponent_bits );
printf( " alpha_premultiplied = %d\n", jxl->info.alpha_premultiplied );
printf( " preview.xsize = %d\n", jxl->info.preview.xsize );
printf( " preview.ysize = %d\n", jxl->info.preview.ysize );
printf( " animation.tps_numerator = %d\n",
jxl->info.animation.tps_numerator );
printf( " animation.tps_denominator = %d\n",
jxl->info.animation.tps_denominator );
printf( " animation.num_loops = %d\n", jxl->info.animation.num_loops );
printf( " animation.have_timecodes = %d\n",
jxl->info.animation.have_timecodes );
}
#endif /*DEBUG*/
static int
vips_foreign_load_jxl_set_header( VipsForeignLoadJxl *jxl, VipsImage *out )
{
VipsBandFormat format;
VipsInterpretation interpretation;
switch( jxl->format.data_type ) {
case JXL_TYPE_UINT8:
format = VIPS_FORMAT_UCHAR;
break;
case JXL_TYPE_UINT16:
format = VIPS_FORMAT_USHORT;
break;
case JXL_TYPE_UINT32:
format = VIPS_FORMAT_UINT;
break;
case JXL_TYPE_FLOAT:
format = VIPS_FORMAT_FLOAT;
break;
default:
g_assert_not_reached();
}
switch( jxl->info.num_color_channels ) {
case 1:
switch( format ) {
case VIPS_FORMAT_UCHAR:
interpretation = VIPS_INTERPRETATION_B_W;
break;
case VIPS_FORMAT_USHORT:
case VIPS_FORMAT_UINT:
interpretation = VIPS_INTERPRETATION_GREY16;
break;
default:
interpretation = VIPS_INTERPRETATION_B_W;
break;
}
break;
case 3:
switch( format ) {
case VIPS_FORMAT_UCHAR:
interpretation = VIPS_INTERPRETATION_sRGB;
break;
case VIPS_FORMAT_USHORT:
case VIPS_FORMAT_UINT:
interpretation = VIPS_INTERPRETATION_RGB16;
break;
case VIPS_FORMAT_FLOAT:
interpretation = VIPS_INTERPRETATION_scRGB;
break;
default:
interpretation = VIPS_INTERPRETATION_sRGB;
break;
}
break;
default:
interpretation = VIPS_INTERPRETATION_MULTIBAND;
break;
}
/* 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.xsize, jxl->info.ysize, jxl->format.num_channels,
format, VIPS_CODING_NONE, interpretation, 1.0, 1.0 );
if( jxl->icc_data &&
jxl->icc_size > 0 ) {
vips_image_set_blob( out, VIPS_META_ICC_NAME,
(VipsCallbackFn) vips_area_free_cb,
jxl->icc_data, jxl->icc_size );
jxl->icc_data = NULL;
jxl->icc_size = 0;
}
vips_image_set_int( out,
VIPS_META_ORIENTATION, jxl->info.orientation );
return( 0 );
}
static int
vips_foreign_load_jxl_header( VipsForeignLoad *load )
{
VipsForeignLoadJxl *jxl = (VipsForeignLoadJxl *) load;
JxlDecoderStatus status;
#ifdef DEBUG
printf( "vips_foreign_load_jxl_header:\n" );
#endif /*DEBUG*/
if( vips_foreign_load_jxl_fill_input( jxl, 0 ) )
return( -1 );
JxlDecoderSetInput( jxl->decoder,
jxl->input_buffer, jxl->bytes_in_buffer );
/* Read to the end of the header.
*/
do {
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 );
}
#ifdef DEBUG
vips_foreign_load_jxl_print_info( jxl );
#endif /*DEBUG*/
/* Pick a pixel format to decode to.
*/
jxl->format.num_channels =
jxl->info.num_color_channels +
jxl->info.num_extra_channels;
if( jxl->info.exponent_bits_per_sample > 0 ||
jxl->info.alpha_exponent_bits > 0 )
jxl->format.data_type = JXL_TYPE_FLOAT;
else if( jxl->info.bits_per_sample > 16 )
jxl->format.data_type = JXL_TYPE_UINT32;
else if( jxl->info.bits_per_sample > 8 )
jxl->format.data_type = JXL_TYPE_UINT16;
else
jxl->format.data_type = JXL_TYPE_UINT8;
jxl->format.endianness = JXL_NATIVE_ENDIAN;
jxl->format.align = 0;
break;
case JXL_DEC_COLOR_ENCODING:
if( JxlDecoderGetICCProfileSize( jxl->decoder,
&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( NULL,
jxl->icc_size )) )
return( -1 );
if( JxlDecoderGetColorAsICCProfile( jxl->decoder,
&jxl->format,
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_NEED_IMAGE_OUT_BUFFER );
if( vips_foreign_load_jxl_set_header( jxl, load->out ) )
return( -1 );
VIPS_SETSTR( load->out->filename,
vips_connection_filename( VIPS_CONNECTION( jxl->source ) ) );
return( 0 );
}
static int
vips_foreign_load_jxl_load( VipsForeignLoad *load )
{
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( load );
VipsForeignLoadJxl *jxl = (VipsForeignLoadJxl *) load;
VipsImage **t = (VipsImage **)
vips_object_local_array( VIPS_OBJECT( load ), 3 );
size_t buffer_size;
JxlDecoderStatus status;
#ifdef DEBUG
printf( "vips_foreign_load_jxl_load:\n" );
#endif /*DEBUG*/
t[0] = vips_image_new();
if( vips_foreign_load_jxl_set_header( jxl, t[0] ) )
return( -1 );
/* Read to the end of the image.
*/
do {
switch( (status = vips_foreign_load_jxl_process( jxl )) ) {
case JXL_DEC_ERROR:
vips_foreign_load_jxl_error( jxl,
"JxlDecoderProcessInput" );
return( -1 );
case JXL_DEC_NEED_IMAGE_OUT_BUFFER:
if( vips_image_write_prepare( t[0] ) )
return( -1 );
if( JxlDecoderImageOutBufferSize( jxl->decoder,
&jxl->format,
&buffer_size ) ) {
vips_foreign_load_jxl_error( jxl,
"JxlDecoderImageOutBufferSize" );
return( -1 );
}
if( buffer_size !=
VIPS_IMAGE_SIZEOF_IMAGE( t[0] ) ) {
vips_error( class->nickname,
"%s", _( "bad buffer size" ) );
return( -1 );
}
if( JxlDecoderSetImageOutBuffer( jxl->decoder,
&jxl->format,
VIPS_IMAGE_ADDR( t[0], 0, 0 ),
VIPS_IMAGE_SIZEOF_IMAGE( t[0] ) ) ) {
vips_foreign_load_jxl_error( jxl,
"JxlDecoderSetImageOutBuffer" );
return( -1 );
}
break;
case JXL_DEC_FULL_IMAGE:
/* Image decoded.
*/
break;
default:
break;
}
} while( status != JXL_DEC_SUCCESS );
if( vips_image_write( t[0], load->real ) )
return( -1 );
return( 0 );
}
static void
vips_foreign_load_jxl_class_init( VipsForeignLoadJxlClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
gobject_class->dispose = vips_foreign_load_jxl_dispose;
gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property;
object_class->nickname = "jxlload_base";
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;
}
static void
vips_foreign_load_jxl_init( VipsForeignLoadJxl *jxl )
{
}
typedef struct _VipsForeignLoadJxlFile {
VipsForeignLoadJxl parent_object;
/* Filename for load.
*/
char *filename;
} VipsForeignLoadJxlFile;
typedef VipsForeignLoadJxlClass VipsForeignLoadJxlFileClass;
G_DEFINE_TYPE( VipsForeignLoadJxlFile, vips_foreign_load_jxl_file,
vips_foreign_load_jxl_get_type() );
static int
vips_foreign_load_jxl_file_build( VipsObject *object )
{
VipsForeignLoadJxl *jxl = (VipsForeignLoadJxl *) object;
VipsForeignLoadJxlFile *file = (VipsForeignLoadJxlFile *) object;
if( file->filename &&
!(jxl->source = vips_source_new_from_file( file->filename )) )
return( -1 );
if( VIPS_OBJECT_CLASS( vips_foreign_load_jxl_file_parent_class )->
build( object ) )
return( -1 );
return( 0 );
}
const char *vips__jxl_suffs[] =
{ ".jxl", NULL };
static int
vips_foreign_load_jxl_is_a( const char *filename )
{
VipsSource *source;
gboolean result;
if( !(source = vips_source_new_from_file( filename )) )
return( FALSE );
result = vips_foreign_load_jxl_is_a_source( source );
VIPS_UNREF( source );
return( result );
}
static void
vips_foreign_load_jxl_file_class_init( VipsForeignLoadJxlFileClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsForeignClass *foreign_class = (VipsForeignClass *) class;
VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property;
object_class->nickname = "jxlload";
object_class->build = vips_foreign_load_jxl_file_build;
foreign_class->suffs = vips__jxl_suffs;
load_class->is_a = vips_foreign_load_jxl_is_a;
VIPS_ARG_STRING( class, "filename", 1,
_( "Filename" ),
_( "Filename to load from" ),
VIPS_ARGUMENT_REQUIRED_INPUT,
G_STRUCT_OFFSET( VipsForeignLoadJxlFile, filename ),
NULL );
}
static void
vips_foreign_load_jxl_file_init( VipsForeignLoadJxlFile *jxl )
{
}
typedef struct _VipsForeignLoadJxlBuffer {
VipsForeignLoadJxl parent_object;
/* Load from a buffer.
*/
VipsArea *buf;
} VipsForeignLoadJxlBuffer;
typedef VipsForeignLoadJxlClass VipsForeignLoadJxlBufferClass;
G_DEFINE_TYPE( VipsForeignLoadJxlBuffer, vips_foreign_load_jxl_buffer,
vips_foreign_load_jxl_get_type() );
static int
vips_foreign_load_jxl_buffer_build( VipsObject *object )
{
VipsForeignLoadJxl *jxl = (VipsForeignLoadJxl *) object;
VipsForeignLoadJxlBuffer *buffer =
(VipsForeignLoadJxlBuffer *) object;
if( buffer->buf )
if( !(jxl->source = vips_source_new_from_memory(
VIPS_AREA( buffer->buf )->data,
VIPS_AREA( buffer->buf )->length )) )
return( -1 );
if( VIPS_OBJECT_CLASS( vips_foreign_load_jxl_file_parent_class )->
build( object ) )
return( -1 );
return( 0 );
}
static gboolean
vips_foreign_load_jxl_buffer_is_a( const void *buf, size_t len )
{
VipsSource *source;
gboolean result;
if( !(source = vips_source_new_from_memory( buf, len )) )
return( FALSE );
result = vips_foreign_load_jxl_is_a_source( source );
VIPS_UNREF( source );
return( result );
}
static void
vips_foreign_load_jxl_buffer_class_init( VipsForeignLoadJxlBufferClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property;
object_class->nickname = "jxlload_buffer";
object_class->build = vips_foreign_load_jxl_buffer_build;
load_class->is_a_buffer = vips_foreign_load_jxl_buffer_is_a;
VIPS_ARG_BOXED( class, "buffer", 1,
_( "Buffer" ),
_( "Buffer to load from" ),
VIPS_ARGUMENT_REQUIRED_INPUT,
G_STRUCT_OFFSET( VipsForeignLoadJxlBuffer, buf ),
VIPS_TYPE_BLOB );
}
static void
vips_foreign_load_jxl_buffer_init( VipsForeignLoadJxlBuffer *buffer )
{
}
typedef struct _VipsForeignLoadJxlSource {
VipsForeignLoadJxl parent_object;
/* Load from a source.
*/
VipsSource *source;
} VipsForeignLoadJxlSource;
typedef VipsForeignLoadJxlClass VipsForeignLoadJxlSourceClass;
G_DEFINE_TYPE( VipsForeignLoadJxlSource, vips_foreign_load_jxl_source,
vips_foreign_load_jxl_get_type() );
static int
vips_foreign_load_jxl_source_build( VipsObject *object )
{
VipsForeignLoadJxl *jxl = (VipsForeignLoadJxl *) object;
VipsForeignLoadJxlSource *source =
(VipsForeignLoadJxlSource *) object;
if( source->source ) {
jxl->source = source->source;
g_object_ref( jxl->source );
}
if( VIPS_OBJECT_CLASS(
vips_foreign_load_jxl_source_parent_class )->
build( object ) )
return( -1 );
return( 0 );
}
static void
vips_foreign_load_jxl_source_class_init( VipsForeignLoadJxlSourceClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property;
object_class->nickname = "jxlload_source";
object_class->build = vips_foreign_load_jxl_source_build;
load_class->is_a_source = vips_foreign_load_jxl_is_a_source;
VIPS_ARG_OBJECT( class, "source", 1,
_( "Source" ),
_( "Source to load from" ),
VIPS_ARGUMENT_REQUIRED_INPUT,
G_STRUCT_OFFSET( VipsForeignLoadJxlSource, source ),
VIPS_TYPE_SOURCE );
}
static void
vips_foreign_load_jxl_source_init(
VipsForeignLoadJxlSource *jxl )
{
}
#endif /*HAVE_LIBJXL*/
/**
* vips_jxlload:
* @filename: file to load
* @out: (out): decompressed image
* @...: %NULL-terminated list of optional named arguments
*
* Read a JPEG-XL image.
*
* See also: vips_image_new_from_file().
*
* Returns: 0 on success, -1 on error.
*/
int
vips_jxlload( const char *filename, VipsImage **out, ... )
{
va_list ap;
int result;
va_start( ap, out );
result = vips_call_split( "jxlload", ap, filename, out );
va_end( ap );
return( result );
}
/**
* vips_jxlload_buffer:
* @buf: (array length=len) (element-type guint8): memory area to load
* @len: (type gsize): size of memory area
* @out: (out): image to write
* @...: %NULL-terminated list of optional named arguments
*
* Exactly as vips_jxlload(), but read from a source.
*
* Returns: 0 on success, -1 on error.
*/
int
vips_jxlload_buffer( void *buf, size_t len, VipsImage **out, ... )
{
va_list ap;
VipsBlob *blob;
int result;
/* We don't take a copy of the data or free it.
*/
blob = vips_blob_new( NULL, buf, len );
va_start( ap, out );
result = vips_call_split( "jxlload_buffer", ap, blob, out );
va_end( ap );
vips_area_unref( VIPS_AREA( blob ) );
return( result );
}
/**
* vips_jxlload_source:
* @source: source to load from
* @out: (out): decompressed image
* @...: %NULL-terminated list of optional named arguments
*
* Exactly as vips_jxlload(), but read from a source.
*
* Returns: 0 on success, -1 on error.
*/
int
vips_jxlload_source( VipsSource *source, VipsImage **out, ... )
{
va_list ap;
int result;
va_start( ap, out );
result = vips_call_split( "jxlload_source", ap, source, out );
va_end( ap );
return( result );
}