diff --git a/libvips/colour/icc_transform.c b/libvips/colour/icc_transform.c index fec7d89b..5bb91c26 100644 --- a/libvips/colour/icc_transform.c +++ b/libvips/colour/icc_transform.c @@ -151,7 +151,9 @@ typedef struct _VipsIcc { VipsPCS pcs; int depth; + VipsBlob *in_blob; cmsHPROFILE in_profile; + VipsBlob *out_blob; cmsHPROFILE out_profile; cmsUInt32Number in_icc_format; cmsUInt32Number out_icc_format; @@ -181,6 +183,16 @@ vips_icc_dispose( GObject *gobject ) VIPS_FREEF( cmsCloseProfile, icc->in_profile ); VIPS_FREEF( cmsCloseProfile, icc->out_profile ); + if( icc->in_blob ) { + vips_area_unref( (VipsArea *) icc->in_blob ); + icc->in_blob = NULL; + } + + if( icc->out_blob ) { + vips_area_unref( (VipsArea *) icc->out_blob ); + icc->out_blob = NULL; + } + G_OBJECT_CLASS( vips_icc_parent_class )->dispose( gobject ); } @@ -581,98 +593,72 @@ vips_image_expected_sig( VipsImage *image ) return( expected_sig ); } -static cmsHPROFILE -vips_icc_load_profile_image( VipsImage *image ) +/* Get from a filename, including loading a fallback. + */ +static VipsBlob * +vips_icc_get_profile_file( const char *filename ) { void *data; - size_t data_length; - cmsHPROFILE profile; + size_t size; + + if( (data = vips__fallback_profile_get( filename, &size )) ) + /* We have a fallback profile of this name. + */ + return( vips_blob_new( NULL, data, size ) ); + else if( (data = vips__file_read_name( filename, + vips__icc_dir(), &size )) ) + /* Load from the named file. + */ + return( vips_blob_new( + (VipsCallbackFn) vips_free, data, size ) ); + else + return( NULL ); +} + +/* Get from an image. + */ +static VipsBlob * +vips_icc_get_profile_image( VipsImage *image ) +{ + void *data; + size_t size; 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 )) ) { - g_warning( "%s", _( "corrupt embedded profile" ) ); - return( NULL ); - } - - if( vips_image_expected_bands( image ) != - vips_icc_profile_needs_bands( profile ) ) { - VIPS_FREEF( cmsCloseProfile, profile ); - g_warning( "%s", - _( "embedded profile incompatible with image" ) ); - return( NULL ); - } - if( vips_image_expected_sig( image ) != cmsGetColorSpace( profile ) ) { - VIPS_FREEF( cmsCloseProfile, profile ); - g_warning( "%s", - _( "embedded profile colourspace differs from image" ) ); - return( NULL ); - } - - return( profile ); -} - -static void * -vips_icc_get_profile_file( const char *filename, size_t *data_length ) -{ - void *data; - - /* See if we have a fallback profile of this name. - */ - if( (data = vips__fallback_profile_get( filename, data_length )) ) - return( data ); - - /* Try to load as a filename. - */ - if( (data = vips__file_read_name( filename, - vips__icc_dir(), data_length )) ) - return( data ); - - return( NULL ); -} - -static void * -vips_icc_get_profile_image( VipsImage *image, size_t *data_length ) -{ - void *data; - - if( !vips_image_get_typeof( image, VIPS_META_ICC_NAME ) ) + if( vips_image_get_blob( image, VIPS_META_ICC_NAME, &data, &size ) ) return( NULL ); - if( vips_image_get_blob( image, VIPS_META_ICC_NAME, - &data, data_length ) _) { - g_warning( "%s", _( "corrupt embedded profile" ) ); - return( NULL ); - } - - return( data ); + return( vips_blob_new( NULL, data, size ) ); } +/* Load a profile from a blob and check compatibility. + */ static cmsHPROFILE -vips_icc_load_profile( const char *domain, - VipsImage *image, void *data, size_t *data_length ) +vips_icc_load_profile_blob( VipsBlob *blob, VipsImage *image ) { + const void *data; + size_t size; cmsHPROFILE profile; - if( !(profile = cmsOpenProfileFromMem( data, data_length )) ) { + data = vips_blob_get( blob, &size ); + if( !(profile = cmsOpenProfileFromMem( data, size )) ) { g_warning( "%s", _( "corrupt profile" ) ); return( NULL ); } - if( vips_image_expected_bands( image ) != - vips_icc_profile_needs_bands( profile ) ) { + if( image && + vips_image_expected_bands( image ) != + vips_icc_profile_needs_bands( profile ) ) { VIPS_FREEF( cmsCloseProfile, profile ); - g_warning( _( "profile \"%s\" incompatible with image" ), - filename ); + g_warning( "%s", _( "profile incompatible with image" ) ); return( NULL ); } - if( vips_image_expected_sig( image ) != cmsGetColorSpace( profile ) ) { + if( image && + vips_image_expected_sig( image ) != + cmsGetColorSpace( profile ) ) { VIPS_FREEF( cmsCloseProfile, profile ); - g_warning( _( "profile \"%s\" colourspace " - "differs from image" ), filename ); + g_warning( "%s", + _( "profile colourspace differs from image" ) ); return( NULL ); } @@ -695,23 +681,25 @@ vips_icc_import_build( VipsObject *object ) * 1 0 image * 0 1 file * 1 1 image, then fall back to file - * - * see also import_build. */ if( code->in && (import->embedded || !import->input_profile_filename) ) - icc->in_profile = vips_icc_load_profile_image( code->in ); + icc->in_blob = vips_icc_get_profile_image( code->in ); - if( !icc->in_profile && - code->in && + if( !icc->in_blob && import->input_profile_filename ) { - icc->in_profile = vips_icc_load_profile_file( class->nickname, - code->in, import->input_profile_filename ); + icc->in_blob = vips_icc_get_profile_file( + import->input_profile_filename ); import->used_fallback = TRUE; } + if( icc->in_blob && + code->in ) + icc->in_profile = + vips_icc_load_profile_blob( icc->in_blob, code->in ); + if( !icc->in_profile ) { vips_error( class->nickname, "%s", _( "no input profile" ) ); return( -1 ); @@ -733,23 +721,19 @@ vips_icc_import_build( VipsObject *object ) return( -1 ); /* If we used the fallback profile, we need to attach it to the PCS - * image since the PCS image needs to know about a route back to - * device space. + * image, since the PCS image needs a route back to device space. * * In the same way, we don't remove the embedded input profile on * import. */ - if( import->used_fallback ) { - char *data; - size_t length; - - if( !(data = vips__file_read_name( - import->input_profile_filename, - vips__icc_dir(), &length )) ) - return( -1 ); + if( import->used_fallback && + icc->in_blob ) { + void *data; + size_t size; + data = vips_blob_get( icc->in_blob, &size ); vips_image_set_blob( colour->out, VIPS_META_ICC_NAME, - (VipsCallbackFn) vips_free, data, length ); + NULL, data, size ); } return( 0 ); @@ -897,32 +881,18 @@ vips_icc_export_build( VipsObject *object ) icc->in_profile = cmsCreateXYZProfile(); if( code->in && - !export->output_profile_filename && - vips_image_get_typeof( code->in, VIPS_META_ICC_NAME ) ) { - void *data; - size_t data_length; - - if( vips_image_get_blob( code->in, VIPS_META_ICC_NAME, - &data, &data_length ) || - !(icc->out_profile = cmsOpenProfileFromMem( - data, data_length )) ) { - vips_error( class->nickname, - "%s", _( "unable to load embedded profile" ) ); - return( -1 ); - } - } - else if( export->output_profile_filename ) { - if( !(icc->out_profile = cmsOpenProfileFromFile( - export->output_profile_filename, "r" )) ) { - vips_error( class->nickname, - _( "unable to open profile \"%s\"" ), - export->output_profile_filename ); - return( -1 ); - } + !export->output_profile_filename ) + icc->out_blob = vips_icc_get_profile_image( code->in ); + if( !icc->out_blob && + export->output_profile_filename ) { + icc->out_blob = vips_icc_get_profile_file( + export->output_profile_filename ); colour->profile_filename = export->output_profile_filename; } - else { + + if( !(icc->out_profile = + vips_icc_load_profile_blob( icc->out_blob, NULL )) ) { vips_error( class->nickname, "%s", _( "no output profile" ) ); return( -1 ); } @@ -1115,13 +1085,17 @@ vips_icc_transform_build( VipsObject *object ) if( code->in && (transform->embedded || !transform->input_profile_filename) ) - icc->in_profile = vips_icc_load_profile_image( code->in ); + icc->in_blob = vips_icc_get_profile_image( code->in ); - if( !icc->in_profile && - code->in && + if( !icc->in_blob && transform->input_profile_filename ) - icc->in_profile = vips_icc_load_profile_file( class->nickname, - code->in, transform->input_profile_filename ); + icc->in_blob = vips_icc_get_profile_file( + transform->input_profile_filename ); + + if( icc->in_blob && + code->in ) + icc->in_profile = + vips_icc_load_profile_blob( icc->in_blob, code->in ); if( !icc->in_profile ) { vips_error( class->nickname, "%s", _( "no input profile" ) ); @@ -1129,17 +1103,20 @@ vips_icc_transform_build( VipsObject *object ) } if( transform->output_profile_filename ) { - if( !(icc->out_profile = cmsOpenProfileFromFile( - transform->output_profile_filename, "r" )) ) { - vips_error( class->nickname, - _( "unable to open profile \"%s\"" ), - transform->output_profile_filename ); - return( -1 ); - } - + icc->out_blob = vips_icc_get_profile_file( + transform->output_profile_filename ); colour->profile_filename = transform->output_profile_filename; } + if( icc->out_blob ) + icc->out_profile = + vips_icc_load_profile_blob( icc->out_blob, NULL ); + + if( !icc->out_profile ) { + vips_error( class->nickname, "%s", _( "no output profile" ) ); + return( -1 ); + } + vips_check_intent( class->nickname, icc->in_profile, icc->intent, LCMS_USED_AS_INPUT ); vips_check_intent( class->nickname,