diff --git a/ChangeLog b/ChangeLog index c17de3e6..bc236cb7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -10,10 +10,15 @@ - rename VIPS_OPERATION_RELATIONAL_NOTEQUAL as VIPS_OPERATION_RELATIONAL_NOTEQ for consistency - python vips8 binding -- python vips8 test suite: test_arithmetic.py +- python vips8 test suite: test_arithmetic.py, test_colour.py, + test_conversion.py - better extra band handling by colour, again - move zoomify ImageProperties file, now a better match to the offical tool +8/9/14 started 7.40.10 +- icc_import and icc_transform checks the input profile for compatibility + with the image, thanks James + 8/9/14 started 7.40.9 - support jfif resunit "none" - support GRAY as an input and output ICC space diff --git a/libvips/colour/icc_transform.c b/libvips/colour/icc_transform.c index 12ef4243..c11a6a27 100644 --- a/libvips/colour/icc_transform.c +++ b/libvips/colour/icc_transform.c @@ -28,6 +28,9 @@ * - support XYZ as an alternative PCS * 10/9/14 * - support GRAY as an input and output space + * 29/9/14 + * - check input profiles for compatibility with the input image, thanks + * James */ /* @@ -456,6 +459,86 @@ vips_check_intent( const char *domain, _( "input" ) : _( "output" ) ); } +static int +vips_icc_profile_needs_bands( cmsHPROFILE profile ) +{ + int needs_bands; + + switch( cmsGetColorSpace( profile ) ) { +#ifdef HAVE_LCMS2 + case cmsSigGrayData: + needs_bands = 1; + break; +#endif /*HAVE_LCMS2*/ + + case cmsSigRgbData: + case cmsSigLabData: + case cmsSigXYZData: + needs_bands = 3; + break; + + case cmsSigCmykData: + needs_bands = 4; + break; + + default: + needs_bands = -1; + break; + } + + return( needs_bands ); +} + +static cmsHPROFILE +vips_icc_load_profile_image( const char *domain, VipsImage *image ) +{ + void *data; + size_t data_length; + cmsHPROFILE profile; + + if( !vips_image_get_typeof( image, VIPS_META_ICC_NAME ) ) + return( NULL ); + + if( vips_image_get_blob( image, VIPS_META_ICC_NAME, + &data, &data_length ) || + !(profile = cmsOpenProfileFromMem( data, data_length )) ) { + vips_warn( domain, "%s", _( "corrupt embedded profile" ) ); + return( NULL ); + } + + if( image->Bands != vips_icc_profile_needs_bands( profile ) ) { + VIPS_FREEF( cmsCloseProfile, profile ); + vips_warn( domain, + "%s", _( "embedded profile incompatible with image" ) ); + return( NULL ); + } + + return( profile ); +} + +static cmsHPROFILE +vips_icc_load_profile_file( const char *domain, + VipsImage *image, const char *filename ) +{ + cmsHPROFILE profile; + + if( !(profile = cmsOpenProfileFromFile( filename, "r" )) ) { + vips_error( domain, + _( "unable to open profile \"%s\"" ), filename ); + return( NULL ); + } + + if( image->Bands != vips_icc_profile_needs_bands( profile ) ) { + VIPS_FREEF( cmsCloseProfile, profile ); + vips_warn( domain, + _( "profile \"%s\" incompatible with image" ), + filename ); + return( NULL ); + } + + return( profile ); +} + static int vips_icc_import_build( VipsObject *object ) { @@ -477,30 +560,16 @@ vips_icc_import_build( VipsObject *object ) if( code->in && (import->embedded || - !import->input_profile_filename) && - vips_image_get_typeof( code->in, VIPS_META_ICC_NAME ) ) { - void *data; - size_t data_length; + !import->input_profile_filename) ) + icc->in_profile = vips_icc_load_profile_image( class->nickname, + code->in ); - if( vips_image_get_blob( code->in, VIPS_META_ICC_NAME, - &data, &data_length ) || - !(icc->in_profile = cmsOpenProfileFromMem( - data, data_length )) ) { - vips_error( class->nickname, - "%s", _( "unable to load embedded profile" ) ); - return( -1 ); - } - } - else if( import->input_profile_filename ) { - if( !(icc->in_profile = cmsOpenProfileFromFile( - import->input_profile_filename, "r" )) ) { - vips_error( class->nickname, - _( "unable to open profile \"%s\"" ), - import->input_profile_filename ); - return( -1 ); - } - } - else { + if( !icc->in_profile && + import->input_profile_filename ) + icc->in_profile = vips_icc_load_profile_file( class->nickname, + code->in, import->input_profile_filename ); + + if( !icc->in_profile ) { vips_error( class->nickname, "%s", _( "no input profile" ) ); return( -1 ); } @@ -902,30 +971,16 @@ vips_icc_transform_build( VipsObject *object ) if( code->in && (transform->embedded || - !transform->input_profile_filename) && - vips_image_get_typeof( code->in, VIPS_META_ICC_NAME ) ) { - void *data; - size_t data_length; + !transform->input_profile_filename) ) + icc->in_profile = vips_icc_load_profile_image( class->nickname, + code->in ); - if( vips_image_get_blob( code->in, VIPS_META_ICC_NAME, - &data, &data_length ) || - !(icc->in_profile = cmsOpenProfileFromMem( - data, data_length )) ) { - vips_error( class->nickname, - "%s", _( "unable to load embedded profile" ) ); - return( -1 ); - } - } - else if( transform->input_profile_filename ) { - if( !(icc->in_profile = cmsOpenProfileFromFile( - transform->input_profile_filename, "r" )) ) { - vips_error( class->nickname, - _( "unable to open profile \"%s\"" ), - transform->input_profile_filename ); - return( -1 ); - } - } - else { + if( !icc->in_profile && + transform->input_profile_filename ) + icc->in_profile = vips_icc_load_profile_file( class->nickname, + code->in, transform->input_profile_filename ); + + if( !icc->in_profile ) { vips_error( class->nickname, "%s", _( "no input profile" ) ); return( -1 ); } diff --git a/libvips/iofuncs/util.c b/libvips/iofuncs/util.c index af287175..1942dd1a 100644 --- a/libvips/iofuncs/util.c +++ b/libvips/iofuncs/util.c @@ -575,7 +575,8 @@ vips__file_open_read( const char *filename, const char *fallback_dir, if( (fp = fopen( filename, mode )) ) return( fp ); - if( fallback_dir && !filename_hasdir( filename ) ) { + if( fallback_dir && + !filename_hasdir( filename ) ) { char *path; path = g_build_filename( fallback_dir, filename, NULL ); @@ -586,7 +587,7 @@ vips__file_open_read( const char *filename, const char *fallback_dir, return( fp ); } - vips_error( "vips__file_open_read", + vips_error_system( errno, "vips__file_open_read", _( "unable to open file \"%s\" for reading" ), filename ); return( NULL ); @@ -608,7 +609,7 @@ vips__file_open_write( const char *filename, gboolean text_mode ) #endif /*BINARY_OPEN*/ if( !(fp = fopen( filename, mode )) ) { - vips_error( "vips__file_open_write", + vips_error_system( errno, "vips__file_open_write", _( "unable to open file \"%s\" for writing" ), filename ); return( NULL );