34
34
*/
35
35
36
36
/*
37
- #define DEBUG
38
37
*/
38
+ #define DEBUG
39
39
40
40
#ifdef HAVE_CONFIG_H
41
41
#include <config.h>
@@ -227,9 +227,12 @@ vips_foreign_save_jxl_build( VipsObject *object )
227
227
{
228
228
VipsForeignSave * save = (VipsForeignSave * ) object ;
229
229
VipsForeignSaveJxl * jxl = (VipsForeignSaveJxl * ) object ;
230
+ VipsImage * * t = (VipsImage * * ) vips_object_local_array ( object , 5 );
230
231
231
232
JxlEncoderOptions * options ;
232
233
JxlEncoderStatus status ;
234
+ VipsImage * in ;
235
+ VipsBandFormat format ;
233
236
234
237
if ( VIPS_OBJECT_CLASS ( vips_foreign_save_jxl_parent_class )->
235
238
build ( object ) )
@@ -260,11 +263,28 @@ vips_foreign_save_jxl_build( VipsObject *object )
260
263
return ( -1 );
261
264
}
262
265
266
+ in = save -> ready ;
267
+
268
+ /* Fix the input image format. JXL uses float for 0-1 linear (ie.
269
+ * scRGB) only. We must convert eg. sRGB float to 8-bit for save.
270
+ */
271
+ if ( in -> Type == VIPS_INTERPRETATION_scRGB )
272
+ format = VIPS_FORMAT_FLOAT ;
273
+ else if ( in -> Type == VIPS_INTERPRETATION_RGB16 ||
274
+ in -> Type == VIPS_INTERPRETATION_GREY16 )
275
+ format = VIPS_FORMAT_USHORT ;
276
+ else
277
+ format = VIPS_FORMAT_UCHAR ;
278
+
279
+ if ( vips_cast ( in , & t [0 ], format , NULL ) )
280
+ return ( -1 );
281
+ in = t [0 ];
282
+
263
283
#ifdef HAVE_LIBJXL_JXLENCODERINITBASICINFO
264
284
JxlEncoderInitBasicInfo ( & jxl -> info );
265
285
#endif
266
286
267
- switch ( save -> ready -> BandFmt ) {
287
+ switch ( in -> BandFmt ) {
268
288
case VIPS_FORMAT_UCHAR :
269
289
jxl -> info .bits_per_sample = 8 ;
270
290
jxl -> info .exponent_bits_per_sample = 0 ;
@@ -288,7 +308,7 @@ vips_foreign_save_jxl_build( VipsObject *object )
288
308
break ;
289
309
}
290
310
291
- switch ( save -> ready -> Type ) {
311
+ switch ( in -> Type ) {
292
312
case VIPS_INTERPRETATION_B_W :
293
313
case VIPS_INTERPRETATION_GREY16 :
294
314
jxl -> info .num_color_channels = 1 ;
@@ -301,18 +321,18 @@ vips_foreign_save_jxl_build( VipsObject *object )
301
321
break ;
302
322
303
323
default :
304
- jxl -> info .num_color_channels = save -> ready -> Bands ;
324
+ jxl -> info .num_color_channels = in -> Bands ;
305
325
}
306
326
jxl -> info .num_extra_channels = VIPS_MAX ( 0 ,
307
- save -> ready -> Bands - jxl -> info .num_color_channels );
327
+ in -> Bands - jxl -> info .num_color_channels );
308
328
309
- jxl -> info .xsize = save -> ready -> Xsize ;
310
- jxl -> info .ysize = save -> ready -> Ysize ;
311
- jxl -> format .num_channels = save -> ready -> Bands ;
329
+ jxl -> info .xsize = in -> Xsize ;
330
+ jxl -> info .ysize = in -> Ysize ;
331
+ jxl -> format .num_channels = in -> Bands ;
312
332
jxl -> format .endianness = JXL_NATIVE_ENDIAN ;
313
333
jxl -> format .align = 0 ;
314
334
315
- if ( vips_image_hasalpha ( save -> ready ) ) {
335
+ if ( vips_image_hasalpha ( in ) ) {
316
336
jxl -> info .alpha_bits = jxl -> info .bits_per_sample ;
317
337
jxl -> info .alpha_exponent_bits =
318
338
jxl -> info .exponent_bits_per_sample ;
@@ -322,15 +342,15 @@ vips_foreign_save_jxl_build( VipsObject *object )
322
342
jxl -> info .alpha_bits = 0 ;
323
343
}
324
344
325
- if ( vips_image_get_typeof ( save -> ready , "stonits" ) ) {
345
+ if ( vips_image_get_typeof ( in , "stonits" ) ) {
326
346
double stonits ;
327
347
328
- if ( vips_image_get_double ( save -> ready , "stonits" , & stonits ) )
348
+ if ( vips_image_get_double ( in , "stonits" , & stonits ) )
329
349
return ( -1 );
330
350
jxl -> info .intensity_target = stonits ;
331
351
}
332
352
333
- /* We will be setting the ICC profile, or calling
353
+ /* We will be setting the ICC profile, and/ or calling
334
354
* JxlEncoderSetColorEncoding().
335
355
*/
336
356
jxl -> info .uses_original_profile = TRUE;
@@ -340,13 +360,13 @@ vips_foreign_save_jxl_build( VipsObject *object )
340
360
return ( -1 );
341
361
}
342
362
343
- /* Set ICC profile, sRGB, or scRGB .
363
+ /* Set ICC profile.
344
364
*/
345
- if ( vips_image_get_typeof ( save -> ready , VIPS_META_ICC_NAME ) ) {
365
+ if ( vips_image_get_typeof ( in , VIPS_META_ICC_NAME ) ) {
346
366
const void * data ;
347
367
size_t length ;
348
368
349
- if ( vips_image_get_blob ( save -> ready ,
369
+ if ( vips_image_get_blob ( in ,
350
370
VIPS_META_ICC_NAME , & data , & length ) )
351
371
return ( -1 );
352
372
@@ -360,36 +380,38 @@ vips_foreign_save_jxl_build( VipsObject *object )
360
380
return ( -1 );
361
381
}
362
382
}
363
- else {
364
- if ( save -> ready -> Type == VIPS_INTERPRETATION_scRGB ) {
383
+
384
+ /* libjxl will use linear 0 - 1 by default for float, so we don't need
385
+ * to call JxlColorEncodingSetToLinearSRGB() or
386
+ * JxlColorEncodingSetToSRGB().
387
+ */
388
+ if ( in -> Type == VIPS_INTERPRETATION_scRGB ) {
365
389
#ifdef DEBUG
366
- printf ( "setting sRGB colourspace\n" );
390
+ printf ( "setting scRGB colourspace\n" );
367
391
#endif /*DEBUG*/
368
392
369
- JxlColorEncodingSetToLinearSRGB ( & jxl -> color_encoding ,
370
- jxl -> format .num_channels < 3 );
371
- }
372
- else {
393
+ JxlColorEncodingSetToLinearSRGB ( & jxl -> color_encoding ,
394
+ jxl -> format .num_channels < 3 );
395
+ }
396
+ else {
373
397
#ifdef DEBUG
374
- printf ( "setting scRGB colourspace\n" );
398
+ printf ( "setting sRGB colourspace\n" );
375
399
#endif /*DEBUG*/
376
400
377
- JxlColorEncodingSetToSRGB ( & jxl -> color_encoding ,
378
- jxl -> format .num_channels < 3 );
379
- }
401
+ JxlColorEncodingSetToSRGB ( & jxl -> color_encoding ,
402
+ jxl -> format .num_channels < 3 );
403
+ }
380
404
381
- if ( JxlEncoderSetColorEncoding ( jxl -> encoder ,
382
- & jxl -> color_encoding ) ) {
383
- vips_foreign_save_jxl_error ( jxl ,
384
- "JxlEncoderSetColorEncoding" );
385
- return ( -1 );
386
- }
405
+ if ( JxlEncoderSetColorEncoding ( jxl -> encoder , & jxl -> color_encoding ) ) {
406
+ vips_foreign_save_jxl_error ( jxl ,
407
+ "JxlEncoderSetColorEncoding" );
408
+ return ( -1 );
387
409
}
388
410
389
411
/* Render the entire image in memory. libjxl seems to be missing
390
412
* tile-based write at the moment.
391
413
*/
392
- if ( vips_image_wio_input ( save -> ready ) )
414
+ if ( vips_image_wio_input ( in ) )
393
415
return ( -1 );
394
416
395
417
options = JxlEncoderOptionsCreate ( jxl -> encoder , NULL );
@@ -409,8 +431,8 @@ vips_foreign_save_jxl_build( VipsObject *object )
409
431
#endif /*DEBUG*/
410
432
411
433
if ( JxlEncoderAddImageFrame ( options , & jxl -> format ,
412
- VIPS_IMAGE_ADDR ( save -> ready , 0 , 0 ),
413
- VIPS_IMAGE_SIZEOF_IMAGE ( save -> ready ) ) ) {
434
+ VIPS_IMAGE_ADDR ( in , 0 , 0 ),
435
+ VIPS_IMAGE_SIZEOF_IMAGE ( in ) ) ) {
414
436
vips_foreign_save_jxl_error ( jxl , "JxlEncoderAddImageFrame" );
415
437
return ( -1 );
416
438
}
@@ -485,7 +507,9 @@ vips_foreign_save_jxl_class_init( VipsForeignSaveJxlClass *class )
485
507
486
508
foreign_class -> suffs = vips__jxl_suffs ;
487
509
488
- save_class -> saveable = VIPS_SAVEABLE_ANY ;
510
+ /* This lets throuigh scRGB too, which we then save as jxl float.
511
+ */
512
+ save_class -> saveable = VIPS_SAVEABLE_RGBA ;
489
513
save_class -> format_table = bandfmt_jxl ;
490
514
491
515
VIPS_ARG_INT ( class , "tier" , 10 ,
0 commit comments