From 370641d25b6e7dbb661a2bc6e78729615120bc42 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Fri, 1 Apr 2011 15:11:59 +0100 Subject: [PATCH] stuff oops argh --- libvips/arithmetic/Makefile.am | 2 + libvips/arithmetic/add.c | 250 ++++++++++++++++++++++ libvips/arithmetic/arithmetic.c | 122 +++++++++++ libvips/arithmetic/arithmetic.h | 78 +++++++ libvips/arithmetic/binary.c | 345 +++++++++++++++++++++++++++++++ libvips/arithmetic/binary.h | 89 ++++++++ libvips/deprecated/vips7compat.c | 2 +- libvips/include/vips/image.h | 1 + libvips/iofuncs/image.c | 97 ++++----- libvips/iofuncs/operation.c | 4 +- 10 files changed, 931 insertions(+), 59 deletions(-) create mode 100644 libvips/arithmetic/add.c create mode 100644 libvips/arithmetic/arithmetic.c create mode 100644 libvips/arithmetic/arithmetic.h create mode 100644 libvips/arithmetic/binary.c create mode 100644 libvips/arithmetic/binary.h diff --git a/libvips/arithmetic/Makefile.am b/libvips/arithmetic/Makefile.am index f03a70ec..d5498ef0 100644 --- a/libvips/arithmetic/Makefile.am +++ b/libvips/arithmetic/Makefile.am @@ -25,6 +25,8 @@ libarithmetic_la_SOURCES = \ im_stats.c \ im_subtract.c \ math.c \ + arithmetic.c \ + binary.c \ power.c \ round.c diff --git a/libvips/arithmetic/add.c b/libvips/arithmetic/add.c new file mode 100644 index 00000000..15e52a29 --- /dev/null +++ b/libvips/arithmetic/add.c @@ -0,0 +1,250 @@ +/* add operation + */ + +/* + + Copyright (C) 1991-2005 The National Gallery + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU 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 + + */ + +/* +#define DEBUG + */ + +#ifdef HAVE_CONFIG_H +#include +#endif /*HAVE_CONFIG_H*/ +#include + +#include +#include +#include + +#include + +#include "arithmetic.h" +#include "binary.h" + +#ifdef WITH_DMALLOC +#include +#endif /*WITH_DMALLOC*/ + +/* VipsAdd class + */ + +#define VIPS_TYPE_ADD (vips_add_get_type()) +#define VIPS_ADD( obj ) \ + (G_TYPE_CHECK_INSTANCE_CAST( (obj), \ + VIPS_TYPE_ADD, VipsAdd )) +#define VIPS_ADD_CLASS( klass ) \ + (G_TYPE_CHECK_CLASS_CAST( (klass), \ + VIPS_TYPE_ADD, VipsAddClass)) +#define VIPS_IS_ADD( obj ) \ + (G_TYPE_CHECK_INSTANCE_TYPE( (obj), VIPS_TYPE_ADD )) +#define VIPS_IS_ADD_CLASS( klass ) \ + (G_TYPE_CHECK_CLASS_TYPE( (klass), VIPS_TYPE_ADD )) +#define VIPS_ADD_GET_CLASS( obj ) \ + (G_TYPE_INSTANCE_GET_CLASS( (obj), \ + VIPS_TYPE_ADD, VipsAddClass )) + +typedef VipsBinary VipsAdd; +typedef VipsBinaryClass VipsAddClass; + +G_DEFINE_TYPE( VipsAdd, vips_add, VIPS_TYPE_BINARY ); + +#define LOOP( IN, OUT ) { \ + IN *p1 = (IN *) in[0]; \ + IN *p2 = (IN *) in[1]; \ + OUT *q = (OUT *) out; \ + \ + for( x = 0; x < sz; x++ ) \ + q[x] = p1[x] + p2[x]; \ +} + +static VipsVector *add_vectors[VIPS_FORMAT_LAST] = { NULL }; + +static void +add_buffer( PEL **in, PEL *out, int width, IMAGE *im ) +{ + /* Complex just doubles the size. + */ + const int sz = width * im->Bands * + (vips_bandfmt_iscomplex( im->BandFmt ) ? 2 : 1); + + if( vips_vector_get_enabled() && + add_vectors[im->BandFmt] ) { + VipsVector *vector = add_vectors[im->BandFmt]; + + VipsExecutor ex; + + vips_executor_set_program( &ex, vector, sz ); + vips_executor_set_array( &ex, vector->s[0], in[0] ); + vips_executor_set_array( &ex, vector->s[1], in[1] ); + vips_executor_set_destination( &ex, out ); + + vips_executor_run( &ex ); + } + else { + int x; + + /* Add all input types. Keep types here in sync with + * bandfmt_add[] below. + */ + switch( im->BandFmt ) { + case VIPS_FORMAT_UCHAR: + LOOP( unsigned char, unsigned short ); break; + case VIPS_FORMAT_CHAR: + LOOP( signed char, signed short ); break; + case VIPS_FORMAT_USHORT: + LOOP( unsigned short, unsigned int ); break; + case VIPS_FORMAT_SHORT: + LOOP( signed short, signed int ); break; + case VIPS_FORMAT_UINT: + LOOP( unsigned int, unsigned int ); break; + case VIPS_FORMAT_INT: + LOOP( signed int, signed int ); break; + + case VIPS_FORMAT_FLOAT: + case VIPS_FORMAT_COMPLEX: + LOOP( float, float ); break; + + case VIPS_FORMAT_DOUBLE: + case VIPS_FORMAT_DPCOMPLEX: + LOOP( double, double ); break; + + default: + g_assert( 0 ); + } + } +} + +/* Save a bit of typing. + */ +#define UC IM_BANDFMT_UCHAR +#define C IM_BANDFMT_CHAR +#define US IM_BANDFMT_USHORT +#define S IM_BANDFMT_SHORT +#define UI IM_BANDFMT_UINT +#define I IM_BANDFMT_INT +#define F IM_BANDFMT_FLOAT +#define X IM_BANDFMT_COMPLEX +#define D IM_BANDFMT_DOUBLE +#define DX IM_BANDFMT_DPCOMPLEX + +VipsVector * +im__init_program( VipsVector *vectors[IM_BANDFMT_LAST], + VipsBandFmt format_table[IM_BANDFMT_LAST], VipsBandFmt fmt ) +{ + int isize = im__sizeof_bandfmt[fmt]; + int osize = im__sizeof_bandfmt[format_table[fmt]]; + + VipsVector *v; + + v = vips_vector_new( "binary arith", osize ); + + vips_vector_source_name( v, "s1", isize ); + vips_vector_source_name( v, "s2", isize ); + vips_vector_temporary( v, "t1", osize ); + vips_vector_temporary( v, "t2", osize ); + + vectors[fmt] = v; + + return( v ); +} + +void +im__compile_programs( VipsVector *vectors[IM_BANDFMT_LAST] ) +{ + int fmt; + + for( fmt = 0; fmt < IM_BANDFMT_LAST; fmt++ ) { + if( vectors[fmt] && + !vips_vector_compile( vectors[fmt] ) ) + IM_FREEF( vips_vector_free, vectors[fmt] ); + } + +#ifdef DEBUG + printf( "im__compile_programs: " ); + for( fmt = 0; fmt < IM_BANDFMT_LAST; fmt++ ) + if( vectors[fmt] ) + printf( "%s ", im_BandFmt2char( fmt ) ); + printf( "\n" ); +#endif /*DEBUG*/ +} + +/* Type promotion for addition. Sign and value preserving. Make sure these + * match the case statement in add_buffer() above. + */ +static int bandfmt_add[10] = { +/* UC C US S UI I F X D DX */ + US, S, UI, I, UI, I, F, X, D, DX +}; + +static void +build_programs( void ) +{ + static gboolean done = FALSE; + + VipsVector *v; + + if( done ) + return; + done = TRUE; + + v = im__init_program( add_vectors, bandfmt_add, IM_BANDFMT_UCHAR ); + vips_vector_asm2( v, "convubw", "t1", "s1" ); + vips_vector_asm2( v, "convubw", "t2", "s2" ); + vips_vector_asm3( v, "addw", "d1", "t1", "t2" ); + + v = im__init_program( add_vectors, bandfmt_add, IM_BANDFMT_CHAR ); + vips_vector_asm2( v, "convsbw", "t1", "s1" ); + vips_vector_asm2( v, "convsbw", "t2", "s2" ); + vips_vector_asm3( v, "addw", "d1", "t1", "t2" ); + + v = im__init_program( add_vectors, bandfmt_add, IM_BANDFMT_USHORT ); + vips_vector_asm2( v, "convuwl", "t1", "s1" ); + vips_vector_asm2( v, "convuwl", "t2", "s2" ); + vips_vector_asm3( v, "addl", "d1", "t1", "t2" ); + + v = im__init_program( add_vectors, bandfmt_add, IM_BANDFMT_SHORT ); + vips_vector_asm2( v, "convswl", "t1", "s1" ); + vips_vector_asm2( v, "convswl", "t2", "s2" ); + vips_vector_asm3( v, "addl", "d1", "t1", "t2" ); + + /* + + uint/int are a little slower than C, on a c2d anyway + + float/double/complex are not handled well + + v = im__init_program( add_vectors, IM_BANDFMT_UINT ); + vips_vector_asm3( v, "addl", "d1", "s1", "s2" ); + + v = im__init_program( add_vectors, IM_BANDFMT_INT ); + vips_vector_asm3( v, "addl", "d1", "s1", "s2" ); + + */ + + im__compile_programs( add_vectors ); +} + diff --git a/libvips/arithmetic/arithmetic.c b/libvips/arithmetic/arithmetic.c new file mode 100644 index 00000000..79f43c7f --- /dev/null +++ b/libvips/arithmetic/arithmetic.c @@ -0,0 +1,122 @@ +/* base class for all arithmetic operations + * + * properties: + * - unary, binary or binary with one arg a constant + * - cast binary args 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) + * - LUT-able: ie. arithmetic (image) can be exactly replaced by + * maplut (image, arithmetic (lut)) for 8/16 bit int images + */ + +/* + + Copyright (C) 1991-2005 The National Gallery + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU 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 + + */ + +/* +#define DEBUG + */ + +#ifdef HAVE_CONFIG_H +#include +#endif /*HAVE_CONFIG_H*/ +#include + +#include +#include +#include + +#include + +#include "arithmetic.h" + +#ifdef WITH_DMALLOC +#include +#endif /*WITH_DMALLOC*/ + +/* Properties. + */ +enum { + PROP_OUTPUT = 1, + PROP_LAST +}; + +G_DEFINE_ABSTRACT_TYPE( VipsArithmetic, vips_arithmetic, VIPS_TYPE_OPERATION ); + +static int +vips_arithmetic_build( VipsObject *object ) +{ + VipsArithmetic *arithmetic = VIPS_ARITHMETIC (object); + + if( VIPS_OBJECT_CLASS( vips_arithmetic_parent_class )->build( object ) ) + return( -1 ); + + /* Should we _generate() here? We should keep the params in the object + * ready to be dropped in. + */ + + return( 0 ); +} + +static void +vips_arithmetic_class_init( VipsArithmeticClass *class ) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS( class ); + VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class ); + + GParamSpec *pspec; + + gobject_class->set_property = vips_object_set_property; + gobject_class->get_property = vips_object_get_property; + + vobject_class->build = vips_arithmetic_build; + + pspec = g_param_spec_object( "output-image", + "Output", "Output image", + VIPS_TYPE_IMAGE, + G_PARAM_READWRITE ); + g_object_class_install_property( gobject_class, + PROP_OUTPUT, pspec ); + vips_object_class_install_argument( vobject_class, pspec, + VIPS_ARGUMENT_REQUIRED_OUTPUT, + G_STRUCT_OFFSET( VipsArithmetic, output ) ); +} + +static void +vips_arithmetic_init( VipsArithmetic *arithmetic ) +{ +} + +/* Called from iofuncs to init all operations in this dir. Use a plugin system + * instead? + */ +void +vips_arithmetic_operation_init( void ) +{ + extern GType vips_add_get_type( void ); + + vips_add_get_type(); +} diff --git a/libvips/arithmetic/arithmetic.h b/libvips/arithmetic/arithmetic.h new file mode 100644 index 00000000..50bc233e --- /dev/null +++ b/libvips/arithmetic/arithmetic.h @@ -0,0 +1,78 @@ +/* base class for all arithmetic operations + */ + +/* + + Copyright (C) 1991-2005 The National Gallery + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU 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 + + */ + +#ifndef VIPS_ARITHMETIC_H +#define VIPS_ARITHMETIC_H + +#ifdef __cplusplus +extern "C" { +#endif /*__cplusplus*/ + +#define VIPS_TYPE_ARITHMETIC (vips_arithmetic_get_type()) +#define VIPS_ARITHMETIC( obj ) \ + (G_TYPE_CHECK_INSTANCE_CAST( (obj), \ + VIPS_TYPE_ARITHMETIC, VipsArithmetic )) +#define VIPS_ARITHMETIC_CLASS( klass ) \ + (G_TYPE_CHECK_CLASS_CAST( (klass), \ + VIPS_TYPE_ARITHMETIC, VipsArithmeticClass)) +#define VIPS_IS_ARITHMETIC( obj ) \ + (G_TYPE_CHECK_INSTANCE_TYPE( (obj), VIPS_TYPE_ARITHMETIC )) +#define VIPS_IS_ARITHMETIC_CLASS( klass ) \ + (G_TYPE_CHECK_CLASS_TYPE( (klass), VIPS_TYPE_ARITHMETIC )) +#define VIPS_ARITHMETIC_GET_CLASS( obj ) \ + (G_TYPE_INSTANCE_GET_CLASS( (obj), \ + VIPS_TYPE_ARITHMETIC, VipsArithmeticClass )) + +typedef struct _VipsArithmetic { + VipsOperation parent_instance; + + /* All have an output image. + */ + VipsImage *output; + + /* For each input format, what output format. Used for arithmetic + * too, since we cast inputs to match. + */ + VipsFormat *cast_table; +} VipsArithmetic; + +typedef struct _VipsArithmeticClass { + VipsOperationClass parent_class; + +} VipsArithmeticClass; + +GType vips_arithmetic_get_type( void ); + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +#endif /*VIPS_ARITHMETIC_H*/ + + diff --git a/libvips/arithmetic/binary.c b/libvips/arithmetic/binary.c new file mode 100644 index 00000000..84a3d828 --- /dev/null +++ b/libvips/arithmetic/binary.c @@ -0,0 +1,345 @@ +/* base class for all binary operations + */ + +/* + + Copyright (C) 1991-2005 The National Gallery + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU 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 + + */ + +/* +#define DEBUG + */ + +#ifdef HAVE_CONFIG_H +#include +#endif /*HAVE_CONFIG_H*/ +#include + +#include +#include +#include + +#include + +#include "arithmetic.h" +#include "binary.h" + +#ifdef WITH_DMALLOC +#include +#endif /*WITH_DMALLOC*/ + +/* Properties. + */ +enum { + PROP_LEFT = 1, + PROP_RIGHT, + PROP_LAST +}; + +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 VipsFormat 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 VipsFormat +vips_format_common( VipsFormat a, VipsFormat b ) +{ + if( vips_format_iscomplex( a ) || + vips_format_iscomplex( b ) ) { + if( a == VIPS_FORMAT_DPCOMPLEX || + b == VIPS_FORMAT_DPCOMPLEX ) + return( VIPS_FORMAT_DPCOMPLEX ); + else + return( VIPS_FORMAT_COMPLEX ); + + } + else if( vips_format_isfloat( a ) || + vips_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; + VipsFormat format; + + g_assert( n >= 1 ); + + format = in[0]->BandFmt; + for( i = 1; i < n; i++ ) + fmt = vips_format_common( format, in[i]->BandFmt ); + + for( i = 0; i < n; i++ ) + if( im_clip2fmt( in[i], out[i], format ) ) + 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; + out[0] = out1; + out[1] = out2; + + return( vips__formatalike_vec( in, out, 2 ) ); +} + +/* 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( im_copy( in, out ) ); + 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( im_gbandjoin( bands, out, n ) ); +} + +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__bandalike( const char *domain, + VipsImage *in1, VipsImage *in2, VipsImage *out1, VipsImage *out2 ) +{ + VipsImage *in[2]; + VipsImage *out[2]; + + in[0] = in1; + in[1] = in2; + out[0] = out1; + out[1] = out2; + if( vips__bandalike_vec( domain, in, out, 2 ) ) + return( -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_process_region( VipsRegion *or, void *seq, void *a, void *b ) +{ + VipsRegion **ir = (VipsRegion **) seq; + VipsBinary *binary = VIPS_BINARY( b ); + + 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. + */ + binary->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->description; + VipsArithmetic *arithmetic = VIPS_ARITHMETIC( object ); + VipsBinary *binary = VIPS_BINARY( object ); + + VipsImage *t[5]; + + 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_size_same( domain, binary->left, binary->right ) || + vips_check_uncoded( domain, binary->left ) || + vips_check_uncoded( domain, binary->right ) ) + return( -1 ); + + if( vips_image_new_array( object, t, 4 ) ) + return( -1 ); + + /* Cast our input images up to a common format and bands. + */ + if( vips__formatalike( binary->left, binary->right, t[0], t[1] ) || + vips__bandalike( domain, t[0], t[1], t[2], t[3] ) ) + return( -1 ); + binary->left_processed = t[2]; + binary->right_processed = t[3]; + t[4] = NULL; + + /* Hint demand style. Being a buffer processor, we are happiest with + * thin strips. + */ + if( vips_demand_hint_array( binary->output, + VIPS_DEMAND_STYLE_THINSTRIP, t + 2 ) || + vips_image_copy_fields_array( binary->output, t + 2 ) ) + return( -1 ); + + binary->output->Bands = t[2]->Bands; + binary->output->BandFmt = arithmetic->cast_table[t[2]->BandFmt]; + + if( vips_image_generate( binary->output, + vips_start_many, vips_binary_process_region, + vips_stop_many, + t + 2, binary ) ) + return( -1 ); + + return( 0 ); +} + +static void +vips_binary_class_init( VipsBinaryClass *class ) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS( class ); + VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class ); + + GParamSpec *pspec; + + gobject_class->set_property = vips_object_set_property; + gobject_class->get_property = vips_object_get_property; + + vobject_class->build = vips_binary_build; + + /* Create properties. + */ + pspec = g_param_spec_object( "left-image", + "Left", "Left-hand image argument", + VIPS_TYPE_IMAGE, + G_PARAM_READWRITE ); + g_object_class_install_property( gobject_class, + PROP_LEFT, pspec ); + vips_object_class_install_argument( vobject_class, pspec, + VIPS_ARGUMENT_REQUIRED_INPUT, + G_STRUCT_OFFSET( VipsBinary, left ) ); + + pspec = g_param_spec_object( "right-image", + "Right", "Right-hand image argument", + VIPS_TYPE_IMAGE, + G_PARAM_READWRITE ); + g_object_class_install_property( gobject_class, + PROP_RIGHT, pspec ); + vips_object_class_install_argument( vobject_class, pspec, + VIPS_ARGUMENT_REQUIRED_INPUT, + G_STRUCT_OFFSET( VipsBinary, right ) ); +} + +static void +vips_binary_init( VipsBinary *binary ) +{ + /* Init our instance fields. + */ +} diff --git a/libvips/arithmetic/binary.h b/libvips/arithmetic/binary.h new file mode 100644 index 00000000..88fbd893 --- /dev/null +++ b/libvips/arithmetic/binary.h @@ -0,0 +1,89 @@ +/* base class for all binary operations + */ + +/* + + Copyright (C) 1991-2005 The National Gallery + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU 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 + + */ + +#ifndef VIPS_BINARY_H +#define VIPS_BINARY_H + +#ifdef __cplusplus +extern "C" { +#endif /*__cplusplus*/ + +#define VIPS_TYPE_BINARY (vips_binary_get_type()) +#define VIPS_BINARY( obj ) \ + (G_TYPE_CHECK_INSTANCE_CAST( (obj), VIPS_TYPE_BINARY, VipsBinary )) +#define VIPS_BINARY_CLASS( klass ) \ + (G_TYPE_CHECK_CLASS_CAST( (klass), VIPS_TYPE_BINARY, VipsBinaryClass)) +#define VIPS_IS_BINARY( obj ) \ + (G_TYPE_CHECK_INSTANCE_TYPE( (obj), VIPS_TYPE_BINARY )) +#define VIPS_IS_BINARY_CLASS( klass ) \ + (G_TYPE_CHECK_CLASS_TYPE( (klass), VIPS_TYPE_BINARY )) +#define VIPS_BINARY_GET_CLASS( obj ) \ + (G_TYPE_INSTANCE_GET_CLASS( (obj), VIPS_TYPE_BINARY, VipsBinaryClass )) + +typedef void (*VipsBinaryProcessFn)( VipsBinary *binary, + void *out, void *left, void *right, int width ); + +typedef struct _VipsBinary { + VipsArithmetic parent_instance; + + /* Original left and right image args. + */ + VipsImage *left; + VipsImage *right; + + /* Some intermediates. + */ + VipsImage *t[5]; + + /* Processed images ready for the line function. + */ + VipsImage *left_processed; + VipsImage *right_processed; + + /* The line processor, plus some client data. + */ + VipsBinaryProcessFn process_line; + void *a; + void *b; +} VipsBinary; + +typedef struct _VipsBinaryClass { + VipsArithmeticClass parent_class; + +} VipsBinaryClass; + +GType vips_binary_get_type( void ); + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +#endif /*VIPS_BINARY_H*/ + + diff --git a/libvips/deprecated/vips7compat.c b/libvips/deprecated/vips7compat.c index 0754677d..3a651d67 100644 --- a/libvips/deprecated/vips7compat.c +++ b/libvips/deprecated/vips7compat.c @@ -383,7 +383,7 @@ im_wrapmany( IMAGE **in, IMAGE *out, im_wrapmany_fn fn, void *a, void *b ) } if( vips_image_pio_output( out ) ) return( -1 ); - + /* Hint demand style. Being a buffer processor, we are happiest with * thin strips. */ diff --git a/libvips/include/vips/image.h b/libvips/include/vips/image.h index 68a3f9e6..4e91af84 100644 --- a/libvips/include/vips/image.h +++ b/libvips/include/vips/image.h @@ -356,6 +356,7 @@ gboolean vips_image_get_kill( VipsImage *image ); void vips_image_set_kill( VipsImage *image, gboolean kill ); VipsImage *vips_image_new( const char *mode ); +int vips_image_new_array( VipsObject *parent, VipsImage **images, int n ); VipsImage *vips_image_new_from_file( const char *filename, const char *mode ); VipsImage *vips_image_new_from_file_raw( const char *filename, int xsize, int ysize, int bands, int offset ); diff --git a/libvips/iofuncs/image.c b/libvips/iofuncs/image.c index 85de6394..a751a1ed 100644 --- a/libvips/iofuncs/image.c +++ b/libvips/iofuncs/image.c @@ -247,49 +247,6 @@ * Returns: The address of pixel (x,y) in the image. */ -/** - * vips_image_open_local_array: - * @IM: image to open local to - * @OUT: array to fill with #VipsImage * - * @N: array size - * @NAME: filename to open - * @MODE: mode to open with - * - * Just like vips_image_open(), but opens an array of images. Handy for creating a - * set of temporary images for a function. - * - * Example: - * - * |[ - * VipsImage *t[5]; - * - * if( vips_image_open_local_array( out, t, 5, "some-temps", "p" ) || - * vips_add( a, b, t[0] ) || - * vips_invert( t[0], t[1] ) || - * vips_add( t[1], t[0], t[2] ) || - * vips_costra( t[2], out ) ) - * return( -1 ); - * ]| - * - * See also: vips_image_open(), vips_image_open_local(), vips_local_array(). - * - * Returns: 0 on sucess, or -1 on error - */ - -/** - * vips_image_open_local: - * @IM: image to open local to - * @NAME: filename to open - * @MODE: mode to open with - * - * Just like vips_image_open(), but the #VipsImage will be closed for you - * automatically when @IM is closed. - * - * See also: vips_image_open(), vips_local(). - * - * Returns: a new #VipsImage, or %NULL on error - */ - /* Properties. */ enum { @@ -1515,6 +1472,47 @@ vips_image_new( const char *mode ) return( image ); } +/** + * vips_image_new_array: + * @parent: images unref when this object unrefs + * @OUT: array to fill with #VipsImage * + * @N: array size + * + * Just like vips_image_new(), but opens an array of "p" images. + * Handy for creating a + * set of temporary images for a function. + * + * Example: + * + * |[ + * VipsImage *t[5]; + * + * if( vips_image_new_array( out, t, 5 ) || + * vips_add( a, b, t[0] ) || + * vips_invert( t[0], t[1] ) || + * vips_add( t[1], t[0], t[2] ) || + * vips_costra( t[2], out ) ) + * return( -1 ); + * ]| + * + * See also: vips_image_new(), vips_object_local(). + * + * Returns: 0 on sucess, or -1 on error + */ +int +vips_image_new_array( VipsObject *parent, VipsImage **images, int n ) +{ + int i; + + for( i = 0; i < n; i++ ) { + if( !(images[i] = vips_image_new( "p" )) ) + return( -1 ); + vips_object_local( parent, images[i] ); + } + + return( 0 ); +} + /** * vips_image_new_from_file: * @filename: file to open @@ -1799,18 +1797,6 @@ vips_image_ispartial( VipsImage *image ) return( 0 ); } -int -vips_image_new_array( VipsImage *parent, VipsImage **images, int n ) -{ - int i; - - for( i = 0; i < n; i++ ) - if( !(images[i] = vips_image_new( "p" )) ) - return( -1 ); - - return( 0 ); -} - /* Get the image ready for writing. This can get called many * times. Used by vips_image_generate() and vips_image_write_line(). vips7 * compat can call this as im_setupout(). @@ -2427,4 +2413,3 @@ vips_band_format_iscomplex( VipsBandFormat format ) return( -1 ); } } - diff --git a/libvips/iofuncs/operation.c b/libvips/iofuncs/operation.c index 704921c4..33608d65 100644 --- a/libvips/iofuncs/operation.c +++ b/libvips/iofuncs/operation.c @@ -268,8 +268,8 @@ vips_call( const char *operation_name, ... ) result = vips_operation_call_valist( operation, ap ); va_end( ap ); - /* The operation we have built should now be reffed by one of it's - * arguments ... or have finished it's work. + /* The operation we have built should now have been reffed by one of + * its arguments or have finished its work. Either way, we can unref. */ g_object_unref( operation );