From e14c5607b1948c574822a1415434b08c872e87c3 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Sun, 30 Oct 2011 18:31:45 +0000 Subject: [PATCH] refactor ready for unary arithmetic move most of the logic in binary.c into arithmetic.c ready to share with unary --- TODO | 22 +-- libvips/arithmetic/add.c | 23 ++- libvips/arithmetic/arithmetic.c | 295 +++++++++++++++++++++++++++++- libvips/arithmetic/arithmetic.h | 18 +- libvips/arithmetic/binary.c | 281 +--------------------------- libvips/arithmetic/binary.h | 26 +-- libvips/arithmetic/subtract.c | 18 +- libvips/include/vips/arithmetic.h | 2 +- 8 files changed, 344 insertions(+), 341 deletions(-) diff --git a/TODO b/TODO index 48c069bc..6f194817 100644 --- a/TODO +++ b/TODO @@ -1,4 +1,14 @@ +- lintra_vec next + + so we need a unary.c .. easy copy frombinary.c now that most of binary has + moved into arithmetic + + + + + + - try: $ vips insert Gugg_coloured.jpg x.jpg x.v 100 100 --expand --background "1 2 3" @@ -29,18 +39,6 @@ vips__vector_to_ink: ink = 0x177d660 (0 0 0) -- lintra_vec next - - get rid of binary.c, instead have a general 'pointwise' class which takes - any number of input images and runs a buffer-processing function over them - - fold binary.c into arithmetic.c - - VipsArithmetic has a "number of input images" thing set by subclasses, cf. - format_table - - proper likes "left" and "right" created by subclasses - diff --git a/libvips/arithmetic/add.c b/libvips/arithmetic/add.c index b8e53481..f4677d40 100644 --- a/libvips/arithmetic/add.c +++ b/libvips/arithmetic/add.c @@ -172,19 +172,19 @@ typedef VipsBinaryClass VipsAddClass; G_DEFINE_TYPE( VipsAdd, vips_add, VIPS_TYPE_BINARY ); #define LOOP( IN, OUT ) { \ - IN *p1 = (IN *) left; \ - IN *p2 = (IN *) right; \ + IN *left = (IN *) in[0]; \ + IN *right = (IN *) in[1]; \ OUT *q = (OUT *) out; \ \ for( x = 0; x < sz; x++ ) \ - q[x] = p1[x] + p2[x]; \ + q[x] = left[x] + right[x]; \ } static void -add_buffer( VipsBinary *binary, PEL *out, PEL *left, PEL *right, int width ) +add_buffer( VipsArithmetic *arithmetic, PEL *out, PEL **in, int width ) { - VipsArithmeticClass *class = VIPS_ARITHMETIC_GET_CLASS( binary ); - VipsImage *im = binary->left_processed; + VipsArithmeticClass *class = VIPS_ARITHMETIC_GET_CLASS( arithmetic ); + VipsImage *im = arithmetic->ready[0]; /* Complex just doubles the size. */ @@ -199,8 +199,8 @@ add_buffer( VipsBinary *binary, PEL *out, PEL *left, PEL *right, int width ) VipsExecutor ex; vips_executor_set_program( &ex, v, sz ); - vips_executor_set_array( &ex, v->s[0], left ); - vips_executor_set_array( &ex, v->s[1], right ); + vips_executor_set_array( &ex, v->s[0], in[0] ); + vips_executor_set_array( &ex, v->s[1], in[1] ); vips_executor_set_destination( &ex, out ); vips_executor_run( &ex ); @@ -265,7 +265,6 @@ vips_add_class_init( VipsAddClass *class ) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsArithmeticClass *aclass = VIPS_ARITHMETIC_CLASS( class ); - VipsBinaryClass *bclass = VIPS_BINARY_CLASS( class ); VipsVector *v; object_class->nickname = "add"; @@ -309,7 +308,7 @@ vips_add_class_init( VipsAddClass *class ) vips_arithmetic_compile( aclass ); - bclass->process_line = add_buffer; + aclass->process_line = add_buffer; } static void @@ -318,13 +317,13 @@ vips_add_init( VipsAdd *add ) } int -vips_add( VipsImage *in1, VipsImage *in2, VipsImage **out, ... ) +vips_add( VipsImage *left, VipsImage *right, VipsImage **out, ... ) { va_list ap; int result; va_start( ap, out ); - result = vips_call_split( "add", ap, in1, in2, out ); + result = vips_call_split( "add", ap, left, right, out ); va_end( ap ); return( result ); diff --git a/libvips/arithmetic/arithmetic.c b/libvips/arithmetic/arithmetic.c index 3cd9cb68..579a578c 100644 --- a/libvips/arithmetic/arithmetic.c +++ b/libvips/arithmetic/arithmetic.c @@ -1,8 +1,8 @@ /* base class for all arithmetic operations * * properties: - * - unary, binary or binary with one arg a constant - * - cast binary args to match + * - one output image, one or more inputs + * - cast input images to match * - output is large enough to hold output values (value preserving) * - point-to-point operations (ie. each pixel depends only on the * corresponding pixel in the input) @@ -55,10 +55,249 @@ G_DEFINE_ABSTRACT_TYPE( VipsArithmetic, vips_arithmetic, VIPS_TYPE_OPERATION ); +/* Save a bit of typing. + */ +#define UC VIPS_FORMAT_UCHAR +#define C VIPS_FORMAT_CHAR +#define US VIPS_FORMAT_USHORT +#define S VIPS_FORMAT_SHORT +#define UI VIPS_FORMAT_UINT +#define I VIPS_FORMAT_INT +#define F VIPS_FORMAT_FLOAT +#define X VIPS_FORMAT_COMPLEX +#define D VIPS_FORMAT_DOUBLE +#define DX VIPS_FORMAT_DPCOMPLEX + +/* For two integer types, the "largest", ie. one which can represent the + * full range of both. + */ +static VipsBandFormat format_largest[6][6] = { + /* UC C US S UI I */ +/* UC */ { UC, S, US, S, UI, I }, +/* C */ { S, C, I, S, I, I }, +/* US */ { US, I, US, I, UI, I }, +/* S */ { S, S, I, S, I, I }, +/* UI */ { UI, I, UI, I, UI, I }, +/* I */ { I, I, I, I, I, I } +}; + +/* For two formats, find one which can represent the full range of both. + */ +static VipsBandFormat +vips_format_common( VipsBandFormat a, VipsBandFormat b ) +{ + if( vips_band_format_iscomplex( a ) || + vips_band_format_iscomplex( b ) ) { + if( a == VIPS_FORMAT_DPCOMPLEX || + b == VIPS_FORMAT_DPCOMPLEX ) + return( VIPS_FORMAT_DPCOMPLEX ); + else + return( VIPS_FORMAT_COMPLEX ); + + } + else if( vips_band_format_isfloat( a ) || + vips_band_format_isfloat( b ) ) { + if( a == VIPS_FORMAT_DOUBLE || + b == VIPS_FORMAT_DOUBLE ) + return( VIPS_FORMAT_DOUBLE ); + else + return( VIPS_FORMAT_FLOAT ); + } + else + return( format_largest[a][b] ); +} + +int +vips__formatalike_vec( VipsImage **in, VipsImage **out, int n ) +{ + int i; + VipsBandFormat format; + + g_assert( n >= 1 ); + + format = in[0]->BandFmt; + for( i = 1; i < n; i++ ) + format = vips_format_common( format, in[i]->BandFmt ); + + for( i = 0; i < n; i++ ) + if( vips_cast( in[i], &out[i], format, NULL ) ) + return( -1 ); + + return( 0 ); +} + +int +vips__sizealike_vec( VipsImage **in, VipsImage **out, int n ) +{ + int i; + int width_max; + int height_max; + + g_assert( n >= 1 ); + + width_max = in[0]->Xsize; + height_max = in[0]->Ysize; + for( i = 1; i < n; i++ ) { + width_max = VIPS_MAX( width_max, in[i]->Xsize ); + height_max = VIPS_MAX( height_max, in[i]->Ysize ); + } + + for( i = 0; i < n; i++ ) + if( vips_embed( in[i], &out[i], + 0, 0, width_max, height_max, NULL ) ) + return( -1 ); + + return( 0 ); +} + +/* Make an n-band image. Input 1 or n bands. + */ +int +vips__bandup( const char *domain, VipsImage *in, VipsImage **out, int n ) +{ + VipsImage *bands[256]; + int i; + + if( in->Bands == n ) + return( vips_copy( in, out, NULL ) ); + if( in->Bands != 1 ) { + vips_error( domain, _( "not one band or %d bands" ), n ); + return( -1 ); + } + if( n > 256 || n < 1 ) { + im_error( domain, "%s", _( "bad bands" ) ); + return( -1 ); + } + + for( i = 0; i < n; i++ ) + bands[i] = in; + + return( vips_bandjoin( bands, out, n, NULL ) ); +} + +int +vips__bandalike_vec( const char *domain, + VipsImage **in, VipsImage **out, int n ) +{ + int i; + int max_bands; + + g_assert( n >= 1 ); + + max_bands = in[0]->Bands; + for( i = 1; i < n; i++ ) + max_bands = VIPS_MAX( max_bands, in[i]->Bands ); + for( i = 0; i < n; i++ ) + if( vips__bandup( domain, in[i], &out[i], max_bands ) ) + return( -1 ); + + return( 0 ); +} + +int +vips__formatalike( VipsImage *in1, VipsImage *in2, + VipsImage **out1, VipsImage **out2 ) +{ + IMAGE *in[2]; + IMAGE *out[2]; + + in[0] = in1; + in[1] = in2; + + if( vips__formatalike_vec( in, out, 2 ) ) + return( -1 ); + + *out1 = out[0]; + *out2 = out[1]; + + return( 0 ); +} + +int +vips__sizealike( VipsImage *in1, VipsImage *in2, + VipsImage **out1, VipsImage **out2 ) +{ + IMAGE *in[2]; + IMAGE *out[2]; + + in[0] = in1; + in[1] = in2; + + if( vips__sizealike_vec( in, out, 2 ) ) + return( -1 ); + + *out1 = out[0]; + *out2 = out[1]; + + return( 0 ); +} + +int +vips__bandalike( const char *domain, + VipsImage *in1, VipsImage *in2, VipsImage **out1, VipsImage **out2 ) +{ + VipsImage *in[2]; + VipsImage *out[2]; + + in[0] = in1; + in[1] = in2; + + if( vips__bandalike_vec( domain, in, out, 2 ) ) + return( -1 ); + + *out1 = out[0]; + *out2 = out[1]; + + return( 0 ); +} + +/* Maximum number of input images -- why not? + */ +#define MAX_INPUT_IMAGES (64) + +static int +vips_arithmetic_gen( VipsRegion *or, + void *seq, void *a, void *b, gboolean *stop ) +{ + VipsRegion **ir = (VipsRegion **) seq; + VipsArithmetic *arithmetic = VIPS_ARITHMETIC( b ); + VipsArithmeticClass *class = VIPS_ARITHMETIC_GET_CLASS( arithmetic ); + + PEL *p[MAX_INPUT_IMAGES], *q; + int i, y; + + /* Prepare all input regions and make buffer pointers. + */ + for( i = 0; ir[i]; i++ ) { + if( vips_region_prepare( ir[i], &or->valid ) ) + return( -1 ); + p[i] = (PEL *) VIPS_REGION_ADDR( ir[i], + or->valid.left, or->valid.top ); + } + p[i] = NULL; + q = (PEL *) VIPS_REGION_ADDR( or, or->valid.left, or->valid.top ); + + for( y = 0; y < or->valid.height; y++ ) { + class->process_line( arithmetic, q, p, or->valid.width ); + + for( i = 0; ir[i]; i++ ) + p[i] += VIPS_REGION_LSKIP( ir[i] ); + q += VIPS_REGION_LSKIP( or ); + } + + return( 0 ); +} + static int vips_arithmetic_build( VipsObject *object ) { VipsArithmetic *arithmetic = VIPS_ARITHMETIC( object ); + VipsArithmeticClass *aclass = VIPS_ARITHMETIC_GET_CLASS( arithmetic ); + + VipsImage **format; + VipsImage **band; + VipsImage **size; + int i; #ifdef DEBUG printf( "vips_arithmetic_build: " ); @@ -71,6 +310,53 @@ vips_arithmetic_build( VipsObject *object ) if( VIPS_OBJECT_CLASS( vips_arithmetic_parent_class )->build( object ) ) return( -1 ); + if( arithmetic->n > MAX_INPUT_IMAGES ) { + vips_error( "VipsArithmetic", + "%s", _( "too many input images" ) ); + return( -1 ); + } + for( i = 0; i < arithmetic->n; i++ ) + if( vips_image_pio_input( arithmetic->in[i] ) || + vips_check_bands_1orn( "VipsArithmetic", + arithmetic->in[0], arithmetic->in[i] ) || + vips_check_uncoded( "VipsArithmetic", + arithmetic->in[i] ) ) + return( -1 ); + if( vips_image_pio_output( arithmetic->out ) ) + return( -1 ); + + format = (VipsImage **) + vips_object_local_array( object, arithmetic->n ); + band = (VipsImage **) + vips_object_local_array( object, arithmetic->n ); + size = (VipsImage **) + vips_object_local_array( object, arithmetic->n ); + + /* Cast our input images up to a common format, bands and size. + */ + if( vips__formatalike_vec( arithmetic->in, format, arithmetic->n ) || + vips__bandalike_vec( "VipsArithmetic", + format, band, arithmetic->n ) || + vips__sizealike_vec( band, size, arithmetic->n ) ) + return( -1 ); + + /* Keep a copy of the processed images here for subclasses. + */ + arithmetic->ready = size; + + if( vips_image_copy_fields_array( arithmetic->out, size ) ) + return( -1 ); + vips_demand_hint_array( arithmetic->out, + VIPS_DEMAND_STYLE_THINSTRIP, size ); + + arithmetic->out->Bands = size[0]->Bands; + arithmetic->out->BandFmt = aclass->format_table[size[0]->BandFmt]; + + if( vips_image_generate( arithmetic->out, + vips_start_many, vips_arithmetic_gen, vips_stop_many, + arithmetic->ready, arithmetic ) ) + return( -1 ); + #ifdef DEBUG printf( "vips_arithmetic_build: booltest = %d\n", arithmetic->booltest ); @@ -98,7 +384,10 @@ vips_arithmetic_class_init( VipsArithmeticClass *class ) _( "Output" ), _( "Output image" ), VIPS_ARGUMENT_REQUIRED_OUTPUT, - G_STRUCT_OFFSET( VipsArithmetic, output ) ); + G_STRUCT_OFFSET( VipsArithmetic, out ) ); + + /* Just for testing. + */ VIPS_ARG_BOOL( class, "booltest", 1, _( "Bool test" ), diff --git a/libvips/arithmetic/arithmetic.h b/libvips/arithmetic/arithmetic.h index 37bbd0b6..e6be41b2 100644 --- a/libvips/arithmetic/arithmetic.h +++ b/libvips/arithmetic/arithmetic.h @@ -55,18 +55,30 @@ extern "C" { (G_TYPE_INSTANCE_GET_CLASS( (obj), \ VIPS_TYPE_ARITHMETIC, VipsArithmeticClass )) +struct _VipsArithmetic; +typedef void (*VipsArithmeticProcessFn)( struct _VipsArithmetic *arithmetic, + PEL *out, PEL **in, int width ); + typedef struct _VipsArithmetic { VipsOperation parent_instance; /* All have an output image. */ - VipsImage *output; + VipsImage *out; /* Optional bool argument for testing. */ gboolean booltest; VipsImage *imtest; + /* Array of input arguments, set these from a subclass. + */ + VipsImage **in; + int n; + + /* The input images, ready for the operation. + */ + VipsImage **ready; } VipsArithmetic; typedef struct _VipsArithmeticClass { @@ -84,6 +96,10 @@ typedef struct _VipsArithmeticClass { /* ... and if we've set a program for this format. */ gboolean vector_program[VIPS_FORMAT_LAST]; + + /* The buffer processor. + */ + VipsArithmeticProcessFn process_line; } VipsArithmeticClass; GType vips_arithmetic_get_type( void ); diff --git a/libvips/arithmetic/binary.c b/libvips/arithmetic/binary.c index 01e9312d..ce179363 100644 --- a/libvips/arithmetic/binary.c +++ b/libvips/arithmetic/binary.c @@ -52,293 +52,20 @@ G_DEFINE_ABSTRACT_TYPE( VipsBinary, vips_binary, VIPS_TYPE_ARITHMETIC ); -/* Save a bit of typing. - */ -#define UC VIPS_FORMAT_UCHAR -#define C VIPS_FORMAT_CHAR -#define US VIPS_FORMAT_USHORT -#define S VIPS_FORMAT_SHORT -#define UI VIPS_FORMAT_UINT -#define I VIPS_FORMAT_INT -#define F VIPS_FORMAT_FLOAT -#define X VIPS_FORMAT_COMPLEX -#define D VIPS_FORMAT_DOUBLE -#define DX VIPS_FORMAT_DPCOMPLEX - -/* For two integer types, the "largest", ie. one which can represent the - * full range of both. - */ -static VipsBandFormat format_largest[6][6] = { - /* UC C US S UI I */ -/* UC */ { UC, S, US, S, UI, I }, -/* C */ { S, C, I, S, I, I }, -/* US */ { US, I, US, I, UI, I }, -/* S */ { S, S, I, S, I, I }, -/* UI */ { UI, I, UI, I, UI, I }, -/* I */ { I, I, I, I, I, I } -}; - -/* For two formats, find one which can represent the full range of both. - */ -static VipsBandFormat -vips_format_common( VipsBandFormat a, VipsBandFormat b ) -{ - if( vips_band_format_iscomplex( a ) || - vips_band_format_iscomplex( b ) ) { - if( a == VIPS_FORMAT_DPCOMPLEX || - b == VIPS_FORMAT_DPCOMPLEX ) - return( VIPS_FORMAT_DPCOMPLEX ); - else - return( VIPS_FORMAT_COMPLEX ); - - } - else if( vips_band_format_isfloat( a ) || - vips_band_format_isfloat( b ) ) { - if( a == VIPS_FORMAT_DOUBLE || - b == VIPS_FORMAT_DOUBLE ) - return( VIPS_FORMAT_DOUBLE ); - else - return( VIPS_FORMAT_FLOAT ); - } - else - return( format_largest[a][b] ); -} - -int -vips__formatalike_vec( VipsImage **in, VipsImage **out, int n ) -{ - int i; - VipsBandFormat format; - - g_assert( n >= 1 ); - - format = in[0]->BandFmt; - for( i = 1; i < n; i++ ) - format = vips_format_common( format, in[i]->BandFmt ); - - for( i = 0; i < n; i++ ) - if( vips_cast( in[i], &out[i], format, NULL ) ) - return( -1 ); - - return( 0 ); -} - -int -vips__sizealike_vec( VipsImage **in, VipsImage **out, int n ) -{ - int i; - int width_max; - int height_max; - - g_assert( n >= 1 ); - - width_max = in[0]->Xsize; - height_max = in[0]->Ysize; - for( i = 1; i < n; i++ ) { - width_max = VIPS_MAX( width_max, in[i]->Xsize ); - height_max = VIPS_MAX( height_max, in[i]->Ysize ); - } - - for( i = 0; i < n; i++ ) - if( vips_embed( in[i], &out[i], - 0, 0, width_max, height_max, NULL ) ) - return( -1 ); - - return( 0 ); -} - -/* Make an n-band image. Input 1 or n bands. - */ -int -vips__bandup( const char *domain, VipsImage *in, VipsImage **out, int n ) -{ - VipsImage *bands[256]; - int i; - - if( in->Bands == n ) - return( vips_copy( in, out, NULL ) ); - if( in->Bands != 1 ) { - vips_error( domain, _( "not one band or %d bands" ), n ); - return( -1 ); - } - if( n > 256 || n < 1 ) { - im_error( domain, "%s", _( "bad bands" ) ); - return( -1 ); - } - - for( i = 0; i < n; i++ ) - bands[i] = in; - - return( vips_bandjoin( bands, out, n, NULL ) ); -} - -int -vips__bandalike_vec( const char *domain, - VipsImage **in, VipsImage **out, int n ) -{ - int i; - int max_bands; - - g_assert( n >= 1 ); - - max_bands = in[0]->Bands; - for( i = 1; i < n; i++ ) - max_bands = VIPS_MAX( max_bands, in[i]->Bands ); - for( i = 0; i < n; i++ ) - if( vips__bandup( domain, in[i], &out[i], max_bands ) ) - return( -1 ); - - return( 0 ); -} - -int -vips__formatalike( VipsImage *in1, VipsImage *in2, - VipsImage **out1, VipsImage **out2 ) -{ - IMAGE *in[2]; - IMAGE *out[2]; - - in[0] = in1; - in[1] = in2; - - if( vips__formatalike_vec( in, out, 2 ) ) - return( -1 ); - - *out1 = out[0]; - *out2 = out[1]; - - return( 0 ); -} - -int -vips__sizealike( VipsImage *in1, VipsImage *in2, - VipsImage **out1, VipsImage **out2 ) -{ - IMAGE *in[2]; - IMAGE *out[2]; - - in[0] = in1; - in[1] = in2; - - if( vips__sizealike_vec( in, out, 2 ) ) - return( -1 ); - - *out1 = out[0]; - *out2 = out[1]; - - return( 0 ); -} - -int -vips__bandalike( const char *domain, - VipsImage *in1, VipsImage *in2, VipsImage **out1, VipsImage **out2 ) -{ - VipsImage *in[2]; - VipsImage *out[2]; - - in[0] = in1; - in[1] = in2; - - if( vips__bandalike_vec( domain, in, out, 2 ) ) - return( -1 ); - - *out1 = out[0]; - *out2 = out[1]; - - return( 0 ); -} - -/* Maximum number of input images -- why not? - */ -#define MAX_INPUT_IMAGES (64) - -/* - * FIXME ... generalise this for other classes too - */ - -static int -vips_binary_gen( VipsRegion *or, - void *seq, void *a, void *b, gboolean *stop ) -{ - VipsRegion **ir = (VipsRegion **) seq; - VipsBinary *binary = VIPS_BINARY( b ); - VipsBinaryClass *class = VIPS_BINARY_GET_CLASS( binary ); - - PEL *p[MAX_INPUT_IMAGES], *q; - int i, y; - - /* Prepare all input regions and make buffer pointers. - */ - for( i = 0; ir[i]; i++ ) { - if( vips_region_prepare( ir[i], &or->valid ) ) - return( -1 ); - p[i] = (PEL *) VIPS_REGION_ADDR( ir[i], - or->valid.left, or->valid.top ); - } - p[i] = NULL; - q = (PEL *) VIPS_REGION_ADDR( or, or->valid.left, or->valid.top ); - - for( y = 0; y < or->valid.height; y++ ) { - /* Bizarre double-cast stops a bogus gcc 4.1 compiler warning. - */ - class->process_line( binary, q, p[0], p[1], or->valid.width ); - - for( i = 0; ir[i]; i++ ) - p[i] += VIPS_REGION_LSKIP( ir[i] ); - q += VIPS_REGION_LSKIP( or ); - } - - return( 0 ); -} - static int vips_binary_build( VipsObject *object ) { - VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object ); - const char *domain = class->nickname; VipsArithmetic *arithmetic = VIPS_ARITHMETIC( object ); - VipsArithmeticClass *aclass = VIPS_ARITHMETIC_GET_CLASS( arithmetic ); VipsBinary *binary = VIPS_BINARY( object ); - VipsImage **t = (VipsImage **) vips_object_local_array( object, 6 ); - VipsImage **arry; + arithmetic->n = 2; + arithmetic->in = (VipsImage **) vips_object_local_array( object, 2 ); + arithmetic->in[0] = binary->left; + arithmetic->in[1] = binary->right; if( VIPS_OBJECT_CLASS( vips_binary_parent_class )->build( object ) ) return( -1 ); - if( vips_image_pio_input( binary->left ) || - vips_image_pio_input( binary->right ) || - vips_image_pio_output( arithmetic->output ) || - vips_check_bands_1orn( domain, binary->left, binary->right ) || - vips_check_uncoded( domain, binary->left ) || - vips_check_uncoded( domain, binary->right ) ) - return( -1 ); - - /* Cast our input images up to a common format, bands and size. - */ - if( vips__formatalike( binary->left, binary->right, &t[0], &t[1] ) || - vips__bandalike( domain, t[0], t[1], &t[2], &t[3] ) || - vips__sizealike( t[2], t[3], &t[4], &t[5] ) ) - return( -1 ); - binary->left_processed = t[4]; - binary->right_processed = t[5]; - if( !(arry = vips_allocate_input_array( arithmetic->output, - binary->left_processed, binary->right_processed, NULL )) ) - return( -1 ); - - if( vips_image_copy_fields_array( arithmetic->output, arry ) ) - return( -1 ); - vips_demand_hint_array( arithmetic->output, - VIPS_DEMAND_STYLE_THINSTRIP, arry ); - - arithmetic->output->Bands = t[4]->Bands; - arithmetic->output->BandFmt = aclass->format_table[t[4]->BandFmt]; - - if( vips_image_generate( arithmetic->output, - vips_start_many, vips_binary_gen, vips_stop_many, - arry, binary ) ) - return( -1 ); - return( 0 ); } diff --git a/libvips/arithmetic/binary.h b/libvips/arithmetic/binary.h index 5e878080..c16b3df9 100644 --- a/libvips/arithmetic/binary.h +++ b/libvips/arithmetic/binary.h @@ -46,10 +46,6 @@ extern "C" { #define VIPS_BINARY_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), VIPS_TYPE_BINARY, VipsBinaryClass )) -struct _VipsBinary; -typedef void (*VipsBinaryProcessFn)( struct _VipsBinary *binary, - PEL *out, PEL *left, PEL *right, int width ); - typedef struct _VipsBinary { VipsArithmetic parent_instance; @@ -58,29 +54,9 @@ typedef struct _VipsBinary { VipsImage *left; VipsImage *right; - /* Some intermediates. - */ - VipsImage *t[5]; - - /* Processed images ready for the line function. - */ - VipsImage *left_processed; - VipsImage *right_processed; - - /* Some client data for the line processor, if it wants it. - */ - void *a; - void *b; } VipsBinary; -typedef struct _VipsBinaryClass { - VipsArithmeticClass parent_class; - - /* The line processor. - */ - VipsBinaryProcessFn process_line; - -} VipsBinaryClass; +typedef VipsArithmeticClass VipsBinaryClass; GType vips_binary_get_type( void ); diff --git a/libvips/arithmetic/subtract.c b/libvips/arithmetic/subtract.c index 89406dd9..5a09f484 100644 --- a/libvips/arithmetic/subtract.c +++ b/libvips/arithmetic/subtract.c @@ -166,19 +166,18 @@ typedef VipsBinaryClass VipsSubtractClass; G_DEFINE_TYPE( VipsSubtract, vips_subtract, VIPS_TYPE_BINARY ); #define LOOP( IN, OUT ) { \ - IN *p1 = (IN *) left; \ - IN *p2 = (IN *) right; \ + IN *left = (IN *) in[0]; \ + IN *right = (IN *) in[1]; \ OUT *q = (OUT *) out; \ \ for( x = 0; x < sz; x++ ) \ - q[x] = p1[x] - p2[x]; \ + q[x] = left[x] - right[x]; \ } static void -subtract_buffer( VipsBinary *binary, - PEL *out, PEL *left, PEL *right, int width ) +subtract_buffer( VipsArithmetic *arithmetic, PEL *out, PEL **in, int width ) { - VipsImage *im = binary->left_processed; + VipsImage *im = arithmetic->ready[0]; /* Complex just doubles the size. */ @@ -240,14 +239,13 @@ vips_subtract_class_init( VipsSubtractClass *class ) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsArithmeticClass *aclass = VIPS_ARITHMETIC_CLASS( class ); - VipsBinaryClass *bclass = VIPS_BINARY_CLASS( class ); object_class->nickname = "subtract"; object_class->description = _( "subtract two images" ); vips_arithmetic_set_format_table( aclass, bandfmt_subtract ); - bclass->process_line = subtract_buffer; + aclass->process_line = subtract_buffer; } static void @@ -256,13 +254,13 @@ vips_subtract_init( VipsSubtract *subtract ) } int -vips_subtract( VipsImage *in1, VipsImage *in2, VipsImage **out, ... ) +vips_subtract( VipsImage *left, VipsImage *right, VipsImage **out, ... ) { va_list ap; int result; va_start( ap, out ); - result = vips_call_split( "subtract", ap, in1, in2, out ); + result = vips_call_split( "subtract", ap, left, right, out ); va_end( ap ); return( result ); diff --git a/libvips/include/vips/arithmetic.h b/libvips/include/vips/arithmetic.h index b4904910..4cbd786d 100644 --- a/libvips/include/vips/arithmetic.h +++ b/libvips/include/vips/arithmetic.h @@ -37,7 +37,7 @@ extern "C" { #endif /*__cplusplus*/ -int vips_add( VipsImage *in1, VipsImage *in2, VipsImage **out, ... ) +int vips_add( VipsImage *left, VipsImage *right, VipsImage **out, ... ) __attribute__((sentinel)); int vips_subtract( VipsImage *in1, VipsImage *in2, VipsImage **out, ... ) __attribute__((sentinel));