diff --git a/ChangeLog b/ChangeLog
index a0583dce..4736532c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -7,7 +7,7 @@
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_abs(), im_sign()
redone as classes
- added argument priorites to help control arg ordering
- generate has a 'stop' param to signal successful early termination
diff --git a/libvips/arithmetic/Makefile.am b/libvips/arithmetic/Makefile.am
index 75a444a5..9527c551 100644
--- a/libvips/arithmetic/Makefile.am
+++ b/libvips/arithmetic/Makefile.am
@@ -16,7 +16,7 @@ libarithmetic_la_SOURCES = \
im_multiply.c \
im_point_bilinear.c \
im_remainder.c \
- im_sign.c \
+ sign.c \
im_stats.c \
statistic.c \
statistic.h \
diff --git a/libvips/arithmetic/abs.c b/libvips/arithmetic/abs.c
index 45bf65e9..fa9ba742 100644
--- a/libvips/arithmetic/abs.c
+++ b/libvips/arithmetic/abs.c
@@ -70,16 +70,18 @@
#include "arithmetic.h"
#include "unary.h"
-/**
+/**
* VipsAbs:
* @in: input #VipsImage
* @out: output #VipsImage
*
- * For unsigned formats, this operation calculates (max - @in), eg. (255 -
- * @in) for uchar. For signed and float formats, this operation calculates (-1
- * * @in).
+ * This operation finds the absolute value of an image. It does a copy for
+ * unsigned integer types, negate for negative values in
+ * signed integer types, fabs(3) for
+ * float types, and calculate modulus for complex
+ * types.
*
- * See also: im_lintra().
+ * See also: im_sign().
*
* Returns: 0 on success, -1 on error
*/
diff --git a/libvips/arithmetic/im_sign.c b/libvips/arithmetic/im_sign.c
deleted file mode 100644
index c6875ef9..00000000
--- a/libvips/arithmetic/im_sign.c
+++ /dev/null
@@ -1,142 +0,0 @@
-/* im_sign.c
- *
- * 9/7/02 JC
- * - from im_cmulnorm
- * 9/9/09
- * - gtkdoc, tidies
- */
-
-/*
-
- 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
-
-#define CSIGN( IN, OUT ) { \
- IN *p = (IN *) in; \
- OUT *q = (OUT *) out; \
- int x; \
- \
- for( x = 0; x < n; x++ ) { \
- IN re = p[0]; \
- IN im = p[1]; \
- double fac = sqrt( re * re + im * im ); \
- \
- p += 2; \
- \
- if( fac == 0.0 ) { \
- q[0] = 0.0; \
- q[1] = 0.0; \
- } \
- else { \
- q[0] = re / fac; \
- q[1] = im / fac; \
- } \
- \
- q += 2; \
- } \
-}
-
-#define SIGN( IN, OUT ) { \
- IN *p = (IN *) in; \
- OUT *q = (OUT *) out; \
- int x; \
- \
- for( x = 0; x < n; x++ ) { \
- IN v = p[x]; \
- \
- if( v > 0 ) \
- q[x] = 1; \
- else if( v == 0 ) \
- q[x] = 0; \
- else \
- q[x] = -1; \
- } \
-}
-
-/* sign buffer processor.
- */
-static void
-sign_gen( void *in, void *out, int w, IMAGE *im )
-{
- int n = w * im->Bands;
-
- switch( im->BandFmt ) {
- case IM_BANDFMT_UCHAR: SIGN( unsigned char, signed char ); break;
- case IM_BANDFMT_CHAR: SIGN( signed char, signed char ); break;
- case IM_BANDFMT_USHORT: SIGN( unsigned short, signed char ); break;
- case IM_BANDFMT_SHORT: SIGN( signed short, signed char ); break;
- case IM_BANDFMT_UINT: SIGN( unsigned int, signed char ); break;
- case IM_BANDFMT_INT: SIGN( signed int, signed char ); break;
- case IM_BANDFMT_FLOAT: SIGN( float, signed char ); break;
- case IM_BANDFMT_DOUBLE: SIGN( double, signed char ); break;
- case IM_BANDFMT_COMPLEX: CSIGN( float, float ); break;
- case IM_BANDFMT_DPCOMPLEX: CSIGN( double, double ); break;
-
- default:
- g_assert( 0 );
- }
-}
-
-/**
- * im_sign:
- * @in: input image
- * @out: output image
- *
- * Finds the unit vector in the direction of the pixel value. For non-complex
- * images, it returns a signed char image with values -1, 0, and 1 for negative,
- * zero and positive pixels. For complex images, it returns a
- * complex normalised to length 1.
- *
- * See also: im_abs(), im_cmulnorm(), im_c2amph().
- *
- * Returns: 0 on success, -1 on error
- */
-int
-im_sign( IMAGE *in, IMAGE *out )
-{
- if( im_piocheck( in, out ) ||
- im_check_uncoded( "im_sign", in ) ||
- im_cp_desc( out, in ) )
- return( -1 );
-
- if( !vips_bandfmt_iscomplex( in->BandFmt ) )
- out->BandFmt = IM_BANDFMT_CHAR;
-
- if( im_wrapone( in, out, (im_wrapone_fn) sign_gen, in, NULL ) )
- return( -1 );
-
- return( 0 );
-}
diff --git a/libvips/arithmetic/sign.c b/libvips/arithmetic/sign.c
new file mode 100644
index 00000000..b449b6fe
--- /dev/null
+++ b/libvips/arithmetic/sign.c
@@ -0,0 +1,186 @@
+/* im_sign.c
+ *
+ * 9/7/02 JC
+ * - from im_cmulnorm
+ * 9/9/09
+ * - gtkdoc, tidies
+ * 6/11/11
+ * - redone as a class
+ */
+
+/*
+
+ 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 "unary.h"
+
+/**
+ * VipsSign:
+ * @in: input image
+ * @out: output image
+ *
+ * Finds the unit vector in the direction of the pixel value. For non-complex
+ * images, it returns a signed char image with values -1, 0, and 1 for negative,
+ * zero and positive pixels. For complex images, it returns a
+ * complex normalised to length 1.
+ *
+ * See also: #VipsAbs.
+ */
+
+typedef VipsUnary VipsSign;
+typedef VipsUnaryClass VipsSignClass;
+
+G_DEFINE_TYPE( VipsSign, vips_sign, VIPS_TYPE_UNARY );
+
+#define CSIGN( TYPE ) { \
+ TYPE *p = (TYPE *) in; \
+ TYPE *q = (TYPE *) out; \
+ int x; \
+ \
+ for( x = 0; x < sz; x++ ) { \
+ TYPE re = p[0]; \
+ TYPE im = p[1]; \
+ double fac = sqrt( re * re + im * im ); \
+ \
+ p += 2; \
+ \
+ if( fac == 0.0 ) { \
+ q[0] = 0.0; \
+ q[1] = 0.0; \
+ } \
+ else { \
+ q[0] = re / fac; \
+ q[1] = im / fac; \
+ } \
+ \
+ q += 2; \
+ } \
+}
+
+#define SIGN( TYPE ) { \
+ TYPE *p = (TYPE *) in; \
+ signed char *q = (signed char *) out; \
+ int x; \
+ \
+ for( x = 0; x < sz; x++ ) { \
+ TYPE v = p[x]; \
+ \
+ if( v > 0 ) \
+ q[x] = 1; \
+ else if( v == 0 ) \
+ q[x] = 0; \
+ else \
+ q[x] = -1; \
+ } \
+}
+
+static void
+vips_sign_buffer( VipsArithmetic *arithmetic, PEL *out, PEL **in, int width )
+{
+ VipsImage *im = arithmetic->ready[0];
+ int sz = width * im->Bands;
+
+ switch( im->BandFmt ) {
+ case VIPS_FORMAT_UCHAR: SIGN( unsigned char ); break;
+ case VIPS_FORMAT_CHAR: SIGN( signed char ); break;
+ case VIPS_FORMAT_USHORT: SIGN( unsigned short ); break;
+ case VIPS_FORMAT_SHORT: SIGN( signed short ); break;
+ case VIPS_FORMAT_UINT: SIGN( unsigned int ); break;
+ case VIPS_FORMAT_INT: SIGN( signed int ); break;
+ case VIPS_FORMAT_FLOAT: SIGN( float ); break;
+ case VIPS_FORMAT_DOUBLE: SIGN( double ); break;
+ case VIPS_FORMAT_COMPLEX: CSIGN( float ); break;
+ case VIPS_FORMAT_DPCOMPLEX: CSIGN( 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
+
+static const VipsBandFormat vips_bandfmt_sign[10] = {
+/* UC C US S UI I F X D DX */
+ C, C, C, C, C, C, C, X, C, DX
+};
+
+static void
+vips_sign_class_init( VipsSignClass *class )
+{
+ VipsObjectClass *object_class = (VipsObjectClass *) class;
+ VipsArithmeticClass *aclass = VIPS_ARITHMETIC_CLASS( class );
+
+ object_class->nickname = "sign";
+ object_class->description = _( "unit vector of pixel" );
+
+ vips_arithmetic_set_format_table( aclass, vips_bandfmt_sign );
+
+ aclass->process_line = vips_sign_buffer;
+}
+
+static void
+vips_sign_init( VipsSign *sign )
+{
+}
+
+int
+vips_sign( VipsImage *in, VipsImage **out, ... )
+{
+ va_list ap;
+ int result;
+
+ va_start( ap, out );
+ result = vips_call_split( "sign", ap, in, out );
+ va_end( ap );
+
+ return( result );
+}
diff --git a/libvips/deprecated/vips7compat.c b/libvips/deprecated/vips7compat.c
index f49214f8..5f7a66fe 100644
--- a/libvips/deprecated/vips7compat.c
+++ b/libvips/deprecated/vips7compat.c
@@ -1392,6 +1392,23 @@ im_invert( IMAGE *in, IMAGE *out )
return( 0 );
}
+int
+im_sign( IMAGE *in, IMAGE *out )
+{
+ VipsImage *t;
+
+ if( vips_sign( in, &t,
+ NULL ) )
+ return( -1 );
+ if( vips_image_write( t, out ) ) {
+ g_object_unref( t );
+ return( -1 );
+ }
+ g_object_unref( t );
+
+ return( 0 );
+}
+
int
im_abs( IMAGE *in, IMAGE *out )
{
diff --git a/libvips/include/vips/arithmetic.h b/libvips/include/vips/arithmetic.h
index e11efe79..f676cae7 100644
--- a/libvips/include/vips/arithmetic.h
+++ b/libvips/include/vips/arithmetic.h
@@ -86,6 +86,8 @@ int vips_math( VipsImage *in, VipsImage **out,
__attribute__((sentinel));
int vips_abs( VipsImage *in, VipsImage **out, ... )
__attribute__((sentinel));
+int vips_sign( VipsImage *in, VipsImage **out, ... )
+ __attribute__((sentinel));
@@ -110,7 +112,6 @@ int im_remainder_vec( VipsImage *in, VipsImage *out, int n, double *c );
int im_remainderconst( VipsImage *in, VipsImage *out, double c );
int im_recomb( VipsImage *in, VipsImage *out, DOUBLEMASK *recomb );
-int im_sign( VipsImage *in, VipsImage *out );
int im_floor( VipsImage *in, VipsImage *out );
int im_rint( VipsImage *in, VipsImage *out );
int im_ceil( VipsImage *in, VipsImage *out );
diff --git a/libvips/include/vips/vips7compat.h b/libvips/include/vips/vips7compat.h
index 2d9f4311..998664cc 100644
--- a/libvips/include/vips/vips7compat.h
+++ b/libvips/include/vips/vips7compat.h
@@ -529,6 +529,7 @@ 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 );
int im_abs( VipsImage *in, VipsImage *out );
+int im_sign( VipsImage *in, VipsImage *out );
int im_sintra( VipsImage *in, VipsImage *out );
int im_costra( VipsImage *in, VipsImage *out );