diff --git a/libvips/colour/CMYK2XYZ.c b/libvips/colour/CMYK2XYZ.c index d85dfe12..83e2603c 100644 --- a/libvips/colour/CMYK2XYZ.c +++ b/libvips/colour/CMYK2XYZ.c @@ -92,8 +92,6 @@ vips__CMYK2XYZ_get_fallback_profile( size_t *length ) } /* Shared with XYZ2CMYK.c. - * - * FIXME ... should this remove and replace a non-CMYK profile? */ int vips_CMYK2XYZ_set_fallback_profile( VipsImage *image ) @@ -101,8 +99,11 @@ vips_CMYK2XYZ_set_fallback_profile( VipsImage *image ) size_t data_length; unsigned char *data; + /* Already a profile? Do nothing. We could remove and replace non-CMYK + * profiles I guess. + */ if( vips_image_get_typeof( image, VIPS_META_ICC_NAME ) ) - return( -1 ); + return( 0 ); if( !(data = vips__CMYK2XYZ_get_fallback_profile( &data_length )) ) return( -1 ); @@ -113,11 +114,22 @@ vips_CMYK2XYZ_set_fallback_profile( VipsImage *image ) return( 0 ); } +/* Our actual processing, as a VipsColourTransformFn. + */ +static int +vips_CMYK2XYZ_process( VipsImage *in, VipsImage **out, ... ) +{ + return( vips_icc_import( in, out, + "embedded", TRUE, + "pcs", VIPS_PCS_XYZ, + NULL ) ); +} + static int vips_CMYK2XYZ_build( VipsObject *object ) { VipsCMYK2XYZ *CMYK2XYZ = (VipsCMYK2XYZ *) object; - VipsImage **t = (VipsImage **) vips_object_local_array( object, 7 ); + VipsImage **t = (VipsImage **) vips_object_local_array( object, 2 ); VipsImage *out; @@ -129,10 +141,8 @@ vips_CMYK2XYZ_build( VipsObject *object ) if( vips_copy( CMYK2XYZ->in, &t[0], NULL ) || vips_CMYK2XYZ_set_fallback_profile( t[0] ) || - vips_icc_import( t[0], &t[1], - "embedded", TRUE, - "pcs", VIPS_PCS_XYZ, - NULL ) || + vips__colourspace_process_n( "CMYK2XYZ", + t[0], &t[1], 4, vips_CMYK2XYZ_process ) || vips_image_write( t[1], out ) ) return( -1 ); diff --git a/libvips/colour/XYZ2CMYK.c b/libvips/colour/XYZ2CMYK.c index 66d356f1..bf5cd2b3 100644 --- a/libvips/colour/XYZ2CMYK.c +++ b/libvips/colour/XYZ2CMYK.c @@ -59,11 +59,21 @@ typedef VipsColourCodeClass VipsXYZ2CMYKClass; G_DEFINE_TYPE( VipsXYZ2CMYK, vips_XYZ2CMYK, VIPS_TYPE_OPERATION ); +/* Our actual processing, as a VipsColourTransformFn. + */ +static int +vips_XYZ2CMYK_process( VipsImage *in, VipsImage **out, ... ) +{ + return( vips_icc_export( in, out, + "pcs", VIPS_PCS_XYZ, + NULL ) ); +} + static int vips_XYZ2CMYK_build( VipsObject *object ) { VipsXYZ2CMYK *XYZ2CMYK = (VipsXYZ2CMYK *) object; - VipsImage **t = (VipsImage **) vips_object_local_array( object, 7 ); + VipsImage **t = (VipsImage **) vips_object_local_array( object, 2 ); VipsImage *out; @@ -75,9 +85,8 @@ vips_XYZ2CMYK_build( VipsObject *object ) if( vips_copy( XYZ2CMYK->in, &t[0], NULL ) || vips_CMYK2XYZ_set_fallback_profile( t[0] ) || - vips_icc_export( t[0], &t[1], - "pcs", VIPS_PCS_XYZ, - NULL ) || + vips__colourspace_process_n( "XYZ2CMYK", + t[0], &t[1], 3, vips_XYZ2CMYK_process ) || vips_image_write( t[1], out ) ) return( -1 ); diff --git a/libvips/colour/colourspace.c b/libvips/colour/colourspace.c index 91b7e35d..d8844c17 100644 --- a/libvips/colour/colourspace.c +++ b/libvips/colour/colourspace.c @@ -68,10 +68,6 @@ #include "pcolour.h" -/* A colour-transforming function. - */ -typedef int (*VipsColourTransformFn)( VipsImage *in, VipsImage **out, ... ); - static int vips_scRGB2RGB16( VipsImage *in, VipsImage **out, ... ) { @@ -113,10 +109,12 @@ vips_sRGB2RGB16( VipsImage *in, VipsImage **out, ... ) } /* Process the first @n bands with @fn, detach and reattach remaining bands. + * + * Also used by CMYK2XYZ and XYZ2CMYK. */ -static int -vips_process_n( const char *domain, VipsImage *in, VipsImage **out, - int n, VipsColourTransformFn fn ) +int +vips__colourspace_process_n( const char *domain, + VipsImage *in, VipsImage **out, int n, VipsColourTransformFn fn ) { if( in->Bands > n ) { VipsImage *scope = vips_image_new(); @@ -168,7 +166,8 @@ vips_BW2sRGB_op( VipsImage *in, VipsImage **out, ... ) static int vips_BW2sRGB( VipsImage *in, VipsImage **out, ... ) { - if( vips_process_n( "BW2sRGB", in, out, 1, vips_BW2sRGB_op ) ) + if( vips__colourspace_process_n( "BW2sRGB", + in, out, 1, vips_BW2sRGB_op ) ) return( -1 ); (*out)->Type = VIPS_INTERPRETATION_sRGB; @@ -178,7 +177,8 @@ vips_BW2sRGB( VipsImage *in, VipsImage **out, ... ) static int vips_GREY162RGB16( VipsImage *in, VipsImage **out, ... ) { - if( vips_process_n( "GREY162RGB16", in, out, 1, vips_BW2sRGB_op ) ) + if( vips__colourspace_process_n( "GREY162RGB16", + in, out, 1, vips_BW2sRGB_op ) ) return( -1 ); (*out)->Type = VIPS_INTERPRETATION_RGB16; diff --git a/libvips/colour/pcolour.h b/libvips/colour/pcolour.h index ea993163..da93c9c6 100644 --- a/libvips/colour/pcolour.h +++ b/libvips/colour/pcolour.h @@ -218,6 +218,13 @@ void vips_col_make_tables_RGB_16( void ); int vips_CMYK2XYZ_set_fallback_profile( VipsImage *image ); +/* A colour-transforming function. + */ +typedef int (*VipsColourTransformFn)( VipsImage *in, VipsImage **out, ... ); + +int vips__colourspace_process_n( const char *domain, + VipsImage *in, VipsImage **out, int n, VipsColourTransformFn fn ); + #ifdef __cplusplus } #endif /*__cplusplus*/ diff --git a/test/test-suite/helpers/helpers.py b/test/test-suite/helpers/helpers.py index 884d47b5..c2051724 100644 --- a/test/test-suite/helpers/helpers.py +++ b/test/test-suite/helpers/helpers.py @@ -49,17 +49,18 @@ colour_colourspaces = [pyvips.Interpretation.XYZ, pyvips.Interpretation.LCH, pyvips.Interpretation.CMC, pyvips.Interpretation.LABS, - pyvips.Interpretation.CMYK, pyvips.Interpretation.SCRGB, pyvips.Interpretation.HSV, pyvips.Interpretation.SRGB, pyvips.Interpretation.YXY] +cmyk_colourspaces = [pyvips.Interpretation.CMYK] coded_colourspaces = [pyvips.Interpretation.LABQ] mono_colourspaces = [pyvips.Interpretation.B_W] sixteenbit_colourspaces = [pyvips.Interpretation.GREY16, pyvips.Interpretation.RGB16] all_colourspaces = colour_colourspaces + mono_colourspaces + \ - coded_colourspaces + sixteenbit_colourspaces + coded_colourspaces + sixteenbit_colourspaces + \ + cmyk_colourspaces max_value = {pyvips.BandFormat.UCHAR: 0xff, pyvips.BandFormat.USHORT: 0xffff, diff --git a/test/test-suite/test_colour.py b/test/test-suite/test_colour.py index b9b5a1bc..1e2371f2 100644 --- a/test/test-suite/test_colour.py +++ b/test/test-suite/test_colour.py @@ -71,6 +71,19 @@ class TestColour: # 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):