From 8e72d25c9a2e8547ff290700cb3226b929ce74ae Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Thu, 1 Nov 2012 13:16:54 +0000 Subject: [PATCH] better colourspace sniffing --- TODO | 9 --- libvips/colour/colour.c | 11 +++- libvips/include/vips/header.h | 1 + libvips/iofuncs/header.c | 121 ++++++++++++++++++++++++++++++++++ 4 files changed, 130 insertions(+), 12 deletions(-) diff --git a/TODO b/TODO index f7339af2..6eff1405 100644 --- a/TODO +++ b/TODO @@ -3,15 +3,6 @@ - add mono as a colourspace? also rad? -- something to test if an image is in a supported colourspace? - - at the moment we only look at interpretation, but for things like labq - we should check coding too - - labs needs more checks than that - - _RGB and _sRGB as well - move colour_convert into a separate file - im_icc_ac2rc needs doing once we have a general 'convert' operator diff --git a/libvips/colour/colour.c b/libvips/colour/colour.c index 2a8ebc89..8ad92e56 100644 --- a/libvips/colour/colour.c +++ b/libvips/colour/colour.c @@ -709,6 +709,8 @@ vips_colour_convert_build( VipsObject *object ) VipsImage *x; VipsImage **t; + VipsInterpretation interpretation; + t = (VipsImage **) vips_object_local_array( object, MAX_STEPS ); /* Verify that all input args have been set. @@ -717,9 +719,11 @@ vips_colour_convert_build( VipsObject *object ) build( object ) ) return( -1 ); + interpretation = vips_image_guess_interpretation( convert->in ); + /* No conversion necessary. */ - if( convert->in->Type == convert->space ) { + if( interpretation == convert->space ) { g_object_set( convert, "out", vips_image_new(), NULL ); return( vips_image_write( convert->in, convert->out ) ); @@ -728,13 +732,14 @@ vips_colour_convert_build( VipsObject *object ) x = convert->in; for( i = 0; i < VIPS_NUMBER( vips_colour_routes ); i++ ) - if( vips_colour_routes[i].from == x->Type && + if( vips_colour_routes[i].from == interpretation && vips_colour_routes[i].to == convert->space ) break; if( i == VIPS_NUMBER( vips_colour_routes ) ) { vips_error( "vips_colour_convert", _( "no known route between '%s' and '%s'" ), - vips_enum_nick( VIPS_TYPE_INTERPRETATION, x->Type ), + vips_enum_nick( VIPS_TYPE_INTERPRETATION, + interpretation ), vips_enum_nick( VIPS_TYPE_INTERPRETATION, convert->space ) ); return( -1 ); diff --git a/libvips/include/vips/header.h b/libvips/include/vips/header.h index 65cdc0d8..c658c069 100644 --- a/libvips/include/vips/header.h +++ b/libvips/include/vips/header.h @@ -85,6 +85,7 @@ int vips_image_get_bands( const VipsImage *image ); VipsBandFormat vips_image_get_format( const VipsImage *image ); VipsCoding vips_image_get_coding( const VipsImage *image ); VipsInterpretation vips_image_get_interpretation( const VipsImage *image ); +VipsInterpretation vips_image_guess_interpretation( const VipsImage *image ); double vips_image_get_xres( const VipsImage *image ); double vips_image_get_yres( const VipsImage *image ); int vips_image_get_xoffset( const VipsImage *image ); diff --git a/libvips/iofuncs/header.c b/libvips/iofuncs/header.c index 219bc9bb..ea9b93ec 100644 --- a/libvips/iofuncs/header.c +++ b/libvips/iofuncs/header.c @@ -364,12 +364,133 @@ vips_image_get_coding( const VipsImage *image ) return( image->Coding ); } +/* vips_image_get_interpretation: + * @image: image to guess for + * + * Return the #VipsInterpretation set in the image header. + * Use vips_image_guess_interpretation() is you want a sanity-checked value. + * + * Returns: the #VipsInterpretation from the image header. + */ VipsInterpretation vips_image_get_interpretation( const VipsImage *image ) { return( image->Type ); } +/* Try to pick a sane value for interpretation, assuming Type has been set + * incorrectly. + */ +static VipsInterpretation +vips_image_default_interpretation( const VipsImage *image ) +{ + switch( image->Coding ) { + case VIPS_CODING_LABQ: + return( VIPS_INTERPRETATION_LABQ ); + case VIPS_CODING_RAD: + return( VIPS_INTERPRETATION_RGB ); + default: + break; + } + + if( image->Bands == 1 ) + return( VIPS_INTERPRETATION_B_W ); + else + return( VIPS_INTERPRETATION_MULTIBAND ); +} + +/* vips_image_guess_interpretation: + * @image: image to guess for + * + * Return the #VipsInterpretation for an image, guessing a default value if + * the set value looks wrong. + * + * Returns: a sensible #VipsInterpretation for the image. + */ +VipsInterpretation +vips_image_guess_interpretation( const VipsImage *image ) +{ + gboolean sane; + + sane = TRUE; + switch( image->Type ) { + + case VIPS_INTERPRETATION_MULTIBAND: + if( image->Bands == 1 ) + sane = FALSE; + break; + + case VIPS_INTERPRETATION_B_W: + if( image->Bands > 1 ) + sane = FALSE; + break; + + case VIPS_INTERPRETATION_HISTOGRAM: + if( image->Xsize > 1 && image->Ysize > 1 ) + sane = FALSE; + break; + + case VIPS_INTERPRETATION_FOURIER: + if( !vips_band_format_iscomplex( image->BandFmt ) ) + sane = FALSE; + break; + + case VIPS_INTERPRETATION_XYZ: + case VIPS_INTERPRETATION_LAB: + case VIPS_INTERPRETATION_RGB: + case VIPS_INTERPRETATION_CMC: + case VIPS_INTERPRETATION_LCH: + case VIPS_INTERPRETATION_sRGB: + case VIPS_INTERPRETATION_YXY: + if( image->Bands < 3 ) + sane = FALSE; + break; + + case VIPS_INTERPRETATION_CMYK: + if( image->Bands < 4 ) + sane = FALSE; + break; + + case VIPS_INTERPRETATION_LABQ: + if( image->Coding != VIPS_CODING_LABQ ) + sane = FALSE; + break; + + case VIPS_INTERPRETATION_LABS: + if( image->BandFmt != VIPS_FORMAT_SHORT ) + sane = FALSE; + break; + + case VIPS_INTERPRETATION_RGB16: + if( image->BandFmt == VIPS_FORMAT_CHAR || + image->BandFmt == VIPS_FORMAT_UCHAR || + image->Bands < 3 ) + sane = FALSE; + break; + + case VIPS_INTERPRETATION_GREY16: + if( image->BandFmt == VIPS_FORMAT_CHAR || + image->BandFmt == VIPS_FORMAT_UCHAR ) + sane = FALSE; + break; + + case VIPS_INTERPRETATION_ARRAY: + if( image->Bands != 1 ) + sane = FALSE; + break; + + default: + g_assert( 0 ); + sane = FALSE; + break; + } + + if( sane ) + return( vips_image_get_interpretation( image ) ); + else + return( vips_image_default_interpretation( image ) ); +} + double vips_image_get_xres( const VipsImage *image ) {