refactor ready for unary arithmetic

move most of the logic in binary.c into arithmetic.c ready to share with
unary
This commit is contained in:
John Cupitt 2011-10-30 18:31:45 +00:00
parent 7807efcfbe
commit e14c5607b1
8 changed files with 344 additions and 341 deletions

22
TODO
View File

@ -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

View File

@ -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 );

View File

@ -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" ),

View File

@ -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 );

View File

@ -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 );
}

View File

@ -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 );

View File

@ -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 );

View File

@ -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));