new progress feedback system

This commit is contained in:
John Cupitt 2007-11-07 16:53:01 +00:00
parent a65cfcd884
commit bc84d2ce57
24 changed files with 359 additions and 100 deletions

View File

@ -4,8 +4,11 @@
- break im_wbuffer() out to a separate API
- use im_wbuffer() to make im_vips2jpeg() compress in the background
- also im_vips2png(), im_vips2tiff(), im_vips2ppm()
- new system for propogating progress settings down pipelines unbreaks save
feedback in nip2
- revised evaluation progress system
- new evalstart/evalend/preclose callbacks fix over/underflow reporting
- but the meaning of evalend has changed in a non-backwards-compatible way :(
use preclose instead ito get the old behaviour
- added "--vips-progress" flag to turn on a simple eval progress tracker
28/9/07 started 7.13.1
- vips2dj can print RGB images

4
TODO
View File

@ -1,7 +1,9 @@
- test ppm writer
- update docs, add pages for new cbs
- talk about new progress system in im_add_eval_callback()?
- test ppm writer
- missing libstdc++ in link? what if we configure with no openexr?
added -lstdc++ to VIPS_LIBS, but will this work on solaris etc.? maybe have

View File

@ -37,6 +37,21 @@
extern "C" {
#endif /*__cplusplus*/
/* Default tile geometry.
*/
extern int im__tile_width;
extern int im__tile_height;
extern int im__fatstrip_height;
extern int im__thinstrip_height;
/* Default n threads.
*/
extern int im__concurrency;
/* Give progress feedback.
*/
extern int im__progress;
typedef int (*im__fftproc_fn)( IMAGE *, IMAGE *, IMAGE * );
/* iofuncs
@ -53,7 +68,9 @@ void *im__read_extension_block( IMAGE *im, int *size );
int im__readhist( IMAGE *image );
int im__write_extension_block( IMAGE *im, void *buf, int size );
int im__writehist( IMAGE *image );
int im__start_eval( IMAGE *im );
int im__handle_eval( IMAGE *im, int w, int h );
int im__end_eval( IMAGE *im );
int im__time_destroy( IMAGE *im );
extern int im__read_test;

View File

@ -74,6 +74,10 @@ typedef void *(*im_header_map_fn)( IMAGE *, const char *, GValue *, void * );
int im_init_world( const char *argv0 );
GOptionGroup *im_get_option_group( void );
/* Turn progress feedback on and off.
*/
void im_progress_set( int progress );
const char *im_error_buffer( void );
int im_debugim( IMAGE * );
int im_printlines( IMAGE * );
@ -149,6 +153,8 @@ int im_ismagick( const char * );
int im_isanalyze( const char *filename );
int im_add_close_callback( IMAGE *, im_callback_fn, void *, void * );
int im_add_preclose_callback( IMAGE *, im_callback_fn, void *, void * );
int im_add_evalstart_callback( IMAGE *, im_callback_fn, void *, void * );
int im_add_eval_callback( IMAGE *, im_callback_fn, void *, void * );
int im_add_evalend_callback( IMAGE *, im_callback_fn, void *, void * );

View File

@ -47,17 +47,6 @@ extern "C" {
*/
#define IM__DEFAULT_STACK_SIZE (2 * 1024 * 1024)
/* Default tile geometry.
*/
extern int im__tile_width;
extern int im__tile_height;
extern int im__fatstrip_height;
extern int im__thinstrip_height;
/* Default n threads.
*/
extern int im__concurrency;
/* A work function.
*/
typedef int (*im__work_fn)( REGION *, void *, void *, void * );

View File

@ -35,6 +35,9 @@
* - added RGB16, GREY16
* 30/10/06
* - added im_window_t
* 7/11/07
* - added preclose and evalstart callbacks
* - brought time struct in here
*/
/*
@ -236,12 +239,13 @@ typedef struct {
*/
typedef struct {
struct im__IMAGE *im; /* Image we are part of */
GTimer *start; /* Start time */
time_t unused; /* FIXME ... for compatibility */
int run; /* Time we have been running */
int eta; /* Estimated seconds of computation left */
gint64 tpels; /* Number of pels we expect to calculate */
gint64 npels; /* Number of pels calculated so far */
int percent; /* Percent complete */
GTimer *start; /* Start time */
} im_time_t;
/* Image descriptor for subroutine i/o args
@ -303,7 +307,7 @@ typedef struct im__IMAGE {
GSList *Meta_traverse; /* Traverse order for Meta */
/* Part of mmap() read ... the sizeof() the header we skip from the
* file start. Usually IM_SIZEOF_HEADER, but can be soomething else
* file start. Usually IM_SIZEOF_HEADER, but can be something else
* for binary file read.
*/
int sizeof_header;
@ -330,6 +334,11 @@ typedef struct im__IMAGE {
/* The IMAGE (if any) we should signal eval progress on.
*/
struct im__IMAGE *progress;
/* Some more callbacks. Appended to IMAGE for binary compatibility.
*/
GSList *evalstartfns; /* list of start eval callbacks */
GSList *preclosefns; /* list of pre-close callbacks */
} IMAGE;
/* Only define if IM_ENABLE_DEPRECATED is set.

View File

@ -43,6 +43,8 @@
* 21/4/04 JC
* - now does floor(), not rint() ... you'll need to round yourself
* before calling this if you want round-to-nearest
* 7/11/07
* - use new evalstart/evalend system
*/
/*
@ -100,7 +102,18 @@ typedef struct {
} Clip;
static int
clip_destroy( Clip *clip )
clip_evalstart( Clip *clip )
{
/* Reset counts.
*/
clip->overflow = 0;
clip->underflow = 0;
return( 0 );
}
static int
clip_evalend( Clip *clip )
{
/* Print warnings, if necessary.
*/
@ -128,8 +141,10 @@ clip_new( IMAGE *in, IMAGE *out, int ofmt )
clip->underflow = 0;
clip->overflow = 0;
if( im_add_close_callback( out,
(im_callback_fn) clip_destroy, clip, NULL ) )
if( im_add_evalstart_callback( out,
(im_callback_fn) clip_evalstart, clip, NULL ) ||
im_add_evalend_callback( out,
(im_callback_fn) clip_evalend, clip, NULL ) )
return( NULL );
return( clip );

View File

@ -352,7 +352,7 @@ im__convert_saveable( IMAGE *in, gboolean allow_alpha )
{
IMAGE *out;
if( !(out = im_open( "im__convert_saveable", "p" )) )
if( !(out = im_open( "convert-for-save", "p" )) )
return( NULL );
/* If this is a IM_CODING_LABQ, we can go straight to RGB.

View File

@ -59,6 +59,8 @@
* - sets Xoffset / Yoffset
* 11/11/05
* - simpler inner loop avoids gcc4 bug
* 7/11/07
* - new evalstart/end callbacks
*/
/*
@ -119,19 +121,34 @@ typedef struct {
} Conv;
static int
conv_destroy( Conv *conv )
conv_close( Conv *conv )
{
IM_FREEF( im_free_imask, conv->mask );
return( 0 );
}
static int
conv_evalstart( Conv *conv )
{
/* Reset underflow/overflow count.
*/
conv->overflow = 0;
conv->underflow = 0;
return( 0 );
}
static int
conv_evalend( Conv *conv )
{
/* Print underflow/overflow count.
*/
if( conv->overflow || conv->underflow )
im_warning( "im_conv: %d overflows and %d underflows detected",
im_warn( "im_conv",
_( "%d overflows and %d underflows detected" ),
conv->overflow, conv->underflow );
if( conv->mask ) {
(void) im_free_imask( conv->mask );
conv->mask = NULL;
}
return( 0 );
}
@ -154,7 +171,11 @@ conv_new( IMAGE *in, IMAGE *out, INTMASK *mask )
conv->overflow = 0;
if( im_add_close_callback( out,
(im_callback_fn) conv_destroy, conv, NULL ) ||
(im_callback_fn) conv_close, conv, NULL ) ||
im_add_close_callback( out,
(im_callback_fn) conv_evalstart, conv, NULL ) ||
im_add_close_callback( out,
(im_callback_fn) conv_evalend, conv, NULL ) ||
!(conv->coeff = IM_ARRAY( out, ne, int )) ||
!(conv->mask = im_dup_imask( mask, "conv_mask" )) )
return( NULL );

View File

@ -92,7 +92,7 @@ typedef struct {
} Conv;
static int
conv_destroy( Conv *conv )
conv_close( Conv *conv )
{
if( conv->mask ) {
(void) im_free_dmask( conv->mask );
@ -119,7 +119,7 @@ conv_new( IMAGE *in, IMAGE *out, DOUBLEMASK *mask )
conv->coeff = NULL;
if( im_add_close_callback( out,
(im_callback_fn) conv_destroy, conv, NULL ) ||
(im_callback_fn) conv_close, conv, NULL ) ||
!(conv->coeff = IM_ARRAY( out, ne, double )) ||
!(conv->mask = im_dup_dmask( mask, "conv_mask" )) )
return( NULL );
@ -285,13 +285,14 @@ im_convf_raw( IMAGE *in, IMAGE *out, DOUBLEMASK *mask )
/* Check parameters.
*/
if( !in || in->Coding != IM_CODING_NONE || im_iscomplex( in ) ) {
im_errormsg( "im_convf: input non-complex uncoded please!");
im_error( "im_convf",
_( "non-complex uncoded only" ) );
return( -1 );
}
if( !mask || mask->xsize > 1000 || mask->ysize > 1000 ||
mask->xsize <= 0 || mask->ysize <= 0 || !mask->coeff ||
mask->scale == 0 ) {
im_errormsg( "im_convf: nonsense mask parameters" );
im_error( "im_convf", _( "nonsense mask parameters" ) );
return( -1 );
}
if( im_piocheck( in, out ) )
@ -311,7 +312,7 @@ im_convf_raw( IMAGE *in, IMAGE *out, DOUBLEMASK *mask )
out->Xsize -= mask->xsize - 1;
out->Ysize -= mask->ysize - 1;
if( out->Xsize <= 0 || out->Ysize <= 0 ) {
im_errormsg( "im_convf: image too small for mask" );
im_error( "im_convf", _( "image too small for mask" ) );
return( -1 );
}

View File

@ -47,7 +47,9 @@
* - small speed ups
* 30/6/04
* - heh, 1 band image + 3 band lut + >8bit output has been broken for 9
* years :-)
* years :-)
* 7/11/07
* - new eval start/end system
*/
/*
@ -103,16 +105,22 @@ typedef struct {
int overflow; /* Number of overflows for non-uchar lut */
} LutInfo;
static int
lut_start( LutInfo *st )
{
st->overflow = 0;
return( 0 );
}
/* Print overflows, if any.
*/
static int
end_lut( LutInfo *st )
lut_end( LutInfo *st )
{
if( st->overflow ) {
if( st->overflow )
im_warn( "im_maplut", _( "%d overflows detected" ),
st->overflow );
st->overflow = 0;
}
return( 0 );
}
@ -139,8 +147,10 @@ build_luts( IMAGE *out, IMAGE *lut )
st->clp = st->sz - 1;
st->overflow = 0;
st->table = NULL;
if( im_add_evalend_callback( out,
(im_callback_fn) end_lut, st, NULL ) )
if( im_add_evalstart_callback( out,
(im_callback_fn) lut_start, st, NULL ) ||
im_add_evalend_callback( out,
(im_callback_fn) lut_end, st, NULL ) )
return( NULL );
/* Attach tables.

View File

@ -80,16 +80,20 @@ add_callback( IMAGE *im, GSList **cblist, int (*fn)(), void *a, void *b )
return( 0 );
}
/* Add a close callback to an IMAGE.
*/
int
im_add_close_callback( IMAGE *im, int (*fn)(), void *a, void *b )
{
return( add_callback( im, &im->closefns, fn, a, b ) );
}
int
im_add_preclose_callback( IMAGE *im, int (*fn)(), void *a, void *b )
{
return( add_callback( im, &im->preclosefns, fn, a, b ) );
}
/* Add an eval callback to an IMAGE. You must call this after opening the
* image, but before using it as an argument to an operation.
* image but before using it as an argument to an operation.
*/
int
im_add_eval_callback( IMAGE *im, int (*fn)(), void *a, void *b )
@ -103,14 +107,18 @@ im_add_eval_callback( IMAGE *im, int (*fn)(), void *a, void *b )
return( add_callback( im, &im->evalfns, fn, a, b ) );
}
/* Add an eval end callback to an IMAGE.
*/
int
im_add_evalend_callback( IMAGE *im, int (*fn)(), void *a, void *b )
{
return( add_callback( im, &im->evalendfns, fn, a, b ) );
}
int
im_add_evalstart_callback( IMAGE *im, int (*fn)(), void *a, void *b )
{
return( add_callback( im, &im->evalstartfns, fn, a, b ) );
}
/* Perform a user callback.
*/
static void *

View File

@ -52,6 +52,8 @@
* - call im__writehist() to send history to XML after image data
* 3/1/07
* - free history_list
* 7/11/07
* - added preclose, removed evalend triggers
*/
/*
@ -122,7 +124,9 @@
int
im__close( IMAGE *im )
{
int result = 0;
int result;
result = 0;
/* No action for NULL image.
*/
@ -133,6 +137,11 @@ im__close( IMAGE *im )
printf( "im__close: starting for %s ..\n", im->filename );
#endif /*DEBUG_IO*/
/* Trigger all pre-close fns.
*/
result |= im__trigger_callbacks( im->preclosefns );
IM_FREEF( im_slist_free_all, im->preclosefns );
/* Free any regions defined on this image. This will, in turn, call
* all stop functions still running, freeing all regions we have on
* other images, etc.
@ -157,9 +166,9 @@ im__close( IMAGE *im )
/* Make sure all evalend functions have been called, perform all close
* callbacks, and free eval callbacks.
*/
result |= im__trigger_callbacks( im->evalendfns );
IM_FREEF( im_slist_free_all, im->evalendfns );
IM_FREEF( im_slist_free_all, im->evalstartfns );
IM_FREEF( im_slist_free_all, im->evalfns );
IM_FREEF( im_slist_free_all, im->evalendfns );
result |= im__trigger_callbacks( im->closefns );
IM_FREEF( im_slist_free_all, im->closefns );

View File

@ -41,6 +41,8 @@
* - better how-many-pixels-calculated
* 27/11/06
* - merge background write stuff
* 7/11/07
* - new start/end eval callbacks
*/
/*
@ -284,12 +286,20 @@ eval_to_memory( im_threadgroup_t *tg, REGION *or )
{
int y, chunk;
IMAGE *im = or->im;
int result;
result = 0;
#ifdef DEBUG_IO
int ntiles = 0;
printf( "eval_to_memory: partial image output to memory area\n" );
#endif /*DEBUG_IO*/
/* Signal start of eval.
*/
if( im__start_eval( im ) )
return( -1 );
/* Choose a chunk size ... 1/100th of the height of the image, about.
* This sets the granularity of user feedback on eval progress, but
* does not affect mem requirements etc.
@ -307,24 +317,28 @@ eval_to_memory( im_threadgroup_t *tg, REGION *or )
pos.top = y;
pos.width = im->Xsize;
pos.height = chunk;
if( im_region_image( or, &pos ) )
return( -1 );
if( (result = im_region_image( or, &pos )) )
break;
/* Ask for evaluation of this area.
*/
if( eval_to_region( or, tg ) )
return( -1 );
if( (result = eval_to_region( or, tg )) )
break;
#ifdef DEBUG_IO
ntiles++;
#endif /*DEBUG_IO*/
}
/* Signal end of eval.
*/
result |= im__end_eval( im );
#ifdef DEBUG_IO
printf( "eval_to_memory: success! %d patches written\n", ntiles );
printf( "eval_to_memory: %d patches written\n", ntiles );
#endif /*DEBUG_IO*/
return( 0 );
return( result );
}
/* A write function for VIPS images. Just write() the pixel data.
@ -413,7 +427,7 @@ im_generate( IMAGE *im,
im->stop = stop;
im->client1 = a;
im->client2 = b;
/* Evaluate. Two output styles: to memory area (im_setbuf()
* or im_mmapinrw()) or to file (im_openout()).
*/
@ -433,13 +447,6 @@ im_generate( IMAGE *im,
im_threadgroup_free( tg );
im_region_free( or );
/* Evaluation is now complete, with all sequences finished.
* Trigger evalend callbacks, then free them to make sure we
* don't trigger twice.
*/
res |= im__trigger_callbacks( im->evalendfns );
IM_FREEF( im_slist_free_all, im->evalendfns );
/* Error?
*/
if( res )

View File

@ -27,6 +27,8 @@
* 2/1/07
* - init magic
* - init history_list
* 7/11/07
* - added preclose and evalstart
*/
/*
@ -159,6 +161,9 @@ im_init( const char *filename )
im->progress = NULL;
im->evalstartfns = NULL;
im->preclosefns = NULL;
if( !(im->filename = im_strdup( NULL, filename )) ) {
im_close( im );
return( NULL );

View File

@ -15,6 +15,8 @@
* 8/6/07
* - just warn if plugins fail to load correctly: too annoying to have
* VIPS refuse to start because of a dodgy plugin
* 7/11/07
* - progress feedback option
*/
/*
@ -190,16 +192,18 @@ im__ngettext( const char *msgid, const char *plural, unsigned long int n )
static GOptionEntry option_entries[] = {
{ "vips-concurrency", 'c', 0, G_OPTION_ARG_INT, &im__concurrency,
N_( "evaluate with N concurrent threads" ), "N" },
{ "vips-tile-width", 'c', 0, G_OPTION_ARG_INT, &im__tile_width,
{ "vips-tile-width", 'w', 0, G_OPTION_ARG_INT, &im__tile_width,
N_( "set tile width to N (DEBUG)" ), "N" },
{ "vips-tile-height", 'c', 0, G_OPTION_ARG_INT, &im__tile_height,
{ "vips-tile-height", 'h', 0, G_OPTION_ARG_INT, &im__tile_height,
N_( "set tile height to N (DEBUG)" ), "N" },
{ "vips-thinstrip-height", 'c', 0,
{ "vips-thinstrip-height", 't', 0,
G_OPTION_ARG_INT, &im__thinstrip_height,
N_( "set thinstrip height to N (DEBUG)" ), "N" },
{ "vips-fatstrip-height", 'c', 0,
{ "vips-fatstrip-height", 'f', 0,
G_OPTION_ARG_INT, &im__fatstrip_height,
N_( "set fatstrip height to N (DEBUG)" ), "N" },
{ "vips-progress", 'p', 0, G_OPTION_ARG_NONE, &im__progress,
N_( "show progress feedback" ), NULL },
{ NULL }
};

View File

@ -21,6 +21,8 @@
* - read via a buffer image so we work with mmap window images
* 27/11/06
* - merge threadgroup stuff
* 7/11/07
* - new eval start/progress/end system
*/
/*
@ -199,12 +201,12 @@ im_iterate( IMAGE *im,
{
IMAGE *t;
im_threadgroup_t *tg;
int res;
int result;
if( im_image_sanity( im ) )
return( -1 );
if( !(t = im_open( "im_iterate_buffer", "p" )) )
if( !(t = im_open( "iterate", "p" )) )
return( -1 );
if( im_copy( im, t ) ) {
im_close( t );
@ -223,10 +225,19 @@ im_iterate( IMAGE *im,
im_diagnostics( "im_iterate: using %d threads", tg->nthr );
#endif /*DEBUG_IO*/
res = iterate( tg, t, start, generate, stop, b, c );
/* Signal start of eval.
*/
if( im__start_eval( t ) )
return( -1 );
result = iterate( tg, t, start, generate, stop, b, c );
/* Signal end of eval.
*/
result |= im__end_eval( t );
im_threadgroup_free( tg );
im_close( t );
return( res );
return( result );
}

View File

@ -87,6 +87,9 @@ Modified:
* 20/9/06
* - test for NULL filename/mode, common if you forget to check argc
* (thanks bruno)
* 7/11/07
* - use preclose, not evalend, for delayed save
* - add simple cmd-line progress feedback
*/
/*
@ -163,6 +166,16 @@ static const char *im_suffix_csv[] = {
NULL
};
/* Progress feedback. Only really useful for testing, tbh.
*/
int im__progress = 0;
void
im_progress_set( int progress )
{
im__progress = progress;
}
/* Open a VIPS image and byte-swap the image data if necessary.
*/
static IMAGE *
@ -213,7 +226,7 @@ read_vips( const char *filename )
}
/* Delayed save: if we write to TIFF or to JPEG format, actually do the write
* to a "p" and on evalend do im_vips2tiff() or whatever. Track save
* to a "p" and on preclose do im_vips2tiff() or whatever. Track save
* parameters here.
*/
typedef struct {
@ -222,7 +235,7 @@ typedef struct {
char *filename; /* Save args */
} SaveBlock;
/* From evalend callback: invoke a delayed save.
/* From preclose callback: invoke a delayed save.
*/
static int
invoke_sb( SaveBlock *sb )
@ -246,7 +259,7 @@ attach_sb( IMAGE *out, int (*save_fn)(), const char *filename )
sb->save_fn = save_fn;
sb->filename = im_strdup( out, filename );
if( im_add_evalend_callback( out,
if( im_add_preclose_callback( out,
(im_callback_fn) invoke_sb, (void *) sb, NULL ) )
return( -1 );
@ -277,7 +290,7 @@ open_lazy_start( IMAGE *out, void *a, void *dummy )
OpenLazy *lazy = (OpenLazy *) a;
if( !lazy->lazy_im ) {
if( !(lazy->lazy_im = im_open_local( out, "olstart", "p" )) ||
if( !(lazy->lazy_im = im_open_local( out, "read", "p" )) ||
lazy->read_pixels( lazy->filename, lazy->lazy_im ) ) {
IM_FREEF( im_close, lazy->lazy_im );
return( NULL );
@ -349,6 +362,49 @@ open_sub( OpenLazyFn read_header, OpenLazyFn read_pixels, const char *filename )
return( im );
}
/* Progress feedback.
*/
/* What we track during an eval.
*/
typedef struct {
IMAGE *im;
int last_percent; /* The last %complete we displayed */
} Progress;
int
evalstart_cb( Progress *progress )
{
progress->last_percent = 0;
return( 0 );
}
int
eval_cb( Progress *progress )
{
IMAGE *im = progress->im;
if( im->time->percent != progress->last_percent ) {
printf( "%s: %d%% complete\r",
im->filename, im->time->percent );
fflush( stdout );
progress->last_percent = im->time->percent;
}
return( 0 );
}
int
evalend_cb( Progress *progress )
{
printf( "\n" );
return( 0 );
}
IMAGE *
im_open( const char *filename, const char *mode )
{
@ -478,7 +534,7 @@ im_open( const char *filename, const char *mode )
im = im_openout( filename );
else if( im_filename_suffix_match( filename,
im_suffix_tiff ) ) {
/* TIFF write. Save to a partial, and on evalend
/* TIFF write. Save to a partial, and on preclose
* im_vips2tiff from that.
*/
if( !(im = im_open( "im_open:vips2tiff:1", "p" )) )
@ -550,6 +606,20 @@ im_open( const char *filename, const char *mode )
return( NULL );
}
/* Attach progress feedback, if required.
*/
if( im__progress ) {
Progress *progress = IM_NEW( im, Progress );
progress->im = im;
im_add_evalstart_callback( im,
(im_callback_fn) evalstart_cb, progress, NULL );
im_add_eval_callback( im,
(im_callback_fn) eval_cb, progress, NULL );
im_add_evalend_callback( im,
(im_callback_fn) evalend_cb, progress, NULL );
}
#ifdef DEBUG_IO
printf( "im_open: success for %s (%p)\n", im->filename, im );
#endif /*DEBUG_IO*/

View File

@ -324,6 +324,10 @@ im_printdesc( IMAGE *image )
printf( "user eval callbacks attached\n" );
if( image->evalendfns )
printf( "user evalend callbacks attached\n" );
if( image->evalstartfns )
printf( "user evalstart callbacks attached\n" );
if( image->preclosefns )
printf( "user preclose callbacks attached\n" );
if( image->regions ) {
printf( "%d regions present\n",
g_slist_length( image->regions ) );

View File

@ -105,6 +105,7 @@ im_setupout( IMAGE *im )
printf( "im_setupout: old-style output for %s\n",
im->filename );
#endif /*DEBUG_IO*/
im->dtype = IM_SETBUF;
}

View File

@ -2,6 +2,8 @@
*
* 2/11/07
* - cut from im_generate
* 7/11/07
* - trigger start/end eval callbacks
*/
/*
@ -407,19 +409,22 @@ im_wbuffer( im_threadgroup_t *tg,
im_wbuffer_fn write_fn, void *a, void *b )
{
WriteBuffer *b1, *b2;
int result;
if( im__start_eval( tg->im ) )
return( -1 );
result = 0;
b1 = wbuffer_new( tg, write_fn, a, b );
b2 = wbuffer_new( tg, write_fn, a, b );
if( !b1 || !b2 || wbuffer_eval_to_file( b1, b2 ) ) {
IM_FREEF( wbuffer_free, b1 );
IM_FREEF( wbuffer_free, b2 );
return( -1 );
}
if( !b1 || !b2 || wbuffer_eval_to_file( b1, b2 ) )
result = -1;
im__end_eval( tg->im );
wbuffer_free( b1 );
wbuffer_free( b2 );
return( 0 );
return( result );
}

View File

@ -23,6 +23,8 @@
* - better error messages
* 31/10/03 JC
* - stop early on kill
* 7/11/07
* - add eval start/stop
*/
/*
@ -75,39 +77,52 @@
#endif /*WITH_DMALLOC*/
int
im_writeline( int ypos, IMAGE *image, PEL *linebuffer )
im_writeline( int ypos, IMAGE *im, PEL *linebuffer )
{
int linesize = IM_IMAGE_SIZEOF_LINE( image );
int linesize = IM_IMAGE_SIZEOF_LINE( im );
char *tmp;
/* Is this the start of eval?
*/
if( ypos == 0 )
im__start_eval( im );
/* Possible cases for output: FILE or SETBUF.
*/
switch( image->dtype ) {
switch( im->dtype ) {
case IM_SETBUF:
case IM_SETBUF_FOREIGN:
tmp = image->data + ypos * linesize;
tmp = im->data + ypos * linesize;
memcpy( tmp, linebuffer, linesize );
break;
case IM_OPENOUT:
if( im__write( image->fd, linebuffer, linesize ) )
/* Don't use ypos for this.
*/
if( im__write( im->fd, linebuffer, linesize ) )
return( -1 );
break;
default:
im_errormsg( "im_writeline: unable to output to a %s image",
im_dtype2char( image->dtype ) );
im_error( "im_writeline",
_( "unable to output to a %s image" ),
im_dtype2char( im->dtype ) );
return( -1 );
}
/* Trigger evaluation callbacks for this image.
*/
if( im__handle_eval( image, image->Xsize, 1 ) )
if( im__handle_eval( im, im->Xsize, 1 ) )
return( -1 );
if( im__test_kill( image ) )
if( im__test_kill( im ) )
return( -1 );
/* Is this the end of eval?
*/
if( ypos == im->Ysize - 1 )
im__end_eval( im );
return( 0 );
}

View File

@ -29,6 +29,10 @@
*/
/*
#define DEBUG
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /*HAVE_CONFIG_H*/
@ -50,6 +54,10 @@ int
im__time_destroy( IMAGE *im )
{
if( im->time ) {
#ifdef DEBUG
printf( "im__time_destroy: %s\n", im->filename );
#endif /*DEBUG*/
g_timer_destroy( im->time->start );
im_free( im->time );
im->time = NULL;
@ -69,6 +77,10 @@ time_add( IMAGE *im )
!(time = IM_NEW( NULL, im_time_t )) )
return( -1 );
#ifdef DEBUG
printf( "time_add: %s\n", im->filename );
#endif /*DEBUG*/
time->im = im;
time->start = g_timer_new();
time->run = 0;
@ -98,6 +110,28 @@ update_time( im_time_t *time, int w, int h )
return( 0 );
}
int
im__start_eval( IMAGE *im )
{
im_image_sanity( im );
if( im->progress ) {
#ifdef DEBUG
printf( "im__start_eval: %s\n", im->filename );
#endif /*DEBUG*/
im_image_sanity( im->progress );
if( time_add( im->progress ) )
return( -1 );
if( im__trigger_callbacks( im->progress->evalstartfns ) )
return( -1 );
}
return( 0 );
}
/* Handle eval callbacks. w and h are the size of the tile we made this time.
* We signal progress on the ->progress IMAGE, see im_add_eval_callback(). We
* assume there's no geometry change between adding the feedback request and
@ -107,14 +141,6 @@ int
im__handle_eval( IMAGE *im, int w, int h )
{
if( im->progress ) {
if( !im->progress->time ) {
/* So we just check sanity first time around.
*/
im_image_sanity( im->progress );
if( time_add( im->progress ) )
return( -1 );
}
if( update_time( im->progress->time, w, h ) )
return( -1 );
@ -124,3 +150,24 @@ im__handle_eval( IMAGE *im, int w, int h )
return( 0 );
}
int
im__end_eval( IMAGE *im )
{
im_image_sanity( im );
if( im->progress ) {
#ifdef DEBUG
printf( "im__end_eval: %s\n", im->filename );
#endif /*DEBUG*/
im_image_sanity( im->progress );
if( im__trigger_callbacks( im->progress->evalendfns ) )
return( -1 );
im__time_destroy( im->progress );
}
return( 0 );
}

View File

@ -974,7 +974,7 @@ local_mask( IMAGE *out, DOUBLEMASK *mask )
if( !mask )
return( NULL );
if( im_add_evalend_callback( out,
if( im_add_close_callback( out,
(im_callback_fn) im_free_dmask, mask, NULL ) ) {
im_free_dmask( mask );
return( NULL );