diff --git a/ChangeLog b/ChangeLog index 4ecaaec6..bda9642a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -12,7 +12,7 @@ im_rint(), im_equal*(), im_notequal*(), im_less*(), im_lesseq*(), im_more*(), im_moreeq*(), im_remainder*(), im_and*(), im_or*(), im_eor*(), im_shift*(), im_pow*(), im_exp*(), im_ifthenelse(), im_blend(), im_c2amph(), im_c2rect(), - im_bandmean(), im_c2real(), im_c2imag() + im_bandmean(), im_c2real(), im_c2imag(), im_ri2c() 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 5a968ce4..94002cda 100644 --- a/TODO +++ b/TODO @@ -1,4 +1,4 @@ -- form complex can be an arith binary op +- text vips_complexform() - try diff --git a/libvips/arithmetic/arithmetic.c b/libvips/arithmetic/arithmetic.c index fbabdfe0..8aa13847 100644 --- a/libvips/arithmetic/arithmetic.c +++ b/libvips/arithmetic/arithmetic.c @@ -504,6 +504,7 @@ vips_arithmetic_operation_init( void ) extern GType vips_math2_const_get_type( void ); extern GType vips_complex_get_type( void ); extern GType vips_complexget_get_type( void ); + extern GType vips_complexform_get_type( void ); vips_add_get_type(); vips_subtract_get_type(); @@ -531,4 +532,5 @@ vips_arithmetic_operation_init( void ) vips_math2_const_get_type(); vips_complex_get_type(); vips_complexget_get_type(); + vips_complexform_get_type(); } diff --git a/libvips/arithmetic/complex.c b/libvips/arithmetic/complex.c index 435e9d31..99602a3c 100644 --- a/libvips/arithmetic/complex.c +++ b/libvips/arithmetic/complex.c @@ -65,6 +65,7 @@ #include #include "unary.h" +#include "binary.h" typedef struct _VipsComplex { VipsUnary parent_instance; @@ -575,3 +576,147 @@ vips_imag( VipsImage *in, VipsImage **out, ... ) return( result ); } + +typedef VipsBinary VipsComplexform; +typedef VipsBinaryClass VipsComplexformClass; + +G_DEFINE_TYPE( VipsComplexform, vips_complexform, VIPS_TYPE_BINARY ); + +static int +vips_complexform_build( VipsObject *object ) +{ + VipsBinary *binary = (VipsBinary *) object; + + if( binary->left && + vips_check_noncomplex( "VipsComplexform", binary->left ) ) + return( -1 ); + if( binary->right && + vips_check_noncomplex( "VipsComplexform", binary->right ) ) + return( -1 ); + + if( VIPS_OBJECT_CLASS( vips_complexform_parent_class )-> + build( object ) ) + return( -1 ); + + return( 0 ); +} + +#define CFORM( IN, OUT ) { \ + IN *left = (IN *) in[0]; \ + IN *right = (IN *) in[1]; \ + OUT *q = (OUT *) out; \ + \ + for( x = 0; x < sz; x++ ) { \ + q[0] = left[x]; \ + q[1] = right[x]; \ + \ + q += 2; \ + } \ +} + +static void +vips_complexform_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 bandfmt_complexform[] + * below. + */ + switch( vips_image_get_format( im ) ) { + case VIPS_FORMAT_CHAR: CFORM( signed char, float ); break; + case VIPS_FORMAT_UCHAR: CFORM( unsigned char, float ); break; + case VIPS_FORMAT_SHORT: CFORM( signed short, float ); break; + case VIPS_FORMAT_USHORT:CFORM( unsigned short, float ); break; + case VIPS_FORMAT_INT: CFORM( signed int, float ); break; + case VIPS_FORMAT_UINT: CFORM( unsigned int, float ); break; + case VIPS_FORMAT_FLOAT: CFORM( float, float ); break; + case VIPS_FORMAT_DOUBLE: CFORM( double, 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 division. Sign and value preserving. Make sure + * these match the case statement in complexform_buffer() above. + */ +static int vips_bandfmt_complexform[10] = { +/* UC C US S UI I F X D DX */ + X, X, X, X, X, X, X, X, DX,DX +}; + +static void +vips_complexform_class_init( VipsComplexformClass *class ) +{ + VipsObjectClass *object_class = (VipsObjectClass *) class; + VipsArithmeticClass *aclass = VIPS_ARITHMETIC_CLASS( class ); + + object_class->nickname = "complexform"; + object_class->description = + _( "form a complex image from two real images" ); + object_class->build = vips_complexform_build; + + vips_arithmetic_set_format_table( aclass, vips_bandfmt_complexform ); + + aclass->process_line = vips_complexform_buffer; +} + +static void +vips_complexform_init( VipsComplexform *complexform ) +{ +} + +/** + * vips_complexform: + * @left: input image + * @right: input image + * @out: output image + * + * Compose two real images to make a complex image. If either @left or @right + * are #VIPS_FORMAT_DOUBLE, @out is #VIPS_FORMAT_DPCOMPLEX. Otherwise @out + * is #VIPS_FORMAT_COMPLEX. @left becomes the real component of @out and + * @right the imaginary. + * + * If the number of bands differs, one of the images + * must have one band. In this case, an n-band image is formed from the + * one-band image by joining n copies of the one-band image together, and then + * the two n-band images are operated upon. + * + * See also: vips_complexget(). + * + * Returns: 0 on success, -1 on error + */ +int +vips_complexform( VipsImage *left, VipsImage *right, VipsImage **out, ... ) +{ + va_list ap; + int result; + + va_start( ap, out ); + result = vips_call_split( "complexform", ap, left, right, out ); + va_end( ap ); + + return( result ); +} + + + + + diff --git a/libvips/conversion/Makefile.am b/libvips/conversion/Makefile.am index f3dae9b2..f19d5ef0 100644 --- a/libvips/conversion/Makefile.am +++ b/libvips/conversion/Makefile.am @@ -24,7 +24,6 @@ libconversion_la_SOURCES = \ im_falsecolour.c \ im_msb.c \ im_grid.c \ - im_ri2c.c \ im_scale.c \ im_scaleps.c \ im_subsample.c \ diff --git a/libvips/conversion/im_ri2c.c b/libvips/conversion/im_ri2c.c deleted file mode 100644 index fea79543..00000000 --- a/libvips/conversion/im_ri2c.c +++ /dev/null @@ -1,154 +0,0 @@ -/* im_ri2c - * - * Author: Nicos Dessipris - * Written on: 12/02/1990 - * Modified on : 10/04/1990 - * 16/11/94 JC - * - rewritten with partials - * - more general - * 1/2/10 - * - bandalike - * - better upcasting - * - gtkdoc - * - cleanups - * 28/2/11 - * - oop heh argh was broken, added to test suite - */ - -/* - - 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 - -#define JOIN( TYPE ) { \ - TYPE *p1 = (TYPE *) p[0]; \ - TYPE *p2 = (TYPE *) p[1]; \ - TYPE *q0 = (TYPE *) q; \ - \ - for( x = 0; x < len; x++ ) { \ - q0[0] = p1[x]; \ - q0[1] = p2[x]; \ - \ - q0 += 2; \ - } \ -} - -/* Join two buffers to make a complex. - */ -static void -join_buffer( PEL **p, PEL *q, int n, IMAGE *out ) -{ - int x; - int len = n * out->Bands; - - switch( out->BandFmt ) { - case IM_BANDFMT_COMPLEX: - JOIN( float ); - break; - - case IM_BANDFMT_DPCOMPLEX: - JOIN( double ); - break; - - default: - g_assert( 0 ); - } -} - -/** - * im_ri2c: - * @in1: input image - * @in2: input image - * @out: output image - * - * Compose two real images to make a complex image. If either @in1 or @in2 are - * %IM_BANDFMT_DOUBLE, @out is %IM_BANDFMT_DPCOMPLEX. Otherwise @out is - * %IM_BANDFMT_COMPLEX. @in1 becomes the real component of @out and @in2 the - * imaginary. - * - * If the number of bands differs, one of the images - * must have one band. In this case, an n-band image is formed from the - * one-band image by joining n copies of the one-band image together, and then - * the two n-band images are operated upon. - * - * See also: im_c2real(), im_c2imag(). - * - * Returns: 0 on success, -1 on error - */ -int -im_ri2c( IMAGE *in1, IMAGE *in2, IMAGE *out ) -{ - IMAGE *t[5]; - VipsBandFmt fmt; - - /* Check input image. We don't need to check that sizes match -- - * im_wrapmany does this for us. - */ - if( im_check_uncoded( "im_ri2c", in1 ) || - im_check_uncoded( "im_ri2c", in2 ) || - im_check_noncomplex( "im_ri2c", in1 ) || - im_check_noncomplex( "im_ri2c", in2 ) || - im_check_bands_1orn( "im_ri2c", in1, in2 ) ) - return( -1 ); - - /* If either of the inputs is DOUBLE, we are - * DPCOMPLEX; otherwise we are COMPLEX. - */ - if( in1->BandFmt == IM_BANDFMT_DOUBLE || - in2->BandFmt == IM_BANDFMT_DOUBLE ) - fmt = IM_BANDFMT_DOUBLE; - else - fmt = IM_BANDFMT_FLOAT; - - if( im_open_local_array( out, t, 4, "im_ri2c", "p" ) || - im_clip2fmt( in1, t[0], fmt ) || - im_clip2fmt( in2, t[1], fmt ) || - im__bandalike( "im_ri2c", t[0], t[1], t[2], t[3] ) ) - return( -1 ); - - /* Remember to NULL-terminate. - */ - t[4] = NULL; - - if( im_cp_descv( out, t[2], t[3], NULL ) ) - return( -1 ); - out->BandFmt = (fmt == IM_BANDFMT_DOUBLE) ? - IM_BANDFMT_DPCOMPLEX : IM_BANDFMT_COMPLEX; - - if( im_wrapmany( t + 2, out, (im_wrapmany_fn) join_buffer, out, NULL ) ) - return( -1 ); - - return( 0 ); -} diff --git a/libvips/deprecated/vips7compat.c b/libvips/deprecated/vips7compat.c index 51f34e26..9811896a 100644 --- a/libvips/deprecated/vips7compat.c +++ b/libvips/deprecated/vips7compat.c @@ -2152,3 +2152,19 @@ im_c2imag( IMAGE *in, IMAGE *out ) return( vips__complexget( in, out, VIPS_OPERATION_COMPLEXGET_IMAG ) ); } +int +im_ri2c( IMAGE *in1, IMAGE *in2, IMAGE *out ) +{ + VipsImage *x; + + if( vips_call( "complexform", in1, in2, &x, NULL ) ) + return( -1 ); + if( im_copy( x, out ) ) { + g_object_unref( x ); + return( -1 ); + } + g_object_unref( x ); + + return( 0 ); +} + diff --git a/libvips/include/vips/arithmetic.h b/libvips/include/vips/arithmetic.h index ccb42ed8..0e9a17ff 100644 --- a/libvips/include/vips/arithmetic.h +++ b/libvips/include/vips/arithmetic.h @@ -238,6 +238,9 @@ int vips_real( VipsImage *in, VipsImage **out, ... ) int vips_imag( VipsImage *in, VipsImage **out, ... ) __attribute__((sentinel)); +int vips_complexform( VipsImage *left, VipsImage *right, VipsImage **out, ... ) + __attribute__((sentinel)); + int vips_relational( VipsImage *left, VipsImage *right, VipsImage **out, VipsOperationRelational relational, ... ) __attribute__((sentinel)); diff --git a/libvips/include/vips/conversion.h b/libvips/include/vips/conversion.h index 95173798..14e13d6a 100644 --- a/libvips/include/vips/conversion.h +++ b/libvips/include/vips/conversion.h @@ -206,7 +206,6 @@ int im_scale( VipsImage *in, VipsImage *out ); int im_msb( VipsImage *in, VipsImage *out ); int im_msb_band( VipsImage *in, VipsImage *out, int band ); -int im_ri2c( VipsImage *in1, VipsImage *in2, VipsImage *out ); int im_scaleps( VipsImage *in, VipsImage *out ); int im_falsecolour( VipsImage *in, VipsImage *out ); diff --git a/libvips/include/vips/vips7compat.h b/libvips/include/vips/vips7compat.h index e56ea56d..7a43eb9c 100644 --- a/libvips/include/vips/vips7compat.h +++ b/libvips/include/vips/vips7compat.h @@ -634,6 +634,7 @@ int im_c2amph( VipsImage *in, VipsImage *out ); int im_c2rect( VipsImage *in, VipsImage *out ); int im_c2imag( VipsImage *in, VipsImage *out ); int im_c2real( VipsImage *in, VipsImage *out ); +int im_ri2c( VipsImage *in1, VipsImage *in2, VipsImage *out ); int im_rot90( VipsImage *in, VipsImage *out ); int im_rot180( VipsImage *in, VipsImage *out );