diff --git a/libvips/foreign/spngsave.c b/libvips/foreign/spngsave.c index 1bb2f569..d372666d 100644 --- a/libvips/foreign/spngsave.c +++ b/libvips/foreign/spngsave.c @@ -270,7 +270,7 @@ vips_foreign_save_spng_pack( VipsForeignSaveSpng *spng, VipsPel *q, VipsPel *p, size_t n ) { int pixel_mask = 8 / spng->bitdepth - 1; - int shift = 8 - spng->bitdepth; + int shift = spng->palette ? 0 : 8 - spng->bitdepth; VipsPel bits; size_t x; diff --git a/libvips/resample/thumbnail.c b/libvips/resample/thumbnail.c index 8739c20a..a0293957 100644 --- a/libvips/resample/thumbnail.c +++ b/libvips/resample/thumbnail.c @@ -859,20 +859,37 @@ vips_thumbnail_build( VipsObject *object ) in = t[7]; } else if( thumbnail->export_profile ) { - /* We are in one of the resize space (sRGB, scRGB, B_W, GREY16, - * etc.) and we have an export profile. Go to PCS, then export. + /* If there's some kind of import profile, we can transform to + * the output. Otherwise, we are in one of the resize space + * (sRGB, scRGB, B_W, GREY16, etc.) and need to go to PCS, + * then export. */ - g_info( "exporting with %s", - thumbnail->export_profile ); - if( vips_colourspace( in, &t[7], - VIPS_INTERPRETATION_XYZ, NULL ) || - vips_icc_export( t[7], &t[10], - "output_profile", - thumbnail->export_profile, + if( thumbnail->import_profile || + vips_image_get_typeof( in, VIPS_META_ICC_NAME ) ) { + g_info( "transforming with supplied profiles" ); + if( vips_icc_transform( in, &t[7], + thumbnail->export_profile, + "input_profile", thumbnail->import_profile, "intent", thumbnail->intent, - NULL ) ) - return( -1 ); - in = t[10]; + "embedded", TRUE, + NULL ) ) + return( -1 ); + + in = t[7]; + } + else { + g_info( "exporting with %s", + thumbnail->export_profile ); + if( vips_colourspace( in, &t[7], + VIPS_INTERPRETATION_XYZ, NULL ) || + vips_icc_export( t[7], &t[10], + "output_profile", + thumbnail->export_profile, + "intent", thumbnail->intent, + NULL ) ) + return( -1 ); + in = t[10]; + } } else { /* We are in one of the resize spaces and there's no export diff --git a/test/test-suite/helpers/helpers.py b/test/test-suite/helpers/helpers.py index f2dd9753..cbdfbfa3 100644 --- a/test/test-suite/helpers/helpers.py +++ b/test/test-suite/helpers/helpers.py @@ -9,6 +9,7 @@ import pyvips IMAGES = os.path.join(os.path.dirname(__file__), os.pardir, 'images') JPEG_FILE = os.path.join(IMAGES, "sample.jpg") +JPEG_FILE_XYB = os.path.join(IMAGES, "sample-xyb.jpg") TRUNCATED_FILE = os.path.join(IMAGES, "truncated.jpg") SRGB_FILE = os.path.join(IMAGES, "sRGB.icm") MATLAB_FILE = os.path.join(IMAGES, "sample.mat") diff --git a/test/test-suite/images/sample-xyb.jpg b/test/test-suite/images/sample-xyb.jpg new file mode 100644 index 00000000..6e802dc8 Binary files /dev/null and b/test/test-suite/images/sample-xyb.jpg differ diff --git a/test/test-suite/test_foreign.py b/test/test-suite/test_foreign.py index 4c83b49b..df117cf5 100644 --- a/test/test-suite/test_foreign.py +++ b/test/test-suite/test_foreign.py @@ -1433,14 +1433,12 @@ class TestForeign: # 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) diff --git a/test/test-suite/test_resample.py b/test/test-suite/test_resample.py index a31bd257..c93b889e 100644 --- a/test/test-suite/test_resample.py +++ b/test/test-suite/test_resample.py @@ -2,8 +2,8 @@ import pytest import pyvips -from helpers import JPEG_FILE, OME_FILE, HEIC_FILE, TIF_FILE, all_formats, \ - have, RGBA_FILE, RGBA_CORRECT_FILE, AVIF_FILE +from helpers import JPEG_FILE, JPEG_FILE_XYB, OME_FILE, HEIC_FILE, TIF_FILE, \ + all_formats, have, RGBA_FILE, RGBA_CORRECT_FILE, AVIF_FILE # Run a function expecting a complex image on a two-band image @@ -229,6 +229,21 @@ class TestResample: assert thumb.width < thumb.height assert thumb.height == 100 + @pytest.mark.skipif(not pyvips.at_least_libvips(8, 5), + reason="requires libvips >= 8.5") + def test_thumbnail_icc(self): + im = pyvips.Image.thumbnail(JPEG_FILE_XYB, 442, export_profile="srgb", intent="perceptual") + + assert im.width == 290 + assert im.height == 442 + assert im.bands == 3 + assert im.bands == 3 + + # the colour distance should not deviate too much + # (i.e. the embedded profile should not be ignored) + im_orig = pyvips.Image.new_from_file(JPEG_FILE) + assert im_orig.de00(im).max() < 10 + def test_similarity(self): im = pyvips.Image.new_from_file(JPEG_FILE) im2 = im.similarity(angle=90)