diff --git a/ChangeLog b/ChangeLog index 27070ee2..f6f1cd68 100644 --- a/ChangeLog +++ b/ChangeLog @@ -28,6 +28,7 @@ end of a set of paint actions to trigger an update - parent/child -> upstream/downstream in DAG - set VIPS_ICC_DIR in configure +- ICC profiles are looked for in VIPS_ICC_DIR as a fallback 15/1/10 started 7.21.1 - added "written" callbacks, used to implement write to non-vips formats diff --git a/libvips/colour/im_icc_transform.c b/libvips/colour/im_icc_transform.c index 36986161..071202c3 100644 --- a/libvips/colour/im_icc_transform.c +++ b/libvips/colour/im_icc_transform.c @@ -373,7 +373,8 @@ attach_profile( IMAGE *im, const char *filename ) char *data; unsigned int data_length; - if( !(data = im__file_read_name( filename, &data_length )) ) + if( !(data = im__file_read_name( filename, VIPS_ICC_DIR, + &data_length )) ) return( -1 ); if( im_meta_set_blob( im, IM_META_ICC_NAME, (im_callback_fn) im_free, data, data_length ) ) { diff --git a/libvips/format/im_analyze2vips.c b/libvips/format/im_analyze2vips.c index 5b5af292..79994383 100644 --- a/libvips/format/im_analyze2vips.c +++ b/libvips/format/im_analyze2vips.c @@ -309,7 +309,7 @@ read_header( const char *header ) struct dsr *d; unsigned int len; - if( !(d = (struct dsr *) im__file_read_name( header, &len )) ) + if( !(d = (struct dsr *) im__file_read_name( header, NULL, &len )) ) return( NULL ); if( len != sizeof( struct dsr ) ) { im_free( d ); diff --git a/libvips/format/im_jpeg2vips.c b/libvips/format/im_jpeg2vips.c index 0cc6929f..70760fc7 100644 --- a/libvips/format/im_jpeg2vips.c +++ b/libvips/format/im_jpeg2vips.c @@ -671,7 +671,7 @@ jpeg2vips( const char *name, IMAGE *out, gboolean header_only ) /* Make input. */ - if( !(fp = im__file_open_read( filename )) ) + if( !(fp = im__file_open_read( filename, NULL )) ) return( -1 ); eman.fp = fp; jpeg_stdio_src( &cinfo, fp ); diff --git a/libvips/format/im_png2vips.c b/libvips/format/im_png2vips.c index ef9e4bcf..134915f0 100644 --- a/libvips/format/im_png2vips.c +++ b/libvips/format/im_png2vips.c @@ -138,7 +138,7 @@ read_new( const char *name, IMAGE *out ) read->row_pointer = NULL; read->data = NULL; - if( !(read->fp = im__file_open_read( name )) ) { + if( !(read->fp = im__file_open_read( name, NULL )) ) { read_destroy( read ); return( NULL ); } diff --git a/libvips/format/im_ppm2vips.c b/libvips/format/im_ppm2vips.c index 3e486014..ba59a564 100644 --- a/libvips/format/im_ppm2vips.c +++ b/libvips/format/im_ppm2vips.c @@ -395,7 +395,7 @@ ppm2vips_header( const char *filename, IMAGE *out ) int bits; int ascii; - if( !(fp = im__file_open_read( filename )) ) + if( !(fp = im__file_open_read( filename, NULL )) ) return( -1 ); if( read_header( fp, out, &bits, &ascii ) ) { fclose( fp ); @@ -417,7 +417,7 @@ isppmmmap( const char *filename ) int bits; int ascii; - if( !(fp = im__file_open_read( filename )) ) + if( !(fp = im__file_open_read( filename, NULL )) ) return( -1 ); if( !(im = im_open( "temp", "p" )) ) { @@ -454,7 +454,7 @@ im_ppm2vips( const char *filename, IMAGE *out ) { FILE *fp; - if( !(fp = im__file_open_read( filename )) ) + if( !(fp = im__file_open_read( filename, NULL )) ) return( -1 ); if( parse_ppm( fp, filename, out ) ) { fclose( fp ); diff --git a/libvips/format/im_vips2jpeg.c b/libvips/format/im_vips2jpeg.c index 2c1bdb74..a3b80c5c 100644 --- a/libvips/format/im_vips2jpeg.c +++ b/libvips/format/im_vips2jpeg.c @@ -489,7 +489,8 @@ static int write_profile_file( Write *write, const char *profile ) { if( !(write->profile_bytes = - im__file_read_name( profile, &write->profile_length )) ) + im__file_read_name( profile, VIPS_ICC_DIR, + &write->profile_length )) ) return( -1 ); write_profile_data( &write->cinfo, (JOCTET *) write->profile_bytes, write->profile_length ); diff --git a/libvips/format/im_vips2tiff.c b/libvips/format/im_vips2tiff.c index 9edc0c9c..aa83a7a3 100644 --- a/libvips/format/im_vips2tiff.c +++ b/libvips/format/im_vips2tiff.c @@ -395,7 +395,7 @@ embed_profile_file( TIFF *tif, const char *profile ) char *buffer; unsigned int length; - if( !(buffer = im__file_read_name( profile, &length )) ) + if( !(buffer = im__file_read_name( profile, VIPS_ICC_DIR, &length )) ) return( -1 ); TIFFSetField( tif, TIFFTAG_ICCPROFILE, length, buffer ); im_free( buffer ); diff --git a/libvips/format/radiance.c b/libvips/format/radiance.c index 36fa769d..ef882ffa 100644 --- a/libvips/format/radiance.c +++ b/libvips/format/radiance.c @@ -779,7 +779,7 @@ israd( const char *filename ) printf( "israd: \"%s\"\n", filename ); #endif /*DEBUG*/ - if( !(fin = im__file_open_read( filename )) ) + if( !(fin = im__file_open_read( filename, NULL )) ) return( 0 ); strcpy( format, PICFMT ); result = checkheader( fin, format, NULL ); @@ -825,7 +825,7 @@ read_new( const char *filename, IMAGE *out ) read->prims[3][1] = CIE_y_w; read->buf = NULL; - if( !(read->fin = im__file_open_read( filename )) ) { + if( !(read->fin = im__file_open_read( filename, NULL )) ) { read_destroy( read ); return( NULL ); } diff --git a/libvips/include/vips/util.h b/libvips/include/vips/util.h index 28c1411b..3a2afc04 100644 --- a/libvips/include/vips/util.h +++ b/libvips/include/vips/util.h @@ -225,10 +225,11 @@ char *im_getsuboption( const char *buf ); gint64 im_file_length( int fd ); int im__write( int fd, const void *buf, size_t count ); -FILE *im__file_open_read( const char *filename ); +FILE *im__file_open_read( const char *filename, const char *fallback_dir ); FILE *im__file_open_write( const char *filename ); char *im__file_read( FILE *fp, const char *name, unsigned int *length_out ); -char *im__file_read_name( const char *name, unsigned int *length_out ); +char *im__file_read_name( const char *name, const char *fallback_dir, + unsigned int *length_out ); int im__file_write( void *data, size_t size, size_t nmemb, FILE *stream ); typedef enum { diff --git a/libvips/iofuncs/util.c b/libvips/iofuncs/util.c index 043e53b0..d3b3f28c 100644 --- a/libvips/iofuncs/util.c +++ b/libvips/iofuncs/util.c @@ -817,7 +817,7 @@ im__write( int fd, const void *buf, size_t count ) /* Load up a file as a string. */ char * -im__file_read( FILE *fp, const char *name, unsigned int *length_out ) +im__file_read( FILE *fp, const char *filename, unsigned int *length_out ) { long len; size_t read; @@ -830,7 +830,7 @@ im__file_read( FILE *fp, const char *name, unsigned int *length_out ) if( len > 20 * 1024 * 1024 ) { /* Seems crazy! */ - im_error( "im__file_read", _( "\"%s\" too long" ), name ); + im_error( "im__file_read", _( "\"%s\" too long" ), filename ); return( NULL ); } @@ -873,7 +873,8 @@ im__file_read( FILE *fp, const char *name, unsigned int *length_out ) if( read != (size_t) len ) { im_free( str ); im_error( "im__file_read", - _( "error reading from file \"%s\"" ), name ); + _( "error reading from file \"%s\"" ), + filename ); return( NULL ); } } @@ -886,23 +887,60 @@ im__file_read( FILE *fp, const char *name, unsigned int *length_out ) return( str ); } +/* Does a filename contain a directory separator? + */ +static gboolean +filename_hasdir( const char *filename ) +{ + char *dirname; + gboolean hasdir; + + dirname = g_path_get_dirname( filename ); + hasdir = (strcmp( dirname, "." ) != 0); + g_free( dirname ); + + return( hasdir ); +} + +/* Open a file. We take an optional fallback dir as well and will try opening + * there if opening directly fails. + * + * This is used for things like finding ICC profiles. We try to open the file + * directly first, and if that fails and the filename does not contain a + * directory separator, we try looking in the fallback dir. + */ FILE * -im__file_open_read( const char *filename ) +im__file_open_read( const char *filename, const char *fallback_dir ) { FILE *fp; #ifdef BINARY_OPEN - if( !(fp = fopen( filename, "rb" )) ) { -#else /*BINARY_OPEN*/ - if( !(fp = fopen( filename, "r" )) ) { + fp = fopen( filename, "rb" ); +#else /*!BINARY_OPEN*/ + fp = fopen( filename, "r" ); #endif /*BINARY_OPEN*/ - im_error( "im__file_open_read", - _( "unable to open file \"%s\" for reading" ), - filename ); - return( NULL ); + if( fp ) + return( fp ); + + if( fallback_dir && !filename_hasdir( filename ) ) { + char *path; + + path = g_build_filename( fallback_dir, filename, NULL ); +#ifdef BINARY_OPEN + fp = fopen( path, "rb" ); +#else /*!BINARY_OPEN*/ + fp = fopen( path, "r" ); +#endif /*BINARY_OPEN*/ + g_free( path ); + + if( fp ) + return( fp ); } - return( fp ); + im_error( "im__file_open_read", + _( "unable to open file \"%s\" for reading" ), filename ); + + return( NULL ); } FILE * @@ -924,17 +962,19 @@ im__file_open_write( const char *filename ) return( fp ); } -/* Load from a filename as a string. +/* Load from a filename as a string. Used for things like reading in ICC + * profiles. */ char * -im__file_read_name( const char *name, unsigned int *length_out ) +im__file_read_name( const char *filename, const char *fallback_dir, + unsigned int *length_out ) { FILE *fp; char *buffer; - if( !(fp = im__file_open_read( name )) ) + if( !(fp = im__file_open_read( filename, fallback_dir )) ) return( NULL ); - if( !(buffer = im__file_read( fp, name, length_out )) ) { + if( !(buffer = im__file_read( fp, filename, length_out )) ) { fclose( fp ); return( NULL ); }