diff --git a/ChangeLog b/ChangeLog index 63d87981..6080aeea 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,6 @@ 20/8/11 started 7.27.0 - version bump for new dev cycle -- im_subtract() redone as a class +- im_subtract(), im_avg() redone as classes 10/8/11 started 7.26.3 - don't use G_VALUE_COLLECT_INIT(), many platforms do not have a glib this diff --git a/TODO b/TODO index 0477418a..20660d4a 100644 --- a/TODO +++ b/TODO @@ -1,3 +1,36 @@ +- is our C API too awkward? we'll need + + if( !(c = vips_add( a, b )) || + !(d = vips_add( a, c )) ) + return NULL; + + seems wordy compared to + + if( vips_add( a, b, &c ) || + vips_add( a, c, &d ) ) + return -1; + + plus VipsPool will be more natural with #2, I think, and things like + vips_avg() have to be form #2 + + + + +- could we generate the code for vips_add() automatically? it might be nice to + have them all in one place at least + + + + +- all the old dispatch wrappers could move to deprecated + + + + +- max.c will need an early termination thing for vips_sink ... easy? + + + - support planar tiff diff --git a/libvips/arithmetic/Makefile.am b/libvips/arithmetic/Makefile.am index 986cac07..1839e524 100644 --- a/libvips/arithmetic/Makefile.am +++ b/libvips/arithmetic/Makefile.am @@ -3,7 +3,6 @@ noinst_LTLIBRARIES = libarithmetic.la libarithmetic_la_SOURCES = \ arith_dispatch.c \ im_abs.c \ - im_avg.c \ im_bandmean.c \ im_cross_phase.c \ im_deviate.c \ @@ -22,6 +21,9 @@ libarithmetic_la_SOURCES = \ im_remainder.c \ im_sign.c \ im_stats.c \ + statistic.c \ + statistic.h \ + avg.c \ subtract.c \ math.c \ arithmetic.c \ diff --git a/libvips/arithmetic/add.c b/libvips/arithmetic/add.c index 8e4e68b1..aecdc25d 100644 --- a/libvips/arithmetic/add.c +++ b/libvips/arithmetic/add.c @@ -192,12 +192,14 @@ add_buffer( VipsBinary *binary, PEL *out, PEL *left, PEL *right, int width ) /* Complex just doubles the size. */ - const int sz = width * im->Bands * - (vips_band_format_iscomplex( im->BandFmt ) ? 2 : 1); + const int sz = width * vips_image_get_bands( im ) * + (vips_band_format_iscomplex( vips_image_get_format( im ) ) ? + 2 : 1); VipsVector *v; - if( (v = vips_arithmetic_get_vector( class, im->BandFmt )) ) { + if( (v = vips_arithmetic_get_vector( class, + vips_image_get_format( im ) )) ) { VipsExecutor ex; vips_executor_set_program( &ex, v, sz ); @@ -213,7 +215,7 @@ add_buffer( VipsBinary *binary, PEL *out, PEL *left, PEL *right, int width ) /* Add all input types. Keep types here in sync with * bandfmt_add[] below. */ - switch( im->BandFmt ) { + switch( vips_image_get_format( im ) ) { case VIPS_FORMAT_UCHAR: LOOP( unsigned char, unsigned short ); break; case VIPS_FORMAT_CHAR: @@ -243,21 +245,21 @@ add_buffer( VipsBinary *binary, PEL *out, PEL *left, PEL *right, int width ) /* 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 +#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 addition. Sign and value preserving. Make sure these * match the case statement in add_buffer() above. */ -static int bandfmt_add[10] = { +static const VipsBandFormat bandfmt_add[10] = { /* UC C US S UI I F X D DX */ US, S, UI, I, UI, I, F, X, D, DX }; @@ -314,6 +316,11 @@ vips_add_class_init( VipsAddClass *class ) bclass->process_line = add_buffer; } +static void +vips_add_init( VipsAdd *add ) +{ +} + VipsImage * vips_add( VipsImage *in1, VipsImage *in2, ... ) { @@ -330,8 +337,3 @@ vips_add( VipsImage *in1, VipsImage *in2, ... ) return( out ); } - -static void -vips_add_init( VipsAdd *add ) -{ -} diff --git a/libvips/arithmetic/arithmetic.c b/libvips/arithmetic/arithmetic.c index fd5d4c82..47fa462d 100644 --- a/libvips/arithmetic/arithmetic.c +++ b/libvips/arithmetic/arithmetic.c @@ -144,7 +144,6 @@ vips_arithmetic_class_init( VipsArithmeticClass *class ) vips_object_class_install_argument( vobject_class, pspec, VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET( VipsArithmetic, imtest ) ); - } static void @@ -154,7 +153,7 @@ vips_arithmetic_init( VipsArithmetic *arithmetic ) void vips_arithmetic_set_format_table( VipsArithmeticClass *class, - VipsBandFormat *format_table ) + const VipsBandFormat *format_table ) { int i; @@ -240,8 +239,10 @@ vips_arithmetic_operation_init( void ) { extern GType vips_add_get_type( void ); extern GType vips_subtract_get_type( void ); + extern GType vips_avg_get_type( void ); vips_add_get_type(); vips_subtract_get_type(); + vips_avg_get_type(); } diff --git a/libvips/arithmetic/arithmetic.h b/libvips/arithmetic/arithmetic.h index 19ddb8bf..37bbd0b6 100644 --- a/libvips/arithmetic/arithmetic.h +++ b/libvips/arithmetic/arithmetic.h @@ -75,7 +75,7 @@ typedef struct _VipsArithmeticClass { /* For each input format, what output format. Used for arithmetic * too, since we cast inputs to match. */ - VipsBandFormat *format_table; + const VipsBandFormat *format_table; /* A vector program for each input type. */ @@ -89,7 +89,7 @@ typedef struct _VipsArithmeticClass { GType vips_arithmetic_get_type( void ); void vips_arithmetic_set_format_table( VipsArithmeticClass *klass, - VipsBandFormat *format_table ); + const VipsBandFormat *format_table ); VipsVector *vips_arithmetic_get_vector( VipsArithmeticClass *klass, VipsBandFormat fmt ); void vips_arithmetic_compile( VipsArithmeticClass *klass ); diff --git a/libvips/arithmetic/avg.c b/libvips/arithmetic/avg.c new file mode 100644 index 00000000..895e9d60 --- /dev/null +++ b/libvips/arithmetic/avg.c @@ -0,0 +1,279 @@ +/* avg ... average value of image + * + * Copyright: 1990, J. Cupitt + * + * Author: J. Cupitt + * Written on: 02/08/1990 + * Modified on: + * 5/5/93 JC + * - now does partial images + * - less likely to overflow + * 1/7/93 JC + * - adapted for partial v2 + * - ANSI C + * 21/2/95 JC + * - modernised again + * 11/5/95 JC + * - oops! return( NULL ) in im_avg(), instead of return( -1 ) + * 20/6/95 JC + * - now returns double + * 13/1/05 + * - use 64 bit arithmetic + * 8/12/06 + * - add liboil support + * 18/8/09 + * - gtkdoc, minor reformatting + * 7/9/09 + * - rewrite for im__wrapiter() + * - add complex case (needed for im_max()) + * 8/9/09 + * - wrapscan stuff moved here + * 31/7/10 + * - remove liboil + * 24/8/11 + * - rewrite 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 + 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. + + You should have received a copy of the GNU Lesser 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 + + */ + +#ifdef HAVE_CONFIG_H +#include +#endif /*HAVE_CONFIG_H*/ +#include + +#include +#include +#include + +#include +#include + +#include "statistic.h" + +#ifdef WITH_DMALLOC +#include +#endif /*WITH_DMALLOC*/ + +/** + * VipsAvg: + * @in: input #VipsImage + * @out: output pixel average + * + * This operation finds the average value in an image. It operates on all + * bands of the input image: use im_stats() if you need to calculate an + * average for each band. For complex images, return the average modulus. + * + * See also: im_stats(), im_bandmean(), im_deviate(), im_rank() + */ + +/* Properties. + */ +enum { + PROP_OUTPUT = 1, + PROP_LAST +}; + +typedef struct _VipsAvg { + VipsStatistic parent_instance; + + double sum; + double avg; +} VipsAvg; + +typedef VipsStatisticClass VipsAvgClass; + +G_DEFINE_TYPE( VipsAvg, vips_avg, VIPS_TYPE_STATISTIC ); + +static int +vips_avg_build( VipsObject *object ) +{ + VipsStatistic *statistic = VIPS_STATISTIC( object ); + VipsImage *in = statistic->input; + VipsAvg *avg = (VipsAvg *) object; + + gint64 vals, pels; + double average; + + if( VIPS_OBJECT_CLASS( vips_avg_parent_class )->build( object ) ) + return( -1 ); + + /* Calculate average. For complex, we accumulate re*re + + * im*im, so we need to sqrt. + */ + pels = (gint64) vips_image_get_width( in ) * + vips_image_get_height( in ); + vals = pels * vips_image_get_bands( in ); + average = avg->sum / vals; + if( vips_bandfmt_iscomplex( vips_image_get_format( in ) ) ) + average = sqrt( average ); + g_object_set( object, "out", average, NULL ); + + return( 0 ); +} + +/* Start function: allocate space for a double in which we can accumulate the + * sum for this thread. + */ +static void * +vips_avg_start( VipsStatistic *statistic ) +{ + double *sum; + + if( !(sum = VIPS_NEW( NULL, double )) ) + return( NULL ); + *sum = 0.0; + + return( (void *) sum ); +} + +/* Stop function. Add this little sum to the main sum. + */ +static int +vips_avg_stop( VipsStatistic *statistic, void *seq ) +{ + VipsAvg *avg = (VipsAvg *) statistic; + double *sum = (double *) seq; + + avg->sum += *sum; + + vips_free( seq ); + + return( 0 ); +} + +/* Sum pels in this section. + */ +#define LOOP( TYPE ) { \ + TYPE *p = (TYPE *) in; \ + \ + for( x = 0; x < sz; x++ ) \ + m += p[x]; \ +} + +#define CLOOP( TYPE ) { \ + TYPE *p = (TYPE *) in; \ + \ + for( x = 0; x < sz; x++ ) { \ + double mod, re, im; \ + \ + re = p[0]; \ + im = p[1]; \ + p += 2; \ + mod = re * re + im * im; \ + \ + m += mod; \ + } \ +} + +/* Loop over region, accumulating a sum in *tmp. + */ +static int +vips_avg_scan( VipsStatistic *statistic, void *seq, void *in, int n ) +{ + const VipsImage *im = statistic->input; + const int sz = n * vips_image_get_bands( im ); + + double *sum = (double *) seq; + + int x; + double m; + + m = *sum; + + /* Now generate code for all types. + */ + switch( vips_image_get_format( im ) ) { + case VIPS_FORMAT_UCHAR: LOOP( unsigned char ); break; + case VIPS_FORMAT_CHAR: LOOP( signed char ); break; + case VIPS_FORMAT_USHORT: LOOP( unsigned short ); break; + case VIPS_FORMAT_SHORT: LOOP( signed short ); break; + case VIPS_FORMAT_UINT: LOOP( unsigned int ); break; + case VIPS_FORMAT_INT: LOOP( signed int ); break; + case VIPS_FORMAT_FLOAT: LOOP( float ); break; + case VIPS_FORMAT_DOUBLE: LOOP( double ); break; + case VIPS_FORMAT_COMPLEX: CLOOP( float ); break; + case VIPS_FORMAT_DPCOMPLEX: CLOOP( double ); break; + + default: + g_assert( 0 ); + } + + *sum = m; + + return( 0 ); +} + +static void +vips_avg_class_init( VipsAvgClass *class ) +{ + GObjectClass *gobject_class = (GObjectClass *) class; + VipsObjectClass *object_class = (VipsObjectClass *) class; + VipsStatisticClass *sclass = VIPS_STATISTIC_CLASS( class ); + + GParamSpec *pspec; + + gobject_class->set_property = vips_object_set_property; + gobject_class->get_property = vips_object_get_property; + + object_class->nickname = "avg"; + object_class->description = _( "find image average" ); + object_class->build = vips_avg_build; + + sclass->start = vips_avg_start; + sclass->scan = vips_avg_scan; + sclass->stop = vips_avg_stop; + + pspec = g_param_spec_double( "out", "Output", + _( "Output value" ), + -G_MAXDOUBLE, + G_MAXDOUBLE, + 0.0, + G_PARAM_READWRITE ); + g_object_class_install_property( gobject_class, + PROP_OUTPUT, pspec ); + vips_object_class_install_argument( object_class, pspec, + VIPS_ARGUMENT_REQUIRED_OUTPUT, + G_STRUCT_OFFSET( VipsAvg, avg ) ); +} + +static void +vips_avg_init( VipsAvg *avg ) +{ +} + +int +vips_avg( VipsImage *in, double *out, ... ) +{ + va_list ap; + int result; + + va_start( ap, out ); + result = vips_call_split( "avg", ap, in, out ); + va_end( ap ); + + return( result ); +} diff --git a/libvips/arithmetic/im_avg.c b/libvips/arithmetic/im_avg.c deleted file mode 100644 index b40d1dd3..00000000 --- a/libvips/arithmetic/im_avg.c +++ /dev/null @@ -1,296 +0,0 @@ -/* im_avg.c - * - * Copyright: 1990, J. Cupitt - * - * Author: J. Cupitt - * Written on: 02/08/1990 - * Modified on: - * 5/5/93 JC - * - now does partial images - * - less likely to overflow - * 1/7/93 JC - * - adapted for partial v2 - * - ANSI C - * 21/2/95 JC - * - modernised again - * 11/5/95 JC - * - oops! return( NULL ) in im_avg(), instead of return( -1 ) - * 20/6/95 JC - * - now returns double - * 13/1/05 - * - use 64 bit arithmetic - * 8/12/06 - * - add liboil support - * 18/8/09 - * - gtkdoc, minor reformatting - * 7/9/09 - * - rewrite for im__wrapiter() - * - add complex case (needed for im_max()) - * 8/9/09 - * - wrapscan stuff moved here - * 31/7/10 - * - remove liboil - */ - -/* - - 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 - 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. - - You should have received a copy of the GNU Lesser 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 - - */ - -#ifdef HAVE_CONFIG_H -#include -#endif /*HAVE_CONFIG_H*/ -#include - -#include -#include -#include - -#include -#include - -#ifdef WITH_DMALLOC -#include -#endif /*WITH_DMALLOC*/ - -typedef struct _Wrapscan { - IMAGE *in; - im_start_fn start; - im__wrapscan_fn scan; - im_stop_fn stop; - void *a; - void *b; -} Wrapscan; - -static void * -wrapscan_start( VipsImage *in, void *a, void *b ) -{ - Wrapscan *wrapscan = (Wrapscan *) a; - - return( wrapscan->start( in, wrapscan->a, wrapscan->b ) ); -} - -static int -wrapscan_stop( void *seq, void *a, void *b ) -{ - Wrapscan *wrapscan = (Wrapscan *) a; - - return( wrapscan->stop( seq, wrapscan->a, wrapscan->b ) ); -} - -static int -wrapscan_scan( REGION *reg, void *seq, void *a, void *b ) -{ - Wrapscan *wrapscan = (Wrapscan *) a; - Rect *r = ®->valid; - int lsk = IM_REGION_LSKIP( reg ); - - int y; - PEL *p; - - p = (PEL *) IM_REGION_ADDR( reg, r->left, r->top ); - for( y = 0; y < r->height; y++ ) { - if( wrapscan->scan( p, r->width, seq, - wrapscan->a, wrapscan->b ) ) - return( -1 ); - p += lsk; - } - - return( 0 ); -} - -/* Like vips_sink(), but the scan function works a line at a time, like - * im_wrap*(). Shared with im_min(), im_deviate() etc. - */ -int -im__wrapscan( VipsImage *in, - VipsStart start, im__wrapscan_fn scan, VipsStop stop, - void *a, void *b ) -{ - Wrapscan wrapscan; - - wrapscan.in = in; - wrapscan.start = start; - wrapscan.scan = scan; - wrapscan.stop = stop; - wrapscan.a = a; - wrapscan.b = b; - - return( vips_sink( in, - wrapscan_start, wrapscan_scan, wrapscan_stop, - &wrapscan, NULL ) ); -} - -/* Start function: allocate space for a double in which we can accumulate the - * sum. - */ -static void * -avg_start( IMAGE *out, void *a, void *b ) -{ - double *sum; - - if( !(sum = IM_NEW( NULL, double )) ) - return( NULL ); - *sum = 0.0; - - return( (void *) sum ); -} - -/* Stop function. Add this little sum to the main sum. - */ -static int -avg_stop( void *seq, void *a, void *b ) -{ - double *sum = (double *) seq; - double *global_sum = (double *) b; - - *global_sum += *sum; - - im_free( seq ); - - return( 0 ); -} - -/* Sum pels in this section. - */ -#define LOOP( TYPE ) { \ - TYPE *p = (TYPE *) in; \ - \ - for( x = 0; x < sz; x++ ) \ - m += p[x]; \ -} - -#define CLOOP( TYPE ) { \ - TYPE *p = (TYPE *) in; \ - \ - for( x = 0; x < sz; x++ ) { \ - double mod, re, im; \ - \ - re = p[0]; \ - im = p[1]; \ - p += 2; \ - mod = re * re + im * im; \ - \ - m += mod; \ - } \ -} - -/* Loop over region, accumulating a sum in *tmp. - */ -static int -avg_scan( void *in, int n, void *seq, void *a, void *b ) -{ - const IMAGE *im = (IMAGE *) a; - const int sz = n * im->Bands; - - double *sum = (double *) seq; - - int x; - double m; - - m = *sum; - - /* Now generate code for all types. - */ - switch( im->BandFmt ) { - case IM_BANDFMT_UCHAR: LOOP( unsigned char ); break; - case IM_BANDFMT_CHAR: LOOP( signed char ); break; - case IM_BANDFMT_USHORT: LOOP( unsigned short ); break; - case IM_BANDFMT_SHORT: LOOP( signed short ); break; - case IM_BANDFMT_UINT: LOOP( unsigned int ); break; - case IM_BANDFMT_INT: LOOP( signed int ); 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; - - default: - g_assert( 0 ); - } - - *sum = m; - - return( 0 ); -} - -/** - * im_avg: - * @in: input #IMAGE - * @out: output pixel average - * - * This operation finds the average value in an image. It operates on all - * bands of the input image: use im_stats() if you need to calculate an - * average for each band. For complex images, return the average modulus. - * - * See also: im_stats(), im_bandmean(), im_deviate(), im_rank() - * - * Returns: 0 on success, -1 on error - */ -int -im_avg( IMAGE *in, double *out ) -{ - double global_sum; - gint64 vals, pels; - - /* Check our args. - */ - if( im_pincheck( in ) || - im_check_noncomplex( "im_avg", in ) || - im_check_uncoded( "im_avg", in ) ) - return( -1 ); - - /* Loop over input, summing pixels. - */ - global_sum = 0.0; - if( im__wrapscan( in, - avg_start, avg_scan, avg_stop, in, &global_sum ) ) - return( -1 ); - - /* Calculate and return average. For complex, we accumulate re*re + - * im*im, so we need to sqrt. - */ - pels = (gint64) in->Xsize * in->Ysize; - vals = pels * in->Bands; - *out = global_sum / vals; - if( vips_bandfmt_iscomplex( in->BandFmt ) ) - *out = sqrt( *out ); - - return( 0 ); -} - -/* Get the value of pixel (0, 0). Use this to init the min/max value for - * im_max()/im_stats()/etc. - */ -int -im__value( IMAGE *im, double *value ) -{ - IMAGE *t; - - if( !(t = im_open_local( im, "im__value", "p" )) || - im_extract_areabands( im, t, 0, 0, 1, 1, 0, 1 ) || - im_avg( t, value ) ) - return( -1 ); - - return( 0 ); -} diff --git a/libvips/arithmetic/im_deviate.c b/libvips/arithmetic/im_deviate.c index 3067a3cf..6868882d 100644 --- a/libvips/arithmetic/im_deviate.c +++ b/libvips/arithmetic/im_deviate.c @@ -73,6 +73,74 @@ #include #endif /*WITH_DMALLOC*/ +typedef struct _Wrapscan { + IMAGE *in; + im_start_fn start; + im__wrapscan_fn scan; + im_stop_fn stop; + void *a; + void *b; +} Wrapscan; + +static void * +wrapscan_start( VipsImage *in, void *a, void *b ) +{ + Wrapscan *wrapscan = (Wrapscan *) a; + + return( wrapscan->start( in, wrapscan->a, wrapscan->b ) ); +} + +static int +wrapscan_stop( void *seq, void *a, void *b ) +{ + Wrapscan *wrapscan = (Wrapscan *) a; + + return( wrapscan->stop( seq, wrapscan->a, wrapscan->b ) ); +} + +static int +wrapscan_scan( REGION *reg, void *seq, void *a, void *b ) +{ + Wrapscan *wrapscan = (Wrapscan *) a; + Rect *r = ®->valid; + int lsk = IM_REGION_LSKIP( reg ); + + int y; + PEL *p; + + p = (PEL *) IM_REGION_ADDR( reg, r->left, r->top ); + for( y = 0; y < r->height; y++ ) { + if( wrapscan->scan( p, r->width, seq, + wrapscan->a, wrapscan->b ) ) + return( -1 ); + p += lsk; + } + + return( 0 ); +} + +/* Like vips_sink(), but the scan function works a line at a time, like + * im_wrap*(). Shared with im_min(), im_deviate() etc. + */ +int +im__wrapscan( VipsImage *in, + VipsStart start, im__wrapscan_fn scan, VipsStop stop, + void *a, void *b ) +{ + Wrapscan wrapscan; + + wrapscan.in = in; + wrapscan.start = start; + wrapscan.scan = scan; + wrapscan.stop = stop; + wrapscan.a = a; + wrapscan.b = b; + + return( vips_sink( in, + wrapscan_start, wrapscan_scan, wrapscan_stop, + &wrapscan, NULL ) ); +} + /* Start function: allocate space for a pair of doubles in which we can * accumulate the sum and the sum of squares. */ diff --git a/libvips/arithmetic/im_maxpos.c b/libvips/arithmetic/im_maxpos.c index ace42f5d..d6b7ee3d 100644 --- a/libvips/arithmetic/im_maxpos.c +++ b/libvips/arithmetic/im_maxpos.c @@ -63,6 +63,22 @@ #include #endif /*WITH_DMALLOC*/ +/* Get the value of pixel (0, 0). Use this to init the min/max value for + * im_max()/im_stats()/etc. + */ +int +im__value( IMAGE *im, double *value ) +{ + IMAGE *t; + + if( !(t = im_open_local( im, "im__value", "p" )) || + im_extract_areabands( im, t, 0, 0, 1, 1, 0, 1 ) || + im_avg( t, value ) ) + return( -1 ); + + return( 0 ); +} + /* A position and maximum. */ typedef struct _Maxpos { diff --git a/libvips/arithmetic/statistic.c b/libvips/arithmetic/statistic.c new file mode 100644 index 00000000..bb6eb2f9 --- /dev/null +++ b/libvips/arithmetic/statistic.c @@ -0,0 +1,166 @@ +/* base class for all stats operations + * + * properties: + * - one image in, single value or matrix out + * - output depends on whole of input, ie. we have a sink + * + * 24/8/11 + * - from im_avg.c + */ + +/* + + 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 "statistic.h" + +#ifdef WITH_DMALLOC +#include +#endif /*WITH_DMALLOC*/ + +/* Properties. + */ +enum { + PROP_INPUT = 1, + PROP_LAST +}; + +G_DEFINE_ABSTRACT_TYPE( VipsStatistic, vips_statistic, VIPS_TYPE_OPERATION ); + +static void * +vips_statistic_scan_start( VipsImage *in, void *a, void *b ) +{ + VipsStatistic *statistic = VIPS_STATISTIC( a ); + VipsStatisticClass *class = VIPS_STATISTIC_GET_CLASS( statistic ); + + return( class->start( statistic ) ); +} + +static int +vips_statistic_scan( VipsRegion *region, void *seq, void *a, void *b ) +{ + VipsStatistic *statistic = VIPS_STATISTIC( a ); + VipsStatisticClass *class = VIPS_STATISTIC_GET_CLASS( statistic ); + + VipsRect *r = ®ion->valid; + int lsk = IM_REGION_LSKIP( region ); + + int y; + PEL *p; + + p = (PEL *) IM_REGION_ADDR( region, r->left, r->top ); + for( y = 0; y < r->height; y++ ) { + if( class->scan( statistic, seq, p, r->width ) ) + return( -1 ); + p += lsk; + } + + return( 0 ); +} + +static int +vips_statistic_scan_stop( void *seq, void *a, void *b ) +{ + VipsStatistic *statistic = VIPS_STATISTIC( a ); + VipsStatisticClass *class = VIPS_STATISTIC_GET_CLASS( statistic ); + + return( class->stop( statistic, seq ) ); +} + +static int +vips_statistic_build( VipsObject *object ) +{ + VipsStatistic *statistic = VIPS_STATISTIC( object ); + VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object ); + const char *domain = class->nickname; + +#ifdef DEBUG + printf( "vips_statistic_build: " ); + vips_object_print_name( object ); + printf( "\n" ); +#endif /*DEBUG*/ + + if( VIPS_OBJECT_CLASS( vips_statistic_parent_class )->build( object ) ) + return( -1 ); + + if( vips_image_pio_input( statistic->input ) || + vips_check_uncoded( domain, statistic->input ) ) + return( -1 ); + + if( vips_sink( statistic->input, + vips_statistic_scan_start, + vips_statistic_scan, + vips_statistic_scan_stop, + statistic, NULL ) ) + return( -1 ); + + return( 0 ); +} + +static void +vips_statistic_class_init( VipsStatisticClass *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->nickname = "statistic"; + vobject_class->description = _( "VIPS statistic operations" ); + vobject_class->build = vips_statistic_build; + + pspec = g_param_spec_object( "in", "Input", + _( "Input image" ), + VIPS_TYPE_IMAGE, + G_PARAM_READWRITE ); + g_object_class_install_property( gobject_class, + PROP_INPUT, pspec ); + vips_object_class_install_argument( vobject_class, pspec, + VIPS_ARGUMENT_REQUIRED_INPUT, + G_STRUCT_OFFSET( VipsStatistic, input ) ); +} + +static void +vips_statistic_init( VipsStatistic *statistic ) +{ +} diff --git a/libvips/arithmetic/statistic.h b/libvips/arithmetic/statistic.h new file mode 100644 index 00000000..d71d6509 --- /dev/null +++ b/libvips/arithmetic/statistic.h @@ -0,0 +1,91 @@ +/* base class for all stats 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_STATISTIC_H +#define VIPS_STATISTIC_H + +#ifdef __cplusplus +extern "C" { +#endif /*__cplusplus*/ + +#include + +#define VIPS_TYPE_STATISTIC (vips_statistic_get_type()) +#define VIPS_STATISTIC( obj ) \ + (G_TYPE_CHECK_INSTANCE_CAST( (obj), \ + VIPS_TYPE_STATISTIC, VipsStatistic )) +#define VIPS_STATISTIC_CLASS( klass ) \ + (G_TYPE_CHECK_CLASS_CAST( (klass), \ + VIPS_TYPE_STATISTIC, VipsStatisticClass)) +#define VIPS_IS_STATISTIC( obj ) \ + (G_TYPE_CHECK_INSTANCE_TYPE( (obj), VIPS_TYPE_STATISTIC )) +#define VIPS_IS_STATISTIC_CLASS( klass ) \ + (G_TYPE_CHECK_CLASS_TYPE( (klass), VIPS_TYPE_STATISTIC )) +#define VIPS_STATISTIC_GET_CLASS( obj ) \ + (G_TYPE_INSTANCE_GET_CLASS( (obj), \ + VIPS_TYPE_STATISTIC, VipsStatisticClass )) + +typedef struct _VipsStatistic VipsStatistic; +typedef struct _VipsStatisticClass VipsStatisticClass; + +typedef void *(*VipsStatisticStartFn)( VipsStatistic *statistic ); +typedef int (*VipsStatisticScanFn)( VipsStatistic *statistic, void *seq, + void *p, int n ); +typedef int (*VipsStatisticStopFn)( VipsStatistic *statistic, void *seq ); + +struct _VipsStatistic { + VipsOperation parent_instance; + + /* All have an input image. + */ + VipsImage *input; + + /* Client data for the subclass. + */ + void *a; + void *b; +}; + +struct _VipsStatisticClass { + VipsOperationClass parent_class; + + /* Start/scan/stop, for vips_sink. + */ + VipsStatisticStartFn start; + VipsStatisticScanFn scan; + VipsStatisticStopFn stop; +}; + +GType vips_statistic_get_type( void ); + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +#endif /*VIPS_STATISTIC_H*/ diff --git a/libvips/arithmetic/subtract.c b/libvips/arithmetic/subtract.c index 6b07f573..df597f0e 100644 --- a/libvips/arithmetic/subtract.c +++ b/libvips/arithmetic/subtract.c @@ -186,29 +186,30 @@ subtract_buffer( VipsBinary *binary, /* Complex just doubles the size. */ - const int sz = width * im->Bands * - (vips_band_format_iscomplex( im->BandFmt ) ? 2 : 1); + const int sz = width * vips_image_get_bands( im ) * + (vips_band_format_iscomplex( vips_image_get_format( im ) ) ? + 2 : 1); int x; /* Keep types here in sync with bandfmt_subtract[] * below. */ - switch( im->BandFmt ) { - case IM_BANDFMT_CHAR: LOOP( signed char, signed short ); break; - case IM_BANDFMT_UCHAR: LOOP( unsigned char, signed short ); break; - case IM_BANDFMT_SHORT: LOOP( signed short, signed int ); break; - case IM_BANDFMT_USHORT: LOOP( unsigned short, signed int ); break; - case IM_BANDFMT_INT: LOOP( signed int, signed int ); break; - case IM_BANDFMT_UINT: LOOP( unsigned int, signed int ); break; + switch( vips_image_get_format( im ) ) { + case VIPS_FORMAT_CHAR: LOOP( signed char, signed short ); break; + case VIPS_FORMAT_UCHAR: LOOP( unsigned char, signed short ); break; + case VIPS_FORMAT_SHORT: LOOP( signed short, signed int ); break; + case VIPS_FORMAT_USHORT:LOOP( unsigned short, signed int ); break; + case VIPS_FORMAT_INT: LOOP( signed int, signed int ); break; + case VIPS_FORMAT_UINT: LOOP( unsigned int, signed int ); break; - case IM_BANDFMT_FLOAT: - case IM_BANDFMT_COMPLEX: + case VIPS_FORMAT_FLOAT: + case VIPS_FORMAT_COMPLEX: LOOP( float, float ); break; - case IM_BANDFMT_DOUBLE: - case IM_BANDFMT_DPCOMPLEX: + case VIPS_FORMAT_DOUBLE: + case VIPS_FORMAT_DPCOMPLEX: LOOP( double, double ); break; @@ -219,21 +220,21 @@ subtract_buffer( VipsBinary *binary, /* 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 +#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 subtraction. Sign and value preserving. Make sure these * match the case statement in subtract_buffer() above. */ -static int bandfmt_subtract[10] = { +static const VipsBandFormat bandfmt_subtract[10] = { /* UC C US S UI I F X D DX */ S, S, I, I, I, I, F, X, D, DX }; diff --git a/libvips/deprecated/vips7compat.c b/libvips/deprecated/vips7compat.c index 35d69e1b..9e62af5c 100644 --- a/libvips/deprecated/vips7compat.c +++ b/libvips/deprecated/vips7compat.c @@ -948,3 +948,9 @@ im_subtract( IMAGE *in1, IMAGE *in2, IMAGE *out ) return( 0 ); } + +int +im_avg( IMAGE *in, double *out ) +{ + return( vips_avg( in, out, NULL ) ); +} diff --git a/libvips/include/vips/arithmetic.h b/libvips/include/vips/arithmetic.h index ccc2ec45..5fd3efb9 100644 --- a/libvips/include/vips/arithmetic.h +++ b/libvips/include/vips/arithmetic.h @@ -37,8 +37,13 @@ extern "C" { #endif /*__cplusplus*/ -/* arithmetic - */ +VipsImage *vips_add( VipsImage *in1, VipsImage *in2, ... ); +VipsImage *vips_subtract( VipsImage *in1, VipsImage *in2, ... ); +int vips_avg( VipsImage *in, double *out, ... ); + + + + DOUBLEMASK *im_measure_area( VipsImage *im, int left, int top, int width, int height, int h, int v, @@ -55,8 +60,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_add( VipsImage *in1, VipsImage *in2, VipsImage *out ); -int im_subtract( VipsImage *in1, VipsImage *in2, VipsImage *out ); int im_invert( VipsImage *in, VipsImage *out ); int im_lintra( double a, VipsImage *in, double b, VipsImage *out ); int im_lintra_vec( int n, double *a, VipsImage *in, double *b, VipsImage *out ); diff --git a/libvips/include/vips/header.h b/libvips/include/vips/header.h index 3ab9f554..3cb7edff 100644 --- a/libvips/include/vips/header.h +++ b/libvips/include/vips/header.h @@ -72,18 +72,18 @@ extern "C" { int vips_format_sizeof( VipsBandFormat format ); -int vips_image_get_width( VipsImage *image ); -int vips_image_get_height( VipsImage *image ); -int vips_image_get_bands( VipsImage *image ); -VipsBandFormat vips_image_get_format( VipsImage *image ); -VipsCoding vips_image_get_coding( VipsImage *image ); -VipsInterpretation vips_image_get_interpretation( VipsImage *image ); -double vips_image_get_xres( VipsImage *image ); -double vips_image_get_yres( VipsImage *image ); -int vips_image_get_xoffset( VipsImage *image ); -int vips_image_get_yoffset( VipsImage *image ); -const char *vips_image_get_filename( VipsImage *image ); -const char *vips_image_get_mode( VipsImage *image ); +int vips_image_get_width( const VipsImage *image ); +int vips_image_get_height( const VipsImage *image ); +int vips_image_get_bands( const VipsImage *image ); +VipsBandFormat vips_image_get_format( const VipsImage *image ); +VipsCoding vips_image_get_coding( const VipsImage *image ); +VipsInterpretation vips_image_get_interpretation( const VipsImage *image ); +double vips_image_get_xres( const VipsImage *image ); +double vips_image_get_yres( const VipsImage *image ); +int vips_image_get_xoffset( const VipsImage *image ); +int vips_image_get_yoffset( const VipsImage *image ); +const char *vips_image_get_filename( const VipsImage *image ); +const char *vips_image_get_mode( const VipsImage *image ); void *vips_image_get_data( VipsImage *image );; void vips_image_init_fields( VipsImage *image, @@ -99,6 +99,7 @@ int vips_image_copy_fields( VipsImage *out, VipsImage *in ); int vips_image_set( VipsImage *image, const char *field, GValue *value ); int vips_image_get( VipsImage *image, const char *field, GValue *value_copy ); +int vips_image_get_as_string( VipsImage *image, const char *field, char **out ); GType vips_image_get_typeof( VipsImage *image, const char *field ); gboolean vips_image_remove( VipsImage *image, const char *field ); typedef void *(*VipsImageMapFn)( VipsImage *image, @@ -170,8 +171,6 @@ int vips_image_set_double( VipsImage *image, const char *field, double d ); int vips_image_get_string( VipsImage *image, const char *field, char **out ); int vips_image_set_string( VipsImage *image, const char *field, const char *str ); -int vips_image_get_as_string( VipsImage *image, const char *field, char **out ); -GType vips_image_get_typeof( VipsImage *image, const char *field ); int vips_image_history_printf( VipsImage *image, const char *format, ... ) __attribute__((format(printf, 2, 3))); diff --git a/libvips/include/vips/vips7compat.h b/libvips/include/vips/vips7compat.h index 46f5d33f..afd63ec7 100644 --- a/libvips/include/vips/vips7compat.h +++ b/libvips/include/vips/vips7compat.h @@ -486,6 +486,9 @@ int im_wrapmany( VipsImage **in, VipsImage *out, #define im_concurrency_set vips_concurrency_set #define im_concurrency_get vips_concurrency_get +int im_add( VipsImage *in1, VipsImage *in2, VipsImage *out ); +int im_subtract( VipsImage *in1, VipsImage *in2, VipsImage *out ); + #ifdef __cplusplus } #endif /*__cplusplus*/ diff --git a/libvips/iofuncs/header.c b/libvips/iofuncs/header.c index e9aacdf0..ab6a9f56 100644 --- a/libvips/iofuncs/header.c +++ b/libvips/iofuncs/header.c @@ -343,73 +343,73 @@ meta_init( VipsImage *im ) } int -vips_image_get_width( VipsImage *image ) +vips_image_get_width( const VipsImage *image ) { return( image->Xsize ); } int -vips_image_get_height( VipsImage *image ) +vips_image_get_height( const VipsImage *image ) { return( image->Ysize ); } int -vips_image_get_bands( VipsImage *image ) +vips_image_get_bands( const VipsImage *image ) { return( image->Bands ); } VipsBandFormat -vips_image_get_format( VipsImage *image ) +vips_image_get_format( const VipsImage *image ) { return( image->BandFmt ); } VipsCoding -vips_image_get_coding( VipsImage *image ) +vips_image_get_coding( const VipsImage *image ) { return( image->Coding ); } VipsInterpretation -vips_image_get_interpretation( VipsImage *image ) +vips_image_get_interpretation( const VipsImage *image ) { return( image->Type ); } double -vips_image_get_xres( VipsImage *image ) +vips_image_get_xres( const VipsImage *image ) { return( image->Xres ); } double -vips_image_get_yres( VipsImage *image ) +vips_image_get_yres( const VipsImage *image ) { return( image->Yres ); } int -vips_image_get_xoffset( VipsImage *image ) +vips_image_get_xoffset( const VipsImage *image ) { return( image->Xoffset ); } int -vips_image_get_yoffset( VipsImage *image ) +vips_image_get_yoffset( const VipsImage *image ) { return( image->Yoffset ); } const char * -vips_image_get_filename( VipsImage *image ) +vips_image_get_filename( const VipsImage *image ) { return( image->filename ); } const char * -vips_image_get_mode( VipsImage *image ) +vips_image_get_mode( const VipsImage *image ) { return( image->mode ); } diff --git a/libvips/iofuncs/object.c b/libvips/iofuncs/object.c index f2c02503..6a86998d 100644 --- a/libvips/iofuncs/object.c +++ b/libvips/iofuncs/object.c @@ -125,18 +125,66 @@ vips_object_postclose( VipsObject *object ) } } +static void * +vips_object_check_required( VipsObject *object, GParamSpec *pspec, + VipsArgumentClass *argument_class, + VipsArgumentInstance *argument_instance, + void *a, void *b ) +{ + int *result = (int *) a; + + VIPS_DEBUG_MSG( "vips_object_check_required: %s\n", + g_param_spec_get_name( pspec ) ); + VIPS_DEBUG_MSG( "\trequired: %d\n", + argument_class->flags & VIPS_ARGUMENT_REQUIRED ); + VIPS_DEBUG_MSG( "\tconstruct: %d\n", + argument_class->flags & VIPS_ARGUMENT_CONSTRUCT ); + VIPS_DEBUG_MSG( "\tassigned: %d\n", + argument_instance->assigned ); + + if( (argument_class->flags & VIPS_ARGUMENT_REQUIRED) && + (argument_class->flags & VIPS_ARGUMENT_CONSTRUCT) && + !argument_instance->assigned ) { + vips_error( "VipsObject", + /* used as eg. "parameter out to VipsAdd not set". + */ + _( "parameter %s to %s not set" ), + g_param_spec_get_name( pspec ), + G_OBJECT_TYPE_NAME( object ) ); + *result = -1; + } + + return( NULL ); +} + int vips_object_build( VipsObject *object ) { VipsObjectClass *object_class = VIPS_OBJECT_GET_CLASS( object ); + int result; + #ifdef DEBUG printf( "vips_object_build: " ); vips_object_print_name( object ); printf( "\n" ); #endif /*DEBUG*/ - return( object_class->build( object ) ); + if( object_class->build( object ) ) + return( -1 ); + + /* Check all required arguments have been supplied, don't stop on 1st + * error. + */ + result = 0; + (void) vips_argument_map( object, + vips_object_check_required, &result, NULL ); + + /* ... more checks go here. + */ + object->constructed = TRUE; + + return( result ); } void @@ -840,45 +888,11 @@ vips_object_get_property( GObject *gobject, } } -static void * -vips_object_check_required( VipsObject *object, GParamSpec *pspec, - VipsArgumentClass *argument_class, - VipsArgumentInstance *argument_instance, - void *a, void *b ) -{ - int *result = (int *) a; - - VIPS_DEBUG_MSG( "vips_object_check_required: %s\n", - g_param_spec_get_name( pspec ) ); - VIPS_DEBUG_MSG( "\trequired: %d\n", - argument_class->flags & VIPS_ARGUMENT_REQUIRED ); - VIPS_DEBUG_MSG( "\tconstruct: %d\n", - argument_class->flags & VIPS_ARGUMENT_CONSTRUCT ); - VIPS_DEBUG_MSG( "\tassigned: %d\n", - argument_instance->assigned ); - - if( (argument_class->flags & VIPS_ARGUMENT_REQUIRED) && - (argument_class->flags & VIPS_ARGUMENT_CONSTRUCT) && - !argument_instance->assigned ) { - vips_error( "VipsObject", - /* used as eg. "parameter out to VipsAdd not set". - */ - _( "parameter %s to %s not set" ), - g_param_spec_get_name( pspec ), - G_OBJECT_TYPE_NAME( object ) ); - *result = -1; - } - - return( NULL ); -} - static int vips_object_real_build( VipsObject *object ) { VipsObjectClass *object_class = VIPS_OBJECT_GET_CLASS( object ); - int result; - #ifdef DEBUG printf( "vips_object_real_build: " ); vips_object_print_name( object ); @@ -887,17 +901,6 @@ vips_object_real_build( VipsObject *object ) g_assert( !object->constructed ); - /* Check all required arguments have been supplied, don't stop on 1st - * error. - */ - result = 0; - (void) vips_argument_map( object, - vips_object_check_required, &result, NULL ); - - /* ... more checks go here. - */ - object->constructed = TRUE; - /* It'd be nice if this just copied a pointer rather than did a * strdup(). Set these here rather than in object_init, so that the * class gets a chance to set them. @@ -906,7 +909,14 @@ vips_object_real_build( VipsObject *object ) "nickname", object_class->nickname, "description", object_class->description, NULL ); - return( result ); + /* We can't check that all required args have been set here, since our + * superclasses' build funcs might want to set some one the way out, + * see VipsAvg, for example. + * + * Do these checks in the build dispatch function, see above. + */ + + return( 0 ); } static void @@ -1286,7 +1296,7 @@ vips_object_get_argument_to_string( VipsObject *object, VipsBuf buf = VIPS_BUF_STATIC( str ); vips_object_print_arg( object, pspec, &buf ); - printf( "%s", vips_buf_all( &buf ) ); + printf( "%s\n", vips_buf_all( &buf ) ); } return( 0 );