diff --git a/ChangeLog b/ChangeLog index a1d8e417..622b3357 100644 --- a/ChangeLog +++ b/ChangeLog @@ -13,7 +13,9 @@ - add vips_rect_overlapsrect() - composite is much faster at positioning subimages - dzsave has a new skip_blanks option -- add CMYK as a supported colourspace +- add vips_CMYK2XYZ() and vips_XYZ2CMYK(), plus associated routes +- include cmyk and srgb fallback profiles +- add vips_profile_load() and use it everywhere 4/1/19 started 8.7.4 - fix memory leak in magickload [kleisauke] diff --git a/cplusplus/VError.cpp b/cplusplus/VError.cpp index 67e67348..a3d82188 100644 --- a/cplusplus/VError.cpp +++ b/cplusplus/VError.cpp @@ -32,8 +32,6 @@ #endif /*HAVE_CONFIG_H*/ #include -#include - #include VIPS_NAMESPACE_START diff --git a/cplusplus/VImage.cpp b/cplusplus/VImage.cpp index 3c1acd98..205b46cb 100644 --- a/cplusplus/VImage.cpp +++ b/cplusplus/VImage.cpp @@ -563,7 +563,7 @@ VImage::new_from_file( const char *name, VOption *options ) } VImage -VImage::new_from_buffer( void *buf, size_t len, const char *option_string, +VImage::new_from_buffer( const void *buf, size_t len, const char *option_string, VOption *options ) { const char *operation_name; @@ -588,6 +588,13 @@ VImage::new_from_buffer( void *buf, size_t len, const char *option_string, return( out ); } +VImage +VImage::new_from_buffer( const std::string &buf, const char *option_string, + VOption *options ) +{ + return( new_from_buffer( buf.c_str(), buf.size(), option_string, options ) ); +} + VImage VImage::new_matrix( int width, int height ) { diff --git a/cplusplus/include/vips/VError8.h b/cplusplus/include/vips/VError8.h index 627222c1..29f3e9fb 100644 --- a/cplusplus/include/vips/VError8.h +++ b/cplusplus/include/vips/VError8.h @@ -31,8 +31,8 @@ #ifndef VIPS_VERROR_H #define VIPS_VERROR_H -#include -#include +#include +#include #include #include @@ -43,7 +43,7 @@ class VIPS_CPLUSPLUS_API VError : public std::exception { std::string _what; public: - VError( std::string what ) : _what( what ) {} + VError( const std::string &what ) : _what( what ) {} VError() : _what( vips_error_buffer() ) {} virtual ~VError() throw() {} diff --git a/cplusplus/include/vips/VImage8.h b/cplusplus/include/vips/VImage8.h index d7b745fe..abd0b78a 100644 --- a/cplusplus/include/vips/VImage8.h +++ b/cplusplus/include/vips/VImage8.h @@ -34,7 +34,7 @@ #include #include -#include +#include #include @@ -327,6 +327,12 @@ public: return( vips_image_get_yoffset( get_image() ) ); } + bool + has_alpha() const + { + return( vips_image_hasalpha( get_image() ) ); + } + const char * filename() const { @@ -407,7 +413,7 @@ public: const void * get_blob( const char *field, size_t *length ) const { - void *value; + const void *value; if( vips_image_get_blob( this->get_image(), field, &value, length ) ) @@ -416,6 +422,12 @@ public: return( value ); } + bool + remove( const char *name ) const + { + return( vips_image_remove( get_image(), name ) ); + } + static VOption * option() { @@ -458,7 +470,10 @@ public: return( VImage( image ) ); } - static VImage new_from_buffer( void *buf, size_t len, + static VImage new_from_buffer( const void *buf, size_t len, + const char *option_string, VOption *options = 0 ); + + static VImage new_from_buffer( const std::string &buf, const char *option_string, VOption *options = 0 ); static VImage new_matrix( int width, int height ); @@ -495,6 +510,17 @@ public: return( new_from_image( to_vectorv( 1, pixel ) ) ); } + VImage + copy_memory() const + { + VipsImage *image; + + if( !(image = vips_image_copy_memory( this->get_image() )) ) + throw( VError() ); + + return( VImage( image ) ); + } + VImage write( VImage out ) const; void write_to_file( const char *name, VOption *options = 0 ) const; diff --git a/cplusplus/include/vips/VInterpolate8.h b/cplusplus/include/vips/VInterpolate8.h index 606a696a..8ef6f99e 100644 --- a/cplusplus/include/vips/VInterpolate8.h +++ b/cplusplus/include/vips/VInterpolate8.h @@ -34,7 +34,7 @@ #include #include -#include +#include #include diff --git a/libvips/colour/CMYK2XYZ.c b/libvips/colour/CMYK2XYZ.c index 62eaedc4..33aaeb86 100644 --- a/libvips/colour/CMYK2XYZ.c +++ b/libvips/colour/CMYK2XYZ.c @@ -44,8 +44,8 @@ #include -#include "pcolour.h" #include "profiles.h" +#include "pcolour.h" #ifdef HAVE_LCMS2 @@ -60,61 +60,6 @@ typedef VipsColourCodeClass VipsCMYK2XYZClass; G_DEFINE_TYPE( VipsCMYK2XYZ, vips_CMYK2XYZ, VIPS_TYPE_OPERATION ); -/* Created on first use from a base64 string in profiles.c. - */ -static void *vips_CMYK2XYZ_fallback_profile = NULL; -static size_t vips_CMYK2XYZ_fallback_profile_length = 0; - -static void * -vips_CMYK2XYZ_get_fallback_profile_init( void ) -{ - size_t data_length; - unsigned char *data; - - if( !(data = vips__b64_decode( vips__coded_cmyk, &data_length )) ) - return( NULL ); - vips_CMYK2XYZ_fallback_profile = data; - vips_CMYK2XYZ_fallback_profile_length = data_length; - - return( NULL ); -} - -static void * -vips__CMYK2XYZ_get_fallback_profile( size_t *length ) -{ - GOnce once = G_ONCE_INIT; - - VIPS_ONCE( &once, - (GThreadFunc) vips_CMYK2XYZ_get_fallback_profile_init, NULL ); - - *length = vips_CMYK2XYZ_fallback_profile_length; - - return( vips_CMYK2XYZ_fallback_profile ); -} - -/* Shared with XYZ2CMYK.c. - */ -int -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( 0 ); - - if( !(data = vips__CMYK2XYZ_get_fallback_profile( &data_length )) ) - return( -1 ); - - vips_image_set_blob( image, VIPS_META_ICC_NAME, - NULL, data, data_length ); - - return( 0 ); -} - /* Our actual processing, as a VipsColourTransformFn. */ static int @@ -141,7 +86,7 @@ vips_CMYK2XYZ_build( VipsObject *object ) g_object_set( object, "out", out, NULL ); if( vips_copy( CMYK2XYZ->in, &t[0], NULL ) || - vips_CMYK2XYZ_set_fallback_profile( t[0] ) || + vips__profile_set( t[0], "cmyk" ) || vips__colourspace_process_n( "CMYK2XYZ", t[0], &t[1], 4, vips_CMYK2XYZ_process ) || vips_image_write( t[1], out ) ) diff --git a/libvips/colour/Makefile.am b/libvips/colour/Makefile.am index f2b0c83a..52a4f594 100644 --- a/libvips/colour/Makefile.am +++ b/libvips/colour/Makefile.am @@ -1,13 +1,9 @@ noinst_LTLIBRARIES = libcolour.la -if ENABLE_LCMS -PROFILES = profiles.c profiles.h -else -PROFILES = -endif - libcolour_la_SOURCES = \ - $(PROFILES) \ + profiles.c \ + profiles.h \ + profile_load.c \ colour.c \ pcolour.h \ CMYK2XYZ.c \ @@ -43,7 +39,7 @@ libcolour_la_SOURCES = \ scRGB2sRGB.c profiles.c: - ./wrap_profiles.sh profiles profiles + ./wrap-profiles.sh profiles profiles.c EXTRA_DIST = \ profiles \ diff --git a/libvips/colour/XYZ2CMYK.c b/libvips/colour/XYZ2CMYK.c index 7a9e76e6..919bcb15 100644 --- a/libvips/colour/XYZ2CMYK.c +++ b/libvips/colour/XYZ2CMYK.c @@ -85,7 +85,7 @@ vips_XYZ2CMYK_build( VipsObject *object ) g_object_set( object, "out", out, NULL ); if( vips_copy( XYZ2CMYK->in, &t[0], NULL ) || - vips_CMYK2XYZ_set_fallback_profile( t[0] ) || + vips__profile_set( t[0], "cmyk" ) || vips__colourspace_process_n( "XYZ2CMYK", t[0], &t[1], 3, vips_XYZ2CMYK_process ) || vips_image_write( t[1], out ) ) diff --git a/libvips/colour/colour.c b/libvips/colour/colour.c index 8e2e8810..32528081 100644 --- a/libvips/colour/colour.c +++ b/libvips/colour/colour.c @@ -751,9 +751,10 @@ vips_colour_operation_init( void ) extern GType vips_scRGB2XYZ_get_type( void ); extern GType vips_scRGB2BW_get_type( void ); extern GType vips_XYZ2scRGB_get_type( void ); - extern GType vips_scRGB2sRGB_get_type( void ); + extern GType vips_scRGB2sRGB_get_type( void ); extern GType vips_CMYK2XYZ_get_type( void ); extern GType vips_XYZ2CMYK_get_type( void ); + extern GType vips_profile_load_get_type( void ); #ifdef HAVE_LCMS2 extern GType vips_icc_import_get_type( void ); extern GType vips_icc_export_get_type( void ); @@ -790,6 +791,7 @@ vips_colour_operation_init( void ) vips_scRGB2sRGB_get_type(); vips_CMYK2XYZ_get_type(); vips_XYZ2CMYK_get_type(); + vips_profile_load_get_type(); #ifdef HAVE_LCMS2 vips_icc_import_get_type(); vips_icc_export_get_type(); diff --git a/libvips/colour/icc_transform.c b/libvips/colour/icc_transform.c index 49b40caf..8b219cba 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,63 +593,50 @@ vips_image_expected_sig( VipsImage *image ) return( expected_sig ); } -static cmsHPROFILE -vips_icc_load_profile_image( VipsImage *image ) +/* Get from an image. + */ +static VipsBlob * +vips_icc_get_profile_image( VipsImage *image ) { - void *data; - size_t data_length; - cmsHPROFILE profile; + const 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, &size ) ) + 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( vips_blob_new( NULL, data, size ) ); +} + +/* Load a profile from a blob and check compatibility. + */ +static cmsHPROFILE +vips_icc_load_profile_blob( VipsBlob *blob, VipsImage *image ) +{ + const void *data; + size_t size; + cmsHPROFILE profile; + + 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( "%s", _( "profile incompatible with image" ) ); + return( NULL ); + } + if( image && + vips_image_expected_sig( image ) != + cmsGetColorSpace( 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 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( vips_image_expected_bands( image ) != - vips_icc_profile_needs_bands( profile ) ) { - VIPS_FREEF( cmsCloseProfile, profile ); - g_warning( _( "profile \"%s\" incompatible with image" ), - filename ); - return( NULL ); - } - if( vips_image_expected_sig( image ) != cmsGetColorSpace( profile ) ) { - VIPS_FREEF( cmsCloseProfile, profile ); - g_warning( _( "profile \"%s\" colourspace " - "differs from image" ), filename ); + _( "profile colourspace differs from image" ) ); return( NULL ); } @@ -660,23 +659,26 @@ 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 ); + if( vips_profile_load( import->input_profile_filename, + &icc->in_blob, NULL ) ) + return( -1 ); 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 ); @@ -698,23 +700,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 ) { + const 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 ); @@ -862,38 +860,27 @@ 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 ) { + if( vips_profile_load( export->output_profile_filename, + &icc->out_blob, NULL ) ) + return( -1 ); colour->profile_filename = export->output_profile_filename; } - else { + + if( icc->out_blob && + !(icc->out_profile = + vips_icc_load_profile_blob( icc->out_blob, NULL )) ) { vips_error( class->nickname, "%s", _( "no output profile" ) ); return( -1 ); } - vips_check_intent( class->nickname, - icc->out_profile, icc->intent, LCMS_USED_AS_OUTPUT ); + if( icc->out_profile ) + vips_check_intent( class->nickname, + icc->out_profile, icc->intent, LCMS_USED_AS_OUTPUT ); if( VIPS_OBJECT_CLASS( vips_icc_export_parent_class )->build( object ) ) return( -1 ); @@ -1080,13 +1067,18 @@ 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 ); + if( vips_profile_load( transform->input_profile_filename, + &icc->in_blob, NULL ) ) + return( -1 ); + + 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" ) ); @@ -1094,17 +1086,21 @@ 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 ); - } - + if( vips_profile_load( transform->output_profile_filename, + &icc->out_blob, NULL ) ) + return( -1 ); 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, @@ -1257,7 +1253,7 @@ vips_icc_ac2rc( VipsImage *in, VipsImage **out, const char *profile_filename ) */ gboolean vips_icc_is_compatible_profile( VipsImage *image, - void *data, size_t data_length ) + const void *data, size_t data_length ) { cmsHPROFILE profile; diff --git a/libvips/colour/pcolour.h b/libvips/colour/pcolour.h index da93c9c6..e9a028aa 100644 --- a/libvips/colour/pcolour.h +++ b/libvips/colour/pcolour.h @@ -216,8 +216,6 @@ extern float vips_v2Y_16[65536]; void vips_col_make_tables_RGB_8( void ); 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, ... ); diff --git a/libvips/colour/profile_load.c b/libvips/colour/profile_load.c new file mode 100644 index 00000000..824d8658 --- /dev/null +++ b/libvips/colour/profile_load.c @@ -0,0 +1,254 @@ +/* Load profiles as blobs. + * + * 10/1/19 + * - from CMYK2XYZ.c + */ + +/* + + This file is part of VIPS. + + VIPS is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA + + */ + +/* + + These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk + + */ + +#ifdef HAVE_CONFIG_H +#include +#endif /*HAVE_CONFIG_H*/ +#include + +#include + +#include +#include + +#include + +#include "profiles.h" +#include "pcolour.h" + +typedef struct _VipsProfileLoad { + VipsOperation parent_instance; + + const char *name; + VipsBlob *profile; + +} VipsProfileLoad; + +typedef VipsOperationClass VipsProfileLoadClass; + +G_DEFINE_TYPE( VipsProfileLoad, vips_profile_load, VIPS_TYPE_OPERATION ); + +/* Created on first use from a base64 string in profiles.c. + */ +typedef struct _VipsFallbackProfile { + const char *name; + void *data; + size_t data_length; +} VipsFallbackProfile; + +static GSList *vips_fallback_profile_list = NULL; + +static void * +vips_fallback_profile_get_init( void ) +{ + int i; + + for( i = 0; vips__coded_profiles[i].name; i++ ) { + size_t data_length; + unsigned char *data; + VipsFallbackProfile *fallback; + + if( !(data = vips__b64_decode( + vips__coded_profiles[i].data, &data_length )) ) + return( NULL ); + fallback = g_new( VipsFallbackProfile,1 ); + fallback->name = vips__coded_profiles[i].name; + fallback->data = data; + fallback->data_length = data_length; + vips_fallback_profile_list = g_slist_prepend( + vips_fallback_profile_list, fallback ); + } + + return( NULL ); +} + +static void * +vips_fallback_profile_get( const char *name, size_t *length ) +{ + GOnce once = G_ONCE_INIT; + + GSList *p; + + VIPS_ONCE( &once, (GThreadFunc) vips_fallback_profile_get_init, NULL ); + + for( p = vips_fallback_profile_list; p; p = p->next ) { + VipsFallbackProfile *fallback = (VipsFallbackProfile *) p->data; + + if( strcasecmp( fallback->name, name ) == 0 ) { + *length = fallback->data_length; + + return( fallback->data ); + } + } + + return( NULL ); +} + +static int +vips_profile_load_build( VipsObject *object ) +{ + VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object ); + VipsProfileLoad *load = (VipsProfileLoad *) object; + + size_t length; + const void *data; + VipsBlob *profile; + + if( VIPS_OBJECT_CLASS( vips_profile_load_parent_class )-> + build( object ) ) + return( -1 ); + + if( strcasecmp( load->name, "none" ) == 0 ) { + profile = NULL; + } + else if( (data = vips_fallback_profile_get( load->name, &length )) ) { + profile = vips_blob_new( NULL, data, length ); + } + else if( (data = vips__file_read_name( load->name, + vips__icc_dir(), &length )) ) { + profile = vips_blob_new( NULL, data, length ); + } + else { + vips_error( class->nickname, + _( "unable to load profile \"%s\"" ), load->name ); + return( -1 ); + } + + g_object_set( object, "profile", profile, NULL ); + + if( profile ) { + vips_area_unref( (VipsArea *) profile ); + profile = NULL; + } + + return( 0 ); +} + +static void +vips_profile_load_class_init( VipsProfileLoadClass *class ) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS( class ); + VipsObjectClass *object_class = (VipsObjectClass *) class; + + gobject_class->set_property = vips_object_set_property; + gobject_class->get_property = vips_object_get_property; + + object_class->nickname = "profile_load"; + object_class->description = _( "load named ICC profile" ); + object_class->build = vips_profile_load_build; + + VIPS_ARG_STRING( class, "name", 1, + _( "Name" ), + _( "Profile name" ), + VIPS_ARGUMENT_REQUIRED_INPUT, + G_STRUCT_OFFSET( VipsProfileLoad, name ), + NULL ); + + VIPS_ARG_BOXED( class, "profile", 2, + _( "Profile" ), + _( "Loaded profile" ), + VIPS_ARGUMENT_REQUIRED_OUTPUT, + G_STRUCT_OFFSET( VipsProfileLoad, profile ), + VIPS_TYPE_BLOB ); + +} + +static void +vips_profile_load_init( VipsProfileLoad *load ) +{ +} + +/** + * vips_profile_load: + * @name: name of profile to load + * @profile: (out): loaded profile + * @...: %NULL-terminated list of optional named arguments + * + * Load a named profile. + * + * Profiles are loaded from four sources: + * + * - The special name `"none"` means no profile. @profile will be %NULL in this + * case. + * + * - @name can be the name of one of the ICC profiles embedded in libvips. + * These names can be at least `"cmyk"` and `"srgb"`. + * + * - @name can be the full path to a file. + * + * - @name can be the name of an ICC profile in the system profile directory + * for your platform. + * + * Returns: 0 on success, -1 on error + */ +int +vips_profile_load( const char *name, VipsBlob **profile, ... ) +{ + va_list ap; + int result; + + va_start( ap, profile ); + result = vips_call_split( "profile_load", ap, name, profile ); + va_end( ap ); + + return( result ); +} + +/* Set (or remove) a named profile on an image. + */ +int +vips__profile_set( VipsImage *image, const char *name ) +{ + VipsBlob *profile; + void *data; + size_t length; + + if( vips_profile_load( name, &profile, NULL ) ) + return( -1 ); + + if( profile ) { + data = ((VipsArea *) profile)->data; + length = ((VipsArea *) profile)->length; + vips_image_set_blob( image, VIPS_META_ICC_NAME, + (VipsCallbackFn) NULL, data, length ); + } + else + vips_image_remove( image, VIPS_META_ICC_NAME ); + + if( profile ) { + vips_area_unref( (VipsArea *) profile ); + profile = NULL; + } + + return( 0 ); +} diff --git a/libvips/colour/profiles.c b/libvips/colour/profiles.c index 0550c9e7..82f35cac 100644 --- a/libvips/colour/profiles.c +++ b/libvips/colour/profiles.c @@ -1,6 +1,9 @@ /* coded files, generated automatically */ -char *vips__coded_cmyk = +#include "profiles.h" + +VipsCodedProfile vips__coded_profiles[] = { + { "cmyk", "AA6sbGFyZ2wCIAAAcHJ0ckNNWUtMYWIgB94ACAAZAAwAKAA1YWNzcE1TRlQAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAEAAPbWAAEAAAAA0y1hcmdsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAPZGVzYwAAATgAAABpY3BydAAAAaQAAABnd3RwdAAAAgwAAAAUYmtw" @@ -16872,4 +16875,130 @@ char *vips__coded_cmyk = "LjI5IDMuOTIgMy41NyAzLjIzIDMuMDUgMy40IDQuMjUgNC43NCAzLjc1IDIuNDggMS45NCAxLjcz" "IDEuNDYgMS40IDEuODMgMi41OCAyLjk0IDIuOTUgMi45NCAyLjk1IDIuOTggMy4zMiAzLjk5IDQu" "NDIgNC4yOCAzLjk0IDMuNDcgMy4xMyAzLjM1IDQuMjENCkVORF9EQVRBDQoNCg0KDQoNCgAA" -; + }, + { "sRGB", +"AAAbCmxjbXMCMAAAbW50clJHQiBYWVogB9QACAANAAwAEgAGYWNzcE1TRlQAAAAAbGNtcwAAAAAA" +"AAAAAAAAAAAAAAAAAPbWAAEAAAAA0y1sY21zAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +"AAAAAAAAAAAAAAAAAAAAAAAMZG1uZAAAARQAAABqZGVzYwAAAYAAAABoZG1kZAAAAegAAABod3Rw" +"dAAAAlAAAAAUclhZWgAAAmQAAAAUYlhZWgAAAngAAAAUZ1hZWgAAAowAAAAUclRSQwAAAqAAAAgM" +"Z1RSQwAACqwAAAgMYlRSQwAAErgAAAgMY2hybQAAGsQAAAAkY3BydAAAGugAAAAhZGVzYwAAAAAA" +"AAAQbGNtcyBnZW5lcmF0ZWQgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZGVzYwAAAAAAAAAFc1JH" +"QgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABkZXNjAAAAAAAAAAVzUkdCAAAAAAAAAAAA" +"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAFhZWiAAAAAAAADzPQABAAAAARaYWFlaIAAAAAAAAG+UAAA4" +"7gAAA5BYWVogAAAAAAAAJJ0AAA+DAAC2vlhZWiAAAAAAAABipQAAt5AAABjeY3VydgAAAAAAAAQA" +"AAAABQAKAA8AFAAZAB4AIwAoAC0AMgA3ADsAQABFAEoATwBUAFkAXgBjAGgAbQByAHcAfACBAIYA" +"iwCQAJUAmgCfAKQAqQCuALIAtwC8AMEAxgDLANAA1QDbAOAA5QDrAPAA9gD7AQEBBwENARMBGQEf" +"ASUBKwEyATgBPgFFAUwBUgFZAWABZwFuAXUBfAGDAYsBkgGaAaEBqQGxAbkBwQHJAdEB2QHhAekB" +"8gH6AgMCDAIUAh0CJgIvAjgCQQJLAlQCXQJnAnECegKEAo4CmAKiAqwCtgLBAssC1QLgAusC9QMA" +"AwsDFgMhAy0DOANDA08DWgNmA3IDfgOKA5YDogOuA7oDxwPTA+AD7AP5BAYEEwQgBC0EOwRIBFUE" +"YwRxBH4EjASaBKgEtgTEBNME4QTwBP4FDQUcBSsFOgVJBVgFZwV3BYYFlgWmBbUFxQXVBeUF9gYG" +"BhYGJwY3BkgGWQZqBnsGjAadBq8GwAbRBuMG9QcHBxkHKwc9B08HYQd0B4YHmQesB78H0gflB/gI" +"CwgfCDIIRghaCG4IggiWCKoIvgjSCOcI+wkQCSUJOglPCWQJeQmPCaQJugnPCeUJ+woRCicKPQpU" +"CmoKgQqYCq4KxQrcCvMLCwsiCzkLUQtpC4ALmAuwC8gL4Qv5DBIMKgxDDFwMdQyODKcMwAzZDPMN" +"DQ0mDUANWg10DY4NqQ3DDd4N+A4TDi4OSQ5kDn8Omw62DtIO7g8JDyUPQQ9eD3oPlg+zD88P7BAJ" +"ECYQQxBhEH4QmxC5ENcQ9RETETERTxFtEYwRqhHJEegSBxImEkUSZBKEEqMSwxLjEwMTIxNDE2MT" +"gxOkE8UT5RQGFCcUSRRqFIsUrRTOFPAVEhU0FVYVeBWbFb0V4BYDFiYWSRZsFo8WshbWFvoXHRdB" +"F2UXiReuF9IX9xgbGEAYZRiKGK8Y1Rj6GSAZRRlrGZEZtxndGgQaKhpRGncanhrFGuwbFBs7G2Mb" +"ihuyG9ocAhwqHFIcexyjHMwc9R0eHUcdcB2ZHcMd7B4WHkAeah6UHr4e6R8THz4faR+UH78f6iAV" +"IEEgbCCYIMQg8CEcIUghdSGhIc4h+yInIlUigiKvIt0jCiM4I2YjlCPCI/AkHyRNJHwkqyTaJQkl" +"OCVoJZclxyX3JicmVyaHJrcm6CcYJ0kneierJ9woDSg/KHEooijUKQYpOClrKZ0p0CoCKjUqaCqb" +"Ks8rAis2K2krnSvRLAUsOSxuLKIs1y0MLUEtdi2rLeEuFi5MLoIuty7uLyQvWi+RL8cv/jA1MGww" +"pDDbMRIxSjGCMbox8jIqMmMymzLUMw0zRjN/M7gz8TQrNGU0njTYNRM1TTWHNcI1/TY3NnI2rjbp" +"NyQ3YDecN9c4FDhQOIw4yDkFOUI5fzm8Ofk6Njp0OrI67zstO2s7qjvoPCc8ZTykPOM9Ij1hPaE9" +"4D4gPmA+oD7gPyE/YT+iP+JAI0BkQKZA50EpQWpBrEHuQjBCckK1QvdDOkN9Q8BEA0RHRIpEzkUS" +"RVVFmkXeRiJGZ0arRvBHNUd7R8BIBUhLSJFI10kdSWNJqUnwSjdKfUrESwxLU0uaS+JMKkxyTLpN" +"Ak1KTZNN3E4lTm5Ot08AT0lPk0/dUCdQcVC7UQZRUFGbUeZSMVJ8UsdTE1NfU6pT9lRCVI9U21Uo" +"VXVVwlYPVlxWqVb3V0RXklfgWC9YfVjLWRpZaVm4WgdaVlqmWvVbRVuVW+VcNVyGXNZdJ114Xcle" +"Gl5sXr1fD19hX7NgBWBXYKpg/GFPYaJh9WJJYpxi8GNDY5dj62RAZJRk6WU9ZZJl52Y9ZpJm6Gc9" +"Z5Nn6Wg/aJZo7GlDaZpp8WpIap9q92tPa6dr/2xXbK9tCG1gbbluEm5rbsRvHm94b9FwK3CGcOBx" +"OnGVcfByS3KmcwFzXXO4dBR0cHTMdSh1hXXhdj52m3b4d1Z3s3gReG54zHkqeYl553pGeqV7BHtj" +"e8J8IXyBfOF9QX2hfgF+Yn7CfyN/hH/lgEeAqIEKgWuBzYIwgpKC9INXg7qEHYSAhOOFR4Wrhg6G" +"cobXhzuHn4gEiGmIzokziZmJ/opkisqLMIuWi/yMY4zKjTGNmI3/jmaOzo82j56QBpBukNaRP5Go" +"khGSepLjk02TtpQglIqU9JVflcmWNJaflwqXdZfgmEyYuJkkmZCZ/JpomtWbQpuvnByciZz3nWSd" +"0p5Anq6fHZ+Ln/qgaaDYoUehtqImopajBqN2o+akVqTHpTilqaYapoum/adup+CoUqjEqTepqaoc" +"qo+rAqt1q+msXKzQrUStuK4trqGvFq+LsACwdbDqsWCx1rJLssKzOLOutCW0nLUTtYq2AbZ5tvC3" +"aLfguFm40blKucK6O7q1uy67p7whvJu9Fb2Pvgq+hL7/v3q/9cBwwOzBZ8Hjwl/C28NYw9TEUcTO" +"xUvFyMZGxsPHQce/yD3IvMk6ybnKOMq3yzbLtsw1zLXNNc21zjbOts83z7jQOdC60TzRvtI/0sHT" +"RNPG1EnUy9VO1dHWVdbY11zX4Nhk2OjZbNnx2nba+9uA3AXcit0Q3ZbeHN6i3ynfr+A24L3hROHM" +"4lPi2+Nj4+vkc+T85YTmDeaW5x/nqegy6LzpRunQ6lvq5etw6/vshu0R7ZzuKO6070DvzPBY8OXx" +"cvH/8ozzGfOn9DT0wvVQ9d72bfb794r4Gfio+Tj5x/pX+uf7d/wH/Jj9Kf26/kv+3P9t//9jdXJ2" +"AAAAAAAABAAAAAAFAAoADwAUABkAHgAjACgALQAyADcAOwBAAEUASgBPAFQAWQBeAGMAaABtAHIA" +"dwB8AIEAhgCLAJAAlQCaAJ8ApACpAK4AsgC3ALwAwQDGAMsA0ADVANsA4ADlAOsA8AD2APsBAQEH" +"AQ0BEwEZAR8BJQErATIBOAE+AUUBTAFSAVkBYAFnAW4BdQF8AYMBiwGSAZoBoQGpAbEBuQHBAckB" +"0QHZAeEB6QHyAfoCAwIMAhQCHQImAi8COAJBAksCVAJdAmcCcQJ6AoQCjgKYAqICrAK2AsECywLV" +"AuAC6wL1AwADCwMWAyEDLQM4A0MDTwNaA2YDcgN+A4oDlgOiA64DugPHA9MD4APsA/kEBgQTBCAE" +"LQQ7BEgEVQRjBHEEfgSMBJoEqAS2BMQE0wThBPAE/gUNBRwFKwU6BUkFWAVnBXcFhgWWBaYFtQXF" +"BdUF5QX2BgYGFgYnBjcGSAZZBmoGewaMBp0GrwbABtEG4wb1BwcHGQcrBz0HTwdhB3QHhgeZB6wH" +"vwfSB+UH+AgLCB8IMghGCFoIbgiCCJYIqgi+CNII5wj7CRAJJQk6CU8JZAl5CY8JpAm6Cc8J5Qn7" +"ChEKJwo9ClQKagqBCpgKrgrFCtwK8wsLCyILOQtRC2kLgAuYC7ALyAvhC/kMEgwqDEMMXAx1DI4M" +"pwzADNkM8w0NDSYNQA1aDXQNjg2pDcMN3g34DhMOLg5JDmQOfw6bDrYO0g7uDwkPJQ9BD14Peg+W" +"D7MPzw/sEAkQJhBDEGEQfhCbELkQ1xD1ERMRMRFPEW0RjBGqEckR6BIHEiYSRRJkEoQSoxLDEuMT" +"AxMjE0MTYxODE6QTxRPlFAYUJxRJFGoUixStFM4U8BUSFTQVVhV4FZsVvRXgFgMWJhZJFmwWjxay" +"FtYW+hcdF0EXZReJF64X0hf3GBsYQBhlGIoYrxjVGPoZIBlFGWsZkRm3Gd0aBBoqGlEadxqeGsUa" +"7BsUGzsbYxuKG7Ib2hwCHCocUhx7HKMczBz1HR4dRx1wHZkdwx3sHhYeQB5qHpQevh7pHxMfPh9p" +"H5Qfvx/qIBUgQSBsIJggxCDwIRwhSCF1IaEhziH7IiciVSKCIq8i3SMKIzgjZiOUI8Ij8CQfJE0k" +"fCSrJNolCSU4JWgllyXHJfcmJyZXJocmtyboJxgnSSd6J6sn3CgNKD8ocSiiKNQpBik4KWspnSnQ" +"KgIqNSpoKpsqzysCKzYraSudK9EsBSw5LG4soizXLQwtQS12Last4S4WLkwugi63Lu4vJC9aL5Ev" +"xy/+MDUwbDCkMNsxEjFKMYIxujHyMioyYzKbMtQzDTNGM38zuDPxNCs0ZTSeNNg1EzVNNYc1wjX9" +"Njc2cjauNuk3JDdgN5w31zgUOFA4jDjIOQU5Qjl/Obw5+To2OnQ6sjrvOy07azuqO+g8JzxlPKQ8" +"4z0iPWE9oT3gPiA+YD6gPuA/IT9hP6I/4kAjQGRApkDnQSlBakGsQe5CMEJyQrVC90M6Q31DwEQD" +"REdEikTORRJFVUWaRd5GIkZnRqtG8Ec1R3tHwEgFSEtIkUjXSR1JY0mpSfBKN0p9SsRLDEtTS5pL" +"4kwqTHJMuk0CTUpNk03cTiVObk63TwBPSU+TT91QJ1BxULtRBlFQUZtR5lIxUnxSx1MTU19TqlP2" +"VEJUj1TbVShVdVXCVg9WXFapVvdXRFeSV+BYL1h9WMtZGllpWbhaB1pWWqZa9VtFW5Vb5Vw1XIZc" +"1l0nXXhdyV4aXmxevV8PX2Ffs2AFYFdgqmD8YU9homH1YklinGLwY0Njl2PrZEBklGTpZT1lkmXn" +"Zj1mkmboZz1nk2fpaD9olmjsaUNpmmnxakhqn2r3a09rp2v/bFdsr20IbWBtuW4SbmtuxG8eb3hv" +"0XArcIZw4HE6cZVx8HJLcqZzAXNdc7h0FHRwdMx1KHWFdeF2Pnabdvh3VnezeBF4bnjMeSp5iXnn" +"ekZ6pXsEe2N7wnwhfIF84X1BfaF+AX5ifsJ/I3+Ef+WAR4CogQqBa4HNgjCCkoL0g1eDuoQdhICE" +"44VHhauGDoZyhteHO4efiASIaYjOiTOJmYn+imSKyoswi5aL/IxjjMqNMY2Yjf+OZo7OjzaPnpAG" +"kG6Q1pE/kaiSEZJ6kuOTTZO2lCCUipT0lV+VyZY0lp+XCpd1l+CYTJi4mSSZkJn8mmia1ZtCm6+c" +"HJyJnPedZJ3SnkCerp8dn4uf+qBpoNihR6G2oiailqMGo3aj5qRWpMelOKWpphqmi6b9p26n4KhS" +"qMSpN6mpqhyqj6sCq3Wr6axcrNCtRK24ri2uoa8Wr4uwALB1sOqxYLHWskuywrM4s660JbSctRO1" +"irYBtnm28Ldot+C4WbjRuUq5wro7urW7LrunvCG8m70VvY++Cr6Evv+/er/1wHDA7MFnwePCX8Lb" +"w1jD1MRRxM7FS8XIxkbGw8dBx7/IPci8yTrJuco4yrfLNsu2zDXMtc01zbXONs62zzfPuNA50LrR" +"PNG+0j/SwdNE08bUSdTL1U7V0dZV1tjXXNfg2GTY6Nls2fHadtr724DcBdyK3RDdlt4c3qLfKd+v" +"4DbgveFE4cziU+Lb42Pj6+Rz5PzlhOYN5pbnH+ep6DLovOlG6dDqW+rl63Dr++yG7RHtnO4o7rTv" +"QO/M8Fjw5fFy8f/yjPMZ86f0NPTC9VD13vZt9vv3ivgZ+Kj5OPnH+lf65/t3/Af8mP0p/br+S/7c" +"/23//2N1cnYAAAAAAAAEAAAAAAUACgAPABQAGQAeACMAKAAtADIANwA7AEAARQBKAE8AVABZAF4A" +"YwBoAG0AcgB3AHwAgQCGAIsAkACVAJoAnwCkAKkArgCyALcAvADBAMYAywDQANUA2wDgAOUA6wDw" +"APYA+wEBAQcBDQETARkBHwElASsBMgE4AT4BRQFMAVIBWQFgAWcBbgF1AXwBgwGLAZIBmgGhAakB" +"sQG5AcEByQHRAdkB4QHpAfIB+gIDAgwCFAIdAiYCLwI4AkECSwJUAl0CZwJxAnoChAKOApgCogKs" +"ArYCwQLLAtUC4ALrAvUDAAMLAxYDIQMtAzgDQwNPA1oDZgNyA34DigOWA6IDrgO6A8cD0wPgA+wD" +"+QQGBBMEIAQtBDsESARVBGMEcQR+BIwEmgSoBLYExATTBOEE8AT+BQ0FHAUrBToFSQVYBWcFdwWG" +"BZYFpgW1BcUF1QXlBfYGBgYWBicGNwZIBlkGagZ7BowGnQavBsAG0QbjBvUHBwcZBysHPQdPB2EH" +"dAeGB5kHrAe/B9IH5Qf4CAsIHwgyCEYIWghuCIIIlgiqCL4I0gjnCPsJEAklCToJTwlkCXkJjwmk" +"CboJzwnlCfsKEQonCj0KVApqCoEKmAquCsUK3ArzCwsLIgs5C1ELaQuAC5gLsAvIC+EL+QwSDCoM" +"QwxcDHUMjgynDMAM2QzzDQ0NJg1ADVoNdA2ODakNww3eDfgOEw4uDkkOZA5/DpsOtg7SDu4PCQ8l" +"D0EPXg96D5YPsw/PD+wQCRAmEEMQYRB+EJsQuRDXEPURExExEU8RbRGMEaoRyRHoEgcSJhJFEmQS" +"hBKjEsMS4xMDEyMTQxNjE4MTpBPFE+UUBhQnFEkUahSLFK0UzhTwFRIVNBVWFXgVmxW9FeAWAxYm" +"FkkWbBaPFrIW1hb6Fx0XQRdlF4kXrhfSF/cYGxhAGGUYihivGNUY+hkgGUUZaxmRGbcZ3RoEGioa" +"URp3Gp4axRrsGxQbOxtjG4obshvaHAIcKhxSHHscoxzMHPUdHh1HHXAdmR3DHeweFh5AHmoelB6+" +"HukfEx8+H2kflB+/H+ogFSBBIGwgmCDEIPAhHCFIIXUhoSHOIfsiJyJVIoIiryLdIwojOCNmI5Qj" +"wiPwJB8kTSR8JKsk2iUJJTglaCWXJccl9yYnJlcmhya3JugnGCdJJ3onqyfcKA0oPyhxKKIo1CkG" +"KTgpaymdKdAqAio1KmgqmyrPKwIrNitpK50r0SwFLDksbiyiLNctDC1BLXYtqy3hLhYuTC6CLrcu" +"7i8kL1ovkS/HL/4wNTBsMKQw2zESMUoxgjG6MfIyKjJjMpsy1DMNM0YzfzO4M/E0KzRlNJ402DUT" +"NU01hzXCNf02NzZyNq426TckN2A3nDfXOBQ4UDiMOMg5BTlCOX85vDn5OjY6dDqyOu87LTtrO6o7" +"6DwnPGU8pDzjPSI9YT2hPeA+ID5gPqA+4D8hP2E/oj/iQCNAZECmQOdBKUFqQaxB7kIwQnJCtUL3" +"QzpDfUPARANER0SKRM5FEkVVRZpF3kYiRmdGq0bwRzVHe0fASAVIS0iRSNdJHUljSalJ8Eo3Sn1K" +"xEsMS1NLmkviTCpMcky6TQJNSk2TTdxOJU5uTrdPAE9JT5NP3VAnUHFQu1EGUVBRm1HmUjFSfFLH" +"UxNTX1OqU/ZUQlSPVNtVKFV1VcJWD1ZcVqlW91dEV5JX4FgvWH1Yy1kaWWlZuFoHWlZaplr1W0Vb" +"lVvlXDVchlzWXSddeF3JXhpebF69Xw9fYV+zYAVgV2CqYPxhT2GiYfViSWKcYvBjQ2OXY+tkQGSU" +"ZOllPWWSZedmPWaSZuhnPWeTZ+loP2iWaOxpQ2maafFqSGqfavdrT2una/9sV2yvbQhtYG25bhJu" +"a27Ebx5veG/RcCtwhnDgcTpxlXHwcktypnMBc11zuHQUdHB0zHUodYV14XY+dpt2+HdWd7N4EXhu" +"eMx5KnmJeed6RnqlewR7Y3vCfCF8gXzhfUF9oX4BfmJ+wn8jf4R/5YBHgKiBCoFrgc2CMIKSgvSD" +"V4O6hB2EgITjhUeFq4YOhnKG14c7h5+IBIhpiM6JM4mZif6KZIrKizCLlov8jGOMyo0xjZiN/45m" +"js6PNo+ekAaQbpDWkT+RqJIRknqS45NNk7aUIJSKlPSVX5XJljSWn5cKl3WX4JhMmLiZJJmQmfya" +"aJrVm0Kbr5wcnImc951kndKeQJ6unx2fi5/6oGmg2KFHobaiJqKWowajdqPmpFakx6U4pammGqaL" +"pv2nbqfgqFKoxKk3qamqHKqPqwKrdavprFys0K1ErbiuLa6hrxavi7AAsHWw6rFgsdayS7LCsziz" +"rrQltJy1E7WKtgG2ebbwt2i34LhZuNG5SrnCuju6tbsuu6e8IbybvRW9j74KvoS+/796v/XAcMDs" +"wWfB48JfwtvDWMPUxFHEzsVLxcjGRsbDx0HHv8g9yLzJOsm5yjjKt8s2y7bMNcy1zTXNtc42zrbP" +"N8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp22vvbgNwF3IrdEN2W" +"3hzeot8p36/gNuC94UThzOJT4tvjY+Pr5HPk/OWE5g3mlucf56noMui86Ubp0Opb6uXrcOv77Ibt" +"Ee2c7ijutO9A78zwWPDl8XLx//KM8xnzp/Q09ML1UPXe9m32+/eK+Bn4qPk4+cf6V/rn+3f8B/yY" +"/Sn9uv5L/tz/bf//Y2hybQAAAAAAAwAAAACj1wAAVHsAAEzNAACZmgAAJmYAAA9cdGV4dAAAAABu" +"byBjb3B5cmlnaHQsIHVzZSBmcmVlbHkACg==" + }, + { 0, 0 } +}; diff --git a/libvips/colour/profiles.h b/libvips/colour/profiles.h index 25db4062..e958e6b4 100644 --- a/libvips/colour/profiles.h +++ b/libvips/colour/profiles.h @@ -1,3 +1,10 @@ -/* header for coded files, generated automatically */ +/* The fallback profiles, coded as a set of base64 strings, see + * wrap-profiles.sh + */ +typedef struct _VipsCodedProfile { + const char *name; + const char *data; +} VipsCodedProfile; + +extern VipsCodedProfile vips__coded_profiles[]; -extern char *vips__coded_cmyk ; diff --git a/libvips/colour/profiles/sRGB.icm b/libvips/colour/profiles/sRGB.icm new file mode 100644 index 00000000..1d8f7419 Binary files /dev/null and b/libvips/colour/profiles/sRGB.icm differ diff --git a/libvips/colour/wrap-profiles.sh b/libvips/colour/wrap-profiles.sh index fcfd422f..cfd801b9 100755 --- a/libvips/colour/wrap-profiles.sh +++ b/libvips/colour/wrap-profiles.sh @@ -1,27 +1,22 @@ #!/bin/bash -# code up the binary files in $1 as a set of base64-encoded strings in $2 +# code up the binary files in $1 as a set of name / base64-encoded strings +# in $2 in=$1 -out_c=$2.c -out_h=$2.h +out=$2 -echo "/* coded files, generated automatically */" > $out_c -echo "" >> $out_c +echo "/* coded files, generated automatically */" > $out +echo "" >> $out +echo "#include \"profiles.h\"" >> $out +echo "" >> $out +echo "VipsCodedProfile vips__coded_profiles[] = {" >> $out for file in $in/*; do root=${file%.icm} base=${root##*/} - echo char \*vips__coded_$base = >> $out_c - base64 $file | sed 's/\(.*\)/"\1"/g' >> $out_c - echo ';' >> $out_c + echo " { \"$base\"," >> $out + base64 $file | sed 's/\(.*\)/"\1"/g' >> $out + echo " }," >> $out done - -echo "/* header for coded files, generated automatically */" > $out_h -echo "" >> $out_h -for file in $in/*; do - root=${file%.icm} - base=${root##*/} - echo extern char \*vips__coded_$base ';' >> $out_h -done - - +echo " { 0, 0 }" >> $out +echo "};" >> $out diff --git a/libvips/conversion/cast.c b/libvips/conversion/cast.c index abdc8327..26fa7be4 100644 --- a/libvips/conversion/cast.c +++ b/libvips/conversion/cast.c @@ -194,11 +194,8 @@ G_DEFINE_TYPE( VipsCast, vips_cast, VIPS_TYPE_CONVERSION ); ITYPE * restrict p = (ITYPE *) in; \ OTYPE * restrict q = (OTYPE *) out; \ \ - for( x = 0; x < sz; x++ ) { \ - TEMP v = VIPS_FLOOR( p[x] ); \ - \ - q[x] = CAST( v ); \ - } \ + for( x = 0; x < sz; x++ ) \ + q[x] = CAST( p[x] ); \ } /* Cast complex types to an int type. Just take the real part. @@ -208,10 +205,8 @@ G_DEFINE_TYPE( VipsCast, vips_cast, VIPS_TYPE_CONVERSION ); OTYPE * restrict q = (OTYPE *) out; \ \ for( x = 0; x < sz; x++ ) { \ - TEMP v = VIPS_FLOOR( p[0] ); \ - \ + q[x] = CAST( p[0] ); \ p += 2; \ - q[x] = CAST( v ); \ } \ } diff --git a/libvips/foreign/exif.c b/libvips/foreign/exif.c index 8987b9ef..759e0fdc 100644 --- a/libvips/foreign/exif.c +++ b/libvips/foreign/exif.c @@ -158,7 +158,7 @@ show_values( ExifData *data ) * their default value and we won't know about it. */ static ExifData * -vips_exif_load_data_without_fix( void *data, int length ) +vips_exif_load_data_without_fix( const void *data, int length ) { ExifData *ed; @@ -458,17 +458,17 @@ vips_exif_resolution_from_image( ExifData *ed, VipsImage *image ); int vips__exif_parse( VipsImage *image ) { - void *data; - size_t length; + const void *data; + size_t size; ExifData *ed; VipsExifParams params; const char *str; if( !vips_image_get_typeof( image, VIPS_META_EXIF_NAME ) ) return( 0 ); - if( vips_image_get_blob( image, VIPS_META_EXIF_NAME, &data, &length ) ) + if( vips_image_get_blob( image, VIPS_META_EXIF_NAME, &data, &size ) ) return( -1 ); - if( !(ed = vips_exif_load_data_without_fix( data, length )) ) + if( !(ed = vips_exif_load_data_without_fix( data, size )) ) return( -1 ); #ifdef DEBUG_VERBOSE @@ -1055,21 +1055,21 @@ vips_exif_set_thumbnail( ExifData *ed, VipsImage *im ) /* Update EXIF thumbnail from metadata, if any. */ if( vips_image_get_typeof( im, "jpeg-thumbnail-data" ) ) { - void *data; - size_t length; + const void *data; + size_t size; if( vips_image_get_blob( im, "jpeg-thumbnail-data", - &data, &length ) ) + &data, &size ) ) return( -1 ); /* Again, we should use the exif allocator attached to this * entry, but it is not exposed! */ - if( length > 0 && + if( size > 0 && data ) { - ed->data = malloc( length ); - memcpy( ed->data, data, length ); - ed->size = length; + ed->data = malloc( size ); + memcpy( ed->data, data, size ); + ed->size = size; } } diff --git a/libvips/foreign/foreign.c b/libvips/foreign/foreign.c index 31221ee6..f6c81e3b 100644 --- a/libvips/foreign/foreign.c +++ b/libvips/foreign/foreign.c @@ -1259,15 +1259,6 @@ vips__foreign_convert_saveable( VipsImage *in, VipsImage **ready, g_object_unref( in ); in = out; - - /* We've imported to PCS, we must remove the embedded profile, - * since it no longer matches the image. - * - * For example, when converting CMYK JPG to RGB PNG, we need - * to remove the CMYK profile on import, or the png writer will - * try to attach it when we write the image as RGB. - */ - vips_image_remove( in, VIPS_META_ICC_NAME ); } /* If this is something other than CMYK or RAD, eg. maybe a LAB image, @@ -1518,7 +1509,7 @@ vips__foreign_convert_saveable( VipsImage *in, VipsImage **ready, * want to silently drop the profile in this case. */ if( vips_image_get_typeof( in, VIPS_META_ICC_NAME ) ) { - void *data; + const void *data; size_t length; if( !vips_image_get_blob( in, VIPS_META_ICC_NAME, diff --git a/libvips/foreign/jpegsave.c b/libvips/foreign/jpegsave.c index d93cf5b2..91db15f9 100644 --- a/libvips/foreign/jpegsave.c +++ b/libvips/foreign/jpegsave.c @@ -75,7 +75,7 @@ typedef struct _VipsForeignSaveJpeg { */ int Q; - /* Profile to embed .. "none" means don't attach a profile. + /* Profile to embed. */ char *profile; @@ -434,10 +434,9 @@ vips_foreign_save_jpeg_mime_init( VipsForeignSaveJpegMime *mime ) * * Use @Q to set the JPEG compression factor. Default 75. * - * Use @profile to give the filename of a profile to be embedded in the JPEG. + * Use @profile to give the name of a profile to be embedded in the JPEG. * This does not affect the pixels which are written, just the way - * they are tagged. You can use the special string "none" to mean - * "don't attach a profile". + * they are tagged. See vips_profile_load() for details on profile naming. * * If no profile is specified and the VIPS header * contains an ICC profile named #VIPS_META_ICC_NAME, the diff --git a/libvips/foreign/pngsave.c b/libvips/foreign/pngsave.c index 0033c81e..b64576a7 100644 --- a/libvips/foreign/pngsave.c +++ b/libvips/foreign/pngsave.c @@ -332,8 +332,7 @@ vips_foreign_save_png_buffer_init( VipsForeignSavePngBuffer *buffer ) * * Use @profile to give the filename of a profile to be embedded in the PNG. * This does not affect the pixels which are written, just the way - * they are tagged. You can use the special string "none" to mean - * "don't attach a profile". + * they are tagged. See vips_profile_load() for details on profile naming. * * If @profile is specified and the VIPS header * contains an ICC profile named VIPS_META_ICC_NAME ("icc-profile-data"), the diff --git a/libvips/foreign/tiffsave.c b/libvips/foreign/tiffsave.c index 42c6a089..576ac179 100644 --- a/libvips/foreign/tiffsave.c +++ b/libvips/foreign/tiffsave.c @@ -509,8 +509,7 @@ vips_foreign_save_tiff_buffer_init( VipsForeignSaveTiffBuffer *buffer ) * * Use @profile to give the filename of a profile to be embedded in the TIFF. * This does not affect the pixels which are written, just the way - * they are tagged. You can use the special string "none" to mean - * "don't attach a profile". + * they are tagged. See vips_profile_load() for details on profile naming. * * If no profile is specified and the VIPS header * contains an ICC profile named #VIPS_META_ICC_NAME, the diff --git a/libvips/foreign/vips2jpeg.c b/libvips/foreign/vips2jpeg.c index d68af286..5b8ee613 100644 --- a/libvips/foreign/vips2jpeg.c +++ b/libvips/foreign/vips2jpeg.c @@ -196,8 +196,6 @@ typedef struct { struct jpeg_compress_struct cinfo; ErrorManager eman; JSAMPROW *row_pointer; - char *profile_bytes; - size_t profile_length; VipsImage *inverted; } Write; @@ -207,7 +205,6 @@ write_destroy( Write *write ) jpeg_destroy_compress( &write->cinfo ); VIPS_FREEF( fclose, write->eman.fp ); VIPS_FREE( write->row_pointer ); - VIPS_FREE( write->profile_bytes ); VIPS_UNREF( write->inverted ); g_free( write ); @@ -227,8 +224,6 @@ write_new( VipsImage *in ) write->eman.pub.error_exit = vips__new_error_exit; write->eman.pub.output_message = vips__new_output_message; write->eman.fp = NULL; - write->profile_bytes = NULL; - write->profile_length = 0; write->inverted = NULL; return( write ); @@ -358,35 +353,42 @@ write_profile_data (j_compress_ptr cinfo, static int write_profile_file( Write *write, const char *profile ) { - if( !(write->profile_bytes = - vips__file_read_name( profile, vips__icc_dir(), - &write->profile_length )) ) + VipsBlob *blob; + + if( vips_profile_load( profile, &blob, NULL ) ) return( -1 ); - write_profile_data( &write->cinfo, - (JOCTET *) write->profile_bytes, write->profile_length ); + + if( blob ) { + size_t length; + const void *data = vips_blob_get( blob, &length ); + + write_profile_data( &write->cinfo, (JOCTET *) data, length ); #ifdef DEBUG - printf( "write_profile_file: attached profile \"%s\"\n", profile ); + printf( "write_profile_file: " + "attached profile \"%s\"\n", profile ); #endif /*DEBUG*/ + vips_area_unref( (VipsArea *) blob ); + } + return( 0 ); } static int write_profile_meta( Write *write ) { - void *data; - size_t data_length; + const void *data; + size_t length; - if( vips_image_get_blob( write->in, VIPS_META_ICC_NAME, - &data, &data_length ) ) + if( vips_image_get_blob( write->in, + VIPS_META_ICC_NAME, &data, &length ) ) return( -1 ); - - write_profile_data( &write->cinfo, data, data_length ); + write_profile_data( &write->cinfo, data, length ); #ifdef DEBUG printf( "write_profile_meta: attached %zd byte profile from header\n", - data_length ); + length ); #endif /*DEBUG*/ return( 0 ); @@ -598,10 +600,9 @@ write_vips( Write *write, int qfac, const char *profile, return( -1 ); /* A profile supplied as an argument overrides an embedded - * profile. "none" means don't attach a profile. + * profile. */ - if( profile && - strcmp( profile, "none" ) != 0 && + if( profile && write_profile_file( write, profile ) ) return( -1 ); if( !profile && diff --git a/libvips/foreign/vips2tiff.c b/libvips/foreign/vips2tiff.c index 9a60aa8e..f952aca9 100644 --- a/libvips/foreign/vips2tiff.c +++ b/libvips/foreign/vips2tiff.c @@ -325,24 +325,29 @@ struct _Wtiff { int image_height; }; -/* Embed an ICC profile from a file. +/* Write an ICC Profile from a file into the JPEG stream. */ static int embed_profile_file( TIFF *tif, const char *profile ) { - char *buffer; - size_t length; + VipsBlob *blob; - if( !(buffer = vips__file_read_name( profile, - vips__icc_dir(), &length )) ) + if( vips_profile_load( profile, &blob, NULL ) ) return( -1 ); - TIFFSetField( tif, TIFFTAG_ICCPROFILE, length, buffer ); - vips_free( buffer ); + + if( blob ) { + size_t length; + const void *data = vips_blob_get( blob, &length ); + + TIFFSetField( tif, TIFFTAG_ICCPROFILE, length, data ); #ifdef DEBUG - printf( "vips2tiff: attached profile \"%s\"\n", profile ); + printf( "vips2tiff: attached profile \"%s\"\n", profile ); #endif /*DEBUG*/ + vips_area_unref( (VipsArea *) blob ); + } + return( 0 ); } @@ -351,12 +356,12 @@ embed_profile_file( TIFF *tif, const char *profile ) static int embed_profile_meta( TIFF *tif, VipsImage *im ) { - void *data; - size_t data_length; + const void *data; + size_t length; - if( vips_image_get_blob( im, VIPS_META_ICC_NAME, &data, &data_length ) ) + if( vips_image_get_blob( im, VIPS_META_ICC_NAME, &data, &length ) ) return( -1 ); - TIFFSetField( tif, TIFFTAG_ICCPROFILE, data_length, data ); + TIFFSetField( tif, TIFFTAG_ICCPROFILE, length, data ); #ifdef DEBUG printf( "vips2tiff: attached profile from meta\n" ); @@ -426,8 +431,7 @@ wtiff_layer_new( Wtiff *wtiff, Layer *above, int width, int height ) static int wtiff_embed_profile( Wtiff *wtiff, TIFF *tif ) { - if( wtiff->icc_profile && - strcmp( wtiff->icc_profile, "none" ) != 0 && + if( wtiff->icc_profile && embed_profile_file( tif, wtiff->icc_profile ) ) return( -1 ); @@ -442,15 +446,14 @@ wtiff_embed_profile( Wtiff *wtiff, TIFF *tif ) static int wtiff_embed_xmp( Wtiff *wtiff, TIFF *tif ) { - void *data; - size_t data_length; + const void *data; + size_t size; if( !vips_image_get_typeof( wtiff->im, VIPS_META_XMP_NAME ) ) return( 0 ); - if( vips_image_get_blob( wtiff->im, VIPS_META_XMP_NAME, - &data, &data_length ) ) + if( vips_image_get_blob( wtiff->im, VIPS_META_XMP_NAME, &data, &size ) ) return( -1 ); - TIFFSetField( tif, TIFFTAG_XMLPACKET, data_length, data ); + TIFFSetField( tif, TIFFTAG_XMLPACKET, size, data ); #ifdef DEBUG printf( "vips2tiff: attached XMP from meta\n" ); @@ -462,27 +465,27 @@ wtiff_embed_xmp( Wtiff *wtiff, TIFF *tif ) static int wtiff_embed_iptc( Wtiff *wtiff, TIFF *tif ) { - void *data; - size_t data_length; + const void *data; + size_t size; if( !vips_image_get_typeof( wtiff->im, VIPS_META_IPTC_NAME ) ) return( 0 ); if( vips_image_get_blob( wtiff->im, VIPS_META_IPTC_NAME, - &data, &data_length ) ) + &data, &size ) ) return( -1 ); /* For no very good reason, libtiff stores IPTC as an array of * long, not byte. */ - if( data_length & 3 ) { + if( size & 3 ) { g_warning( "%s", _( "rounding up IPTC data length" ) ); - data_length /= 4; - data_length += 1; + size /= 4; + size += 1; } else - data_length /= 4; + size /= 4; - TIFFSetField( tif, TIFFTAG_RICHTIFFIPTC, data_length, data ); + TIFFSetField( tif, TIFFTAG_RICHTIFFIPTC, size, data ); #ifdef DEBUG printf( "vips2tiff: attached IPTC from meta\n" ); @@ -494,15 +497,15 @@ wtiff_embed_iptc( Wtiff *wtiff, TIFF *tif ) static int wtiff_embed_photoshop( Wtiff *wtiff, TIFF *tif ) { - void *data; - size_t data_length; + const void *data; + size_t size; if( !vips_image_get_typeof( wtiff->im, VIPS_META_PHOTOSHOP_NAME ) ) return( 0 ); if( vips_image_get_blob( wtiff->im, - VIPS_META_PHOTOSHOP_NAME, &data, &data_length ) ) + VIPS_META_PHOTOSHOP_NAME, &data, &size ) ) return( -1 ); - TIFFSetField( tif, TIFFTAG_PHOTOSHOP, data_length, data ); + TIFFSetField( tif, TIFFTAG_PHOTOSHOP, size, data ); #ifdef DEBUG printf( "vips2tiff: attached photoshop data from meta\n" ); diff --git a/libvips/foreign/vips2webp.c b/libvips/foreign/vips2webp.c index 2754f472..92ae96cf 100644 --- a/libvips/foreign/vips2webp.c +++ b/libvips/foreign/vips2webp.c @@ -410,7 +410,7 @@ vips_webp_set_count( VipsWebPWrite *write, int loop_count ) static int vips_webp_set_chunk( VipsWebPWrite *write, - const char *webp_name, void *data, size_t length ) + const char *webp_name, const void *data, size_t length ) { WebPData chunk; @@ -440,7 +440,7 @@ vips_webp_add_chunks( VipsWebPWrite *write, VipsImage *image ) const char *webp_name = vips__webp_names[i].webp; if( vips_image_get_typeof( image, vips_name ) ) { - void *data; + const void *data; size_t length; if( vips_image_get_blob( image, diff --git a/libvips/foreign/vipspng.c b/libvips/foreign/vipspng.c index 5d980425..a890b0be 100644 --- a/libvips/foreign/vipspng.c +++ b/libvips/foreign/vipspng.c @@ -1067,71 +1067,72 @@ write_vips( Write *write, VIPS_RINT( in->Xres * 1000 ), VIPS_RINT( in->Yres * 1000 ), PNG_RESOLUTION_METER ); - /* Set ICC Profile. + /* Metadata */ - if( profile && - !strip ) { - if( strcmp( profile, "none" ) != 0 ) { - void *data; + if( !strip ) { + if( profile ) { + VipsBlob *blob; + + if( vips_profile_load( profile, &blob, NULL ) ) + return( -1 ); + if( blob ) { + size_t length; + const void *data = vips_blob_get( blob, &length ); + +#ifdef DEBUG + printf( "write_vips: attaching %zd bytes " + "of ICC profile\n", length ); +#endif /*DEBUG*/ + + png_set_iCCP( write->pPng, write->pInfo, + "icc", PNG_COMPRESSION_TYPE_BASE, + data, length ); + + vips_area_unref( (VipsArea *) blob ); + } + } + else if( vips_image_get_typeof( in, VIPS_META_ICC_NAME ) ) { + const void *data; size_t length; - if( !(data = vips__file_read_name( profile, - vips__icc_dir(), &length )) ) + if( vips_image_get_blob( in, VIPS_META_ICC_NAME, + &data, &length ) ) return( -1 ); #ifdef DEBUG - printf( "write_vips: " - "attaching %zd bytes of ICC profile\n", - length ); + printf( "write_vips: attaching %zd bytes " + "of ICC profile\n", length ); #endif /*DEBUG*/ - png_set_iCCP( write->pPng, write->pInfo, "icc", + png_set_iCCP( write->pPng, write->pInfo, "icc", PNG_COMPRESSION_TYPE_BASE, data, length ); + } - } - else if( vips_image_get_typeof( in, VIPS_META_ICC_NAME ) && - !strip ) { - void *data; - size_t length; - if( vips_image_get_blob( in, VIPS_META_ICC_NAME, - &data, &length ) ) - return( -1 ); + if( vips_image_get_typeof( in, VIPS_META_XMP_NAME ) ) { + const void *data; + size_t length; + char *str; -#ifdef DEBUG - printf( "write_vips: attaching %zd bytes of ICC profile\n", - length ); -#endif /*DEBUG*/ + /* XMP is attached as a BLOB with no null-termination. + * We must re-add this. + */ + if( vips_image_get_blob( in, + VIPS_META_XMP_NAME, &data, &length ) ) + return( -1 ); - png_set_iCCP( write->pPng, write->pInfo, "icc", - PNG_COMPRESSION_TYPE_BASE, data, length ); - } + str = g_malloc( length + 1 ); + vips_strncpy( str, data, length + 1 ); + vips__png_set_text( write->pPng, write->pInfo, + "XML:com.adobe.xmp", str ); + g_free( str ); + } - if( vips_image_get_typeof( in, VIPS_META_XMP_NAME ) ) { - void *data; - size_t length; - char *str; - - /* XMP is attached as a BLOB with no null-termination. We - * must re-add this. - */ - if( vips_image_get_blob( in, - VIPS_META_XMP_NAME, &data, &length ) ) + if( vips_image_map( in, + write_png_comment, write ) ) return( -1 ); - - str = g_malloc( length + 1 ); - vips_strncpy( str, data, length + 1 ); - vips__png_set_text( write->pPng, write->pInfo, - "XML:com.adobe.xmp", str ); - g_free( str ); } - /* Set any "png-comment-xx-yyy" metadata items. - */ - if( vips_image_map( in, - write_png_comment, write ) ) - return( -1 ); - #ifdef HAVE_IMAGEQUANT if( palette ) { VipsImage *im_index; diff --git a/libvips/include/vips/colour.h b/libvips/include/vips/colour.h index e12c3a34..894f08d5 100644 --- a/libvips/include/vips/colour.h +++ b/libvips/include/vips/colour.h @@ -172,6 +172,8 @@ int vips_CMYK2XYZ( VipsImage *in, VipsImage **out, ... ) int vips_XYZ2CMYK( VipsImage *in, VipsImage **out, ... ) __attribute__((sentinel)); +int vips_profile_load( const char *name, VipsBlob **profile, ... ) + __attribute__((sentinel)); int vips_icc_present( void ); int vips_icc_transform( VipsImage *in, VipsImage **out, const char *output_profile, ... ) @@ -183,7 +185,7 @@ int vips_icc_export( VipsImage *in, VipsImage **out, ... ) int vips_icc_ac2rc( VipsImage *in, VipsImage **out, const char *profile_filename ); gboolean vips_icc_is_compatible_profile( VipsImage *image, - void *data, size_t data_length ); + const void *data, size_t data_length ); int vips_dE76( VipsImage *left, VipsImage *right, VipsImage **out, ... ) __attribute__((sentinel)); diff --git a/libvips/include/vips/header.h b/libvips/include/vips/header.h index 1b0e1305..6f4d2a89 100644 --- a/libvips/include/vips/header.h +++ b/libvips/include/vips/header.h @@ -194,11 +194,12 @@ void vips_image_set_area( VipsImage *image, int vips_image_get_area( const VipsImage *image, const char *name, void **data ); void vips_image_set_blob( VipsImage *image, - const char *name, VipsCallbackFn free_fn, void *data, size_t length ); + const char *name, + VipsCallbackFn free_fn, const void *data, size_t length ); void vips_image_set_blob_copy( VipsImage *image, const char *name, const void *data, size_t length ); -int vips_image_get_blob( const VipsImage *image, const char *name, - void **data, size_t *length ); +int vips_image_get_blob( const VipsImage *image, + const char *name, const void **data, size_t *length ); int vips_image_get_int( const VipsImage *image, const char *name, int *out ); void vips_image_set_int( VipsImage *image, const char *name, int i ); diff --git a/libvips/include/vips/internal.h b/libvips/include/vips/internal.h index 9365efbd..62ec1319 100644 --- a/libvips/include/vips/internal.h +++ b/libvips/include/vips/internal.h @@ -269,6 +269,8 @@ void vips__reorder_clear( VipsImage *image ); VipsWindow *vips_window_take( VipsWindow *window, VipsImage *im, int top, int height ); +int vips__profile_set( VipsImage *image, const char *name ); + #ifdef __cplusplus } #endif /*__cplusplus*/ diff --git a/libvips/include/vips/type.h b/libvips/include/vips/type.h index 2ca154d8..9e578ab3 100644 --- a/libvips/include/vips/type.h +++ b/libvips/include/vips/type.h @@ -158,9 +158,9 @@ typedef struct _VipsBlob { } VipsBlob; VipsBlob *vips_blob_new( VipsCallbackFn free_fn, - const void *data, size_t size ); -VipsBlob *vips_blob_copy( const void *data, size_t size ); -const void *vips_blob_get( VipsBlob *blob, size_t *size ); + const void *data, size_t length ); +VipsBlob *vips_blob_copy( const void *data, size_t length ); +const void *vips_blob_get( VipsBlob *blob, size_t *length ); GType vips_blob_get_type(void); /** @@ -224,7 +224,7 @@ void vips_value_set_ref_string( GValue *value, const char *str ); void *vips_value_get_blob( const GValue *value, size_t *length ); void vips_value_set_blob( GValue *value, - VipsCallbackFn free_fn, void *data, size_t length ); + VipsCallbackFn free_fn, const void *data, size_t length ); void vips_value_set_blob_free( GValue *value, void *data, size_t length ); void vips_value_set_array( GValue *value, diff --git a/libvips/iofuncs/header.c b/libvips/iofuncs/header.c index 29a6b04d..b2ae7d0c 100644 --- a/libvips/iofuncs/header.c +++ b/libvips/iofuncs/header.c @@ -1365,13 +1365,13 @@ vips_image_get_area( const VipsImage *image, const char *name, void **data ) * See also: vips_image_get_blob(), vips_image_set(). */ void -vips_image_set_blob( VipsImage *image, - const char *name, VipsCallbackFn free_fn, void *data, size_t length ) +vips_image_set_blob( VipsImage *image, const char *name, + VipsCallbackFn free_fn, const void *data, size_t size ) { GValue value = { 0 }; g_value_init( &value, VIPS_TYPE_BLOB ); - vips_value_set_blob( &value, free_fn, data, length ); + vips_value_set_blob( &value, free_fn, data, size ); vips_image_set( image, name, &value ); g_value_unset( &value ); } @@ -1431,7 +1431,7 @@ vips_image_set_blob_copy( VipsImage *image, */ int vips_image_get_blob( const VipsImage *image, const char *name, - void **data, size_t *length ) + const void **data, size_t *length ) { GValue value_copy = { 0 }; diff --git a/libvips/iofuncs/type.c b/libvips/iofuncs/type.c index 6d106a99..d59f4b56 100644 --- a/libvips/iofuncs/type.c +++ b/libvips/iofuncs/type.c @@ -376,6 +376,9 @@ void * vips_area_get_data( VipsArea *area, size_t *length, int *n, GType *type, size_t *sizeof_type ) { + if( !area ) + return( NULL ); + if( length ) *length = area->length; if( n ) @@ -599,8 +602,8 @@ vips_ref_string_get_type( void ) /** * vips_blob_new: * @free_fn: (scope async) (allow-none): @data will be freed with this function - * @data: (array length=size) (element-type guint8) (transfer full): data to store - * @size: number of bytes in @data + * @data: (array length=length) (element-type guint8) (transfer full): data to store + * @length: number of bytes in @data * * Like vips_area_new(), but track a length as well. The returned #VipsBlob * takes ownership of @data and will free it with @free_fn. Pass NULL for @@ -614,20 +617,20 @@ vips_ref_string_get_type( void ) * Returns: (transfer full): the new #VipsBlob. */ VipsBlob * -vips_blob_new( VipsCallbackFn free_fn, const void *data, size_t size ) +vips_blob_new( VipsCallbackFn free_fn, const void *data, size_t length ) { VipsArea *area; area = vips_area_new( free_fn, (void *) data ); - area->length = size; + area->length = length; return( (VipsBlob *) area ); } /** * vips_blob_copy: - * @data: (array length=size) (element-type guint8) (transfer none): data to store - * @size: number of bytes in @data + * @data: (array length=length) (element-type guint8) (transfer none): data to store + * @length: number of bytes in @data * * Like vips_blob_new(), but take a copy of the data. Useful for bindings * which strugle with callbacks. @@ -637,15 +640,15 @@ vips_blob_new( VipsCallbackFn free_fn, const void *data, size_t size ) * Returns: (transfer full): the new #VipsBlob. */ VipsBlob * -vips_blob_copy( const void *data, size_t size ) +vips_blob_copy( const void *data, size_t length ) { void *data_copy; VipsArea *area; - data_copy = vips_malloc( NULL, size ); - memcpy( data_copy, data, size ); + data_copy = vips_malloc( NULL, length ); + memcpy( data_copy, data, length ); area = vips_area_new( (VipsCallbackFn) g_free, data_copy ); - area->length = size; + area->length = length; return( (VipsBlob *) area ); } @@ -653,19 +656,19 @@ vips_blob_copy( const void *data, size_t size ) /** * vips_blob_get: * @blob: #VipsBlob to fetch from - * @size: return number of bytes of data + * @length: return number of bytes of data * * Get the data from a #VipsBlob. * * See also: vips_blob_new(). * - * Returns: (array length=size) (element-type guint8) (transfer none): the data + * Returns: (array length=length) (element-type guint8) (transfer none): the data */ const void * -vips_blob_get( VipsBlob *blob, size_t *size ) +vips_blob_get( VipsBlob *blob, size_t *length ) { return( vips_area_get_data( VIPS_AREA( blob ), - size, NULL, NULL, NULL ) ); + length, NULL, NULL, NULL ) ); } /* Transform a blob to a G_TYPE_STRING. @@ -674,12 +677,12 @@ static void transform_blob_g_string( const GValue *src_value, GValue *dest_value ) { void *blob; - size_t blob_length; + size_t length; char buf[256]; - blob = vips_value_get_blob( src_value, &blob_length ); + blob = vips_value_get_blob( src_value, &length ); vips_snprintf( buf, 256, "VIPS_TYPE_BLOB, data = %p, length = %zd", - blob, blob_length ); + blob, length ); g_value_set_string( dest_value, buf ); } @@ -689,11 +692,11 @@ static void transform_blob_save_string( const GValue *src_value, GValue *dest_value ) { void *blob; - size_t blob_length; + size_t length; char *b64; - blob = vips_value_get_blob( src_value, &blob_length ); - if( (b64 = vips__b64_encode( blob, blob_length )) ) { + blob = vips_value_get_blob( src_value, &length ); + if( (b64 = vips__b64_encode( blob, length )) ) { vips_value_set_save_string( dest_value, b64 ); vips_free( b64 ); } @@ -709,12 +712,12 @@ transform_save_string_blob( const GValue *src_value, GValue *dest_value ) { const char *b64; void *blob; - size_t blob_length; + size_t length; b64 = vips_value_get_save_string( src_value ); - if( (blob = vips__b64_decode( b64, &blob_length )) ) + if( (blob = vips__b64_decode( b64, &length )) ) vips_value_set_blob( dest_value, - (VipsCallbackFn) vips_free, blob, blob_length ); + (VipsCallbackFn) vips_free, blob, length ); else /* No error return from transform, but we should set it to * something. @@ -1556,7 +1559,7 @@ vips_value_set_ref_string( GValue *value, const char *str ) * @length: length of memory area * * Sets @value to hold a @data. When @value is freed, @data will be - * freed with @free_fn. @value also holds a note of the length of the memory + * freed with @free_fn. @value also holds a note of the size of the memory * area. * * blobs are things like ICC profiles or EXIF data. They are relocatable, and @@ -1567,7 +1570,7 @@ vips_value_set_ref_string( GValue *value, const char *str ) */ void vips_value_set_blob( GValue *value, - VipsCallbackFn free_fn, void *data, size_t length ) + VipsCallbackFn free_fn, const void *data, size_t length ) { VipsBlob *blob;