new progress feedback system
This commit is contained in:
parent
a65cfcd884
commit
bc84d2ce57
@ -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
4
TODO
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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 * );
|
||||
|
||||
|
@ -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 * );
|
||||
|
@ -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.
|
||||
|
@ -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 );
|
||||
|
@ -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.
|
||||
|
@ -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 );
|
||||
|
@ -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 );
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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 *
|
||||
|
@ -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 );
|
||||
|
||||
|
@ -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 )
|
||||
|
@ -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 );
|
||||
|
@ -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 }
|
||||
};
|
||||
|
||||
|
@ -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 );
|
||||
}
|
||||
|
@ -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*/
|
||||
|
@ -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 ) );
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 );
|
||||
}
|
||||
|
@ -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 );
|
||||
}
|
||||
|
@ -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 );
|
||||
}
|
||||
|
@ -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 );
|
||||
|
Loading…
Reference in New Issue
Block a user