diff --git a/ChangeLog b/ChangeLog index b6534538..cbd0d639 100644 --- a/ChangeLog +++ b/ChangeLog @@ -29,6 +29,8 @@ - deprecate im_linreg(): easily done by combining other operators - deprecate im_point(): easily done by combining other operators - add binary complex operations, with cross_phase as the only one so far +- added vips_bandbool(), with vips_bandand(), _bandor(), _bandeor() as + convenience functions 14/11/12 started 7.30.6 - capture tiff warnings earlier diff --git a/TODO b/TODO index a6ae64a9..a1094af9 100644 --- a/TODO +++ b/TODO @@ -1,3 +1,7 @@ +- vips_invert() on complex should just invert real part + +- boolean.c ... operator member should be called @operation, not @boolean + - add vips_band()/vips_bor() - now we've removed round-to-nearest from NN, we need something extra in the diff --git a/libvips/arithmetic/arithmetic.c b/libvips/arithmetic/arithmetic.c index 350d2eb7..cc253bbc 100644 --- a/libvips/arithmetic/arithmetic.c +++ b/libvips/arithmetic/arithmetic.c @@ -359,7 +359,7 @@ vips__bandup( const char *domain, VipsImage *in, VipsImage **out, int n ) return( -1 ); } if( n > 256 || n < 1 ) { - im_error( domain, "%s", _( "bad bands" ) ); + vips_error( domain, "%s", _( "bad bands" ) ); return( -1 ); } diff --git a/libvips/arithmetic/boolean.c b/libvips/arithmetic/boolean.c index 50349b02..2c512892 100644 --- a/libvips/arithmetic/boolean.c +++ b/libvips/arithmetic/boolean.c @@ -206,8 +206,7 @@ vips_boolean_class_init( VipsBooleanClass *class ) gobject_class->get_property = vips_object_get_property; object_class->nickname = "boolean"; - object_class->description = - _( "a boolean operation on a pair of images" ); + object_class->description = _( "boolean operation on two images" ); object_class->build = vips_boolean_build; vips_arithmetic_set_format_table( aclass, vips_bandfmt_boolean ); diff --git a/libvips/conversion/Makefile.am b/libvips/conversion/Makefile.am index fadfdcf0..043fe8b7 100644 --- a/libvips/conversion/Makefile.am +++ b/libvips/conversion/Makefile.am @@ -19,6 +19,7 @@ libconversion_la_SOURCES = \ black.c \ recomb.c \ bandmean.c \ + bandbool.c \ bandary.h \ bandary.c \ rot.c \ diff --git a/libvips/conversion/bandbool.c b/libvips/conversion/bandbool.c new file mode 100644 index 00000000..192bbfe4 --- /dev/null +++ b/libvips/conversion/bandbool.c @@ -0,0 +1,346 @@ +/* bandbool.c --- bool op across image bands + * + * 7/12/12 + * - from boolean.c + */ + +/* + + Copyright (C) 1991-2005 The National Gallery + + This library 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.1 of the License, or (at your option) any later version. + + This library 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 library; 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 "bandary.h" + +typedef struct _VipsBandbool { + VipsBandary parent_instance; + + VipsImage *in; + + VipsOperationBoolean operation; + +} VipsBandbool; + +typedef VipsBandaryClass VipsBandboolClass; + +G_DEFINE_TYPE( VipsBandbool, vips_bandbool, VIPS_TYPE_BANDARY ); + +static int +vips_bandbool_build( VipsObject *object ) +{ + VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object ); + VipsBandary *bandary = (VipsBandary *) object; + VipsBandbool *bandbool = (VipsBandbool *) object; + + if( bandbool->in && + vips_check_noncomplex( class->nickname, bandbool->in ) ) + return( -1 ); + + /* << and >> don't work over bands. + */ + if( bandbool->operation == VIPS_OPERATION_BOOLEAN_LSHIFT || + bandbool->operation == VIPS_OPERATION_BOOLEAN_RSHIFT ) { + vips_error( class->nickname, + _( "operator %s not supported across image bands" ), + vips_enum_nick( VIPS_TYPE_OPERATION_BOOLEAN, + bandbool->operation ) ); + return( -1 ); + } + + if( bandbool->in && + bandbool->in->Bands == 1 ) + return( vips_bandary_copy( bandary ) ); + + bandary->out_bands = 1; + bandary->n = 1; + bandary->in = &bandbool->in; + + if( VIPS_OBJECT_CLASS( vips_bandbool_parent_class )-> + build( object ) ) + return( -1 ); + + return( 0 ); +} + +#define SWITCH( I, F, OP ) \ + switch( vips_image_get_format( im ) ) { \ + case VIPS_FORMAT_UCHAR: I( unsigned char, OP ); break; \ + case VIPS_FORMAT_CHAR: I( signed char, OP ); break; \ + case VIPS_FORMAT_USHORT: I( unsigned short, OP ); break; \ + case VIPS_FORMAT_SHORT: I( signed short, OP ); break; \ + case VIPS_FORMAT_UINT: I( unsigned int, OP ); break; \ + case VIPS_FORMAT_INT: I( signed int, OP ); break; \ + case VIPS_FORMAT_FLOAT: F( float, OP ); break; \ + case VIPS_FORMAT_DOUBLE: F( double, OP ); break;\ + \ + default: \ + g_assert( 0 ); \ + } + +#define LOOPB( TYPE, OP ) { \ + TYPE *p = (TYPE *) in[0]; \ + TYPE *q = (TYPE *) out; \ + \ + for( x = 0; x < width; x++ ) { \ + TYPE acc; \ + \ + acc = p[0]; \ + for( b = 1; b < bands; b++ ) \ + acc = acc OP p[b]; \ + \ + q[x] = acc; \ + p += bands; \ + } \ +} + +#define FLOOPB( TYPE, OP ) { \ + TYPE *p = (TYPE *) in[0]; \ + int *q = (int *) out; \ + \ + for( x = 0; x < width; x++ ) { \ + int acc; \ + \ + acc = (int) p[0]; \ + for( b = 1; b < bands; b++ ) \ + acc = acc OP ((int) p[b]); \ + \ + q[x] = acc; \ + p += bands; \ + } \ +} + +static void +vips_bandbool_buffer( VipsBandary *bandary, + VipsPel *out, VipsPel **in, int width ) +{ + VipsBandbool *bandbool = (VipsBandbool *) bandary; + VipsImage *im = bandary->ready[0]; + int bands = im->Bands; + + int x, b; + + switch( bandbool->operation ) { + case VIPS_OPERATION_BOOLEAN_AND: + SWITCH( LOOPB, FLOOPB, & ); + break; + + case VIPS_OPERATION_BOOLEAN_OR: + SWITCH( LOOPB, FLOOPB, | ); + break; + + case VIPS_OPERATION_BOOLEAN_EOR: + SWITCH( LOOPB, FLOOPB, ^ ); + break; + + default: + g_assert( 0 ); + } +} + +/* 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 + +/* Type conversions for boolean. + */ +static const VipsBandFormat vips_bandfmt_boolean[10] = { +/* UC C US S UI I F X D DX */ + UC, C, US, S, UI, I, I, I, I, I, +}; + +static void +vips_bandbool_class_init( VipsBandboolClass *class ) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS( class ); + VipsObjectClass *object_class = (VipsObjectClass *) class; + VipsBandaryClass *bandary_class = VIPS_BANDARY_CLASS( class ); + + gobject_class->set_property = vips_object_set_property; + gobject_class->get_property = vips_object_get_property; + + object_class->nickname = "bandbool"; + object_class->description = _( "boolean operation across image bands" ); + object_class->build = vips_bandbool_build; + + bandary_class->process_line = vips_bandbool_buffer; + + VIPS_ARG_IMAGE( class, "in", 0, + _( "Input" ), + _( "Input image argument" ), + VIPS_ARGUMENT_REQUIRED_INPUT, + G_STRUCT_OFFSET( VipsBandbool, in ) ); + + VIPS_ARG_ENUM( class, "boolean", 200, + _( "Operation" ), + _( "boolean to perform" ), + VIPS_ARGUMENT_REQUIRED_INPUT, + G_STRUCT_OFFSET( VipsBandbool, operation ), + VIPS_TYPE_OPERATION_BOOLEAN, + VIPS_OPERATION_BOOLEAN_AND ); +} + +static void +vips_bandbool_init( VipsBandbool *bandbool ) +{ + bandbool->operation = VIPS_OPERATION_BOOLEAN_AND; +} + +static int +vips_bandboolv( VipsImage *in, VipsImage **out, + VipsOperationBoolean operation, va_list ap ) +{ + return( vips_call_split( "bandbool", ap, in, out, operation ) ); +} + +/** + * vips_bandbool: + * @im: left-hand input #VipsImage + * @out: output #VipsImage + * @operation: boolean operation to perform + * @...: %NULL-terminated list of optional named arguments + * + * Perform various boolean operations across the bands of an image. For + * example, a three-band uchar image operated on with + * #VIPS_OPERATION_BOOLEAN_AND will produce a one-band uchar image where each + * pixel is the bitwise and of the band elements of the corresponding pixel in + * the input image. + * + * The output image is the same format as the input image for integer + * types. Float types are cast to int before processing. Complex types are not + * supported. + * + * The output image always has one band. + * + * See also: vips_boolean_const(). + * + * Returns: 0 on success, -1 on error + */ +int +vips_bandbool( VipsImage *in, VipsImage **out, + VipsOperationBoolean operation, ... ) +{ + va_list ap; + int result; + + va_start( ap, operation ); + result = vips_bandboolv( in, out, operation, ap ); + va_end( ap ); + + return( result ); +} + +/** + * vips_bandand: + * @in: left-hand input #VipsImage + * @out: output #VipsImage + * @...: %NULL-terminated list of optional named arguments + * + * Perform #VIPS_OPERATION_BOOLEAN_AND on an image. See + * vips_bandbool(). + * + * Returns: 0 on success, -1 on error + */ +int +vips_bandand( VipsImage *in, VipsImage **out, ... ) +{ + va_list ap; + int result; + + va_start( ap, out ); + result = vips_bandboolv( in, out, VIPS_OPERATION_BOOLEAN_AND, ap ); + va_end( ap ); + + return( result ); +} + +/** + * vips_bandor: + * @in: left-hand input #VipsImage + * @out: output #VipsImage + * @...: %NULL-terminated list of optional named arguments + * + * Perform #VIPS_OPERATION_BOOLEAN_OR on an image. See + * vips_bandbool(). + * + * Returns: 0 on success, -1 on error + */ +int +vips_bandor( VipsImage *in, VipsImage **out, ... ) +{ + va_list ap; + int result; + + va_start( ap, out ); + result = vips_bandboolv( in, out, VIPS_OPERATION_BOOLEAN_OR, ap ); + va_end( ap ); + + return( result ); +} + +/** + * vips_bandeor: + * @in: left-hand input #VipsImage + * @out: output #VipsImage + * @...: %NULL-terminated list of optional named arguments + * + * Perform #VIPS_OPERATION_BOOLEAN_EOR on an image. See + * vips_bandbool(). + * + * Returns: 0 on success, -1 on error + */ +int +vips_bandeor( VipsImage *in, VipsImage **out, ... ) +{ + va_list ap; + int result; + + va_start( ap, out ); + result = vips_bandboolv( in, out, VIPS_OPERATION_BOOLEAN_EOR, ap ); + va_end( ap ); + + return( result ); +} + diff --git a/libvips/conversion/bandmean.c b/libvips/conversion/bandmean.c index bd4b58b9..698c2ea5 100644 --- a/libvips/conversion/bandmean.c +++ b/libvips/conversion/bandmean.c @@ -161,15 +161,13 @@ vips_bandmean_build( VipsObject *object ) VipsBandary *bandary = (VipsBandary *) object; VipsBandmean *bandmean = (VipsBandmean *) object; + if( bandmean->in && + bandmean->in->Bands == 1 ) + return( vips_bandary_copy( bandary ) ); + bandary->out_bands = 1; - - if( bandmean->in ) { - bandary->n = 1; - bandary->in = &bandmean->in; - - if( bandmean->in->Bands == 1 ) - return( vips_bandary_copy( bandary ) ); - } + bandary->n = 1; + bandary->in = &bandmean->in; if( VIPS_OBJECT_CLASS( vips_bandmean_parent_class )->build( object ) ) return( -1 ); diff --git a/libvips/conversion/conversion.c b/libvips/conversion/conversion.c index b4accff8..d1d68f05 100644 --- a/libvips/conversion/conversion.c +++ b/libvips/conversion/conversion.c @@ -123,6 +123,7 @@ vips_conversion_operation_init( void ) extern GType vips_recomb_get_type( void ); extern GType vips_bandmean_get_type( void ); extern GType vips_flatten_get_type( void ); + extern GType vips_bandbool_get_type( void ); vips_copy_get_type(); vips_tile_cache_get_type(); @@ -144,6 +145,7 @@ vips_conversion_operation_init( void ) vips_recomb_get_type(); vips_bandmean_get_type(); vips_flatten_get_type(); + vips_bandbool_get_type(); } /* The common part of most binary conversion diff --git a/libvips/include/vips/conversion.h b/libvips/include/vips/conversion.h index 3c63035c..91f5b36b 100644 --- a/libvips/include/vips/conversion.h +++ b/libvips/include/vips/conversion.h @@ -216,8 +216,20 @@ int vips_bandjoin2( VipsImage *in1, VipsImage *in2, VipsImage **out, ... ) __attribute__((sentinel)); int vips_bandmean( VipsImage *in, VipsImage **out, ... ) __attribute__((sentinel)); + +int vips_bandbool( VipsImage *in, VipsImage **out, + VipsOperationBoolean operation, ... ) + __attribute__((sentinel)); +int vips_bandand( VipsImage *in, VipsImage **out, ... ) + __attribute__((sentinel)); +int vips_bandor( VipsImage *in, VipsImage **out, ... ) + __attribute__((sentinel)); +int vips_bandeor( VipsImage *in, VipsImage **out, ... ) + __attribute__((sentinel)); + int vips_recomb( VipsImage *in, VipsImage **out, VipsImage *m, ... ) __attribute__((sentinel)); + int vips_black( VipsImage **out, int width, int height, ... ) __attribute__((sentinel)); int vips_rot( VipsImage *in, VipsImage **out, VipsAngle angle, ... )