# vim: set fileencoding=utf-8 : import pytest import pyvips from helpers import JPEG_FILE, SRGB_FILE, colour_colourspaces, \ mono_colourspaces, assert_almost_equal_objects, skip_if_no class TestColour: def test_colourspace(self): # mid-grey in Lab ... put 42 in the extra band, it should be copied # unmodified test = pyvips.Image.black(100, 100) + [50, 0, 0, 42] test = test.copy(interpretation=pyvips.Interpretation.LAB) # a long series should come in a circle im = test for col in colour_colourspaces + [pyvips.Interpretation.LAB]: im = im.colourspace(col) assert im.interpretation == col for i in range(0, 4): min_l = im.extract_band(i).min() max_h = im.extract_band(i).max() assert pytest.approx(min_l) == max_h pixel = im(10, 10) assert pytest.approx(pixel[3], 0.01) == 42 # alpha won't be equal for RGB16, but it should be preserved if we go # there and back im = im.colourspace(pyvips.Interpretation.RGB16) im = im.colourspace(pyvips.Interpretation.LAB) before = test(10, 10) after = im(10, 10) assert_almost_equal_objects(before, after, threshold=0.1) # go between every pair of colour spaces for start in colour_colourspaces: for end in colour_colourspaces: im = test.colourspace(start) im2 = im.colourspace(end) im3 = im2.colourspace(pyvips.Interpretation.LAB) before = test(10, 10) after = im3(10, 10) assert_almost_equal_objects(before, after, threshold=0.1) # test Lab->XYZ on mid-grey # checked against http://www.brucelindbloom.com im = test.colourspace(pyvips.Interpretation.XYZ) after = im(10, 10) assert_almost_equal_objects(after, [17.5064, 18.4187, 20.0547, 42]) # grey->colour->grey should be equal for mono_fmt in mono_colourspaces: test_grey = test.colourspace(mono_fmt) im = test_grey for col in colour_colourspaces + [mono_fmt]: im = im.colourspace(col) assert im.interpretation == col [before, alpha_before] = test_grey(10, 10) [after, alpha_after] = im(10, 10) assert abs(alpha_after - alpha_before) < 1 if mono_fmt == pyvips.Interpretation.GREY16: # GREY16 can wind up rather different due to rounding assert abs(after - before) < 30 else: # but 8-bit we should hit exactly assert abs(after - before) < 1 # we should be able to go from cmyk to any 3-band space and back again, # approximately cmyk = test.colourspace(pyvips.Interpretation.CMYK) for end in colour_colourspaces: im = cmyk.colourspace(end) im2 = im.colourspace(pyvips.Interpretation.CMYK) before = cmyk(10, 10) after = im2(10, 10) assert_almost_equal_objects(before, after, threshold=10) # test results from Bruce Lindbloom's calculator: # http://www.brucelindbloom.com def test_dE00(self): # put 42 in the extra band, it should be copied unmodified reference = pyvips.Image.black(100, 100) + [50, 10, 20, 42] reference = reference.copy(interpretation=pyvips.Interpretation.LAB) sample = pyvips.Image.black(100, 100) + [40, -20, 10] sample = sample.copy(interpretation=pyvips.Interpretation.LAB) difference = reference.dE00(sample) result, alpha = difference(10, 10) assert pytest.approx(result, 0.001) == 30.238 assert pytest.approx(alpha, 0.001) == 42.0 def test_dE76(self): # put 42 in the extra band, it should be copied unmodified reference = pyvips.Image.black(100, 100) + [50, 10, 20, 42] reference = reference.copy(interpretation=pyvips.Interpretation.LAB) sample = pyvips.Image.black(100, 100) + [40, -20, 10] sample = sample.copy(interpretation=pyvips.Interpretation.LAB) difference = reference.dE76(sample) result, alpha = difference(10, 10) assert pytest.approx(result, 0.001) == 33.166 assert pytest.approx(alpha, 0.001) == 42.0 # the vips CMC calculation is based on distance in a colorspace # derived from the CMC formula, so it won't match exactly ... # see vips_LCh2CMC() for details def test_dECMC(self): reference = pyvips.Image.black(100, 100) + [50, 10, 20, 42] reference = reference.copy(interpretation=pyvips.Interpretation.LAB) sample = pyvips.Image.black(100, 100) + [55, 11, 23] sample = sample.copy(interpretation=pyvips.Interpretation.LAB) difference = reference.dECMC(sample) result, alpha = difference(10, 10) assert abs(result - 4.97) < 0.5 assert pytest.approx(alpha, 0.001) == 42.0 @skip_if_no("icc_import") def test_icc(self): test = pyvips.Image.new_from_file(JPEG_FILE) im = test.icc_import().icc_export() assert im.dE76(test).max() < 6 im = test.icc_import() im2 = im.icc_export(depth=16) assert im2.format == pyvips.BandFormat.USHORT im3 = im2.icc_import() assert (im - im3).abs().max() < 3 im = test.icc_import(intent=pyvips.Intent.ABSOLUTE) im2 = im.icc_export(intent=pyvips.Intent.ABSOLUTE) assert im2.dE76(test).max() < 6 im = test.icc_import() im2 = im.icc_export(output_profile=SRGB_FILE) im3 = im.colourspace(pyvips.Interpretation.SRGB) assert im2.dE76(im3).max() < 6 before_profile = test.get("icc-profile-data") im = test.icc_transform(SRGB_FILE) after_profile = im.get("icc-profile-data") im2 = test.icc_import() im3 = im2.colourspace(pyvips.Interpretation.SRGB) assert im.dE76(im3).max() < 6 assert len(before_profile) != len(after_profile) im = test.icc_import(input_profile=SRGB_FILE) im2 = test.icc_import() assert 6 < im.dE76(im2).max() im = test.icc_import(pcs=pyvips.PCS.XYZ) assert im.interpretation == pyvips.Interpretation.XYZ im = test.icc_import() assert im.interpretation == pyvips.Interpretation.LAB # even without lcms, we should have a working approximation def test_cmyk(self): test = pyvips.Image.new_from_file(JPEG_FILE) im = test.colourspace("cmyk").colourspace("srgb") before = test(582, 210) after = im(582, 210) assert_almost_equal_objects(before, after, threshold=10) if __name__ == '__main__': pytest.main()