im_iterate() calls start from workers, added im_hist_indexed()
This commit is contained in:
parent
d99a4eea40
commit
cff79f403a
@ -59,6 +59,9 @@
|
||||
- im_generate() checks that im_demand_hint() has been called for this image
|
||||
- im_jpeg2vips.c, set scale_num on shrink (thanks Guido)
|
||||
- heh argh reading history always stopped after the first line (thanks Haida)
|
||||
- added im_histindexed
|
||||
- new im_iterate() calls start functions from workers so resources they make
|
||||
are owned by the worker thread
|
||||
|
||||
25/3/09 started 7.18.0
|
||||
- revised version numbers
|
||||
|
@ -9,6 +9,7 @@ libhistograms_lut_la_SOURCES = \
|
||||
im_histgr.c \
|
||||
im_histnD.c \
|
||||
im_histplot.c \
|
||||
im_histindexed.c \
|
||||
im_histspec.c \
|
||||
im_hsp.c \
|
||||
im_identity.c \
|
||||
|
@ -107,6 +107,31 @@ static im_function heq_desc = {
|
||||
heq_args /* Arg list */
|
||||
};
|
||||
|
||||
static im_arg_desc histindexed_args[] = {
|
||||
IM_INPUT_IMAGE( "index" ),
|
||||
IM_INPUT_IMAGE( "value" ),
|
||||
IM_OUTPUT_IMAGE( "out" )
|
||||
};
|
||||
|
||||
/* Call im_histindexed via arg vector.
|
||||
*/
|
||||
static int
|
||||
histindexed_vec( im_object *argv )
|
||||
{
|
||||
return( im_hist_indexed( argv[0], argv[1], argv[2] ) );
|
||||
}
|
||||
|
||||
/* Description of im_histindexed.
|
||||
*/
|
||||
static im_function histindexed_desc = {
|
||||
"im_hist_indexed", /* Name */
|
||||
"make a histogram with an index image", /* Description */
|
||||
IM_FN_PIO, /* Flags */
|
||||
histindexed_vec, /* Dispatch function */
|
||||
IM_NUMBER( histindexed_args ), /* Size of arg list */
|
||||
histindexed_args /* Arg list */
|
||||
};
|
||||
|
||||
/* Call im_hist via arg vector.
|
||||
*/
|
||||
static int
|
||||
@ -779,6 +804,7 @@ static im_function *hist_list[] = {
|
||||
&hist_desc,
|
||||
&histcum_desc,
|
||||
&histeq_desc,
|
||||
&histindexed_desc,
|
||||
&histgr_desc,
|
||||
&histnD_desc,
|
||||
&histnorm_desc,
|
||||
|
351
libvips/histograms_lut/im_histindexed.c
Normal file
351
libvips/histograms_lut/im_histindexed.c
Normal file
@ -0,0 +1,351 @@
|
||||
/* indexed histogram: use an index image to pick the bins
|
||||
*
|
||||
* 13/10/09
|
||||
* - from im_histgr.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
|
||||
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif /*HAVE_CONFIG_H*/
|
||||
#include <vips/intl.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <vips/vips.h>
|
||||
|
||||
#ifdef WITH_DMALLOC
|
||||
#include <dmalloc.h>
|
||||
#endif /*WITH_DMALLOC*/
|
||||
|
||||
/* Accumulate a histogram in one of these.
|
||||
*/
|
||||
typedef struct {
|
||||
IMAGE *index; /* Get bin number from here */
|
||||
IMAGE *value; /* Add values from here */
|
||||
IMAGE *out;
|
||||
|
||||
REGION *vreg; /* Get value pixels with this */
|
||||
|
||||
int bands; /* Number of bands in output */
|
||||
int size; /* Length of bins */
|
||||
int mx; /* Maximum value we have seen */
|
||||
double *bins; /* All the bins! */
|
||||
} Histogram;
|
||||
|
||||
/* Free a Histogram.
|
||||
*/
|
||||
static void
|
||||
hist_free( Histogram *hist )
|
||||
{
|
||||
IM_FREE( hist->bins );
|
||||
IM_FREEF( im_region_free, hist->vreg );
|
||||
IM_FREE( hist );
|
||||
}
|
||||
|
||||
/* Build a Histogram.
|
||||
*/
|
||||
static Histogram *
|
||||
hist_build( IMAGE *index, IMAGE *value, IMAGE *out, int bands, int size )
|
||||
{
|
||||
Histogram *hist;
|
||||
|
||||
if( !(hist = IM_NEW( NULL, Histogram )) )
|
||||
return( NULL );
|
||||
|
||||
hist->index = index;
|
||||
hist->value = value;
|
||||
hist->out = out;
|
||||
hist->vreg = NULL;
|
||||
hist->bands = bands;
|
||||
hist->size = size;
|
||||
hist->mx = 0;
|
||||
hist->bins = NULL;
|
||||
|
||||
if( !(hist->bins = IM_ARRAY( NULL, bands * size, double )) ||
|
||||
!(hist->vreg = im_region_create( value )) ) {
|
||||
hist_free( hist );
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
memset( hist->bins, 0, bands * size * sizeof( double ) );
|
||||
|
||||
return( hist );
|
||||
}
|
||||
|
||||
/* Build a sub-hist, based on the main hist.
|
||||
*/
|
||||
static void *
|
||||
hist_start( IMAGE *out, void *a, void *b )
|
||||
{
|
||||
Histogram *mhist = (Histogram *) a;
|
||||
|
||||
return( (void *)
|
||||
hist_build( mhist->index, mhist->value, mhist->out,
|
||||
mhist->bands, mhist->size ) );
|
||||
}
|
||||
|
||||
/* Join a sub-hist onto the main hist, then free it.
|
||||
*/
|
||||
static int
|
||||
hist_stop( void *seq, void *a, void *b )
|
||||
{
|
||||
Histogram *shist = (Histogram *) seq;
|
||||
Histogram *mhist = (Histogram *) a;
|
||||
int i;
|
||||
|
||||
g_assert( shist->bands == mhist->bands && shist->size == mhist->size );
|
||||
|
||||
/* Add on sub-data.
|
||||
*/
|
||||
mhist->mx = IM_MAX( mhist->mx, shist->mx );
|
||||
for( i = 0; i < mhist->bands * mhist->size; i++ )
|
||||
mhist->bins[i] += shist->bins[i];
|
||||
|
||||
hist_free( shist );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* Accumulate a buffer of pels, uchar index.
|
||||
*/
|
||||
#define ACCUMULATE_UCHAR( TYPE ) { \
|
||||
int x, z; \
|
||||
TYPE *tv = (TYPE *) v; \
|
||||
\
|
||||
for( x = 0; x < width; x++ ) { \
|
||||
double *bin = hist->bins + i[x] * bands; \
|
||||
\
|
||||
for( z = 0; z < bands; z++ ) \
|
||||
bin[z] += tv[z]; \
|
||||
\
|
||||
tv += bands; \
|
||||
} \
|
||||
}
|
||||
|
||||
/* A uchar index image.
|
||||
*/
|
||||
static int
|
||||
hist_scan_uchar( REGION *reg, void *seq, void *a, void *b )
|
||||
{
|
||||
Histogram *hist = (Histogram *) seq;
|
||||
Rect *r = ®->valid;
|
||||
IMAGE *value = hist->value;
|
||||
int bands = value->Bands;
|
||||
int width = r->width;
|
||||
|
||||
int y;
|
||||
|
||||
/* Need the correspondiing area of the value image.
|
||||
*/
|
||||
if( im_prepare( hist->vreg, r ) )
|
||||
return( -1 );
|
||||
|
||||
/* Accumulate!
|
||||
*/
|
||||
for( y = 0; y < r->height; y++ ) {
|
||||
PEL *i = (PEL *) IM_REGION_ADDR( reg, r->left, r->top + y );
|
||||
PEL *v = (PEL *) IM_REGION_ADDR( hist->vreg,
|
||||
r->left, r->top + y );
|
||||
|
||||
switch( value->BandFmt ) {
|
||||
case IM_BANDFMT_UCHAR:
|
||||
ACCUMULATE_UCHAR( unsigned char ); break;
|
||||
case IM_BANDFMT_CHAR:
|
||||
ACCUMULATE_UCHAR( signed char ); break;
|
||||
case IM_BANDFMT_USHORT:
|
||||
ACCUMULATE_UCHAR( unsigned short ); break;
|
||||
case IM_BANDFMT_SHORT:
|
||||
ACCUMULATE_UCHAR( signed short ); break;
|
||||
case IM_BANDFMT_UINT:
|
||||
ACCUMULATE_UCHAR( unsigned int ); break;
|
||||
case IM_BANDFMT_INT:
|
||||
ACCUMULATE_UCHAR( signed int ); break;
|
||||
case IM_BANDFMT_FLOAT:
|
||||
ACCUMULATE_UCHAR( float ); break;
|
||||
case IM_BANDFMT_DOUBLE:
|
||||
ACCUMULATE_UCHAR( double ); break;
|
||||
|
||||
default:
|
||||
g_assert( 0 );
|
||||
}
|
||||
}
|
||||
|
||||
/* Max is always 255.
|
||||
*/
|
||||
hist->mx = 255;
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* Accumulate a buffer of pels, ushort index.
|
||||
*/
|
||||
#define ACCUMULATE_USHORT( TYPE ) { \
|
||||
int x, z; \
|
||||
TYPE *tv = (TYPE *) v; \
|
||||
\
|
||||
for( x = 0; x < width; x++ ) { \
|
||||
int ix = i[x]; \
|
||||
double *bin = hist->bins + ix * bands; \
|
||||
\
|
||||
if( ix > mx ) \
|
||||
mx = ix; \
|
||||
\
|
||||
for( z = 0; z < bands; z++ ) \
|
||||
bin[z] += tv[z]; \
|
||||
\
|
||||
tv += bands; \
|
||||
} \
|
||||
}
|
||||
|
||||
/* A ushort index image.
|
||||
*/
|
||||
static int
|
||||
hist_scan_ushort( REGION *reg, void *seq, void *a, void *b )
|
||||
{
|
||||
Histogram *hist = (Histogram *) seq;
|
||||
Rect *r = ®->valid;
|
||||
IMAGE *value = hist->value;
|
||||
int bands = value->Bands;
|
||||
int width = r->width;
|
||||
|
||||
int y, mx;
|
||||
|
||||
/* Need the correspondiing area of the value image.
|
||||
*/
|
||||
if( im_prepare( hist->vreg, r ) )
|
||||
return( -1 );
|
||||
|
||||
/* Accumulate!
|
||||
*/
|
||||
mx = hist->mx;
|
||||
for( y = 0; y < r->height; y++ ) {
|
||||
unsigned short *i = (unsigned short *) IM_REGION_ADDR( reg,
|
||||
r->left, r->top + y );
|
||||
PEL *v = (PEL *) IM_REGION_ADDR( hist->vreg,
|
||||
r->left, r->top + y );
|
||||
|
||||
switch( value->BandFmt ) {
|
||||
case IM_BANDFMT_UCHAR:
|
||||
ACCUMULATE_USHORT( unsigned char ); break;
|
||||
case IM_BANDFMT_CHAR:
|
||||
ACCUMULATE_USHORT( signed char ); break;
|
||||
case IM_BANDFMT_USHORT:
|
||||
ACCUMULATE_USHORT( unsigned short ); break;
|
||||
case IM_BANDFMT_SHORT:
|
||||
ACCUMULATE_USHORT( signed short ); break;
|
||||
case IM_BANDFMT_UINT:
|
||||
ACCUMULATE_USHORT( unsigned int ); break;
|
||||
case IM_BANDFMT_INT:
|
||||
ACCUMULATE_USHORT( signed int ); break;
|
||||
case IM_BANDFMT_FLOAT:
|
||||
ACCUMULATE_USHORT( float ); break;
|
||||
case IM_BANDFMT_DOUBLE:
|
||||
ACCUMULATE_USHORT( double ); break;
|
||||
|
||||
default:
|
||||
g_assert( 0 );
|
||||
}
|
||||
}
|
||||
|
||||
/* Note the maximum.
|
||||
*/
|
||||
hist->mx = mx;
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static int
|
||||
hist_write( IMAGE *out, Histogram *hist )
|
||||
{
|
||||
if( im_cp_descv( out, hist->index, hist->value, NULL ) )
|
||||
return( -1 );
|
||||
im_initdesc( out,
|
||||
hist->mx + 1, 1, hist->value->Bands,
|
||||
IM_BBITS_DOUBLE, IM_BANDFMT_DOUBLE,
|
||||
IM_CODING_NONE, IM_TYPE_HISTOGRAM, 1.0, 1.0, 0, 0 );
|
||||
if( im_setupout( out ) )
|
||||
return( -1 );
|
||||
|
||||
if( im_writeline( 0, out, (PEL *) hist->bins ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int
|
||||
im_hist_indexed( IMAGE *index, IMAGE *value, IMAGE *out )
|
||||
{
|
||||
int size; /* Length of hist */
|
||||
Histogram *mhist;
|
||||
im_generate_fn scanfn;
|
||||
|
||||
/* Check images. PIO from in, WIO to out.
|
||||
*/
|
||||
if( im_pincheck( index ) ||
|
||||
im_pincheck( value ) ||
|
||||
im_outcheck( out ) ||
|
||||
im_check_uncoded( "im_hist_indexed", index ) ||
|
||||
im_check_uncoded( "im_hist_indexed", value ) ||
|
||||
im_check_noncomplex( "im_hist_indexed", value ) ||
|
||||
im_check_same_size( "im_hist_indexed", index, value ) ||
|
||||
im_check_u8or16( "im_hist_indexed", index ) ||
|
||||
im_check_mono( "im_hist_indexed", index ) )
|
||||
return( -1 );
|
||||
|
||||
/* Find the range of pixel values we must handle.
|
||||
*/
|
||||
if( index->BandFmt == IM_BANDFMT_UCHAR ) {
|
||||
size = 256;
|
||||
scanfn = hist_scan_uchar;
|
||||
}
|
||||
else {
|
||||
size = 65536;
|
||||
scanfn = hist_scan_ushort;
|
||||
}
|
||||
|
||||
/* Build main hist we accumulate data in.
|
||||
*/
|
||||
if( !(mhist = hist_build( index, value, out, value->Bands, size )) )
|
||||
return( -1 );
|
||||
|
||||
/* Accumulate data.
|
||||
*/
|
||||
if( im_iterate( index,
|
||||
hist_start, scanfn, hist_stop, mhist, NULL ) ||
|
||||
hist_write( out, mhist ) ) {
|
||||
hist_free( mhist );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
hist_free( mhist );
|
||||
|
||||
return( 0 );
|
||||
}
|
@ -52,6 +52,7 @@ int im_check_complex( const char *domain, IMAGE *im );
|
||||
int im_check_format( const char *domain, IMAGE *im, VipsBandFmt fmt );
|
||||
int im_check_mono( const char *domain, IMAGE *im );
|
||||
int im_check_int( const char *domain, IMAGE *im );
|
||||
int im_check_u8or16( const char *domain, IMAGE *im );
|
||||
int im_check_same_size( const char *domain, IMAGE *im1, IMAGE *im2 );
|
||||
int im_check_same_bands( const char *domain, IMAGE *im1, IMAGE *im2 );
|
||||
int im_check_same_format( const char *domain, IMAGE *im1, IMAGE *im2 );
|
||||
|
@ -210,6 +210,7 @@ int im_maplut( IMAGE *, IMAGE *, IMAGE * );
|
||||
int im_gammacorrect( IMAGE *, IMAGE *, double );
|
||||
int im_heq( IMAGE *in, IMAGE *out, int bandno );
|
||||
int im_hist( IMAGE *in, IMAGE *out, int bandno );
|
||||
int im_hist_indexed( IMAGE *index, IMAGE *value, IMAGE *out );
|
||||
int im_histeq( IMAGE *in, IMAGE *out );
|
||||
int im_histnorm( IMAGE *in, IMAGE *out );
|
||||
int im_histcum( IMAGE *in, IMAGE *out );
|
||||
|
@ -737,6 +737,31 @@ im_check_int( const char *domain, IMAGE *im )
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* im_check_u8or16:
|
||||
* @domain: the originating domain for the error message
|
||||
* @im: image to check
|
||||
*
|
||||
* Check that the image is 8 or 16-bit unsigned integer.
|
||||
* Otherwise set an error message
|
||||
* and return non-zero.
|
||||
*
|
||||
* Returns: 0 if OK, -1 otherwise.
|
||||
*
|
||||
* See also: im_error().
|
||||
*/
|
||||
int
|
||||
im_check_u8or16( const char *domain, IMAGE *im )
|
||||
{
|
||||
if( im->BandFmt != IM_BANDFMT_UCHAR &&
|
||||
im->BandFmt != IM_BANDFMT_USHORT ) {
|
||||
im_error( domain, "%s",
|
||||
_( "image must be 8- or 16-bit unsigned integer" ) );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* im_check_same_size:
|
||||
@ -966,7 +991,6 @@ im_isscalar( IMAGE *im )
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* im_iscomplex:
|
||||
* @im: image to test
|
||||
|
@ -73,10 +73,144 @@
|
||||
#include <dmalloc.h>
|
||||
#endif /*WITH_DMALLOC*/
|
||||
|
||||
/* Track this stuff during an im_iterate().
|
||||
*/
|
||||
typedef struct _Iterate {
|
||||
IMAGE *im;
|
||||
|
||||
/* We need a temp "p" image between the source image and us to
|
||||
* make sure we can't damage the original.
|
||||
*/
|
||||
IMAGE *t;
|
||||
|
||||
/* Store our sequence values in tg->thr[i]->a. The seq values in the
|
||||
* regions are used by the im_copy() to t.
|
||||
*/
|
||||
im_threadgroup_t *tg;
|
||||
|
||||
im_start_fn start;
|
||||
im_generate_fn generate;
|
||||
im_stop_fn stop;
|
||||
void *b;
|
||||
void *c;
|
||||
} Iterate;
|
||||
|
||||
/* Call all stop functions.
|
||||
*/
|
||||
static int
|
||||
iterate_call_all_stop( Iterate *iter, im_threadgroup_t *tg )
|
||||
{
|
||||
int i;
|
||||
|
||||
for( i = 0; i < tg->nthr; i++ ) {
|
||||
if( tg->thr[i]->a && iter->stop ) {
|
||||
if( iter->stop( tg->thr[i]->a, iter->b, iter->c ) )
|
||||
/* Drastic!
|
||||
*/
|
||||
im_error( "im_iterate",
|
||||
_( "stop function failed "
|
||||
"for image \"%s\"" ),
|
||||
iter->im->filename );
|
||||
tg->thr[i]->a = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static void
|
||||
iterate_free( Iterate *iter )
|
||||
{
|
||||
/* Check all the stop functions have been called.
|
||||
*/
|
||||
if( iter->tg ) {
|
||||
int i;
|
||||
|
||||
for( i = 0; i < iter->tg->nthr; i++ )
|
||||
g_assert( !iter->tg->thr[i]->a );
|
||||
}
|
||||
|
||||
IM_FREEF( im_threadgroup_free, iter->tg );
|
||||
IM_FREEF( im_close, iter->t );
|
||||
}
|
||||
|
||||
/* Call the start function for this thread, if necessary.
|
||||
*/
|
||||
static int
|
||||
iterate_call_start( Iterate *iter, im_thread_t *thr )
|
||||
{
|
||||
if( !thr->a && iter->start ) {
|
||||
g_mutex_lock( iter->t->sslock );
|
||||
thr->a = iter->start( iter->t, iter->b, iter->c );
|
||||
g_mutex_unlock( iter->t->sslock );
|
||||
|
||||
if( !thr->a ) {
|
||||
im_error( "im_iterate",
|
||||
_( "start function failed for image \"%s\"" ),
|
||||
iter->im->filename );
|
||||
return( -1 );
|
||||
}
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* Our generate function. We need to call the user's start function from the
|
||||
* worker thread so that any regions it makes are owned by the thread.
|
||||
*/
|
||||
static int
|
||||
iterate_gen( REGION *reg, void *seq, void *a, void *b )
|
||||
{
|
||||
Iterate *iter = (Iterate *) a;
|
||||
im_thread_t *thr = (im_thread_t *) b;
|
||||
|
||||
/* Make sure the start function has run and we have the sequence value
|
||||
* set.
|
||||
*/
|
||||
iterate_call_start( iter, thr );
|
||||
seq = thr->a;
|
||||
|
||||
return( iter->generate( reg, seq, iter->b, iter->c ) );
|
||||
}
|
||||
|
||||
static int
|
||||
iterate_init( Iterate *iter,
|
||||
IMAGE *im,
|
||||
im_start_fn start, im_generate_fn generate, im_stop_fn stop,
|
||||
void *b, void *c )
|
||||
{
|
||||
iter->im = im;
|
||||
iter->t = NULL;
|
||||
iter->tg = NULL;
|
||||
iter->start = start;
|
||||
iter->generate = generate;
|
||||
iter->stop = stop;
|
||||
iter->b = b;
|
||||
iter->c = c;
|
||||
|
||||
if( !(iter->t = im_open( "iterate", "p" )) ||
|
||||
im_copy( iter->im, iter->t ) ||
|
||||
!(iter->tg = im_threadgroup_create( iter->t )) ) {
|
||||
iterate_free( iter );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
iter->tg->work = iterate_gen;
|
||||
iter->tg->inplace = 0;
|
||||
|
||||
#ifdef DEBUG_IO
|
||||
if( iter->tg->nthr > 1 )
|
||||
im_diagnostics( "im_iterate: using %d threads",
|
||||
iter->tg->nthr );
|
||||
#endif /*DEBUG_IO*/
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* Loop over an image, preparing in parts with threads.
|
||||
*/
|
||||
static int
|
||||
eval_to_image( im_threadgroup_t *tg, IMAGE *im )
|
||||
iterate_loop( Iterate *iter, im_threadgroup_t *tg, IMAGE *t )
|
||||
{
|
||||
int x, y;
|
||||
Rect image;
|
||||
@ -87,13 +221,13 @@ eval_to_image( im_threadgroup_t *tg, IMAGE *im )
|
||||
|
||||
image.left = 0;
|
||||
image.top = 0;
|
||||
image.width = im->Xsize;
|
||||
image.height = im->Ysize;
|
||||
image.width = t->Xsize;
|
||||
image.height = t->Ysize;
|
||||
|
||||
/* Loop over or, attaching to all sub-parts in turn.
|
||||
*/
|
||||
for( y = 0; y < im->Ysize; y += tg->ph )
|
||||
for( x = 0; x < im->Xsize; x += tg->pw ) {
|
||||
for( y = 0; y < t->Ysize; y += tg->ph )
|
||||
for( x = 0; x < t->Xsize; x += tg->pw ) {
|
||||
im_thread_t *thr;
|
||||
Rect pos;
|
||||
Rect clipped;
|
||||
@ -114,6 +248,11 @@ eval_to_image( im_threadgroup_t *tg, IMAGE *im )
|
||||
|
||||
thr->pos = clipped;
|
||||
|
||||
/* Other stuff we want passed to iterate_gen().
|
||||
*/
|
||||
thr->b = iter;
|
||||
thr->c = thr;
|
||||
|
||||
/* Start worker going.
|
||||
*/
|
||||
im_threadgroup_trigger( thr );
|
||||
@ -121,7 +260,7 @@ eval_to_image( im_threadgroup_t *tg, IMAGE *im )
|
||||
/* Trigger any eval callbacks on our source image,
|
||||
* check for errors.
|
||||
*/
|
||||
if( im__handle_eval( im, tg->pw, tg->ph ) ||
|
||||
if( im__handle_eval( t, tg->pw, tg->ph ) ||
|
||||
im_threadgroup_iserror( tg ) ) {
|
||||
/* Don't kill threads yet ... we may want to
|
||||
* get some error stuff out of them.
|
||||
@ -143,56 +282,6 @@ eval_to_image( im_threadgroup_t *tg, IMAGE *im )
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static int
|
||||
iterate( im_threadgroup_t *tg, IMAGE *im,
|
||||
im_start_fn start, im_generate_fn generate, im_stop_fn stop,
|
||||
void *b, void *c )
|
||||
{
|
||||
int i;
|
||||
int res;
|
||||
|
||||
#ifdef DEBUG_IO
|
||||
if( tg && tg->nthr > 1 )
|
||||
im_diagnostics( "im_iterate: using %d threads", tg->nthr );
|
||||
#endif /*DEBUG_IO*/
|
||||
|
||||
/* Call all the start functions, and pop in the sequence values.
|
||||
*/
|
||||
for( i = 0; i < tg->nthr; i++ ) {
|
||||
if( start && !(tg->thr[i]->a = start( im, b, c )) ) {
|
||||
im_error( "im_iterate",
|
||||
_( "start function failed for image \"%s\"" ),
|
||||
im->filename );
|
||||
return( -1 );
|
||||
}
|
||||
tg->thr[i]->b = b;
|
||||
tg->thr[i]->c = c;
|
||||
}
|
||||
|
||||
/* Loop and generate multi-thread.
|
||||
*/
|
||||
res = eval_to_image( tg, im );
|
||||
|
||||
/* Call all stop functions.
|
||||
*/
|
||||
for( i = 0; i < tg->nthr; i++ ) {
|
||||
if( tg->thr[i]->a && stop ) {
|
||||
/* Trigger the stop function.
|
||||
*/
|
||||
if( stop( tg->thr[i]->a, b, c ) )
|
||||
/* Drastic!
|
||||
*/
|
||||
im_error( "im_iterate",
|
||||
_( "stop function failed "
|
||||
"for image \"%s\"" ),
|
||||
im->filename );
|
||||
tg->thr[i]->a = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return( res );
|
||||
}
|
||||
|
||||
/**
|
||||
* im_iterate:
|
||||
* @im: scan over this image
|
||||
@ -215,44 +304,30 @@ im_iterate( IMAGE *im,
|
||||
im_start_fn start, im_generate_fn generate, im_stop_fn stop,
|
||||
void *b, void *c )
|
||||
{
|
||||
IMAGE *t;
|
||||
im_threadgroup_t *tg;
|
||||
Iterate iter;
|
||||
int result;
|
||||
|
||||
g_assert( !im_image_sanity( im ) );
|
||||
|
||||
if( !(t = im_open( "iterate", "p" )) )
|
||||
if( iterate_init( &iter, im, start, generate, stop, b, c ) )
|
||||
return( -1 );
|
||||
if( im_copy( im, t ) ) {
|
||||
im_close( t );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
if( !(tg = im_threadgroup_create( t )) ) {
|
||||
im_close( t );
|
||||
return( -1 );
|
||||
}
|
||||
tg->work = generate;
|
||||
tg->inplace = 0;
|
||||
|
||||
#ifdef DEBUG_IO
|
||||
if( tg && tg->nthr > 1 )
|
||||
im_diagnostics( "im_iterate: using %d threads", tg->nthr );
|
||||
#endif /*DEBUG_IO*/
|
||||
|
||||
/* Signal start of eval.
|
||||
*/
|
||||
if( im__start_eval( t ) )
|
||||
if( im__start_eval( iter.t ) ) {
|
||||
iterate_free( &iter );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
result = iterate( tg, t, start, generate, stop, b, c );
|
||||
/* Loop and generate multi-thread.
|
||||
*/
|
||||
result = iterate_loop( &iter, iter.tg, iter.t );
|
||||
|
||||
/* Signal end of eval.
|
||||
*/
|
||||
result |= im__end_eval( t );
|
||||
|
||||
im_threadgroup_free( tg );
|
||||
im_close( t );
|
||||
result |= im__end_eval( iter.t );
|
||||
result |= iterate_call_all_stop( &iter, iter.tg );
|
||||
iterate_free( &iter );
|
||||
|
||||
return( result );
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user