696 lines
18 KiB
C
696 lines
18 KiB
C
/* save as jpeg-xl
|
|
*
|
|
* 18/3/20
|
|
* - from heifload.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
|
|
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif /*HAVE_CONFIG_H*/
|
|
#include <vips/intl.h>
|
|
|
|
#ifdef HAVE_LIBJXL
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <vips/vips.h>
|
|
#include <vips/internal.h>
|
|
|
|
#include <jxl/encode.h>
|
|
#include <jxl/thread_parallel_runner.h>
|
|
|
|
#include "pforeign.h"
|
|
|
|
/* TODO:
|
|
*
|
|
* - libjxl currently seems to be missing API to attach a profile
|
|
*
|
|
* - libjxl encode only works in one shot mode, so there's no way to write in
|
|
* chunks
|
|
*
|
|
* - add metadata support EXIF, XMP, etc. api for this is on the way
|
|
*
|
|
* - add animation support
|
|
*
|
|
* - libjxl is currently missing error messages (I think)
|
|
*
|
|
* - fix scRGB gamma
|
|
*/
|
|
|
|
#define OUTPUT_BUFFER_SIZE (4096)
|
|
|
|
typedef struct _VipsForeignSaveJxl {
|
|
VipsForeignSave parent_object;
|
|
|
|
/* Where to write (set by subclasses).
|
|
*/
|
|
VipsTarget *target;
|
|
|
|
/* Encoder options.
|
|
*/
|
|
int tier;
|
|
double distance;
|
|
int effort;
|
|
gboolean lossless;
|
|
int Q;
|
|
|
|
/* Base image properties.
|
|
*/
|
|
JxlBasicInfo info;
|
|
JxlColorEncoding color_encoding;
|
|
JxlPixelFormat format;
|
|
|
|
/* Encoder state.
|
|
*/
|
|
void *runner;
|
|
JxlEncoder *encoder;
|
|
|
|
/* Write buffer.
|
|
*/
|
|
uint8_t output_buffer[OUTPUT_BUFFER_SIZE];
|
|
|
|
} VipsForeignSaveJxl;
|
|
|
|
typedef VipsForeignSaveClass VipsForeignSaveJxlClass;
|
|
|
|
G_DEFINE_ABSTRACT_TYPE( VipsForeignSaveJxl, vips_foreign_save_jxl,
|
|
VIPS_TYPE_FOREIGN_SAVE );
|
|
|
|
static void
|
|
vips_foreign_save_jxl_dispose( GObject *gobject )
|
|
{
|
|
VipsForeignSaveJxl *jxl = (VipsForeignSaveJxl *) gobject;
|
|
|
|
VIPS_FREEF( JxlThreadParallelRunnerDestroy, jxl->runner );
|
|
VIPS_FREEF( JxlEncoderDestroy, jxl->encoder );
|
|
|
|
G_OBJECT_CLASS( vips_foreign_save_jxl_parent_class )->
|
|
dispose( gobject );
|
|
}
|
|
|
|
static void
|
|
vips_foreign_save_jxl_error( VipsForeignSaveJxl *jxl, const char *details )
|
|
{
|
|
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( jxl );
|
|
|
|
/* TODO ... jxl has no way to get error messages at the moment.
|
|
*/
|
|
vips_error( class->nickname, "error %s", details );
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
static void
|
|
vips_foreign_save_jxl_print_info( JxlBasicInfo *info )
|
|
{
|
|
printf( "JxlBasicInfo:\n" );
|
|
printf( " have_container = %d\n", info->have_container );
|
|
printf( " xsize = %d\n", info->xsize );
|
|
printf( " ysize = %d\n", info->ysize );
|
|
printf( " bits_per_sample = %d\n", info->bits_per_sample );
|
|
printf( " exponent_bits_per_sample = %d\n",
|
|
info->exponent_bits_per_sample );
|
|
printf( " intensity_target = %g\n", info->intensity_target );
|
|
printf( " min_nits = %g\n", info->min_nits );
|
|
printf( " relative_to_max_display = %d\n",
|
|
info->relative_to_max_display );
|
|
printf( " linear_below = %g\n", info->linear_below );
|
|
printf( " uses_original_profile = %d\n",
|
|
info->uses_original_profile );
|
|
printf( " have_preview = %d\n", info->have_preview );
|
|
printf( " have_animation = %d\n", info->have_animation );
|
|
printf( " orientation = %d\n", info->orientation );
|
|
printf( " num_color_channels = %d\n", info->num_color_channels );
|
|
printf( " num_extra_channels = %d\n", info->num_extra_channels );
|
|
printf( " alpha_bits = %d\n", info->alpha_bits );
|
|
printf( " alpha_exponent_bits = %d\n", info->alpha_exponent_bits );
|
|
printf( " alpha_premultiplied = %d\n", info->alpha_premultiplied );
|
|
printf( " preview.xsize = %d\n", info->preview.xsize );
|
|
printf( " preview.ysize = %d\n", info->preview.ysize );
|
|
printf( " animation.tps_numerator = %d\n",
|
|
info->animation.tps_numerator );
|
|
printf( " animation.tps_denominator = %d\n",
|
|
info->animation.tps_denominator );
|
|
printf( " animation.num_loops = %d\n", info->animation.num_loops );
|
|
printf( " animation.have_timecodes = %d\n",
|
|
info->animation.have_timecodes );
|
|
}
|
|
|
|
static void
|
|
vips_foreign_save_jxl_print_format( JxlPixelFormat *format )
|
|
{
|
|
printf( "JxlPixelFormat:\n" );
|
|
printf( " data_type = " );
|
|
switch( format->data_type ) {
|
|
case JXL_TYPE_UINT8:
|
|
printf( "JXL_TYPE_UINT8" );
|
|
break;
|
|
|
|
case JXL_TYPE_UINT16:
|
|
printf( "JXL_TYPE_UINT16" );
|
|
break;
|
|
|
|
case JXL_TYPE_UINT32:
|
|
printf( "JXL_TYPE_UINT32" );
|
|
break;
|
|
|
|
case JXL_TYPE_FLOAT:
|
|
printf( "JXL_TYPE_FLOAT" );
|
|
break;
|
|
|
|
default:
|
|
printf( "(unknown)" );
|
|
break;
|
|
}
|
|
printf( "\n" );
|
|
printf( " num_channels = %d\n", format->num_channels );
|
|
printf( " endianness = %d\n", format->endianness );
|
|
printf( " align = %zd\n", format->align );
|
|
}
|
|
|
|
static void
|
|
vips_foreign_save_jxl_print_status( JxlEncoderStatus status )
|
|
{
|
|
switch( status ) {
|
|
case JXL_ENC_SUCCESS:
|
|
printf( "JXL_ENC_SUCCESS\n" );
|
|
break;
|
|
|
|
case JXL_ENC_ERROR:
|
|
printf( "JXL_ENC_ERROR\n" );
|
|
break;
|
|
|
|
case JXL_ENC_NEED_MORE_OUTPUT:
|
|
printf( "JXL_ENC_NEED_MORE_OUTPUT\n" );
|
|
break;
|
|
|
|
case JXL_ENC_NOT_SUPPORTED:
|
|
printf( "JXL_ENC_NOT_SUPPORTED\n" );
|
|
break;
|
|
|
|
default:
|
|
printf( "JXL_ENC_<unknown>\n" );
|
|
break;
|
|
}
|
|
}
|
|
#endif /*DEBUG*/
|
|
|
|
static int
|
|
vips_foreign_save_jxl_build( VipsObject *object )
|
|
{
|
|
VipsForeignSave *save = (VipsForeignSave *) object;
|
|
VipsForeignSaveJxl *jxl = (VipsForeignSaveJxl *) object;
|
|
|
|
JxlEncoderOptions *options;
|
|
JxlEncoderStatus status;
|
|
|
|
if( VIPS_OBJECT_CLASS( vips_foreign_save_jxl_parent_class )->
|
|
build( object ) )
|
|
return( -1 );
|
|
|
|
/* If Q is set and distance is not, use Q to set a rough distance
|
|
* value. Formula stolen from cjxl.c and very roughly approximates
|
|
* libjpeg values.
|
|
*/
|
|
if( !vips_object_argument_isset( object, "distance" ) )
|
|
jxl->distance = jxl->Q >= 30 ?
|
|
0.1 + (100 - jxl->Q) * 0.09 :
|
|
6.4 + pow(2.5, (30 - jxl->Q) / 5.0f) / 6.25f;
|
|
|
|
/* Distance 0 is lossless. libjxl will fail for lossy distance 0.
|
|
*/
|
|
if( jxl->distance == 0 )
|
|
jxl->lossless = TRUE;
|
|
|
|
jxl->runner = JxlThreadParallelRunnerCreate( NULL,
|
|
vips_concurrency_get() );
|
|
jxl->encoder = JxlEncoderCreate( NULL );
|
|
|
|
if( JxlEncoderSetParallelRunner( jxl->encoder,
|
|
JxlThreadParallelRunner, jxl->runner ) ) {
|
|
vips_foreign_save_jxl_error( jxl,
|
|
"JxlDecoderSetParallelRunner" );
|
|
return( -1 );
|
|
}
|
|
|
|
JxlEncoderInitBasicInfo( &jxl->info );
|
|
|
|
switch( save->ready->BandFmt ) {
|
|
case VIPS_FORMAT_UCHAR:
|
|
jxl->info.bits_per_sample = 8;
|
|
jxl->info.exponent_bits_per_sample = 0;
|
|
jxl->format.data_type = JXL_TYPE_UINT8;
|
|
break;
|
|
|
|
case VIPS_FORMAT_USHORT:
|
|
jxl->info.bits_per_sample = 16;
|
|
jxl->info.exponent_bits_per_sample = 0;
|
|
jxl->format.data_type = JXL_TYPE_UINT16;
|
|
break;
|
|
|
|
case VIPS_FORMAT_UINT:
|
|
jxl->info.bits_per_sample = 32;
|
|
jxl->info.exponent_bits_per_sample = 0;
|
|
jxl->format.data_type = JXL_TYPE_UINT32;
|
|
break;
|
|
|
|
case VIPS_FORMAT_FLOAT:
|
|
jxl->info.bits_per_sample = 32;
|
|
jxl->info.exponent_bits_per_sample = 8;
|
|
jxl->format.data_type = JXL_TYPE_FLOAT;
|
|
break;
|
|
|
|
default:
|
|
g_assert_not_reached();
|
|
break;
|
|
}
|
|
|
|
switch( save->ready->Type ) {
|
|
case VIPS_INTERPRETATION_B_W:
|
|
case VIPS_INTERPRETATION_GREY16:
|
|
jxl->info.num_color_channels = 1;
|
|
break;
|
|
|
|
case VIPS_INTERPRETATION_sRGB:
|
|
case VIPS_INTERPRETATION_scRGB:
|
|
case VIPS_INTERPRETATION_RGB16:
|
|
jxl->info.num_color_channels = 3;
|
|
break;
|
|
|
|
default:
|
|
jxl->info.num_color_channels = save->ready->Bands;
|
|
}
|
|
jxl->info.num_extra_channels = VIPS_MAX( 0,
|
|
save->ready->Bands - jxl->info.num_color_channels );
|
|
|
|
jxl->info.xsize = save->ready->Xsize;
|
|
jxl->info.ysize = save->ready->Ysize;
|
|
jxl->format.num_channels = save->ready->Bands;
|
|
jxl->format.endianness = JXL_NATIVE_ENDIAN;
|
|
jxl->format.align = 0;
|
|
|
|
if( vips_image_hasalpha( save->ready ) ) {
|
|
jxl->info.alpha_bits = jxl->info.bits_per_sample;
|
|
jxl->info.alpha_exponent_bits =
|
|
jxl->info.exponent_bits_per_sample;
|
|
}
|
|
else {
|
|
jxl->info.alpha_exponent_bits = 0;
|
|
jxl->info.alpha_bits = 0;
|
|
}
|
|
|
|
if( vips_image_get_typeof( save->ready, "stonits" ) ) {
|
|
double stonits;
|
|
|
|
if( vips_image_get_double( save->ready, "stonits", &stonits ) )
|
|
return( -1 );
|
|
jxl->info.intensity_target = stonits;
|
|
}
|
|
|
|
/* FIXME libjxl doesn't seem to have this API yet.
|
|
*
|
|
if( vips_image_get_typeof( save->ready, VIPS_META_ICC_NAME ) ) {
|
|
const void *data;
|
|
size_t length;
|
|
|
|
if( vips_image_get_blob( save->ready,
|
|
VIPS_META_ICC_NAME, &data, &length ) )
|
|
return( -1 );
|
|
|
|
jxl->info.uses_original_profile = JXL_TRUE;
|
|
... attach profile
|
|
}
|
|
else
|
|
jxl->info.uses_original_profile = JXL_FALSE;
|
|
*/
|
|
|
|
/* Remove this when libjxl gets API to attach an ICC profile.
|
|
*/
|
|
jxl->info.uses_original_profile = JXL_FALSE;
|
|
|
|
if( JxlEncoderSetBasicInfo( jxl->encoder, &jxl->info ) ) {
|
|
vips_foreign_save_jxl_error( jxl, "JxlEncoderSetBasicInfo" );
|
|
return( -1 );
|
|
}
|
|
|
|
JxlColorEncodingSetToSRGB( &jxl->color_encoding,
|
|
jxl->format.num_channels < 3 );
|
|
if( JxlEncoderSetColorEncoding( jxl->encoder, &jxl->color_encoding ) ) {
|
|
vips_foreign_save_jxl_error( jxl,
|
|
"JxlEncoderSetColorEncoding" );
|
|
return( -1 );
|
|
}
|
|
|
|
/* Render the entire image in memory. libjxl seems to be missing
|
|
* tile-based write at the moment.
|
|
*/
|
|
if( vips_image_wio_input( save->ready ) )
|
|
return( -1 );
|
|
|
|
options = JxlEncoderOptionsCreate( jxl->encoder, NULL );
|
|
JxlEncoderOptionsSetDecodingSpeed( options, jxl->tier );
|
|
JxlEncoderOptionsSetDistance( options, jxl->distance );
|
|
JxlEncoderOptionsSetEffort( options, jxl->effort );
|
|
JxlEncoderOptionsSetLossless( options, jxl->lossless );
|
|
|
|
#ifdef DEBUG
|
|
vips_foreign_save_jxl_print_info( &jxl->info );
|
|
vips_foreign_save_jxl_print_format( &jxl->format );
|
|
printf( "JxlEncoderOptions:\n" );
|
|
printf( " tier = %d\n", jxl->tier );
|
|
printf( " distance = %g\n", jxl->distance );
|
|
printf( " effort = %d\n", jxl->effort );
|
|
printf( " lossless = %d\n", jxl->lossless );
|
|
#endif /*DEBUG*/
|
|
|
|
if( JxlEncoderAddImageFrame( options, &jxl->format,
|
|
VIPS_IMAGE_ADDR( save->ready, 0, 0 ),
|
|
VIPS_IMAGE_SIZEOF_IMAGE( save->ready ) ) ) {
|
|
vips_foreign_save_jxl_error( jxl, "JxlEncoderAddImageFrame" );
|
|
return( -1 );
|
|
}
|
|
|
|
do {
|
|
uint8_t *out;
|
|
size_t avail_out;
|
|
|
|
out = jxl->output_buffer;
|
|
avail_out = OUTPUT_BUFFER_SIZE;
|
|
status = JxlEncoderProcessOutput( jxl->encoder,
|
|
&out, &avail_out );
|
|
switch( status ) {
|
|
case JXL_ENC_SUCCESS:
|
|
case JXL_ENC_NEED_MORE_OUTPUT:
|
|
if( vips_target_write( jxl->target,
|
|
jxl->output_buffer,
|
|
OUTPUT_BUFFER_SIZE - avail_out ) )
|
|
return( -1 );
|
|
break;
|
|
|
|
default:
|
|
vips_foreign_save_jxl_error( jxl,
|
|
"JxlEncoderProcessOutput" );
|
|
#ifdef DEBUG
|
|
vips_foreign_save_jxl_print_status( status );
|
|
#endif /*DEBUG*/
|
|
return( -1 );
|
|
}
|
|
} while( status != JXL_ENC_SUCCESS );
|
|
|
|
vips_target_finish( jxl->target );
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
/* Save a bit of typing.
|
|
*/
|
|
#define UC VIPS_FORMAT_UCHAR
|
|
#define US VIPS_FORMAT_USHORT
|
|
#define UI VIPS_FORMAT_UINT
|
|
#define F VIPS_FORMAT_FLOAT
|
|
|
|
/* Type promotion for save ... unsigned ints + float + double.
|
|
*/
|
|
static int bandfmt_jpeg[10] = {
|
|
/* UC C US S UI I F X D DX */
|
|
UC, UC, US, US, UI, UI, F, F, F, F
|
|
};
|
|
|
|
static void
|
|
vips_foreign_save_jxl_class_init( VipsForeignSaveJxlClass *class )
|
|
{
|
|
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
|
|
VipsObjectClass *object_class = (VipsObjectClass *) class;
|
|
VipsForeignClass *foreign_class = (VipsForeignClass *) class;
|
|
VipsForeignSaveClass *save_class = (VipsForeignSaveClass *) class;
|
|
|
|
gobject_class->dispose = vips_foreign_save_jxl_dispose;
|
|
gobject_class->set_property = vips_object_set_property;
|
|
gobject_class->get_property = vips_object_get_property;
|
|
|
|
object_class->nickname = "jxlsave_base";
|
|
object_class->description = _( "save image in JPEG-XL format" );
|
|
object_class->build = vips_foreign_save_jxl_build;
|
|
|
|
foreign_class->suffs = vips__jxl_suffs;
|
|
|
|
save_class->saveable = VIPS_SAVEABLE_ANY;
|
|
save_class->format_table = bandfmt_jpeg;
|
|
|
|
VIPS_ARG_INT( class, "tier", 10,
|
|
_( "Tier" ),
|
|
_( "Decode speed tier" ),
|
|
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
|
G_STRUCT_OFFSET( VipsForeignSaveJxl, tier ),
|
|
0, 4, 0 );
|
|
|
|
VIPS_ARG_DOUBLE( class, "distance", 11,
|
|
_( "Distance" ),
|
|
_( "Target butteraugli distance" ),
|
|
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
|
G_STRUCT_OFFSET( VipsForeignSaveJxl, distance ),
|
|
0, 15, 1.0 );
|
|
|
|
VIPS_ARG_INT( class, "effort", 12,
|
|
_( "effort" ),
|
|
_( "Encoding effort" ),
|
|
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
|
G_STRUCT_OFFSET( VipsForeignSaveJxl, effort ),
|
|
3, 9, 7 );
|
|
|
|
VIPS_ARG_BOOL( class, "lossless", 13,
|
|
_( "Lossless" ),
|
|
_( "Enable lossless compression" ),
|
|
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
|
G_STRUCT_OFFSET( VipsForeignSaveJxl, lossless ),
|
|
FALSE );
|
|
|
|
VIPS_ARG_INT( class, "Q", 14,
|
|
_( "Q" ),
|
|
_( "Quality factor" ),
|
|
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
|
G_STRUCT_OFFSET( VipsForeignSaveJxl, Q ),
|
|
0, 100, 75 );
|
|
|
|
}
|
|
|
|
static void
|
|
vips_foreign_save_jxl_init( VipsForeignSaveJxl *jxl )
|
|
{
|
|
jxl->tier = 0;
|
|
jxl->distance = 1.0;
|
|
jxl->effort = 7;
|
|
jxl->lossless = FALSE;
|
|
jxl->Q = 75;
|
|
}
|
|
|
|
typedef struct _VipsForeignSaveJxlFile {
|
|
VipsForeignSaveJxl parent_object;
|
|
|
|
/* Filename for save.
|
|
*/
|
|
char *filename;
|
|
|
|
} VipsForeignSaveJxlFile;
|
|
|
|
typedef VipsForeignSaveJxlClass VipsForeignSaveJxlFileClass;
|
|
|
|
G_DEFINE_TYPE( VipsForeignSaveJxlFile, vips_foreign_save_jxl_file,
|
|
vips_foreign_save_jxl_get_type() );
|
|
|
|
static int
|
|
vips_foreign_save_jxl_file_build( VipsObject *object )
|
|
{
|
|
VipsForeignSaveJxl *jxl = (VipsForeignSaveJxl *) object;
|
|
VipsForeignSaveJxlFile *file = (VipsForeignSaveJxlFile *) object;
|
|
|
|
if( !(jxl->target = vips_target_new_to_file( file->filename )) )
|
|
return( -1 );
|
|
|
|
if( VIPS_OBJECT_CLASS( vips_foreign_save_jxl_file_parent_class )->
|
|
build( object ) )
|
|
return( -1 );
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
static void
|
|
vips_foreign_save_jxl_file_class_init( VipsForeignSaveJxlFileClass *class )
|
|
{
|
|
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
|
|
VipsObjectClass *object_class = (VipsObjectClass *) class;
|
|
|
|
gobject_class->set_property = vips_object_set_property;
|
|
gobject_class->get_property = vips_object_get_property;
|
|
|
|
object_class->nickname = "jxlsave";
|
|
object_class->build = vips_foreign_save_jxl_file_build;
|
|
|
|
VIPS_ARG_STRING( class, "filename", 1,
|
|
_( "Filename" ),
|
|
_( "Filename to load from" ),
|
|
VIPS_ARGUMENT_REQUIRED_INPUT,
|
|
G_STRUCT_OFFSET( VipsForeignSaveJxlFile, filename ),
|
|
NULL );
|
|
|
|
}
|
|
|
|
static void
|
|
vips_foreign_save_jxl_file_init( VipsForeignSaveJxlFile *file )
|
|
{
|
|
}
|
|
|
|
typedef struct _VipsForeignSaveJxlBuffer {
|
|
VipsForeignSaveJxl parent_object;
|
|
|
|
/* Save to a buffer.
|
|
*/
|
|
VipsArea *buf;
|
|
|
|
} VipsForeignSaveJxlBuffer;
|
|
|
|
typedef VipsForeignSaveJxlClass VipsForeignSaveJxlBufferClass;
|
|
|
|
G_DEFINE_TYPE( VipsForeignSaveJxlBuffer, vips_foreign_save_jxl_buffer,
|
|
vips_foreign_save_jxl_get_type() );
|
|
|
|
static int
|
|
vips_foreign_save_jxl_buffer_build( VipsObject *object )
|
|
{
|
|
VipsForeignSaveJxl *jxl = (VipsForeignSaveJxl *) object;
|
|
VipsForeignSaveJxlBuffer *buffer =
|
|
(VipsForeignSaveJxlBuffer *) object;
|
|
|
|
VipsBlob *blob;
|
|
|
|
if( !(jxl->target = vips_target_new_to_memory()) )
|
|
return( -1 );
|
|
|
|
if( VIPS_OBJECT_CLASS( vips_foreign_save_jxl_buffer_parent_class )->
|
|
build( object ) )
|
|
return( -1 );
|
|
|
|
g_object_get( jxl->target, "blob", &blob, NULL );
|
|
g_object_set( buffer, "buffer", blob, NULL );
|
|
vips_area_unref( VIPS_AREA( blob ) );
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
static void
|
|
vips_foreign_save_jxl_buffer_class_init(
|
|
VipsForeignSaveJxlBufferClass *class )
|
|
{
|
|
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
|
|
VipsObjectClass *object_class = (VipsObjectClass *) class;
|
|
|
|
gobject_class->set_property = vips_object_set_property;
|
|
gobject_class->get_property = vips_object_get_property;
|
|
|
|
object_class->nickname = "jxlsave_buffer";
|
|
object_class->build = vips_foreign_save_jxl_buffer_build;
|
|
|
|
VIPS_ARG_BOXED( class, "buffer", 1,
|
|
_( "Buffer" ),
|
|
_( "Buffer to save to" ),
|
|
VIPS_ARGUMENT_REQUIRED_OUTPUT,
|
|
G_STRUCT_OFFSET( VipsForeignSaveJxlBuffer, buf ),
|
|
VIPS_TYPE_BLOB );
|
|
|
|
}
|
|
|
|
static void
|
|
vips_foreign_save_jxl_buffer_init( VipsForeignSaveJxlBuffer *buffer )
|
|
{
|
|
}
|
|
|
|
typedef struct _VipsForeignSaveJxlTarget {
|
|
VipsForeignSaveJxl parent_object;
|
|
|
|
VipsTarget *target;
|
|
} VipsForeignSaveJxlTarget;
|
|
|
|
typedef VipsForeignSaveJxlClass VipsForeignSaveJxlTargetClass;
|
|
|
|
G_DEFINE_TYPE( VipsForeignSaveJxlTarget, vips_foreign_save_jxl_target,
|
|
vips_foreign_save_jxl_get_type() );
|
|
|
|
static int
|
|
vips_foreign_save_jxl_target_build( VipsObject *object )
|
|
{
|
|
VipsForeignSaveJxl *jxl = (VipsForeignSaveJxl *) object;
|
|
VipsForeignSaveJxlTarget *target =
|
|
(VipsForeignSaveJxlTarget *) object;
|
|
|
|
if( target->target ) {
|
|
jxl->target = target->target;
|
|
g_object_ref( jxl->target );
|
|
}
|
|
|
|
if( VIPS_OBJECT_CLASS( vips_foreign_save_jxl_target_parent_class )->
|
|
build( object ) )
|
|
return( -1 );
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
static void
|
|
vips_foreign_save_jxl_target_class_init(
|
|
VipsForeignSaveJxlTargetClass *class )
|
|
{
|
|
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
|
|
VipsObjectClass *object_class = (VipsObjectClass *) class;
|
|
|
|
gobject_class->set_property = vips_object_set_property;
|
|
gobject_class->get_property = vips_object_get_property;
|
|
|
|
object_class->nickname = "jxlsave_target";
|
|
object_class->build = vips_foreign_save_jxl_target_build;
|
|
|
|
VIPS_ARG_OBJECT( class, "target", 1,
|
|
_( "Target" ),
|
|
_( "Target to save to" ),
|
|
VIPS_ARGUMENT_REQUIRED_INPUT,
|
|
G_STRUCT_OFFSET( VipsForeignSaveJxlTarget, target ),
|
|
VIPS_TYPE_TARGET );
|
|
|
|
}
|
|
|
|
static void
|
|
vips_foreign_save_jxl_target_init( VipsForeignSaveJxlTarget *target )
|
|
{
|
|
}
|
|
|
|
#endif /*HAVE_LIBJXL*/
|
|
|
|
/* The C API wrappers are defined in foreign.c.
|
|
*/
|