diff --git a/ChangeLog b/ChangeLog index 895fc337..354506cc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -7,7 +7,8 @@ im_lintra(), im_lintra_vec(), im_black(), im_rot90, im_rot180(), im_rot270() im_sintra(), im_costra(), im_tantra(), im_asintra(), im_acostra(), im_atantra(), im_exptra(), im_exp10tra(), im_logtra(), im_log10tra(), - im_abs(), im_sign(), im_max(), im_maxpos(), im_deviate(), im_divide() + im_abs(), im_sign(), im_max(), im_maxpos(), im_deviate(), im_divide(), + im_multiply() redone as classes - added argument priorites to help control arg ordering - generate has a 'stop' param to signal successful early termination diff --git a/TODO b/TODO index 9c461ae8..c10f54fe 100644 --- a/TODO +++ b/TODO @@ -1,4 +1,9 @@ -- doing VipsMax +- max is broken + + $ ~/vips-7.26/bin/vips-7.26 vips im_max sarto_ng.tif + 255 + $ vips max sarto_ng.tif + 165.000000 diff --git a/libvips/arithmetic/Makefile.am b/libvips/arithmetic/Makefile.am index 3374d213..ab2de947 100644 --- a/libvips/arithmetic/Makefile.am +++ b/libvips/arithmetic/Makefile.am @@ -12,7 +12,7 @@ libarithmetic_la_SOURCES = \ im_maxpos_avg.c \ im_maxpos_vec.c \ im_measure.c \ - im_multiply.c \ + multiply.c \ im_point_bilinear.c \ im_remainder.c \ sign.c \ diff --git a/libvips/arithmetic/arithmetic.c b/libvips/arithmetic/arithmetic.c index 7119120f..e4d73c22 100644 --- a/libvips/arithmetic/arithmetic.c +++ b/libvips/arithmetic/arithmetic.c @@ -503,6 +503,7 @@ vips_arithmetic_operation_init( void ) { extern GType vips_add_get_type( void ); extern GType vips_subtract_get_type( void ); + extern GType vips_multiply_get_type( void ); extern GType vips_divide_get_type( void ); extern GType vips_invert_get_type( void ); extern GType vips_avg_get_type( void ); @@ -516,6 +517,7 @@ vips_arithmetic_operation_init( void ) vips_add_get_type(); vips_subtract_get_type(); + vips_multiply_get_type(); vips_divide_get_type(); vips_invert_get_type(); vips_avg_get_type(); diff --git a/libvips/arithmetic/max.c b/libvips/arithmetic/max.c index 28e19e30..5d4e998d 100644 --- a/libvips/arithmetic/max.c +++ b/libvips/arithmetic/max.c @@ -135,11 +135,10 @@ vips_max_build( VipsObject *object ) static void * vips_max_start( VipsStatistic *statistic ) { - VipsMax *global = (VipsMax *) statistic; VipsMax *max; max = g_new( VipsMax, 1 ); - *max = *global; + max->set = FALSE; return( (void *) max ); } @@ -152,8 +151,8 @@ vips_max_stop( VipsStatistic *statistic, void *seq ) VipsMax *global = (VipsMax *) statistic; VipsMax *max = (VipsMax *) seq; - if( !global->set || - max->max < global->max ) { + if( max->set && + (!global->set || max->max > global->max) ) { global->max = max->max; global->x = max->x; global->y = max->y; @@ -190,7 +189,7 @@ vips_max_stop( VipsStatistic *statistic, void *seq ) /* real max with an upper bound. */ -#define LOOPL( TYPE, UPPER ) { \ +#define LOOPU( TYPE, UPPER ) { \ TYPE *p = (TYPE *) in; \ TYPE m; \ \ @@ -254,18 +253,18 @@ vips_max_scan( VipsStatistic *statistic, void *seq, int i; switch( vips_image_get_format( statistic->in ) ) { - case IM_BANDFMT_UCHAR: LOOPL( unsigned char, 0 ); break; - case IM_BANDFMT_CHAR: LOOPL( signed char, SCHAR_MAX ); break; - case IM_BANDFMT_USHORT: LOOPL( unsigned short, 0 ); break; - case IM_BANDFMT_SHORT: LOOPL( signed short, SHRT_MAX ); break; - case IM_BANDFMT_UINT: LOOPL( unsigned int, 0 ); break; - case IM_BANDFMT_INT: LOOPL( signed int, INT_MAX ); break; + case IM_BANDFMT_UCHAR: LOOPU( unsigned char, UCHAR_MAX ); break; + case IM_BANDFMT_CHAR: LOOPU( signed char, SCHAR_MAX ); break; + case IM_BANDFMT_USHORT: LOOPU( unsigned short, USHRT_MAX ); break; + case IM_BANDFMT_SHORT: LOOPU( signed short, SHRT_MAX ); break; + case IM_BANDFMT_UINT: LOOPU( unsigned int, UINT_MAX ); break; + case IM_BANDFMT_INT: LOOPU( signed int, INT_MAX ); break; - case IM_BANDFMT_FLOAT: LOOP( float ); break; - case IM_BANDFMT_DOUBLE: LOOP( double ); break; + case IM_BANDFMT_FLOAT: LOOP( float ); break; + case IM_BANDFMT_DOUBLE: LOOP( double ); break; - case IM_BANDFMT_COMPLEX: CLOOP( float ); break; - case IM_BANDFMT_DPCOMPLEX: CLOOP( double ); break; + case IM_BANDFMT_COMPLEX:CLOOP( float ); break; + case IM_BANDFMT_DPCOMPLEX:CLOOP( double ); break; default: g_assert( 0 ); diff --git a/libvips/arithmetic/min.c b/libvips/arithmetic/min.c index d422fbbc..be91d76b 100644 --- a/libvips/arithmetic/min.c +++ b/libvips/arithmetic/min.c @@ -136,11 +136,10 @@ vips_min_build( VipsObject *object ) static void * vips_min_start( VipsStatistic *statistic ) { - VipsMin *global = (VipsMin *) statistic; VipsMin *min; min = g_new( VipsMin, 1 ); - *min = *global; + min->set = FALSE; return( (void *) min ); } @@ -153,8 +152,8 @@ vips_min_stop( VipsStatistic *statistic, void *seq ) VipsMin *global = (VipsMin *) statistic; VipsMin *min = (VipsMin *) seq; - if( !global->set || - min->min < global->min ) { + if( min->set && + (!global->set || min->min < global->min) ) { global->min = min->min; global->x = min->x; global->y = min->y; diff --git a/libvips/arithmetic/im_multiply.c b/libvips/arithmetic/multiply.c similarity index 57% rename from libvips/arithmetic/im_multiply.c rename to libvips/arithmetic/multiply.c index 02f4f4c5..e27838de 100644 --- a/libvips/arithmetic/im_multiply.c +++ b/libvips/arithmetic/multiply.c @@ -25,23 +25,25 @@ * - add gtkdoc comments * 31/7/10 * - remove liboil + * 7/11/11 + * - redo as a class */ /* - 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 + 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 Lesser General Public License for more details. + GNU General Public License for more details. - You should have received a copy of the GNU Lesser General Public License + 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 @@ -53,6 +55,10 @@ */ +/* +#define DEBUG + */ + #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ @@ -63,95 +69,15 @@ #include #include -#include -/* Complex multiply. - */ -#define CLOOP( TYPE ) { \ - TYPE *p1 = (TYPE *) in[0]; \ - TYPE *p2 = (TYPE *) in[1]; \ - TYPE *q = (TYPE *) out; \ - \ - for( x = 0; x < sz; x++ ) { \ - double x1 = p1[0]; \ - double y1 = p1[1]; \ - double x2 = p2[0]; \ - double y2 = p2[1]; \ - \ - p1 += 2; \ - p2 += 2; \ - \ - q[0] = x1 * x2 - y1 * y2; \ - q[1] = x1 * y2 + x2 * y1; \ - \ - q += 2; \ - } \ -} - -/* Real multiply. - */ -#define RLOOP( 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 void -multiply_buffer( PEL **in, PEL *out, int width, IMAGE *im ) -{ - const int sz = width * im->Bands; - - int x; - - /* Multiply all input types. Keep types here in sync with - * bandfmt_multiply[] below. - */ - switch( im->BandFmt ) { - case IM_BANDFMT_CHAR: RLOOP( signed char, signed short ); break; - case IM_BANDFMT_UCHAR: RLOOP( unsigned char, unsigned short ); break; - case IM_BANDFMT_SHORT: RLOOP( signed short, signed int ); break; - case IM_BANDFMT_USHORT: RLOOP( unsigned short, unsigned int ); break; - case IM_BANDFMT_INT: RLOOP( signed int, signed int ); break; - case IM_BANDFMT_UINT: RLOOP( unsigned int, unsigned int ); break; - case IM_BANDFMT_FLOAT: RLOOP( float, float ); break; - case IM_BANDFMT_COMPLEX: CLOOP( float ); break; - case IM_BANDFMT_DOUBLE: RLOOP( double, double ); break; - case IM_BANDFMT_DPCOMPLEX: CLOOP( 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 - -/* Type promotion for multiplication. Sign and value preserving. Make sure - * these match the case statement in multiply_buffer() above. - */ -static int bandfmt_multiply[10] = { -/* UC C US S UI I F X D DX */ - US, S, UI, I, UI, I, F, X, D, DX -}; +#include "arithmetic.h" +#include "binary.h" /** - * im_multiply: - * @in1: input #IMAGE 1 - * @in2: input #IMAGE 2 - * @out: output #IMAGE + * VipsMultiply: + * @in1: input #VipsImage 1 + * @in2: input #VipsImage 2 + * @out: output #VipsImage * * This operation calculates @in1 * @in2 and writes the result to @out. * @@ -169,7 +95,7 @@ static int bandfmt_multiply[10] = { * following table is used to determine the output type: * * - * im_multiply() type promotion + * VipsMultiply type promotion * * * @@ -225,15 +151,129 @@ static int bandfmt_multiply[10] = { * In other words, the output type is just large enough to hold the whole * range of possible values. * - * See also: im_divide(), im_lintra(). + * See also: im_multiply(), im_lintra(). * * Returns: 0 on success, -1 on error */ -int -im_multiply( IMAGE *in1, IMAGE *in2, IMAGE *out ) -{ - return( im__arith_binary( "im_multiply", - in1, in2, out, - bandfmt_multiply, - (im_wrapmany_fn) multiply_buffer, NULL ) ); + +typedef VipsBinary VipsMultiply; +typedef VipsBinaryClass VipsMultiplyClass; + +G_DEFINE_TYPE( VipsMultiply, vips_multiply, VIPS_TYPE_BINARY ); + +/* Complex multiply. + */ +#define CLOOP( TYPE ) { \ + TYPE *left = (TYPE *) in[0]; \ + TYPE *right = (TYPE *) in[1]; \ + TYPE *q = (TYPE *) out; \ + \ + for( x = 0; x < sz; x++ ) { \ + double x1 = left[0]; \ + double y1 = left[1]; \ + double x2 = right[0]; \ + double y2 = right[1]; \ + \ + left += 2; \ + right += 2; \ + \ + q[0] = x1 * x2 - y1 * y2; \ + q[1] = x1 * y2 + x2 * y1; \ + \ + q += 2; \ + } \ +} + +/* Real multiply. + */ +#define RLOOP( IN, OUT ) { \ + IN *left = (IN *) in[0]; \ + IN *right = (IN *) in[1]; \ + OUT *q = (OUT *) out; \ + \ + for( x = 0; x < sz; x++ ) \ + q[x] = left[x] * right[x]; \ +} + +static void +vips_multiply_buffer( VipsArithmetic *arithmetic, + PEL *out, PEL **in, int width ) +{ + VipsImage *im = arithmetic->ready[0]; + const int sz = width * vips_image_get_bands( im ); + + int x; + + /* Keep types here in sync with vips_bandfmt_multiply[] + * below. + */ + switch( vips_image_get_format( im ) ) { + case VIPS_FORMAT_CHAR: RLOOP( signed char, signed short ); break; + case VIPS_FORMAT_UCHAR: RLOOP( unsigned char, signed short ); break; + case VIPS_FORMAT_SHORT: RLOOP( signed short, signed int ); break; + case VIPS_FORMAT_USHORT:RLOOP( unsigned short, signed int ); break; + case VIPS_FORMAT_INT: RLOOP( signed int, signed int ); break; + case VIPS_FORMAT_UINT: RLOOP( unsigned int, signed int ); break; + case VIPS_FORMAT_FLOAT: RLOOP( float, float ); break; + case VIPS_FORMAT_DOUBLE: RLOOP( double, double ); break; + + case VIPS_FORMAT_COMPLEX: CLOOP( float ); break; + case VIPS_FORMAT_DPCOMPLEX: CLOOP( double ); 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 promotion for multiplication. Sign and value preserving. Make sure + * these match the case statement in multiply_buffer() above. + */ +static int vips_bandfmt_multiply[10] = { +/* UC C US S UI I F X D DX */ + US, S, UI, I, UI, I, F, X, D, DX +}; + +static void +vips_multiply_class_init( VipsMultiplyClass *class ) +{ + VipsObjectClass *object_class = (VipsObjectClass *) class; + VipsArithmeticClass *aclass = VIPS_ARITHMETIC_CLASS( class ); + + object_class->nickname = "multiply"; + object_class->description = _( "multiply two images" ); + + vips_arithmetic_set_format_table( aclass, vips_bandfmt_multiply ); + + aclass->process_line = vips_multiply_buffer; +} + +static void +vips_multiply_init( VipsMultiply *multiply ) +{ +} + +int +vips_multiply( VipsImage *left, VipsImage *right, VipsImage **out, ... ) +{ + va_list ap; + int result; + + va_start( ap, out ); + result = vips_call_split( "multiply", ap, left, right, out ); + va_end( ap ); + + return( result ); } diff --git a/libvips/deprecated/vips7compat.c b/libvips/deprecated/vips7compat.c index cf535458..9d471a31 100644 --- a/libvips/deprecated/vips7compat.c +++ b/libvips/deprecated/vips7compat.c @@ -928,6 +928,22 @@ im_subtract( IMAGE *in1, IMAGE *in2, IMAGE *out ) return( 0 ); } +int +im_multiply( IMAGE *in1, IMAGE *in2, IMAGE *out ) +{ + VipsImage *x; + + if( vips_call( "multiply", in1, in2, &x, NULL ) ) + return( -1 ); + if( im_copy( x, out ) ) { + g_object_unref( x ); + return( -1 ); + } + g_object_unref( x ); + + return( 0 ); +} + int im_divide( IMAGE *in1, IMAGE *in2, IMAGE *out ) { diff --git a/libvips/include/vips/arithmetic.h b/libvips/include/vips/arithmetic.h index f459afd6..12d7ea30 100644 --- a/libvips/include/vips/arithmetic.h +++ b/libvips/include/vips/arithmetic.h @@ -70,6 +70,8 @@ int vips_add( VipsImage *left, VipsImage *right, VipsImage **out, ... ) __attribute__((sentinel)); int vips_subtract( VipsImage *in1, VipsImage *in2, VipsImage **out, ... ) __attribute__((sentinel)); +int vips_multiply( VipsImage *left, VipsImage *right, VipsImage **out, ... ) + __attribute__((sentinel)); int vips_divide( VipsImage *left, VipsImage *right, VipsImage **out, ... ) __attribute__((sentinel)); int vips_avg( VipsImage *in, double *out, ... ) @@ -108,7 +110,6 @@ int im_maxpos_vec( VipsImage *im, int *xpos, int *ypos, double *maxima, int n ); int im_minpos_vec( VipsImage *im, int *xpos, int *ypos, double *minima, int n ); int im_bandmean( VipsImage *in, VipsImage *out ); -int im_multiply( VipsImage *in1, VipsImage *in2, VipsImage *out ); int im_remainder( VipsImage *in1, VipsImage *in2, VipsImage *out ); int im_remainder_vec( VipsImage *in, VipsImage *out, int n, double *c ); int im_remainderconst( VipsImage *in, VipsImage *out, double c ); diff --git a/libvips/include/vips/vips7compat.h b/libvips/include/vips/vips7compat.h index 3aa4a191..05f80702 100644 --- a/libvips/include/vips/vips7compat.h +++ b/libvips/include/vips/vips7compat.h @@ -522,6 +522,7 @@ size_t im_ref_string_get_length( const GValue *value ); int im_add( VipsImage *in1, VipsImage *in2, VipsImage *out ); int im_subtract( VipsImage *in1, VipsImage *in2, VipsImage *out ); +int im_multiply( VipsImage *in1, VipsImage *in2, VipsImage *out ); int im_divide( VipsImage *in1, VipsImage *in2, VipsImage *out ); int im_min( VipsImage *in, double *out ); int im_minpos( VipsImage *in, int *xpos, int *ypos, double *out );