set basic jxl image metadata from vips

This commit is contained in:
John Cupitt 2021-04-03 16:32:02 +01:00
parent e93d0ab83c
commit b82ca537e7

View File

@ -55,6 +55,15 @@
#include "pforeign.h" #include "pforeign.h"
/* TODO:
*
* - libjxl currently seems to be missing API to attach a profile
*
* - libjxl seems to only work in one shot mode, so there's no way to write in
* chunks
*
*/
#define OUTPUT_BUFFER_SIZE (4096) #define OUTPUT_BUFFER_SIZE (4096)
typedef struct _VipsForeignSaveJxl { typedef struct _VipsForeignSaveJxl {
@ -68,8 +77,7 @@ typedef struct _VipsForeignSaveJxl {
*/ */
JxlBasicInfo info; JxlBasicInfo info;
JxlColorEncoding color_encoding; JxlColorEncoding color_encoding;
size_t icc_size; JxlPixelFormat format;
uint8_t *icc_data;
/* Encoder state. /* Encoder state.
*/ */
@ -109,9 +117,6 @@ vips_foreign_save_jxl_error( VipsForeignSaveJxl *jxl, const char *details )
vips_error( class->nickname, "%s", details ); vips_error( class->nickname, "%s", details );
} }
static JxlPixelFormat vips_foreign_save_jxl_format =
{3, JXL_TYPE_FLOAT, JXL_NATIVE_ENDIAN, 0};
static int static int
vips_foreign_save_jxl_build( VipsObject *object ) vips_foreign_save_jxl_build( VipsObject *object )
{ {
@ -136,32 +141,120 @@ vips_foreign_save_jxl_build( VipsObject *object )
return( -1 ); return( -1 );
} }
jxl->info.xsize = save->ready->Xsize; switch( save->ready->BandFmt ) {
jxl->info.ysize = save->ready->Ysize; 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.bits_per_sample = 32;
jxl->info.exponent_bits_per_sample = 8; 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_exponent_bits = 0;
jxl->info.alpha_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; 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 ) ) { if( JxlEncoderSetBasicInfo( jxl->encoder, &jxl->info ) ) {
vips_foreign_save_jxl_error( jxl, "JxlEncoderSetBasicInfo" ); vips_foreign_save_jxl_error( jxl, "JxlEncoderSetBasicInfo" );
return( -1 ); return( -1 );
} }
JxlColorEncodingSetToSRGB( &jxl->color_encoding, JxlColorEncodingSetToSRGB( &jxl->color_encoding,
vips_foreign_save_jxl_format.num_channels < 3 ); jxl->format.num_channels < 3 );
if( JxlEncoderSetColorEncoding( jxl->encoder, &jxl->color_encoding ) ) { if( JxlEncoderSetColorEncoding( jxl->encoder, &jxl->color_encoding ) ) {
vips_foreign_save_jxl_error( jxl, vips_foreign_save_jxl_error( jxl,
"JxlEncoderSetColorEncoding" ); "JxlEncoderSetColorEncoding" );
return( -1 ); return( -1 );
} }
/* Render the entire image in memory. libjxl seems to be missing
* tile-based write.
*/
if( vips_image_wio_input( save->ready ) ) if( vips_image_wio_input( save->ready ) )
return( -1 ); return( -1 );
encoder_options = JxlEncoderOptionsCreate( jxl->encoder, NULL ); encoder_options = JxlEncoderOptionsCreate( jxl->encoder, NULL );
if( JxlEncoderAddImageFrame( encoder_options, if( JxlEncoderAddImageFrame( encoder_options, &jxl->format,
&vips_foreign_save_jxl_format,
VIPS_IMAGE_ADDR( save->ready, 0, 0 ), VIPS_IMAGE_ADDR( save->ready, 0, 0 ),
VIPS_IMAGE_SIZEOF_IMAGE( save->ready ) ) ) { VIPS_IMAGE_SIZEOF_IMAGE( save->ready ) ) ) {
vips_foreign_save_jxl_error( jxl, "JxlEncoderAddImageFrame" ); vips_foreign_save_jxl_error( jxl, "JxlEncoderAddImageFrame" );
@ -197,13 +290,18 @@ vips_foreign_save_jxl_build( VipsObject *object )
return( 0 ); 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 #define F VIPS_FORMAT_FLOAT
/* Type promotion for save ... just always go to uchar. /* Type promotion for save ... unsigned ints + float + double.
*/ */
static int bandfmt_jpeg[10] = { static int bandfmt_jpeg[10] = {
/* UC C US S UI I F X D DX */ /* UC C US S UI I F X D DX */
F, F, F, F, F, F, F, F, F, F UC, UC, US, US, UI, UI, F, F, F, F
}; };
static void static void