libvips/libvips/boolean/boolean.c

546 lines
13 KiB
C

/* boolean.c --- various bit operations
*
* Modified:
* 15/12/94 JC
* - ANSIfied
* - adapted to partials with im_wrap...
* 25/1/95 JC
* - added check1ary(), check2ary()
* 8/2/95 JC
* - new im_wrapmany
* 19/7/95 JC
* - added im_shiftleft() and im_shiftright()
* 6/7/98 JC
* - added _vec forms
* - removed *p++ stuff
* 10/9/99 JC
* - and/or/eor now do all int types
* 10/10/02 JC
* - renamed im_and() etc. as im_andimage() to remove breakage in the C++
* layer if operator names are turned on
* 30/6/04
* - now cast float/complex args to int
* 11/9/09
* - use new im__cast_and__call()
* - therefore now supports 1-band $op n-band
* 17/9/09
* - moved to im__arith_binary*()
* - renamed im_eor_vec() as im_eorimage_vec() for C++ sanity
*/
/*
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 <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#include <stdio.h>
#include <math.h>
#include <vips/vips.h>
#include <vips/internal.h>
#ifdef WITH_DMALLOC
#include <dmalloc.h>
#endif /*WITH_DMALLOC*/
/* 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
/* Type conversions for boolean.
*/
static int bandfmt_bool[10] = {
/* UC C US S UI I F X D DX */
UC, C, US, S, UI, I, I, I, I, I,
};
#define BINARY( IN, OUT, OP ) { \
OUT *tq = (OUT *) q; \
IN *tp1 = (IN *) p[0]; \
IN *tp2 = (IN *) p[1]; \
\
for( i = 0; i < ne; i++ ) \
tq[i] = (OUT) tp1[i] OP (OUT) tp2[i]; \
}
#define BINARY_BUFFER( NAME, OP ) \
static void \
NAME ## _buffer( PEL **p, PEL *q, int n, IMAGE *im ) \
{ \
/* Complex just doubles the size. \
*/ \
const int ne = n * im->Bands * (im_iscomplex( im ) ? 2 : 1); \
\
int i; \
\
switch( im->BandFmt ) { \
case IM_BANDFMT_CHAR: \
BINARY( signed char, signed char, OP ); break; \
case IM_BANDFMT_UCHAR: \
BINARY( unsigned char, unsigned char, OP ); break; \
case IM_BANDFMT_SHORT: \
BINARY( signed short, signed short, OP ); break; \
case IM_BANDFMT_USHORT: \
BINARY( unsigned short, unsigned short, OP ); break; \
case IM_BANDFMT_INT: \
BINARY( signed int, signed int, OP ); break; \
case IM_BANDFMT_UINT: \
BINARY( unsigned int, unsigned int, OP ); break; \
case IM_BANDFMT_FLOAT: \
BINARY( float, signed int, OP ); break; \
case IM_BANDFMT_COMPLEX: \
BINARY( float, signed int, OP ); break; \
case IM_BANDFMT_DOUBLE: \
BINARY( double, signed int, OP ); break; \
case IM_BANDFMT_DPCOMPLEX: \
BINARY( double, signed int, OP ); break; \
\
default: \
g_assert( 0 ); \
} \
}
BINARY_BUFFER( AND, & )
/**
* im_andimage:
* @in1: input #IMAGE 1
* @in2: input #IMAGE 2
* @out: output #IMAGE
*
* This operation calculates @in1 & @in2 and writes the result to @out.
* The images must be the same size. They may have any format. They may differ
* in their number of bands, see above.
*
* See also: im_orimage().
*
* Returns: 0 on success, -1 on error
*/
int
im_andimage( IMAGE *in1, IMAGE *in2, IMAGE *out )
{
return( im__arith_binary( "im_andimage",
in1, in2, out,
bandfmt_bool,
(im_wrapmany_fn) AND_buffer, NULL ) );
}
BINARY_BUFFER( OR, | )
/**
* im_orimage:
* @in1: input #IMAGE 1
* @in2: input #IMAGE 2
* @out: output #IMAGE
*
* This operation calculates @in1 | @in2 and writes the result to @out.
* The images must be the same size. They may have any format. They may differ
* in their number of bands, see above.
*
* See also: im_eorimage().
*
* Returns: 0 on success, -1 on error
*/
int
im_orimage( IMAGE *in1, IMAGE *in2, IMAGE *out )
{
return( im__arith_binary( "im_orimage",
in1, in2, out,
bandfmt_bool,
(im_wrapmany_fn) OR_buffer, NULL ) );
}
BINARY_BUFFER( EOR, ^ )
/**
* im_eorimage:
* @in1: input #IMAGE 1
* @in2: input #IMAGE 2
* @out: output #IMAGE
*
* This operation calculates @in1 ^ @in2 and writes the result to @out.
* The images must be the same size. They may have any format. They may differ
* in their number of bands, see above.
*
* See also: im_eorimage_vec(), im_andimage().
*
* Returns: 0 on success, -1 on error
*/
int
im_eorimage( IMAGE *in1, IMAGE *in2, IMAGE *out )
{
return( im__arith_binary( "im_eorimage",
in1, in2, out,
bandfmt_bool,
(im_wrapmany_fn) EOR_buffer, NULL ) );
}
#define CONST1( IN, OUT, OP ) { \
OUT *tq = (OUT *) q; \
IN *tp = (IN *) p; \
IN tc = *((IN *) vector); \
\
for( i = 0; i < ne; i++ ) \
tq[i] = (OUT) tp[i] OP (OUT) tc; \
}
#define CONST1_BUFFER( NAME, OP ) \
static void \
NAME ## 1_buffer( PEL *p, PEL *q, int n, PEL *vector, IMAGE *im ) \
{ \
/* Complex just doubles the size. \
*/ \
const int ne = n * im->Bands * (im_iscomplex( im ) ? 2 : 1); \
\
int i; \
\
switch( im->BandFmt ) { \
case IM_BANDFMT_CHAR: \
CONST1( signed char, signed char, OP ); break; \
case IM_BANDFMT_UCHAR: \
CONST1( unsigned char, unsigned char, OP ); break; \
case IM_BANDFMT_SHORT: \
CONST1( signed short, signed short, OP ); break; \
case IM_BANDFMT_USHORT: \
CONST1( unsigned short, unsigned short, OP ); break; \
case IM_BANDFMT_INT: \
CONST1( signed int, signed int, OP ); break; \
case IM_BANDFMT_UINT: \
CONST1( unsigned int, unsigned int, OP ); break; \
case IM_BANDFMT_FLOAT: \
CONST1( float, signed int, OP ); break; \
case IM_BANDFMT_COMPLEX: \
CONST1( float, signed int, OP ); break; \
case IM_BANDFMT_DOUBLE: \
CONST1( double, signed int, OP ); break; \
case IM_BANDFMT_DPCOMPLEX: \
CONST1( double, signed int, OP ); break; \
\
default: \
g_assert( 0 ); \
} \
}
#define CONSTN( IN, OUT, OP ) { \
OUT *tq = (OUT *) q; \
IN *tp = (IN *) p; \
IN *tc = (IN *) vector; \
\
for( i = 0, x = 0; x < n; x++ ) \
for( b = 0; b < bands; b++, i++ ) \
tq[i] = (OUT) tp[i] OP (OUT) tc[b]; \
}
#define CONSTN_BUFFER( NAME, OP ) \
static void \
NAME ## n_buffer( PEL *p, PEL *q, int n, PEL *vector, IMAGE *im ) \
{ \
const int bands = im->Bands; \
\
int i, x, b; \
\
switch( im->BandFmt ) { \
case IM_BANDFMT_CHAR: \
CONSTN( signed char, signed char, OP ); break; \
case IM_BANDFMT_UCHAR: \
CONSTN( unsigned char, unsigned char, OP ); break; \
case IM_BANDFMT_SHORT: \
CONSTN( signed short, signed short, OP ); break; \
case IM_BANDFMT_USHORT: \
CONSTN( unsigned short, unsigned short, OP ); break; \
case IM_BANDFMT_INT: \
CONSTN( signed int, signed int, OP ); break; \
case IM_BANDFMT_UINT: \
CONSTN( unsigned int, unsigned int, OP ); break; \
case IM_BANDFMT_FLOAT: \
CONSTN( float, signed int, OP ); break; \
case IM_BANDFMT_COMPLEX: \
CONSTN( float, signed int, OP ); break; \
case IM_BANDFMT_DOUBLE: \
CONSTN( double, signed int, OP ); break; \
case IM_BANDFMT_DPCOMPLEX: \
CONSTN( double, signed int, OP ); break; \
\
default: \
g_assert( 0 ); \
} \
}
CONST1_BUFFER( AND, & )
CONSTN_BUFFER( AND, & )
/**
* im_andimage_vec:
* @in: input #IMAGE 1
* @out: output #IMAGE
* @n: array length
* @c: array of constants
*
* This operation calculates @in & @c (bitwise and of image pixels with array
* @c) and writes the result to @out.
*
* See also: im_andimage(), im_orimage_vec().
*
* Returns: 0 on success, -1 on error
*/
int
im_andimage_vec( IMAGE *in, IMAGE *out, int n, double *c )
{
return( im__arith_binary_const( "im_andimage",
in, out, n, c,
bandfmt_bool,
(im_wrapone_fn) AND1_buffer,
(im_wrapone_fn) ANDn_buffer ) );
}
/**
* im_andimageconst:
* @in: input #IMAGE 1
* @out: output #IMAGE
* @c: constant
*
* This operation calculates @in & @c (bitwise and of image pixels with
* constant
* @c) and writes the result to @out.
*
* See also: im_andimage(), im_orimage_vec().
*
* Returns: 0 on success, -1 on error
*/
int
im_andimageconst( IMAGE *in, IMAGE *out, double c )
{
return( im_andimage_vec( in, out, 1, &c ) );
}
CONST1_BUFFER( OR, | )
CONSTN_BUFFER( OR, | )
/**
* im_orimage_vec:
* @in: input #IMAGE 1
* @out: output #IMAGE
* @n: array length
* @c: array of constants
*
* This operation calculates @in | @c (bitwise or of image pixels with array
* @c) and writes the result to @out.
*
* See also: im_andimage(), im_orimageconst().
*
* Returns: 0 on success, -1 on error
*/
int
im_orimage_vec( IMAGE *in, IMAGE *out, int n, double *c )
{
return( im__arith_binary_const( "im_orimage",
in, out, n, c,
bandfmt_bool,
(im_wrapone_fn) OR1_buffer,
(im_wrapone_fn) ORn_buffer ) );
}
/**
* im_orimageconst:
* @in: input #IMAGE 1
* @out: output #IMAGE
* @c: constant
*
* This operation calculates @in | @c (bitwise or of image pixels with
* constant
* @c) and writes the result to @out.
*
* See also: im_andimage(), im_orimage_vec().
*
* Returns: 0 on success, -1 on error
*/
int
im_orimageconst( IMAGE *in, IMAGE *out, double c )
{
return( im_orimage_vec( in, out, 1, &c ) );
}
CONST1_BUFFER( EOR, ^ )
CONSTN_BUFFER( EOR, ^ )
/**
* im_eorimage_vec:
* @in: input #IMAGE 1
* @out: output #IMAGE
* @n: array length
* @c: array of constants
*
* This operation calculates @in ^ @c (bitwise exclusive-or of image pixels
* with array
* @c) and writes the result to @out.
*
* See also: im_andimage(), im_orimageconst().
*
* Returns: 0 on success, -1 on error
*/
int
im_eorimage_vec( IMAGE *in, IMAGE *out, int n, double *c )
{
return( im__arith_binary_const( "im_eorimage",
in, out, n, c,
bandfmt_bool,
(im_wrapone_fn) EOR1_buffer,
(im_wrapone_fn) EORn_buffer ) );
}
/**
* im_eorimageconst:
* @in: input #IMAGE 1
* @out: output #IMAGE
* @c: constant
*
* This operation calculates @in ^ @c (bitwise exclusive-or of image pixels
* with
* constant
* @c) and writes the result to @out.
*
* See also: im_andimage(), im_orimage_vec().
*
* Returns: 0 on success, -1 on error
*/
int
im_eorimageconst( IMAGE *in, IMAGE *out, double c )
{
return( im_eorimage_vec( in, out, 1, &c ) );
}
CONST1_BUFFER( SHIFTL, << )
CONSTN_BUFFER( SHIFTL, << )
/**
* im_shiftleft_vec:
* @in: input #IMAGE
* @out: output #IMAGE
* @n: array length
* @c: array of constants
*
* This operation calculates @in << @c (left-shift by @c bits
* with array
* @c) and writes the result to @out.
*
* See also: im_andimage(), im_orimageconst().
*
* Returns: 0 on success, -1 on error
*/
int
im_shiftleft_vec( IMAGE *in, IMAGE *out, int n, double *c )
{
return( im__arith_binary_const( "im_shiftleft",
in, out, n, c,
bandfmt_bool,
(im_wrapone_fn) SHIFTL1_buffer,
(im_wrapone_fn) SHIFTLn_buffer ) );
}
/**
* im_shiftleft:
* @in: input #IMAGE
* @out: output #IMAGE
* @n: constant
*
* This operation calculates @in << @n (left-shift by @n bits)
* and writes the result to @out.
*
* See also: im_andimage(), im_orimageconst().
*
* Returns: 0 on success, -1 on error
*/
int
im_shiftleft( IMAGE *in, IMAGE *out, int n )
{
double c = n;
return( im_shiftleft_vec( in, out, 1, &c ) );
}
CONST1_BUFFER( SHIFTR, >> )
CONSTN_BUFFER( SHIFTR, >> )
/**
* im_shiftright_vec:
* @in: input #IMAGE
* @out: output #IMAGE
* @n: array length
* @c: array of constants
*
* This operation calculates @in << @c (right-shift by @c bits
* with array
* @c) and writes the result to @out.
*
* See also: im_andimage(), im_orimageconst().
*
* Returns: 0 on success, -1 on error
*/
int
im_shiftright_vec( IMAGE *in, IMAGE *out, int n, double *c )
{
return( im__arith_binary_const( "im_shiftright",
in, out, n, c,
bandfmt_bool,
(im_wrapone_fn) SHIFTR1_buffer,
(im_wrapone_fn) SHIFTRn_buffer ) );
}
/**
* im_shiftright:
* @in: input #IMAGE
* @out: output #IMAGE
* @n: constant
*
* This operation calculates @in >> @n (right-shift by @n bits)
* and writes the result to @out.
*
* See also: im_andimage(), im_orimageconst().
*
* Returns: 0 on success, -1 on error
*/
int
im_shiftright( IMAGE *in, IMAGE *out, int n )
{
double c = n;
return( im_shiftright_vec( in, out, 1, &c ) );
}