diff --git a/ChangeLog b/ChangeLog index 81ee057f..3daefd12 100644 --- a/ChangeLog +++ b/ChangeLog @@ -12,6 +12,7 @@ - im_flood() and friends rewritten, typically 4x faster - removed --with-cimg option, added --disable-cxx - added im_system_image() (thanks Roland) +- added postclose callbacks 26/11/09 started 7.20.3 - updated en_GB.po translation diff --git a/benchmark/benchmarkn.sh b/benchmark/benchmarkn.sh index a702a730..a2cff47e 100755 --- a/benchmark/benchmarkn.sh +++ b/benchmark/benchmarkn.sh @@ -27,7 +27,7 @@ echo " by" `header -f Ysize temp.v` "pixels" echo "starting benchmark ..." echo "chain=$chain" -for cpus in 1 2 ; do +for cpus in 1 2 3 4 5 6 ; do export IM_CONCURRENCY=$cpus echo IM_CONCURRENCY=$IM_CONCURRENCY diff --git a/libvips/conversion/conver_dispatch.c b/libvips/conversion/conver_dispatch.c index fe234dcc..b04690af 100644 --- a/libvips/conversion/conver_dispatch.c +++ b/libvips/conversion/conver_dispatch.c @@ -92,26 +92,30 @@ static int system_image_vec( im_object *argv ) { IMAGE *in = argv[0]; - char *in_format = argv[1]; - char *out_format = argv[2]; - char *cmd = argv[3]; - char **log = (char **) &argv[4]; - char **out_file = (char **) &argv[5]; + IMAGE *out = argv[1]; + char *in_format = argv[2]; + char *out_format = argv[3]; + char *cmd = argv[4]; + char **log = (char **) &argv[5]; - *out_file = im_system_image( in, in_format, out_format, cmd, log ); - if( !*out_file ) - *out_file = im_strdup( NULL, "" ); + IMAGE *out_image; + if( (out_image = im_system_image( in, + in_format, out_format, cmd, log )) ) + im_copy_file( out_image, out ); + + /* We always succeed, but out may be invalid. + */ return( 0 ); } static im_arg_desc system_image_args[] = { - IM_INPUT_IMAGE( "im" ), + IM_INPUT_IMAGE( "in" ), + IM_OUTPUT_IMAGE( "out" ), IM_INPUT_STRING( "in_format" ), IM_INPUT_STRING( "out_format" ), IM_INPUT_STRING( "command" ), - IM_OUTPUT_STRING( "log" ), - IM_OUTPUT_STRING( "out_file" ) + IM_OUTPUT_STRING( "log" ) }; static im_function system_image_desc = { diff --git a/libvips/conversion/im_copy_file.c b/libvips/conversion/im_copy_file.c index 0a3763ce..0cf99434 100644 --- a/libvips/conversion/im_copy_file.c +++ b/libvips/conversion/im_copy_file.c @@ -60,7 +60,7 @@ im_copy_file( IMAGE *in, IMAGE *out ) if( !im_isfile( in ) ) { IMAGE *disc; - if( !(disc = im__open_temp()) ) + if( !(disc = im__open_temp( "%s.v" )) ) return( -1 ); if( im_add_close_callback( out, (im_callback_fn) im_close, disc, NULL ) ) { diff --git a/libvips/conversion/im_system.c b/libvips/conversion/im_system.c index a9edd45b..bca31d04 100644 --- a/libvips/conversion/im_system.c +++ b/libvips/conversion/im_system.c @@ -79,7 +79,7 @@ im_system( IMAGE *im, const char *cmd, char **out ) if( !im_isfile( im ) ) { IMAGE *disc; - if( !(disc = im__open_temp()) ) + if( !(disc = im__open_temp( "%s.v" )) ) return( -1 ); if( im_copy( im, disc ) || im_system( disc, cmd, out ) ) { diff --git a/libvips/conversion/im_system_image.c b/libvips/conversion/im_system_image.c index 45a48743..a40e8c8d 100644 --- a/libvips/conversion/im_system_image.c +++ b/libvips/conversion/im_system_image.c @@ -60,31 +60,20 @@ static int system_image( IMAGE *im, - const char *in_name, const char *out_name, const char *cmd_format, + IMAGE *in_image, IMAGE *out_image, const char *cmd_format, char **log ) { - IMAGE *disc; + const char *in_name = in_image->filename; + const char *out_name = out_image->filename; FILE *fp; char line[IM_MAX_STRSIZE]; char txt[IM_MAX_STRSIZE]; VipsBuf buf = VIPS_BUF_STATIC( txt ); int result; - if( !(disc = im_open( in_name, "w" )) ) + if( im_copy( im, in_image ) || + !(fp = im_popenf( cmd_format, "r", in_name, out_name )) ) return( -1 ); - if( im_copy( im, disc ) ) { - im_close( im ); - g_unlink( in_name ); - - return( -1 ); - } - im_close( im ); - - if( !(fp = im_popenf( cmd_format, "r", in_name, out_name )) ) { - g_unlink( in_name ); - - return( -1 ); - } while( fgets( line, IM_MAX_STRSIZE, fp ) ) if( !vips_buf_appends( &buf, line ) ) @@ -92,15 +81,14 @@ system_image( IMAGE *im, result = pclose( fp ); - g_unlink( in_name ); - if( log ) *log = im_strdup( NULL, vips_buf_all( &buf ) ); return( result ); } -/* +/** + * im_system_image: Run a command on an image, returning a new image. @@ -127,29 +115,29 @@ system_image( IMAGE *im, */ -char * +IMAGE * im_system_image( IMAGE *im, const char *in_format, const char *out_format, const char *cmd_format, char **log ) { - char *in_name; - char *out_name; + IMAGE *in_image; + IMAGE *out_image; if( log ) *log = NULL; - in_name = im__temp_name( in_format ); - out_name = im__temp_name( in_format ); + in_image = im__open_temp( in_format ); + out_image = im__open_temp( out_format ); - if( !in_name || - !out_name || - system_image( im, in_name, out_name, cmd_format, log ) ) { - g_free( in_name ); - g_free( out_name ); + if( !in_image || + !out_image || + system_image( im, in_image, out_image, cmd_format, log ) ) { + im_close( in_image ); + im_close( out_image ); return( NULL ); } - g_free( in_name ); + im_close( in_image ); - return( out_name ); + return( out_image ); } diff --git a/libvips/include/vips/callback.h b/libvips/include/vips/callback.h index 0f19fc0f..1fe5a98f 100644 --- a/libvips/include/vips/callback.h +++ b/libvips/include/vips/callback.h @@ -40,6 +40,7 @@ typedef int (*im_callback_fn)( void *a, void *b ); int im_add_close_callback( IMAGE *im, im_callback_fn fn, void *a, void *b ); int im_add_preclose_callback( IMAGE *im, im_callback_fn fn, void *a, void *b ); +int im_add_postclose_callback( IMAGE *im, im_callback_fn fn, void *a, void *b ); int im_add_evalstart_callback( IMAGE *im, im_callback_fn fn, void *a, void *b ); int im_add_eval_callback( IMAGE *im, im_callback_fn fn, void *a, void *b ); diff --git a/libvips/include/vips/conversion.h b/libvips/include/vips/conversion.h index dd538ec8..11661fcb 100644 --- a/libvips/include/vips/conversion.h +++ b/libvips/include/vips/conversion.h @@ -111,7 +111,7 @@ int im_subsample( IMAGE *in, IMAGE *out, int x, int y ); int im_zoom( IMAGE *in, IMAGE *out, int x, int y ); int im_system( IMAGE *im, const char *cmd, char **out ); -char *im_system_image( IMAGE *im, +IMAGE *im_system_image( IMAGE *im, const char *in_format, const char *out_format, const char *cmd_format, char **log ); diff --git a/libvips/include/vips/image.h b/libvips/include/vips/image.h index 39ad77cc..44bf7a23 100644 --- a/libvips/include/vips/image.h +++ b/libvips/include/vips/image.h @@ -240,6 +240,11 @@ typedef struct _VipsImage { * relationships, so it's a mandatory thing. */ gboolean hint_set; + + /* Post-close callbacks happen on finalize. Eg. deleting the file + * associated with this temp image. + */ + GSList *postclosefns; } VipsImage; extern const size_t im__sizeof_bandfmt[]; diff --git a/libvips/include/vips/util.h b/libvips/include/vips/util.h index 949ec036..28c1411b 100644 --- a/libvips/include/vips/util.h +++ b/libvips/include/vips/util.h @@ -255,7 +255,7 @@ int im_isvips( const char *filename ); int im_amiMSBfirst( void ); char *im__temp_name( const char *format ); -IMAGE *im__open_temp( void ); +IMAGE *im__open_temp( const char *format ); int im_bits_of_fmt( VipsBandFmt fmt ); diff --git a/libvips/iofuncs/callback.c b/libvips/iofuncs/callback.c index 9ce363fa..f34894d4 100644 --- a/libvips/iofuncs/callback.c +++ b/libvips/iofuncs/callback.c @@ -108,11 +108,11 @@ add_callback( IMAGE *im, GSList **cblist, im_callback_fn fn, void *a, void *b ) * * Attaches a close callback @fn to @im. * - * Close callbacks are triggered exactly once when the image has been closed + * Close callbacks are triggered exactly once, when the image has been closed * and most resources freed, but just before the memory for @im is released. * * Close callbacks are a good place to free memory that was need to generate - * @im, delete temporary files and so on. You can close other images and there + * @im. You can close other images and there * may even be circularity in your close lists. * * See also: im_malloc() (implemented with im_add_close_callback()), @@ -127,6 +127,29 @@ im_add_close_callback( IMAGE *im, im_callback_fn fn, void *a, void *b ) return( add_callback( im, &im->closefns, fn, a, b ) ); } +/** + * im_add_postclose_callback: + * @im: image to attach callback to + * @fn: callback function + * @a: user data 1 + * @b: user data 2 + * + * Attaches a close callback @fn to @im. + * + * Post-close callbacks are triggered exactly once, just before the memory + * associated with @im is released. + * + * Close callbacks are a good place to delete temporary files. You can close + * other images and there may even be circularity in your close lists. + * + * Returns: 0 on success, or -1 on error. + */ +int +im_add_postclose_callback( IMAGE *im, im_callback_fn fn, void *a, void *b ) +{ + return( add_callback( im, &im->postclosefns, fn, a, b ) ); +} + /** * im_add_preclose_callback: * @im: image to attach callback to diff --git a/libvips/iofuncs/debug.c b/libvips/iofuncs/debug.c index 6bbae846..868b2ec3 100644 --- a/libvips/iofuncs/debug.c +++ b/libvips/iofuncs/debug.c @@ -393,16 +393,18 @@ im_printdesc( IMAGE *image ) */ if( image->generate ) printf( "generate function attached\n" ); + if( image->preclosefns ) + printf( "preclose callbacks attached\n" ); if( image->closefns ) printf( "close callbacks attached\n" ); + if( image->postclosefns ) + printf( "postclose callbacks attached\n" ); if( image->evalfns ) printf( "eval callbacks attached\n" ); if( image->evalendfns ) printf( "evalend callbacks attached\n" ); if( image->evalstartfns ) printf( "evalstart callbacks attached\n" ); - if( image->preclosefns ) - printf( "preclose callbacks attached\n" ); if( image->invalidatefns ) printf( "invalidate callbacks attached\n" ); if( image->regions ) { diff --git a/libvips/iofuncs/im_close.c b/libvips/iofuncs/im_close.c index f1618d41..ecd099c0 100644 --- a/libvips/iofuncs/im_close.c +++ b/libvips/iofuncs/im_close.c @@ -50,6 +50,8 @@ * released * 6/10/09 * - gtkdoc comment + * 10/1/09 + * - added postclose */ /* @@ -294,6 +296,8 @@ im_close( IMAGE *im ) /* Final cleanup. */ + result |= im__trigger_callbacks( im->postclosefns ); + IM_FREEF( im_slist_free_all, im->postclosefns ); IM_FREEF( g_mutex_free, im->sslock ); IM_FREE( im->filename ); IM_FREE( im->Hist ); diff --git a/libvips/iofuncs/init.c b/libvips/iofuncs/init.c index c0f727bb..0a496fb2 100644 --- a/libvips/iofuncs/init.c +++ b/libvips/iofuncs/init.c @@ -32,6 +32,8 @@ * - add file_length * 8/10/09 * - add set_hint + * 10/1/09 + * - added postclose */ /* @@ -173,6 +175,8 @@ im_init( const char *filename ) im->hint_set = FALSE; + im->postclosefns = NULL; + if( !(im->filename = im_strdup( NULL, filename )) ) { im_close( im ); return( NULL ); diff --git a/libvips/iofuncs/util.c b/libvips/iofuncs/util.c index bbbd40a8..ea876d6c 100644 --- a/libvips/iofuncs/util.c +++ b/libvips/iofuncs/util.c @@ -1546,14 +1546,15 @@ im__temp_name( const char *format ) } /* Make a disc IMAGE which will be automatically unlinked on im_close(). + * Format is something like "%s.v" for a vips file. */ IMAGE * -im__open_temp( void ) +im__open_temp( const char *format ) { char *name; IMAGE *disc; - if( !(name = im__temp_name( "%s.v" )) ) + if( !(name = im__temp_name( format )) ) return( NULL ); if( !(disc = im_open( name, "w" )) ) { @@ -1562,7 +1563,10 @@ im__open_temp( void ) } g_free( name ); - if( im_add_close_callback( disc, + /* Needs to be postclose so we can rewindd disc after write without + * deleting the file. + */ + if( im_add_postclose_callback( disc, (im_callback_fn) unlink, disc->filename, NULL ) ) { im_close( disc ); g_unlink( name ); diff --git a/libvips/mask/rw_mask.c b/libvips/mask/rw_mask.c index 75f02b3b..e22bd237 100644 --- a/libvips/mask/rw_mask.c +++ b/libvips/mask/rw_mask.c @@ -184,7 +184,7 @@ im_create_imask( const char *filename, int xs, int ys ) INTMASK * im_create_imaskv( const char *filename, int xs, int ys, ... ) -{ +{ va_list ap; INTMASK *m;