From c61b458904d7bb666dbd87d21ffccd91391dd05d Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Sat, 18 Jun 2022 16:40:10 +0100 Subject: [PATCH] add jxlsave tests and revise colour encoding set see https://github.com/libvips/libvips/issues/2872 --- libvips/foreign/jxlsave.c | 36 +++++++++++++++++++++----- test/test-suite/test_foreign.py | 45 +++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 6 deletions(-) diff --git a/libvips/foreign/jxlsave.c b/libvips/foreign/jxlsave.c index b1fe1b9f..94ed4fa2 100644 --- a/libvips/foreign/jxlsave.c +++ b/libvips/foreign/jxlsave.c @@ -34,8 +34,8 @@ */ /* - */ #define DEBUG + */ #ifdef HAVE_CONFIG_H #include @@ -360,11 +360,7 @@ vips_foreign_save_jxl_build( VipsObject *object ) return( -1 ); } - /* Set the colour encoding. Either ICC based, or sRGB. - * - * libjxl will use linear 0 - 1 by default for float, so we - * don't need to call JxlColorEncodingSetToLinearSRGB() or - * JxlColorEncodingSetToSRGB(). + /* Set any ICC profile. */ if( vips_image_get_typeof( in, VIPS_META_ICC_NAME ) ) { const void *data; @@ -384,6 +380,34 @@ vips_foreign_save_jxl_build( VipsObject *object ) return( -1 ); } } + else { + /* If there's no ICC profile, we must set the colour encoding + * ourselves. + */ + if( in->Type == VIPS_INTERPRETATION_scRGB ) { +#ifdef DEBUG + printf( "setting scRGB colourspace\n" ); +#endif /*DEBUG*/ + + JxlColorEncodingSetToLinearSRGB( &jxl->color_encoding, + jxl->format.num_channels < 3 ); + } + else { +#ifdef DEBUG + printf( "setting sRGB colourspace\n" ); +#endif /*DEBUG*/ + + 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. diff --git a/test/test-suite/test_foreign.py b/test/test-suite/test_foreign.py index f48b8ebb..11b997c6 100644 --- a/test/test-suite/test_foreign.py +++ b/test/test-suite/test_foreign.py @@ -1375,6 +1375,51 @@ class TestForeign: # im2 = pyvips.Image.new_from_buffer(buf, "") # assert (im == im2).min() == 255 + @skip_if_no("jxlsave") + def test_jxlsave(self): + # save and load with an icc profile + self.save_load_buffer("jxlsave_buffer", "jxlload_buffer", + self.colour, 120) + + # with no icc profile + no_profile = self.colour.copy() + no_profile.remove("icc-profile-data") + self.save_load_buffer("jxlsave_buffer", "jxlload_buffer", + no_profile, 120) + + # scrgb mode + scrgb = self.colour.colourspace("scrgb") + no_profile.remove("icc-profile-data") + self.save_load_buffer("jxlsave_buffer", "jxlload_buffer", + scrgb, 120) + + # scrgb mode, no profile + scrgb_no_profile = scrgb.copy() + scrgb_no_profile.remove("icc-profile-data") + no_profile.remove("icc-profile-data") + self.save_load_buffer("jxlsave_buffer", "jxlload_buffer", + scrgb_no_profile, 120) + + # 16-bit mode + rgb16 = self.colour.colourspace("rgb16") + self.save_load_buffer("jxlsave_buffer", "jxlload_buffer", + rgb16, 30000) + + # repeat for lossless mode + self.save_load_buffer("jxlsave_buffer", "jxlload_buffer", + self.colour, 0, lossless=True) + self.save_load_buffer("jxlsave_buffer", "jxlload_buffer", + no_profile, 0, lossless=True) + self.save_load_buffer("jxlsave_buffer", "jxlload_buffer", + scrgb, 0, lossless=True) + self.save_load_buffer("jxlsave_buffer", "jxlload_buffer", + scrgb_no_profile, 0, lossless=True) + + # lossy should be much smaller than lossless + lossy = self.colour.jxlsave_buffer() + lossless = self.colour.jxlsave_buffer(lossless=True) + assert len(lossy) < len(lossless) / 5 + @skip_if_no("gifsave") def test_gifsave(self): # Animated GIF round trip