redone ifthenelse/blend as classes
relational/ can now go, woo
This commit is contained in:
parent
cf09916df9
commit
2f7de7f8d0
|
@ -11,7 +11,7 @@
|
|||
im_multiply(), im_stats(), im_measure(), im_recomb(), im_floor(), im_ceil(),
|
||||
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_pow*(), im_exp*(), im_ifthenelse(), im_blend()
|
||||
redone as classes
|
||||
- added argument priorites to help control arg ordering
|
||||
- generate has a 'stop' param to signal successful early termination
|
||||
|
|
14
TODO
14
TODO
|
@ -1,26 +1,15 @@
|
|||
- move ifthenelse / blend to conversion? or arithmetic?
|
||||
|
||||
not ternary arithmetic ops since the condition image is always ucharo
|
||||
|
||||
maybe a subclass of binary, since the then & else images do need to be
|
||||
upcast to match
|
||||
|
||||
|
||||
|
||||
|
||||
- try an area operation, like conv, VipsArea? oops no haha what name should we
|
||||
use?
|
||||
|
||||
|
||||
|
||||
|
||||
- test _O_TEMPORARY thing on Windows
|
||||
|
||||
|
||||
|
||||
|
||||
- avg/dev etc. should uncode images? eg. labq2lab etc.
|
||||
|
||||
how about ifthenelse?
|
||||
|
||||
|
||||
|
||||
|
@ -30,7 +19,6 @@
|
|||
|
||||
|
||||
|
||||
|
||||
- vipsimage should be cached too, eg.
|
||||
|
||||
VipsImage *a = vips_image_new_from_file( "poop.jpg" );
|
||||
|
|
|
@ -642,7 +642,6 @@ AC_OUTPUT([
|
|||
libvips/morphology/Makefile
|
||||
libvips/mosaicing/Makefile
|
||||
libvips/other/Makefile
|
||||
libvips/relational/Makefile
|
||||
libvips/resample/Makefile
|
||||
libvips/video/Makefile
|
||||
libvipsCC/include/Makefile
|
||||
|
|
|
@ -26,7 +26,6 @@ SUBDIRS = \
|
|||
morphology \
|
||||
mosaicing \
|
||||
other \
|
||||
relational \
|
||||
video \
|
||||
.
|
||||
|
||||
|
@ -60,7 +59,6 @@ libvips_la_LIBADD = \
|
|||
morphology/libmorphology.la \
|
||||
mosaicing/libmosaicing.la \
|
||||
other/libother.la \
|
||||
relational/librelational.la \
|
||||
video/libvideo.la \
|
||||
@VIPS_LIBS@
|
||||
|
||||
|
|
|
@ -1,229 +0,0 @@
|
|||
/* im_ifthenelse.c --- use a condition image to join two images together
|
||||
*
|
||||
* Modified:
|
||||
* 9/2/95 JC
|
||||
* - partialed and ANSIfied
|
||||
* 11/9/95 JC
|
||||
* - return( 0 ) missing! oops
|
||||
* 15/4/05
|
||||
* - now just evals left/right if all zero/all one
|
||||
* 7/10/06
|
||||
* - set THINSTRIP
|
||||
* 23/9/09
|
||||
* - gtkdoc comment
|
||||
* 23/9/09
|
||||
* - use im_check*()
|
||||
* - allow many-band conditional and single-band a/b
|
||||
* - allow a/b to differ in format and bands
|
||||
* 25/6/10
|
||||
* - let the conditional image be any format by adding a (!=0) if
|
||||
* necessary
|
||||
* 17/5/11
|
||||
* - added sizealike
|
||||
* 14/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 <config.h>
|
||||
#endif /*HAVE_CONFIG_H*/
|
||||
#include <vips/intl.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <vips/vips.h>
|
||||
|
||||
#include "binary.h"
|
||||
#include "unaryconst.h"
|
||||
|
||||
/**
|
||||
* VipsIfthenelse:
|
||||
* @left: left-hand input #VipsImage
|
||||
* @right: right-hand input #VipsImage
|
||||
* @out: output #VipsImage
|
||||
* @ifthenelse: ifthenelse operation to perform
|
||||
*
|
||||
* Perform various ifthenelse operations on pairs of images.
|
||||
*
|
||||
* The output type is always uchar, with 0 for FALSE and 255 for TRUE.
|
||||
*
|
||||
* Less-than and greater-than for complex images compare the modulus.
|
||||
*
|
||||
* If the images differ in size, the smaller image is enlarged to match the
|
||||
* larger by adding zero pixels along the bottom and right.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The two input images are cast up to the smallest common type (see table
|
||||
* Smallest common format in
|
||||
* <link linkend="VIPS-arithmetic">arithmetic</link>).
|
||||
*
|
||||
* See also: #VipsBoolean, #VipsIfthenelseConst.
|
||||
*/
|
||||
|
||||
typedef struct _VipsIfthenelse {
|
||||
VipsBinary parent_instance;
|
||||
|
||||
/* The condition image is always uchar.
|
||||
*/
|
||||
VipsImage *condition;
|
||||
|
||||
} VipsIfthenelse;
|
||||
|
||||
typedef VipsBinaryClass VipsIfthenelseClass;
|
||||
|
||||
G_DEFINE_TYPE( VipsIfthenelse, vips_ifthenelse, VIPS_TYPE_BINARY );
|
||||
|
||||
static int
|
||||
vips_ifthenelse_build( VipsObject *object )
|
||||
{
|
||||
VipsIfthenelse *ifthenelse = (VipsIfthenelse *) object;
|
||||
VipsArithmetic *arithmetic = (VipsArithmetic *) object;
|
||||
|
||||
if( VIPS_OBJECT_CLASS( vips_ifthenelse_parent_class )->build( object ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
#define RLOOP( TYPE, ROP ) { \
|
||||
TYPE *left = (TYPE *) in[0]; \
|
||||
TYPE *right = (TYPE *) in[1]; \
|
||||
PEL *q = (PEL *) out; \
|
||||
\
|
||||
for( x = 0; x < sz; x++ ) \
|
||||
q[x] = (left[x] ROP right[x]) ? 255 : 0; \
|
||||
}
|
||||
|
||||
#define CLOOP( TYPE, COP ) { \
|
||||
TYPE *left = (TYPE *) in[0]; \
|
||||
TYPE *right = (TYPE *) in[1]; \
|
||||
PEL *q = (PEL *) out; \
|
||||
\
|
||||
for( x = 0; x < sz; x++ ) { \
|
||||
q[x] = COP( left[0], left[1], right[0], right[1]) ? 255 : 0; \
|
||||
\
|
||||
left += 2; \
|
||||
right += 2; \
|
||||
} \
|
||||
}
|
||||
|
||||
static void
|
||||
vips_ifthenelse_buffer( VipsArithmetic *arithmetic,
|
||||
PEL *out, PEL **in, int width )
|
||||
{
|
||||
VipsIfthenelse *ifthenelse = (VipsIfthenelse *) arithmetic;
|
||||
VipsImage *im = arithmetic->ready[0];
|
||||
const int sz = width * vips_image_get_bands( im );
|
||||
|
||||
int x;
|
||||
|
||||
switch( vips_image_get_format( im ) ) {
|
||||
case VIPS_FORMAT_UCHAR: R( unsigned char, ROP ); break;
|
||||
case VIPS_FORMAT_CHAR: R( signed char, ROP ); break;
|
||||
case VIPS_FORMAT_USHORT: R( unsigned short, ROP ); break;
|
||||
case VIPS_FORMAT_SHORT: R( signed short, ROP ); break;
|
||||
case VIPS_FORMAT_UINT: R( unsigned int, ROP ); break;
|
||||
case VIPS_FORMAT_INT: R( signed int, ROP ); break;
|
||||
case VIPS_FORMAT_FLOAT: R( float, ROP ); break;
|
||||
case VIPS_FORMAT_DOUBLE: R( double, ROP ); break;
|
||||
case VIPS_FORMAT_COMPLEX: C( float, COP ); break;
|
||||
case VIPS_FORMAT_DPCOMPLEX: C( double, COP ); 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_ifthenelse[10] = {
|
||||
/* UC C US S UI I F X D DX */
|
||||
UC, C, US, S, UI, I, F, X, D, DX
|
||||
};
|
||||
|
||||
static void
|
||||
vips_ifthenelse_class_init( VipsIfthenelseClass *class )
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
|
||||
VipsObjectClass *object_class = (VipsObjectClass *) class;
|
||||
VipsArithmeticClass *aclass = VIPS_ARITHMETIC_CLASS( class );
|
||||
|
||||
gobject_class->set_property = vips_object_set_property;
|
||||
gobject_class->get_property = vips_object_get_property;
|
||||
|
||||
object_class->nickname = "ifthenelse";
|
||||
object_class->description =
|
||||
_( "a ifthenelse operation on a pair of images" );
|
||||
object_class->build = vips_ifthenelse_build;
|
||||
|
||||
vips_arithmetic_set_format_table( aclass, vips_bandfmt_ifthenelse );
|
||||
|
||||
aclass->process_line = vips_ifthenelse_buffer;
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
vips_ifthenelse_init( VipsIfthenelse *ifthenelse )
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
vips_ifthenelse( VipsImage *left, VipsImage *right, VipsImage **out,
|
||||
VipsOperationIfthenelse ifthenelse, ... )
|
||||
{
|
||||
va_list ap;
|
||||
int result;
|
||||
|
||||
va_start( ap, ifthenelse );
|
||||
result = vips_call_split( "ifthenelse", ap, left, right, out,
|
||||
ifthenelse );
|
||||
va_end( ap );
|
||||
|
||||
return( result );
|
||||
}
|
|
@ -14,6 +14,7 @@ libconversion_la_SOURCES = \
|
|||
bandjoin.c \
|
||||
black.c \
|
||||
rot.c \
|
||||
ifthenelse.c \
|
||||
conver_dispatch.c \
|
||||
im_c2amph.c \
|
||||
im_c2rect.c \
|
||||
|
|
|
@ -115,6 +115,7 @@ vips_conversion_operation_init( void )
|
|||
extern GType vips_bandjoin_get_type( void );
|
||||
extern GType vips_black_get_type( void );
|
||||
extern GType vips_rot_get_type( void );
|
||||
extern GType vips_ifthenelse_get_type( void );
|
||||
|
||||
vips_copy_get_type();
|
||||
vips_embed_get_type();
|
||||
|
@ -128,6 +129,7 @@ vips_conversion_operation_init( void )
|
|||
vips_bandjoin_get_type();
|
||||
vips_black_get_type();
|
||||
vips_rot_get_type();
|
||||
vips_ifthenelse_get_type();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,468 @@
|
|||
/* ifthenelse.c --- use a condition image to join two images together
|
||||
*
|
||||
* Modified:
|
||||
* 9/2/95 JC
|
||||
* - partialed and ANSIfied
|
||||
* 11/9/95 JC
|
||||
* - return( 0 ) missing! oops
|
||||
* 15/4/05
|
||||
* - now just evals left/right if all zero/all one
|
||||
* 7/10/06
|
||||
* - set THINSTRIP
|
||||
* 23/9/09
|
||||
* - gtkdoc comment
|
||||
* 23/9/09
|
||||
* - use im_check*()
|
||||
* - allow many-band conditional and single-band a/b
|
||||
* - allow a/b to differ in format and bands
|
||||
* 25/6/10
|
||||
* - let the conditional image be any format by adding a (!=0) if
|
||||
* necessary
|
||||
* 17/5/11
|
||||
* - added sizealike
|
||||
* 14/11/11
|
||||
* - redone 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
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
#define VIPS_DEBUG
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif /*HAVE_CONFIG_H*/
|
||||
#include <vips/intl.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <vips/vips.h>
|
||||
#include <vips/internal.h>
|
||||
#include <vips/debug.h>
|
||||
|
||||
#include "conversion.h"
|
||||
|
||||
/**
|
||||
* VipsIfthenelse:
|
||||
* @cond: condition #VipsImage
|
||||
* @in1: then #VipsImage
|
||||
* @in2: else #VipsImage
|
||||
* @out: output #VipsImage
|
||||
*
|
||||
* This operation scans the condition image @cond
|
||||
* and uses it to select pixels from either the then image @in1 or the else
|
||||
* image @in2. Non-zero means @in1, 0 means @in2.
|
||||
*
|
||||
* Any image can have either 1 band or n bands, where n is the same for all
|
||||
* the non-1-band images. Single band images are then effectively copied to
|
||||
* make n-band images.
|
||||
*
|
||||
* Images @in1 and @in2 are cast up to the smallest common format. @cond is
|
||||
* cast to uchar.
|
||||
*
|
||||
* If the images differ in size, the smaller images are enlarged to match the
|
||||
* largest by adding zero pixels along the bottom and right.
|
||||
*
|
||||
* If @blend is %TRUE, then values in @out are smoothly blended between @in1
|
||||
* and @in2 using the formula:
|
||||
*
|
||||
* @out = (@cond / 255) * @in1 + (1 - @cond / 255) * @in2
|
||||
*
|
||||
* See also: #VipsEqual.
|
||||
*/
|
||||
|
||||
typedef struct _VipsIfthenelse {
|
||||
VipsConversion parent_instance;
|
||||
|
||||
/* Params.
|
||||
*/
|
||||
VipsImage *cond;
|
||||
VipsImage *in1;
|
||||
VipsImage *in2;
|
||||
|
||||
gboolean blend;
|
||||
|
||||
} VipsIfthenelse;
|
||||
|
||||
typedef VipsConversionClass VipsIfthenelseClass;
|
||||
|
||||
G_DEFINE_TYPE( VipsIfthenelse, vips_ifthenelse, VIPS_TYPE_CONVERSION );
|
||||
|
||||
#define IBLEND1( TYPE ) { \
|
||||
TYPE *a = (TYPE *) ap; \
|
||||
TYPE *b = (TYPE *) bp; \
|
||||
TYPE *q = (TYPE *) qp; \
|
||||
\
|
||||
for( i = 0, x = 0; x < n; i++, x += bands ) { \
|
||||
const int v = c[i]; \
|
||||
\
|
||||
for( z = x; z < x + bands; z++ ) \
|
||||
q[z] = (v * a[z] + (255 - v) * b[z] + 128) / 255; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define IBLENDN( TYPE ) { \
|
||||
TYPE *a = (TYPE *) ap; \
|
||||
TYPE *b = (TYPE *) bp; \
|
||||
TYPE *q = (TYPE *) qp; \
|
||||
\
|
||||
for( x = 0; x < n; x += bands ) { \
|
||||
for( z = x; z < x + bands; z++ ) { \
|
||||
const int v = c[z]; \
|
||||
\
|
||||
q[z] = (v * a[z] + (255 - v) * b[z] + 128) / 255; \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
#define FBLEND1( TYPE ) { \
|
||||
TYPE *a = (TYPE *) ap; \
|
||||
TYPE *b = (TYPE *) bp; \
|
||||
TYPE *q = (TYPE *) qp; \
|
||||
\
|
||||
for( i = 0, x = 0; x < n; i++, x += bands ) { \
|
||||
const double v = c[i] / 255.0; \
|
||||
\
|
||||
for( z = x; z < x + bands; z++ ) \
|
||||
q[z] = v * a[z] + (1.0 - v) * b[z]; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define FBLENDN( TYPE ) { \
|
||||
TYPE *a = (TYPE *) ap; \
|
||||
TYPE *b = (TYPE *) bp; \
|
||||
TYPE *q = (TYPE *) qp; \
|
||||
\
|
||||
for( x = 0; x < n; x += bands ) { \
|
||||
for( z = x; z < x + bands; z++ ) { \
|
||||
const double v = c[z] / 255.0; \
|
||||
\
|
||||
q[z] = v * a[z] + (1.0 - v) * b[z]; \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CBLEND1( TYPE ) { \
|
||||
TYPE *a = (TYPE *) ap; \
|
||||
TYPE *b = (TYPE *) bp; \
|
||||
TYPE *q = (TYPE *) qp; \
|
||||
\
|
||||
for( i = 0, x = 0; x < n; i++, x += bands ) { \
|
||||
const double v = c[i] / 255.0; \
|
||||
\
|
||||
for( z = x; z < x + 2 * bands; z++ ) \
|
||||
q[z] = v * a[z] + (1.0 - v) * b[z]; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CBLENDN( TYPE ) { \
|
||||
TYPE *a = (TYPE *) ap; \
|
||||
TYPE *b = (TYPE *) bp; \
|
||||
TYPE *q = (TYPE *) qp; \
|
||||
\
|
||||
for( x = 0; x < n; x += bands ) { \
|
||||
for( z = x; z < x + bands; z++ ) { \
|
||||
const double v = c[z] / 255.0; \
|
||||
\
|
||||
q[2 * z] = v * a[2 * z] + (1.0 - v) * b[2 * z]; \
|
||||
q[2 * z + 1] = v * a[2 * z + 1] + \
|
||||
(1.0 - v) * b[2 * z + 1]; \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
/* Blend with a 1-band conditional image.
|
||||
*/
|
||||
static void
|
||||
vips_blend1_buffer( PEL *qp, PEL *c, PEL *ap, PEL *bp, int width,
|
||||
VipsImage *im )
|
||||
{
|
||||
int i, x, z;
|
||||
const int bands = im->Bands;
|
||||
const int n = width * bands;
|
||||
|
||||
switch( im->BandFmt ) {
|
||||
case VIPS_FORMAT_UCHAR: IBLEND1( unsigned char ); break;
|
||||
case VIPS_FORMAT_CHAR: IBLEND1( signed char ); break;
|
||||
case VIPS_FORMAT_USHORT: IBLEND1( unsigned short ); break;
|
||||
case VIPS_FORMAT_SHORT: IBLEND1( signed short ); break;
|
||||
case VIPS_FORMAT_UINT: IBLEND1( unsigned int ); break;
|
||||
case VIPS_FORMAT_INT: IBLEND1( signed int ); break;
|
||||
case VIPS_FORMAT_FLOAT: FBLEND1( float ); break;
|
||||
case VIPS_FORMAT_DOUBLE: FBLEND1( double ); break;
|
||||
case VIPS_FORMAT_COMPLEX: CBLEND1( float ); break;
|
||||
case VIPS_FORMAT_DPCOMPLEX: CBLEND1( double ); break;
|
||||
|
||||
default:
|
||||
g_assert( 0 );
|
||||
}
|
||||
}
|
||||
|
||||
/* Blend with a many band conditional image.
|
||||
*/
|
||||
static void
|
||||
vips_blendn_buffer( PEL *qp, PEL *c, PEL *ap, PEL *bp, int width,
|
||||
VipsImage *im )
|
||||
{
|
||||
int x, z;
|
||||
const int bands = im->Bands;
|
||||
const int n = width * bands;
|
||||
|
||||
switch( im->BandFmt ) {
|
||||
case VIPS_FORMAT_UCHAR: IBLENDN( unsigned char ); break;
|
||||
case VIPS_FORMAT_CHAR: IBLENDN( signed char ); break;
|
||||
case VIPS_FORMAT_USHORT: IBLENDN( unsigned short ); break;
|
||||
case VIPS_FORMAT_SHORT: IBLENDN( signed short ); break;
|
||||
case VIPS_FORMAT_UINT: IBLENDN( unsigned int ); break;
|
||||
case VIPS_FORMAT_INT: IBLENDN( signed int ); break;
|
||||
case VIPS_FORMAT_FLOAT: FBLENDN( float ); break;
|
||||
case VIPS_FORMAT_DOUBLE: FBLENDN( double ); break;
|
||||
case VIPS_FORMAT_COMPLEX: CBLENDN( float ); break;
|
||||
case VIPS_FORMAT_DPCOMPLEX: CBLENDN( double ); break;
|
||||
|
||||
default:
|
||||
g_assert( 0 );
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
vips_ifthenelse_gen( VipsRegion *or, void *seq, void *client1, void *client2,
|
||||
gboolean *stop )
|
||||
{
|
||||
VipsRegion **ir = (VipsRegion **) seq;
|
||||
VipsIfthenelse *ifthenelse = (VipsIfthenelse *) client2;
|
||||
VipsRect *r = &or->valid;
|
||||
int le = r->left;
|
||||
int to = r->top;
|
||||
int bo = VIPS_RECT_BOTTOM( r );
|
||||
|
||||
VipsImage *c = ir[2]->im;
|
||||
VipsImage *a = ir[0]->im;
|
||||
|
||||
int size, width;
|
||||
int i, x, y, z;
|
||||
|
||||
int all0, alln0;
|
||||
|
||||
if( c->Bands == 1 ) {
|
||||
/* Copying PEL-sized units with a one-band conditional.
|
||||
*/
|
||||
size = VIPS_IMAGE_SIZEOF_PEL( a );
|
||||
width = r->width;
|
||||
}
|
||||
else {
|
||||
/* Copying ELEMENT sized-units with an n-band conditional.
|
||||
*/
|
||||
size = VIPS_IMAGE_SIZEOF_ELEMENT( a );
|
||||
width = r->width * a->Bands;
|
||||
}
|
||||
|
||||
if( vips_region_prepare( ir[2], r ) )
|
||||
return( -1 );
|
||||
|
||||
/* Is the conditional all zero or all non-zero? We can avoid asking
|
||||
* for one of the inputs to be calculated.
|
||||
*/
|
||||
all0 = *((PEL *) VIPS_REGION_ADDR( ir[2], le, to )) == 0;
|
||||
alln0 = *((PEL *) VIPS_REGION_ADDR( ir[2], le, to )) != 0;
|
||||
for( y = to; y < bo; y++ ) {
|
||||
PEL *p = (PEL *) VIPS_REGION_ADDR( ir[2], le, y );
|
||||
|
||||
for( x = 0; x < width; x++ ) {
|
||||
all0 &= p[x] == 0;
|
||||
alln0 &= p[x] != 0;
|
||||
}
|
||||
|
||||
if( !all0 && !alln0 )
|
||||
break;
|
||||
}
|
||||
|
||||
if( alln0 ) {
|
||||
/* All non-zero. Point or at the then image.
|
||||
*/
|
||||
if( vips_region_prepare( ir[0], r ) ||
|
||||
vips_region_region( or, ir[0], r, r->left, r->top ) )
|
||||
return( -1 );
|
||||
}
|
||||
else if( all0 ) {
|
||||
/* All zero. Point or at the else image.
|
||||
*/
|
||||
if( vips_region_prepare( ir[1], r ) ||
|
||||
vips_region_region( or, ir[1], r, r->left, r->top ) )
|
||||
return( -1 );
|
||||
}
|
||||
else {
|
||||
/* Mix of set and clear ... ask for both then and else parts
|
||||
* and interleave.
|
||||
*/
|
||||
if( vips_region_prepare( ir[0], r ) ||
|
||||
vips_region_prepare( ir[1], r ) )
|
||||
return( -1 );
|
||||
|
||||
for( y = to; y < bo; y++ ) {
|
||||
PEL *ap = (PEL *) VIPS_REGION_ADDR( ir[0], le, y );
|
||||
PEL *bp = (PEL *) VIPS_REGION_ADDR( ir[1], le, y );
|
||||
PEL *cp = (PEL *) VIPS_REGION_ADDR( ir[2], le, y );
|
||||
PEL *q = (PEL *) VIPS_REGION_ADDR( or, le, y );
|
||||
|
||||
if( ifthenelse->blend ) {
|
||||
if( c->Bands == 1 )
|
||||
vips_blend1_buffer( q,
|
||||
cp, ap, bp, r->width, a );
|
||||
else
|
||||
vips_blendn_buffer( q,
|
||||
cp, ap, bp, r->width, a );
|
||||
}
|
||||
else {
|
||||
for( x = 0, i = 0; i < width; i++, x += size )
|
||||
if( cp[i] )
|
||||
for( z = x; z < x + size; z++ )
|
||||
q[z] = ap[z];
|
||||
else
|
||||
for( z = x; z < x + size; z++ )
|
||||
q[z] = bp[z];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static int
|
||||
vips_ifthenelse_build( VipsObject *object )
|
||||
{
|
||||
VipsConversion *conversion = VIPS_CONVERSION( object );
|
||||
VipsIfthenelse *ifthenelse = (VipsIfthenelse *) object;
|
||||
|
||||
VipsImage *all[3];
|
||||
VipsImage **band = (VipsImage **) vips_object_local_array( object, 3 );
|
||||
VipsImage **size = (VipsImage **) vips_object_local_array( object, 3 );
|
||||
VipsImage **format =
|
||||
(VipsImage **) vips_object_local_array( object, 3 );
|
||||
|
||||
if( VIPS_OBJECT_CLASS( vips_ifthenelse_parent_class )->build( object ) )
|
||||
return( -1 );
|
||||
|
||||
/* We have to have the condition image last since we want the output
|
||||
* image to inherit its properties from the then/else parts.
|
||||
*/
|
||||
all[0] = ifthenelse->in1;
|
||||
all[1] = ifthenelse->in2;
|
||||
all[2] = ifthenelse->cond;
|
||||
|
||||
/* No need to check input images, sizealike and friends will do this
|
||||
* for us.
|
||||
*/
|
||||
|
||||
/* Cast our input images up to a common bands and size.
|
||||
*/
|
||||
if( vips__bandalike_vec( "VipsIfthenelse", all, band, 3, 0 ) ||
|
||||
vips__sizealike_vec( band, size, 3 ) )
|
||||
return( -1 );
|
||||
|
||||
/* Condition is cast to uchar, then/else to a common type.
|
||||
*/
|
||||
if( vips_cast( size[2], &format[2], VIPS_FORMAT_UCHAR, NULL ) )
|
||||
return( -1 );
|
||||
if( vips__formatalike_vec( size, format, 2 ) )
|
||||
return( -1 );
|
||||
|
||||
if( vips_image_copy_fields_array( conversion->out, format ) )
|
||||
return( -1 );
|
||||
vips_demand_hint_array( conversion->out,
|
||||
VIPS_DEMAND_STYLE_SMALLTILE, format );
|
||||
|
||||
if( vips_image_generate( conversion->out,
|
||||
vips_start_many, vips_ifthenelse_gen, vips_stop_many,
|
||||
format, ifthenelse ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static void
|
||||
vips_ifthenelse_class_init( VipsIfthenelseClass *class )
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
|
||||
VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class );
|
||||
|
||||
VIPS_DEBUG_MSG( "vips_ifthenelse_class_init\n" );
|
||||
|
||||
gobject_class->set_property = vips_object_set_property;
|
||||
gobject_class->get_property = vips_object_get_property;
|
||||
|
||||
vobject_class->nickname = "ifthenelse";
|
||||
vobject_class->description = _( "ifthenelse an image" );
|
||||
vobject_class->build = vips_ifthenelse_build;
|
||||
|
||||
VIPS_ARG_IMAGE( class, "cond", -2,
|
||||
_( "Condition" ),
|
||||
_( "Condition input image" ),
|
||||
VIPS_ARGUMENT_REQUIRED_INPUT,
|
||||
G_STRUCT_OFFSET( VipsIfthenelse, cond ) );
|
||||
|
||||
VIPS_ARG_IMAGE( class, "in1", -1,
|
||||
_( "Then image" ),
|
||||
_( "Source for TRUE pixels" ),
|
||||
VIPS_ARGUMENT_REQUIRED_INPUT,
|
||||
G_STRUCT_OFFSET( VipsIfthenelse, in1 ) );
|
||||
|
||||
VIPS_ARG_IMAGE( class, "in2", 0,
|
||||
_( "Else image" ),
|
||||
_( "Source for FALSE pixels" ),
|
||||
VIPS_ARGUMENT_REQUIRED_INPUT,
|
||||
G_STRUCT_OFFSET( VipsIfthenelse, in2 ) );
|
||||
|
||||
VIPS_ARG_BOOL( class, "blend", 4,
|
||||
_( "blend" ),
|
||||
_( "Blend smoothly between then and else parts" ),
|
||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||
G_STRUCT_OFFSET( VipsIfthenelse, blend ),
|
||||
FALSE );
|
||||
}
|
||||
|
||||
static void
|
||||
vips_ifthenelse_init( VipsIfthenelse *ifthenelse )
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
vips_ifthenelse( VipsImage *cond, VipsImage *in1, VipsImage *in2,
|
||||
VipsImage **out, ... )
|
||||
{
|
||||
va_list ap;
|
||||
int result;
|
||||
|
||||
va_start( ap, out );
|
||||
result = vips_call_split( "ifthenelse", ap, cond, in1, in2, out );
|
||||
va_end( ap );
|
||||
|
||||
return( result );
|
||||
}
|
|
@ -1486,12 +1486,20 @@ static im_function vips2mask_desc = {
|
|||
|
||||
/* One image plus one constant in, one image out.
|
||||
*/
|
||||
static im_arg_desc const_in_one_out[] = {
|
||||
static im_arg_desc int_in_one_out[] = {
|
||||
IM_INPUT_IMAGE( "in1" ),
|
||||
IM_OUTPUT_IMAGE( "out" ),
|
||||
IM_INPUT_INT( "c" )
|
||||
};
|
||||
|
||||
/* One image plus one constant in, one image out.
|
||||
*/
|
||||
static im_arg_desc double_in_one_out[] = {
|
||||
IM_INPUT_IMAGE( "in1" ),
|
||||
IM_OUTPUT_IMAGE( "out" ),
|
||||
IM_INPUT_DOUBLE( "c" )
|
||||
};
|
||||
|
||||
/* One image plus doublevec in, one image out.
|
||||
*/
|
||||
static im_arg_desc vec_in_one_out[] = {
|
||||
|
@ -1536,8 +1544,8 @@ static im_function andimageconst_desc = {
|
|||
"bitwise and of an image with a constant",
|
||||
IM_FN_PTOP | IM_FN_PIO, /* Flags */
|
||||
andimageconst_vec, /* Dispatch function */
|
||||
IM_NUMBER( const_in_one_out ), /* Size of arg list */
|
||||
const_in_one_out /* Arg list */
|
||||
IM_NUMBER( int_in_one_out ), /* Size of arg list */
|
||||
int_in_one_out /* Arg list */
|
||||
};
|
||||
|
||||
/* Call im_andimage_vec via arg vector.
|
||||
|
@ -1597,8 +1605,8 @@ static im_function orimageconst_desc = {
|
|||
"bitwise or of an image with a constant",
|
||||
IM_FN_PTOP | IM_FN_PIO, /* Flags */
|
||||
orimageconst_vec, /* Dispatch function */
|
||||
IM_NUMBER( const_in_one_out ), /* Size of arg list */
|
||||
const_in_one_out /* Arg list */
|
||||
IM_NUMBER( int_in_one_out ), /* Size of arg list */
|
||||
int_in_one_out /* Arg list */
|
||||
};
|
||||
|
||||
/* Call im_orimage_vec via arg vector.
|
||||
|
@ -1658,8 +1666,8 @@ static im_function eorimageconst_desc = {
|
|||
"bitwise eor of an image with a constant",
|
||||
IM_FN_PTOP | IM_FN_PIO, /* Flags */
|
||||
eorimageconst_vec, /* Dispatch function */
|
||||
IM_NUMBER( const_in_one_out ), /* Size of arg list */
|
||||
const_in_one_out /* Arg list */
|
||||
IM_NUMBER( int_in_one_out ), /* Size of arg list */
|
||||
int_in_one_out /* Arg list */
|
||||
};
|
||||
|
||||
/* Call im_eorimage_vec via arg vector.
|
||||
|
@ -1700,8 +1708,8 @@ static im_function shiftleft_desc = {
|
|||
"shift image n bits to left",
|
||||
IM_FN_PTOP | IM_FN_PIO, /* Flags */
|
||||
shiftleft_vec, /* Dispatch function */
|
||||
IM_NUMBER( const_in_one_out ), /* Size of arg list */
|
||||
const_in_one_out /* Arg list */
|
||||
IM_NUMBER( int_in_one_out ), /* Size of arg list */
|
||||
int_in_one_out /* Arg list */
|
||||
};
|
||||
|
||||
/* Call im_shiftleft_vec via arg vector.
|
||||
|
@ -1742,8 +1750,8 @@ static im_function shiftright_desc = {
|
|||
"shift integer image n bits to right",
|
||||
IM_FN_PTOP | IM_FN_PIO, /* Flags */
|
||||
shiftright_vec, /* Dispatch function */
|
||||
IM_NUMBER( const_in_one_out ), /* Size of arg list */
|
||||
const_in_one_out /* Arg list */
|
||||
IM_NUMBER( int_in_one_out ), /* Size of arg list */
|
||||
int_in_one_out /* Arg list */
|
||||
};
|
||||
|
||||
/* Call im_shiftright_vec via arg vector.
|
||||
|
@ -1767,6 +1775,420 @@ static im_function shiftright_vec_desc = {
|
|||
vec_in_one_out /* Arg list */
|
||||
};
|
||||
|
||||
/* Call im_equal via arg vector.
|
||||
*/
|
||||
static int
|
||||
equal_vec( im_object *argv )
|
||||
{
|
||||
return( im_equal( argv[0], argv[1], argv[2] ) );
|
||||
}
|
||||
|
||||
/* Description of im_equal.
|
||||
*/
|
||||
static im_function equal_desc = {
|
||||
"im_equal", /* Name */
|
||||
"two images equal in value", /* Description */
|
||||
IM_FN_PTOP | IM_FN_PIO, /* Flags */
|
||||
equal_vec, /* Dispatch function */
|
||||
IM_NUMBER( two_in_one_out ), /* Size of arg list */
|
||||
two_in_one_out /* Arg list */
|
||||
};
|
||||
|
||||
/* Call im_equalconst via arg vector.
|
||||
*/
|
||||
static int
|
||||
equalconst_vec( im_object *argv )
|
||||
{
|
||||
double c = *((double *) argv[2]);
|
||||
|
||||
return( im_equalconst( argv[0], argv[1], c ) );
|
||||
}
|
||||
|
||||
/* Description of im_equalconst.
|
||||
*/
|
||||
static im_function equalconst_desc = {
|
||||
"im_equalconst", /* Name */
|
||||
"image equals const", /* Description */
|
||||
IM_FN_PTOP | IM_FN_PIO, /* Flags */
|
||||
equalconst_vec, /* Dispatch function */
|
||||
IM_NUMBER( double_in_one_out ), /* Size of arg list */
|
||||
double_in_one_out /* Arg list */
|
||||
};
|
||||
|
||||
/* Call im_equal_vec via arg vector.
|
||||
*/
|
||||
static int
|
||||
equal_vec_vec( im_object *argv )
|
||||
{
|
||||
im_doublevec_object *rv = (im_doublevec_object *) argv[2];
|
||||
|
||||
return( im_equal_vec( argv[0], argv[1], rv->n, rv->vec ) );
|
||||
}
|
||||
|
||||
/* Description of im_equal_vec.
|
||||
*/
|
||||
static im_function equal_vec_desc = {
|
||||
"im_equal_vec", /* Name */
|
||||
"image equals doublevec", /* Description */
|
||||
IM_FN_PTOP | IM_FN_PIO, /* Flags */
|
||||
equal_vec_vec, /* Dispatch function */
|
||||
IM_NUMBER( vec_in_one_out ), /* Size of arg list */
|
||||
vec_in_one_out /* Arg list */
|
||||
};
|
||||
|
||||
/* Call im_notequal via arg vector.
|
||||
*/
|
||||
static int
|
||||
notequal_vec( im_object *argv )
|
||||
{
|
||||
return( im_notequal( argv[0], argv[1], argv[2] ) );
|
||||
}
|
||||
|
||||
/* Description of im_notequal.
|
||||
*/
|
||||
static im_function notequal_desc = {
|
||||
"im_notequal", /* Name */
|
||||
"two images not equal in value",/* Description */
|
||||
IM_FN_PTOP | IM_FN_PIO, /* Flags */
|
||||
notequal_vec, /* Dispatch function */
|
||||
IM_NUMBER( two_in_one_out ), /* Size of arg list */
|
||||
two_in_one_out /* Arg list */
|
||||
};
|
||||
|
||||
/* Call im_notequalconst via arg vector.
|
||||
*/
|
||||
static int
|
||||
notequalconst_vec( im_object *argv )
|
||||
{
|
||||
double c = *((double *) argv[2]);
|
||||
|
||||
return( im_notequalconst( argv[0], argv[1], c ) );
|
||||
}
|
||||
|
||||
/* Description of im_notequalconst.
|
||||
*/
|
||||
static im_function notequalconst_desc = {
|
||||
"im_notequalconst", /* Name */
|
||||
"image does not equal const", /* Description */
|
||||
IM_FN_PTOP | IM_FN_PIO, /* Flags */
|
||||
notequalconst_vec, /* Dispatch function */
|
||||
IM_NUMBER( double_in_one_out ), /* Size of arg list */
|
||||
double_in_one_out /* Arg list */
|
||||
};
|
||||
|
||||
/* Call im_notequal_vec via arg vector.
|
||||
*/
|
||||
static int
|
||||
notequal_vec_vec( im_object *argv )
|
||||
{
|
||||
im_doublevec_object *rv = (im_doublevec_object *) argv[2];
|
||||
|
||||
return( im_notequal_vec( argv[0], argv[1], rv->n, rv->vec ) );
|
||||
}
|
||||
|
||||
/* Description of im_notequal_vec.
|
||||
*/
|
||||
static im_function notequal_vec_desc = {
|
||||
"im_notequal_vec", /* Name */
|
||||
"image does not equal doublevec", /* Description */
|
||||
IM_FN_PTOP | IM_FN_PIO, /* Flags */
|
||||
notequal_vec_vec, /* Dispatch function */
|
||||
IM_NUMBER( vec_in_one_out ), /* Size of arg list */
|
||||
vec_in_one_out /* Arg list */
|
||||
};
|
||||
|
||||
/* Call im_less via arg vector.
|
||||
*/
|
||||
static int
|
||||
less_vec( im_object *argv )
|
||||
{
|
||||
return( im_less( argv[0], argv[1], argv[2] ) );
|
||||
}
|
||||
|
||||
/* Description of im_less.
|
||||
*/
|
||||
static im_function less_desc = {
|
||||
"im_less", /* Name */
|
||||
"in1 less than in2 in value", /* Description */
|
||||
IM_FN_PTOP | IM_FN_PIO, /* Flags */
|
||||
less_vec, /* Dispatch function */
|
||||
IM_NUMBER( two_in_one_out ), /* Size of arg list */
|
||||
two_in_one_out /* Arg list */
|
||||
};
|
||||
|
||||
/* Call im_lessconst via arg vector.
|
||||
*/
|
||||
static int
|
||||
lessconst_vec( im_object *argv )
|
||||
{
|
||||
double c = *((double *) argv[2]);
|
||||
|
||||
return( im_lessconst( argv[0], argv[1], c ) );
|
||||
}
|
||||
|
||||
/* Description of im_lessconst.
|
||||
*/
|
||||
static im_function lessconst_desc = {
|
||||
"im_lessconst", /* Name */
|
||||
"in less than const", /* Description */
|
||||
IM_FN_PTOP | IM_FN_PIO, /* Flags */
|
||||
lessconst_vec, /* Dispatch function */
|
||||
IM_NUMBER( double_in_one_out ), /* Size of arg list */
|
||||
double_in_one_out /* Arg list */
|
||||
};
|
||||
|
||||
/* Call im_less_vec via arg vector.
|
||||
*/
|
||||
static int
|
||||
less_vec_vec( im_object *argv )
|
||||
{
|
||||
im_doublevec_object *rv = (im_doublevec_object *) argv[2];
|
||||
|
||||
return( im_less_vec( argv[0], argv[1], rv->n, rv->vec ) );
|
||||
}
|
||||
|
||||
/* Description of im_less_vec.
|
||||
*/
|
||||
static im_function less_vec_desc = {
|
||||
"im_less_vec", /* Name */
|
||||
"in less than doublevec", /* Description */
|
||||
IM_FN_PTOP | IM_FN_PIO, /* Flags */
|
||||
less_vec_vec, /* Dispatch function */
|
||||
IM_NUMBER( vec_in_one_out ), /* Size of arg list */
|
||||
vec_in_one_out /* Arg list */
|
||||
};
|
||||
|
||||
/* Call im_more via arg vector.
|
||||
*/
|
||||
static int
|
||||
more_vec( im_object *argv )
|
||||
{
|
||||
return( im_more( argv[0], argv[1], argv[2] ) );
|
||||
}
|
||||
|
||||
/* Description of im_more.
|
||||
*/
|
||||
static im_function more_desc = {
|
||||
"im_more", /* Name */
|
||||
"in1 more than in2 in value", /* Description */
|
||||
IM_FN_PTOP | IM_FN_PIO, /* Flags */
|
||||
more_vec, /* Dispatch function */
|
||||
IM_NUMBER( two_in_one_out ), /* Size of arg list */
|
||||
two_in_one_out /* Arg list */
|
||||
};
|
||||
|
||||
/* Call im_moreconst via arg vector.
|
||||
*/
|
||||
static int
|
||||
moreconst_vec( im_object *argv )
|
||||
{
|
||||
double c = *((double *) argv[2]);
|
||||
|
||||
return( im_moreconst( argv[0], argv[1], c ) );
|
||||
}
|
||||
|
||||
/* Description of im_moreconst.
|
||||
*/
|
||||
static im_function moreconst_desc = {
|
||||
"im_moreconst", /* Name */
|
||||
"in more than const", /* Description */
|
||||
IM_FN_PTOP | IM_FN_PIO, /* Flags */
|
||||
moreconst_vec, /* Dispatch function */
|
||||
IM_NUMBER( double_in_one_out ), /* Size of arg list */
|
||||
double_in_one_out /* Arg list */
|
||||
};
|
||||
|
||||
/* Call im_more_vec via arg vector.
|
||||
*/
|
||||
static int
|
||||
more_vec_vec( im_object *argv )
|
||||
{
|
||||
im_doublevec_object *rv = (im_doublevec_object *) argv[2];
|
||||
|
||||
return( im_more_vec( argv[0], argv[1], rv->n, rv->vec ) );
|
||||
}
|
||||
|
||||
/* Description of im_more_vec.
|
||||
*/
|
||||
static im_function more_vec_desc = {
|
||||
"im_more_vec", /* Name */
|
||||
"in more than doublevec", /* Description */
|
||||
IM_FN_PTOP | IM_FN_PIO, /* Flags */
|
||||
more_vec_vec, /* Dispatch function */
|
||||
IM_NUMBER( vec_in_one_out ), /* Size of arg list */
|
||||
vec_in_one_out /* Arg list */
|
||||
};
|
||||
|
||||
/* Call im_moreeq via arg vector.
|
||||
*/
|
||||
static int
|
||||
moreeq_vec( im_object *argv )
|
||||
{
|
||||
return( im_moreeq( argv[0], argv[1], argv[2] ) );
|
||||
}
|
||||
|
||||
/* Description of im_moreeq.
|
||||
*/
|
||||
static im_function moreeq_desc = {
|
||||
"im_moreeq", /* Name */
|
||||
"in1 more than or equal to in2 in value",
|
||||
IM_FN_PTOP | IM_FN_PIO, /* Flags */
|
||||
moreeq_vec, /* Dispatch function */
|
||||
IM_NUMBER( two_in_one_out ), /* Size of arg list */
|
||||
two_in_one_out /* Arg list */
|
||||
};
|
||||
|
||||
/* Call im_moreeqconst via arg vector.
|
||||
*/
|
||||
static int
|
||||
moreeqconst_vec( im_object *argv )
|
||||
{
|
||||
double c = *((double *) argv[2]);
|
||||
|
||||
return( im_moreeqconst( argv[0], argv[1], c ) );
|
||||
}
|
||||
|
||||
/* Description of im_moreeqconst.
|
||||
*/
|
||||
static im_function moreeqconst_desc = {
|
||||
"im_moreeqconst", /* Name */
|
||||
"in more than or equal to const",
|
||||
IM_FN_PTOP | IM_FN_PIO, /* Flags */
|
||||
moreeqconst_vec, /* Dispatch function */
|
||||
IM_NUMBER( double_in_one_out ), /* Size of arg list */
|
||||
double_in_one_out /* Arg list */
|
||||
};
|
||||
|
||||
/* Call im_moreeq_vec via arg vector.
|
||||
*/
|
||||
static int
|
||||
moreeq_vec_vec( im_object *argv )
|
||||
{
|
||||
im_doublevec_object *rv = (im_doublevec_object *) argv[2];
|
||||
|
||||
return( im_moreeq_vec( argv[0], argv[1], rv->n, rv->vec ) );
|
||||
}
|
||||
|
||||
/* Description of im_moreeq_vec.
|
||||
*/
|
||||
static im_function moreeq_vec_desc = {
|
||||
"im_moreeq_vec", /* Name */
|
||||
"in more than or equal to doublevec",
|
||||
IM_FN_PTOP | IM_FN_PIO, /* Flags */
|
||||
moreeq_vec_vec, /* Dispatch function */
|
||||
IM_NUMBER( vec_in_one_out ), /* Size of arg list */
|
||||
vec_in_one_out /* Arg list */
|
||||
};
|
||||
|
||||
/* Call im_lesseq via arg vector.
|
||||
*/
|
||||
static int
|
||||
lesseq_vec( im_object *argv )
|
||||
{
|
||||
return( im_lesseq( argv[0], argv[1], argv[2] ) );
|
||||
}
|
||||
|
||||
/* Description of im_lesseq.
|
||||
*/
|
||||
static im_function lesseq_desc = {
|
||||
"im_lesseq", /* Name */
|
||||
"in1 less than or equal to in2 in value",
|
||||
IM_FN_PTOP | IM_FN_PIO, /* Flags */
|
||||
lesseq_vec, /* Dispatch function */
|
||||
IM_NUMBER( two_in_one_out ), /* Size of arg list */
|
||||
two_in_one_out /* Arg list */
|
||||
};
|
||||
|
||||
/* Call im_lesseqconst via arg vector.
|
||||
*/
|
||||
static int
|
||||
lesseqconst_vec( im_object *argv )
|
||||
{
|
||||
double c = *((double *) argv[2]);
|
||||
|
||||
return( im_lesseqconst( argv[0], argv[1], c ) );
|
||||
}
|
||||
|
||||
/* Description of im_lesseqconst.
|
||||
*/
|
||||
static im_function lesseqconst_desc = {
|
||||
"im_lesseqconst", /* Name */
|
||||
"in less than or equal to const",
|
||||
IM_FN_PTOP | IM_FN_PIO, /* Flags */
|
||||
lesseqconst_vec, /* Dispatch function */
|
||||
IM_NUMBER( double_in_one_out ), /* Size of arg list */
|
||||
double_in_one_out /* Arg list */
|
||||
};
|
||||
|
||||
/* Call im_lesseq_vec via arg vector.
|
||||
*/
|
||||
static int
|
||||
lesseq_vec_vec( im_object *argv )
|
||||
{
|
||||
im_doublevec_object *rv = (im_doublevec_object *) argv[2];
|
||||
|
||||
return( im_lesseq_vec( argv[0], argv[1], rv->n, rv->vec ) );
|
||||
}
|
||||
|
||||
/* Description of im_lesseq_vec.
|
||||
*/
|
||||
static im_function lesseq_vec_desc = {
|
||||
"im_lesseq_vec", /* Name */
|
||||
"in less than or equal to doublevec",
|
||||
IM_FN_PTOP | IM_FN_PIO, /* Flags */
|
||||
lesseq_vec_vec, /* Dispatch function */
|
||||
IM_NUMBER( vec_in_one_out ), /* Size of arg list */
|
||||
vec_in_one_out /* Arg list */
|
||||
};
|
||||
|
||||
/* If-then-else args.
|
||||
*/
|
||||
static im_arg_desc ifthenelse_args[] = {
|
||||
IM_INPUT_IMAGE( "cond" ),
|
||||
IM_INPUT_IMAGE( "in1" ),
|
||||
IM_INPUT_IMAGE( "in2" ),
|
||||
IM_OUTPUT_IMAGE( "out" )
|
||||
};
|
||||
|
||||
/* Call im_blend via arg vector.
|
||||
*/
|
||||
static int
|
||||
blend_vec( im_object *argv )
|
||||
{
|
||||
return( im_blend( argv[0], argv[1], argv[2], argv[3] ) );
|
||||
}
|
||||
|
||||
/* Description of im_blend.
|
||||
*/
|
||||
static im_function blend_desc = {
|
||||
"im_blend", /* Name */
|
||||
"use cond image to blend between images in1 and in2",
|
||||
IM_FN_PTOP | IM_FN_PIO, /* Flags */
|
||||
blend_vec, /* Dispatch function */
|
||||
IM_NUMBER( ifthenelse_args ), /* Size of arg list */
|
||||
ifthenelse_args /* Arg list */
|
||||
};
|
||||
|
||||
/* Call im_ifthenelse via arg vector.
|
||||
*/
|
||||
static int
|
||||
ifthenelse_vec( im_object *argv )
|
||||
{
|
||||
return( im_ifthenelse( argv[0], argv[1], argv[2], argv[3] ) );
|
||||
}
|
||||
|
||||
/* Description of im_ifthenelse.
|
||||
*/
|
||||
static im_function ifthenelse_desc = {
|
||||
"im_ifthenelse", /* Name */
|
||||
"use cond image to choose pels from image in1 or in2",
|
||||
IM_FN_PTOP | IM_FN_PIO, /* Flags */
|
||||
ifthenelse_vec, /* Dispatch function */
|
||||
IM_NUMBER( ifthenelse_args ), /* Size of arg list */
|
||||
ifthenelse_args /* Arg list */
|
||||
};
|
||||
|
||||
|
||||
/* Package up all these functions.
|
||||
*/
|
||||
static im_function *deprecated_list[] = {
|
||||
|
@ -1833,7 +2255,27 @@ static im_function *deprecated_list[] = {
|
|||
&shiftleft_vec_desc,
|
||||
&shiftleft_desc,
|
||||
&shiftright_vec_desc,
|
||||
&shiftright_desc
|
||||
&shiftright_desc,
|
||||
&blend_desc,
|
||||
&equal_desc,
|
||||
&equal_vec_desc,
|
||||
&equalconst_desc,
|
||||
&ifthenelse_desc,
|
||||
&less_desc,
|
||||
&less_vec_desc,
|
||||
&lessconst_desc,
|
||||
&lesseq_desc,
|
||||
&lesseq_vec_desc,
|
||||
&lesseqconst_desc,
|
||||
&more_desc,
|
||||
&more_vec_desc,
|
||||
&moreconst_desc,
|
||||
&moreeq_desc,
|
||||
&moreeq_vec_desc,
|
||||
&moreeqconst_desc,
|
||||
¬equal_desc,
|
||||
¬equal_vec_desc,
|
||||
¬equalconst_desc
|
||||
};
|
||||
|
||||
/* Package of functions.
|
||||
|
|
|
@ -72,7 +72,6 @@ extern im_package im__mask;
|
|||
extern im_package im__morphology;
|
||||
extern im_package im__mosaicing;
|
||||
extern im_package im__other;
|
||||
extern im_package im__relational;
|
||||
extern im_package im__resample;
|
||||
extern im_package im__video;
|
||||
|
||||
|
@ -584,7 +583,6 @@ static im_package *built_in[] = {
|
|||
&im__morphology,
|
||||
&im__mosaicing,
|
||||
&im__other,
|
||||
&im__relational,
|
||||
&im__resample,
|
||||
&im__video
|
||||
};
|
||||
|
|
|
@ -2042,3 +2042,37 @@ im_expntra( IMAGE *in, IMAGE *out, double c )
|
|||
return( im_expntra_vec( in, out, 1, &c ) );
|
||||
}
|
||||
|
||||
int
|
||||
im_ifthenelse( VipsImage *c, VipsImage *a, VipsImage *b, VipsImage *out )
|
||||
{
|
||||
VipsImage *t;
|
||||
|
||||
if( vips_ifthenelse( c, a, b, &t,
|
||||
NULL ) )
|
||||
return( -1 );
|
||||
if( vips_image_write( t, out ) ) {
|
||||
g_object_unref( t );
|
||||
return( -1 );
|
||||
}
|
||||
g_object_unref( t );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int
|
||||
im_blend( VipsImage *c, VipsImage *a, VipsImage *b, VipsImage *out )
|
||||
{
|
||||
VipsImage *t;
|
||||
|
||||
if( vips_ifthenelse( c, a, b, &t,
|
||||
"blend", TRUE,
|
||||
NULL ) )
|
||||
return( -1 );
|
||||
if( vips_image_write( t, out ) ) {
|
||||
g_object_unref( t );
|
||||
return( -1 );
|
||||
}
|
||||
g_object_unref( t );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
|
|
@ -165,6 +165,9 @@ int vips_black( VipsImage **out, int width, int height, ... )
|
|||
__attribute__((sentinel));
|
||||
int vips_rot( VipsImage *in, VipsImage **out, VipsAngle angle, ... )
|
||||
__attribute__((sentinel));
|
||||
int vips_ifthenelse( VipsImage *cond, VipsImage *in1, VipsImage *in2,
|
||||
VipsImage **out, ... )
|
||||
__attribute__((sentinel));
|
||||
|
||||
|
||||
int im_copy_file( VipsImage *in, VipsImage *out );
|
||||
|
|
|
@ -37,8 +37,6 @@
|
|||
extern "C" {
|
||||
#endif /*__cplusplus*/
|
||||
|
||||
int im_ifthenelse( VipsImage *c, VipsImage *a, VipsImage *b, VipsImage *out );
|
||||
int im_blend( VipsImage *c, VipsImage *a, VipsImage *b, VipsImage *out );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -635,6 +635,9 @@ int im_rot90( VipsImage *in, VipsImage *out );
|
|||
int im_rot180( VipsImage *in, VipsImage *out );
|
||||
int im_rot270( VipsImage *in, VipsImage *out );
|
||||
|
||||
int im_ifthenelse( VipsImage *c, VipsImage *a, VipsImage *b, VipsImage *out );
|
||||
int im_blend( VipsImage *c, VipsImage *a, VipsImage *b, VipsImage *out );
|
||||
|
||||
DOUBLEMASK *im_vips2mask( VipsImage *in, const char *filename );
|
||||
int im_mask2vips( DOUBLEMASK *in, VipsImage *out );
|
||||
|
||||
|
|
|
@ -648,7 +648,8 @@ vips_region_image( VipsRegion *reg, VipsRect *r )
|
|||
* Returns: 0 on success, or -1 for error.
|
||||
*/
|
||||
int
|
||||
vips_region_region( VipsRegion *reg, VipsRegion *dest, VipsRect *r, int x, int y )
|
||||
vips_region_region( VipsRegion *reg,
|
||||
VipsRegion *dest, VipsRect *r, int x, int y )
|
||||
{
|
||||
VipsRect image;
|
||||
VipsRect wanted;
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
noinst_LTLIBRARIES = librelational.la
|
||||
|
||||
librelational_la_SOURCES = \
|
||||
im_ifthenelse.c \
|
||||
im_blend.c \
|
||||
relational_dispatch.c
|
||||
|
||||
INCLUDES = -I${top_srcdir}/libvips/include @VIPS_CFLAGS@ @VIPS_INCLUDES@
|
|
@ -1,404 +0,0 @@
|
|||
/* im_blend.c --- blend images with a condition image
|
||||
*
|
||||
* Modified:
|
||||
* 15/4/05
|
||||
* - from im_ifthenelse()
|
||||
* 8/7/05
|
||||
* - oops, broken for some combinations of band differences (thanks Joe)
|
||||
* 23/9/09
|
||||
* - gtkdoc comments
|
||||
* - use im_check*()
|
||||
* - allow many-band conditional and single-band a/b
|
||||
* - allow a/b to differ in format and bands
|
||||
* 27/6/11
|
||||
* - sizealike as well
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
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 <vips/vips.h>
|
||||
#include <vips/internal.h>
|
||||
|
||||
#define iblend1( TYPE ) { \
|
||||
TYPE *a = (TYPE *) ap; \
|
||||
TYPE *b = (TYPE *) bp; \
|
||||
TYPE *q = (TYPE *) qp; \
|
||||
\
|
||||
for( i = 0, x = 0; x < n; i++, x += bands ) { \
|
||||
const int v = c[i]; \
|
||||
\
|
||||
for( z = x; z < x + bands; z++ ) \
|
||||
q[z] = (v * a[z] + (255 - v) * b[z] + 128) / 255; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define iblendn( TYPE ) { \
|
||||
TYPE *a = (TYPE *) ap; \
|
||||
TYPE *b = (TYPE *) bp; \
|
||||
TYPE *q = (TYPE *) qp; \
|
||||
\
|
||||
for( x = 0; x < n; x += bands ) { \
|
||||
for( z = x; z < x + bands; z++ ) { \
|
||||
const int v = c[z]; \
|
||||
\
|
||||
q[z] = (v * a[z] + (255 - v) * b[z] + 128) / 255; \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
#define fblend1( TYPE ) { \
|
||||
TYPE *a = (TYPE *) ap; \
|
||||
TYPE *b = (TYPE *) bp; \
|
||||
TYPE *q = (TYPE *) qp; \
|
||||
\
|
||||
for( i = 0, x = 0; x < n; i++, x += bands ) { \
|
||||
const double v = c[i] / 255.0; \
|
||||
\
|
||||
for( z = x; z < x + bands; z++ ) \
|
||||
q[z] = v * a[z] + (1.0 - v) * b[z]; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define fblendn( TYPE ) { \
|
||||
TYPE *a = (TYPE *) ap; \
|
||||
TYPE *b = (TYPE *) bp; \
|
||||
TYPE *q = (TYPE *) qp; \
|
||||
\
|
||||
for( x = 0; x < n; x += bands ) { \
|
||||
for( z = x; z < x + bands; z++ ) { \
|
||||
const double v = c[z] / 255.0; \
|
||||
\
|
||||
q[z] = v * a[z] + (1.0 - v) * b[z]; \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
#define cblend1( TYPE ) { \
|
||||
TYPE *a = (TYPE *) ap; \
|
||||
TYPE *b = (TYPE *) bp; \
|
||||
TYPE *q = (TYPE *) qp; \
|
||||
\
|
||||
for( i = 0, x = 0; x < n; i++, x += bands ) { \
|
||||
const double v = c[i] / 255.0; \
|
||||
\
|
||||
for( z = x; z < x + 2 * bands; z++ ) \
|
||||
q[z] = v * a[z] + (1.0 - v) * b[z]; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define cblendn( TYPE ) { \
|
||||
TYPE *a = (TYPE *) ap; \
|
||||
TYPE *b = (TYPE *) bp; \
|
||||
TYPE *q = (TYPE *) qp; \
|
||||
\
|
||||
for( x = 0; x < n; x += bands ) { \
|
||||
for( z = x; z < x + bands; z++ ) { \
|
||||
const double v = c[z] / 255.0; \
|
||||
\
|
||||
q[2 * z] = v * a[2 * z] + (1.0 - v) * b[2 * z]; \
|
||||
q[2 * z + 1] = v * a[2 * z + 1] + \
|
||||
(1.0 - v) * b[2 * z + 1]; \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
/* Blend with a 1-band conditional image.
|
||||
*/
|
||||
static void
|
||||
blend1_buffer( PEL *qp, PEL *c, PEL *ap, PEL *bp, int width, IMAGE *im )
|
||||
{
|
||||
int i, x, z;
|
||||
const int bands = im->Bands;
|
||||
const int n = width * bands;
|
||||
|
||||
switch( im->BandFmt ) {
|
||||
case IM_BANDFMT_UCHAR:
|
||||
iblend1( unsigned char ); break;
|
||||
case IM_BANDFMT_CHAR:
|
||||
iblend1( signed char ); break;
|
||||
case IM_BANDFMT_USHORT:
|
||||
iblend1( unsigned short ); break;
|
||||
case IM_BANDFMT_SHORT:
|
||||
iblend1( signed short ); break;
|
||||
case IM_BANDFMT_UINT:
|
||||
iblend1( unsigned int ); break;
|
||||
case IM_BANDFMT_INT:
|
||||
iblend1( signed int ); break;
|
||||
case IM_BANDFMT_FLOAT:
|
||||
fblend1( float ); break;
|
||||
case IM_BANDFMT_DOUBLE:
|
||||
fblend1( double ); break;
|
||||
case IM_BANDFMT_COMPLEX:
|
||||
cblend1( float ); break;
|
||||
case IM_BANDFMT_DPCOMPLEX:
|
||||
cblend1( double ); break;
|
||||
|
||||
default:
|
||||
g_assert( 0 );
|
||||
}
|
||||
}
|
||||
|
||||
/* Blend with a many band conditional image.
|
||||
*/
|
||||
static void
|
||||
blendn_buffer( PEL *qp, PEL *c, PEL *ap, PEL *bp, int width, IMAGE *im )
|
||||
{
|
||||
int x, z;
|
||||
const int bands = im->Bands;
|
||||
const int n = width * bands;
|
||||
|
||||
switch( im->BandFmt ) {
|
||||
case IM_BANDFMT_UCHAR:
|
||||
iblendn( unsigned char ); break;
|
||||
case IM_BANDFMT_CHAR:
|
||||
iblendn( signed char ); break;
|
||||
case IM_BANDFMT_USHORT:
|
||||
iblendn( unsigned short ); break;
|
||||
case IM_BANDFMT_SHORT:
|
||||
iblendn( signed short ); break;
|
||||
case IM_BANDFMT_UINT:
|
||||
iblendn( unsigned int ); break;
|
||||
case IM_BANDFMT_INT:
|
||||
iblendn( signed int ); break;
|
||||
case IM_BANDFMT_FLOAT:
|
||||
fblendn( float ); break;
|
||||
case IM_BANDFMT_DOUBLE:
|
||||
fblendn( double ); break;
|
||||
case IM_BANDFMT_COMPLEX:
|
||||
cblendn( float ); break;
|
||||
case IM_BANDFMT_DPCOMPLEX:
|
||||
cblendn( double ); break;
|
||||
|
||||
default:
|
||||
g_assert( 0 );
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
blend_gen( REGION *or, void *seq, void *client1, void *client2 )
|
||||
{
|
||||
REGION **ir = (REGION **) seq;
|
||||
Rect *r = &or->valid;
|
||||
int le = r->left;
|
||||
int to = r->top;
|
||||
int bo = IM_RECT_BOTTOM(r);
|
||||
|
||||
IMAGE *c = ir[0]->im;
|
||||
IMAGE *a = ir[1]->im;
|
||||
|
||||
int c_elements = r->width * c->Bands;
|
||||
int x, y;
|
||||
|
||||
int all0, all255;
|
||||
|
||||
/* Ask for condition pixels.
|
||||
*/
|
||||
if( im_prepare( ir[0], r ) )
|
||||
return( -1 );
|
||||
|
||||
/* Is the conditional all zero or all non-zero? We can avoid asking
|
||||
* for one of the inputs to be calculated.
|
||||
*/
|
||||
all0 = *((PEL *) IM_REGION_ADDR( ir[0], le, to )) == 0;
|
||||
all255 = *((PEL *) IM_REGION_ADDR( ir[0], le, to )) == 255;
|
||||
for( y = to; y < bo; y++ ) {
|
||||
PEL *p = (PEL *) IM_REGION_ADDR( ir[0], le, y );
|
||||
|
||||
for( x = 0; x < c_elements; x++ ) {
|
||||
all0 &= p[x] == 0;
|
||||
all255 &= p[x] == 255;
|
||||
}
|
||||
|
||||
if( !all0 && !all255 )
|
||||
break;
|
||||
}
|
||||
|
||||
if( all255 ) {
|
||||
/* All 255. Point or at the then image.
|
||||
*/
|
||||
if( im_prepare( ir[1], r ) ||
|
||||
im_region_region( or, ir[1], r, r->left, r->top ) )
|
||||
return( -1 );
|
||||
}
|
||||
else if( all0 ) {
|
||||
/* All zero. Point or at the else image.
|
||||
*/
|
||||
if( im_prepare( ir[2], r ) ||
|
||||
im_region_region( or, ir[2], r, r->left, r->top ) )
|
||||
return( -1 );
|
||||
}
|
||||
else {
|
||||
/* Mix of set and clear ... ask for both then and else parts and
|
||||
* interleave.
|
||||
*/
|
||||
if( im_prepare( ir[1], r ) || im_prepare( ir[2], r ) )
|
||||
return( -1 );
|
||||
|
||||
for( y = to; y < bo; y++ ) {
|
||||
PEL *cp = (PEL *) IM_REGION_ADDR( ir[0], le, y );
|
||||
PEL *ap = (PEL *) IM_REGION_ADDR( ir[1], le, y );
|
||||
PEL *bp = (PEL *) IM_REGION_ADDR( ir[2], le, y );
|
||||
PEL *q = (PEL *) IM_REGION_ADDR( or, le, y );
|
||||
|
||||
if( c->Bands == 1 )
|
||||
blend1_buffer( q, cp, ap, bp, r->width, a );
|
||||
else
|
||||
blendn_buffer( q, cp, ap, bp, r->width, a );
|
||||
}
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static int
|
||||
blend( IMAGE *c, IMAGE *a, IMAGE *b, IMAGE *out )
|
||||
{
|
||||
IMAGE **in;
|
||||
|
||||
/* Check args.
|
||||
*/
|
||||
if( im_check_uncoded( "im_blend", c ) ||
|
||||
im_check_uncoded( "im_blend", a ) ||
|
||||
im_check_uncoded( "im_blend", b ) ||
|
||||
im_check_format( "im_blend", c, IM_BANDFMT_UCHAR ) ||
|
||||
im_check_format_same( "im_blend", a, b ) ||
|
||||
im_check_bands_same( "im_blend", a, b ) ||
|
||||
im_check_bands_1orn( "im_blend", c, a ) ||
|
||||
im_check_size_same( "im_blend", a, b ) ||
|
||||
im_check_size_same( "im_blend", a, c ) ||
|
||||
im_piocheck( c, out ) ||
|
||||
im_pincheck( a ) ||
|
||||
im_pincheck( b ) )
|
||||
return( -1 );
|
||||
|
||||
/* Make output image.
|
||||
*/
|
||||
if( im_cp_descv( out, a, b, c, NULL ) )
|
||||
return( -1 );
|
||||
out->Bands = IM_MAX( c->Bands, a->Bands );
|
||||
if( im_demand_hint( out, IM_THINSTRIP, a, b, c, NULL ) )
|
||||
return( -1 );
|
||||
|
||||
if( !(in = im_allocate_input_array( out, c, a, b, NULL )) ||
|
||||
im_generate( out,
|
||||
im_start_many, blend_gen, im_stop_many, in, NULL ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* im_blend:
|
||||
* @c: condition #IMAGE
|
||||
* @a: then #IMAGE
|
||||
* @b: else #IMAGE
|
||||
* @out: output #IMAGE
|
||||
*
|
||||
* This operation scans the condition image @c
|
||||
* and uses it to blend pixels from either the then image @a or the else
|
||||
* image @b. 255 means @a only, 0 means @b only, and intermediate values are a
|
||||
* mixture.
|
||||
*
|
||||
* Any image may have either 1 band or n bands, where n is the same for all
|
||||
* the non-1-band images. Single band images are then effectively copied to
|
||||
* make n-band images.
|
||||
*
|
||||
* Images @a and @b are cast up to the smallest common format.
|
||||
*
|
||||
* If the images differ in size, the smaller images are enlarged to match the
|
||||
* largest by adding zero pixels along the bottom and right.
|
||||
*
|
||||
* See also: im_ifthenelse(), im_equal().
|
||||
*
|
||||
* Returns: 0 on success, -1 on error
|
||||
*/
|
||||
int
|
||||
im_blend( IMAGE *c, IMAGE *a, IMAGE *b, IMAGE *out )
|
||||
{
|
||||
/* If a and b are both LABPACK, repack agan after the blend.
|
||||
*/
|
||||
const int repack = a->Coding == IM_CODING_LABQ &&
|
||||
b->Coding == IM_CODING_LABQ;
|
||||
|
||||
IMAGE *t[12];
|
||||
|
||||
if( im_open_local_array( out, t, 12, "im_blend", "p" ) )
|
||||
return( -1 );
|
||||
|
||||
/* Unpack LABPACK as a courtesy.
|
||||
*/
|
||||
if( a->Coding == IM_CODING_LABQ ) {
|
||||
if( im_LabQ2Lab( a, t[0] ) )
|
||||
return( -1 );
|
||||
a = t[0];
|
||||
}
|
||||
if( b->Coding == IM_CODING_LABQ ) {
|
||||
if( im_LabQ2Lab( b, t[1] ) )
|
||||
return( -1 );
|
||||
b = t[1];
|
||||
}
|
||||
|
||||
/* c must be uchar.
|
||||
*/
|
||||
if( c->BandFmt != IM_BANDFMT_UCHAR ) {
|
||||
if( im_clip2fmt( c, t[2], IM_BANDFMT_UCHAR ) )
|
||||
return( -1 );
|
||||
|
||||
c = t[2];
|
||||
}
|
||||
|
||||
/* Make a and b match in bands and format.
|
||||
*/
|
||||
if( im__formatalike( a, b, t[3], t[4] ) ||
|
||||
im__bandalike( "im_blend", t[3], t[4], t[6], t[7] ) )
|
||||
return( -1 );
|
||||
|
||||
/* Make a, b and c match in size.
|
||||
*/
|
||||
t[5] = c;
|
||||
if( im__sizealike_vec( t + 5, t + 8, 3 ) )
|
||||
return( -1 );
|
||||
|
||||
if( blend( t[8], t[9], t[10], t[11] ) )
|
||||
return( -1 );
|
||||
|
||||
if( repack ) {
|
||||
if( im_Lab2LabQ( t[11], out ) )
|
||||
return( -1 );
|
||||
}
|
||||
else {
|
||||
if( im_copy( t[11], out ) )
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
|
@ -1,540 +0,0 @@
|
|||
/* VIPS function dispatch tables for relational.
|
||||
*
|
||||
* J. Cupitt, 23/2/95
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
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 <vips/vips.h>
|
||||
|
||||
/**
|
||||
* SECTION: relational
|
||||
* @short_description: relational comparisons between pairs of images and
|
||||
* images and constants
|
||||
* @see_also: <link linkend="libvips-arithmetic">arithmetic</link>
|
||||
* @stability: Stable
|
||||
* @include: vips/vips.h
|
||||
*
|
||||
* These operations perform comparison operations, such as equals, on
|
||||
* every pixel in an image or pair of images.
|
||||
* All will work with
|
||||
* images of any type or any mixture of types of any size and of any number
|
||||
* of bands.
|
||||
*
|
||||
* For binary operations, 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.
|
||||
*
|
||||
* In the same way, for operations that take an array constant, such as
|
||||
* im_equal_vec(), you can mix single-element arrays or single-band images
|
||||
* freely.
|
||||
*
|
||||
* The output type is always unsigned char,
|
||||
* with 255 for every band element for which the condition
|
||||
* is true, and 0 for every other element.
|
||||
* For complex images, the operations calculate and compare the modulus.
|
||||
*
|
||||
* For binary operations on pairs of images, the images must match in size.
|
||||
*/
|
||||
|
||||
/* Two images in, one out.
|
||||
*/
|
||||
static im_arg_desc two_in_one_out[] = {
|
||||
IM_INPUT_IMAGE( "in1" ),
|
||||
IM_INPUT_IMAGE( "in2" ),
|
||||
IM_OUTPUT_IMAGE( "out" )
|
||||
};
|
||||
|
||||
/* One image plus one constant in, one image out.
|
||||
*/
|
||||
static im_arg_desc const_in_one_out[] = {
|
||||
IM_INPUT_IMAGE( "in" ),
|
||||
IM_OUTPUT_IMAGE( "out" ),
|
||||
IM_INPUT_DOUBLE( "c" )
|
||||
};
|
||||
|
||||
/* One image plus doublevec in, one image out.
|
||||
*/
|
||||
static im_arg_desc vec_in_one_out[] = {
|
||||
IM_INPUT_IMAGE( "in" ),
|
||||
IM_OUTPUT_IMAGE( "out" ),
|
||||
IM_INPUT_DOUBLEVEC( "vec" )
|
||||
};
|
||||
|
||||
/* Call im_equal via arg vector.
|
||||
*/
|
||||
static int
|
||||
equal_vec( im_object *argv )
|
||||
{
|
||||
return( im_equal( argv[0], argv[1], argv[2] ) );
|
||||
}
|
||||
|
||||
/* Description of im_equal.
|
||||
*/
|
||||
static im_function equal_desc = {
|
||||
"im_equal", /* Name */
|
||||
"two images equal in value", /* Description */
|
||||
IM_FN_PTOP | IM_FN_PIO, /* Flags */
|
||||
equal_vec, /* Dispatch function */
|
||||
IM_NUMBER( two_in_one_out ), /* Size of arg list */
|
||||
two_in_one_out /* Arg list */
|
||||
};
|
||||
|
||||
/* Call im_equalconst via arg vector.
|
||||
*/
|
||||
static int
|
||||
equalconst_vec( im_object *argv )
|
||||
{
|
||||
double c = *((double *) argv[2]);
|
||||
|
||||
return( im_equalconst( argv[0], argv[1], c ) );
|
||||
}
|
||||
|
||||
/* Description of im_equalconst.
|
||||
*/
|
||||
static im_function equalconst_desc = {
|
||||
"im_equalconst", /* Name */
|
||||
"image equals const", /* Description */
|
||||
IM_FN_PTOP | IM_FN_PIO, /* Flags */
|
||||
equalconst_vec, /* Dispatch function */
|
||||
IM_NUMBER( const_in_one_out ), /* Size of arg list */
|
||||
const_in_one_out /* Arg list */
|
||||
};
|
||||
|
||||
/* Call im_equal_vec via arg vector.
|
||||
*/
|
||||
static int
|
||||
equal_vec_vec( im_object *argv )
|
||||
{
|
||||
im_doublevec_object *rv = (im_doublevec_object *) argv[2];
|
||||
|
||||
return( im_equal_vec( argv[0], argv[1], rv->n, rv->vec ) );
|
||||
}
|
||||
|
||||
/* Description of im_equal_vec.
|
||||
*/
|
||||
static im_function equal_vec_desc = {
|
||||
"im_equal_vec", /* Name */
|
||||
"image equals doublevec", /* Description */
|
||||
IM_FN_PTOP | IM_FN_PIO, /* Flags */
|
||||
equal_vec_vec, /* Dispatch function */
|
||||
IM_NUMBER( vec_in_one_out ), /* Size of arg list */
|
||||
vec_in_one_out /* Arg list */
|
||||
};
|
||||
|
||||
/* Call im_notequal via arg vector.
|
||||
*/
|
||||
static int
|
||||
notequal_vec( im_object *argv )
|
||||
{
|
||||
return( im_notequal( argv[0], argv[1], argv[2] ) );
|
||||
}
|
||||
|
||||
/* Description of im_notequal.
|
||||
*/
|
||||
static im_function notequal_desc = {
|
||||
"im_notequal", /* Name */
|
||||
"two images not equal in value",/* Description */
|
||||
IM_FN_PTOP | IM_FN_PIO, /* Flags */
|
||||
notequal_vec, /* Dispatch function */
|
||||
IM_NUMBER( two_in_one_out ), /* Size of arg list */
|
||||
two_in_one_out /* Arg list */
|
||||
};
|
||||
|
||||
/* Call im_notequalconst via arg vector.
|
||||
*/
|
||||
static int
|
||||
notequalconst_vec( im_object *argv )
|
||||
{
|
||||
double c = *((double *) argv[2]);
|
||||
|
||||
return( im_notequalconst( argv[0], argv[1], c ) );
|
||||
}
|
||||
|
||||
/* Description of im_notequalconst.
|
||||
*/
|
||||
static im_function notequalconst_desc = {
|
||||
"im_notequalconst", /* Name */
|
||||
"image does not equal const", /* Description */
|
||||
IM_FN_PTOP | IM_FN_PIO, /* Flags */
|
||||
notequalconst_vec, /* Dispatch function */
|
||||
IM_NUMBER( const_in_one_out ), /* Size of arg list */
|
||||
const_in_one_out /* Arg list */
|
||||
};
|
||||
|
||||
/* Call im_notequal_vec via arg vector.
|
||||
*/
|
||||
static int
|
||||
notequal_vec_vec( im_object *argv )
|
||||
{
|
||||
im_doublevec_object *rv = (im_doublevec_object *) argv[2];
|
||||
|
||||
return( im_notequal_vec( argv[0], argv[1], rv->n, rv->vec ) );
|
||||
}
|
||||
|
||||
/* Description of im_notequal_vec.
|
||||
*/
|
||||
static im_function notequal_vec_desc = {
|
||||
"im_notequal_vec", /* Name */
|
||||
"image does not equal doublevec", /* Description */
|
||||
IM_FN_PTOP | IM_FN_PIO, /* Flags */
|
||||
notequal_vec_vec, /* Dispatch function */
|
||||
IM_NUMBER( vec_in_one_out ), /* Size of arg list */
|
||||
vec_in_one_out /* Arg list */
|
||||
};
|
||||
|
||||
/* Call im_less via arg vector.
|
||||
*/
|
||||
static int
|
||||
less_vec( im_object *argv )
|
||||
{
|
||||
return( im_less( argv[0], argv[1], argv[2] ) );
|
||||
}
|
||||
|
||||
/* Description of im_less.
|
||||
*/
|
||||
static im_function less_desc = {
|
||||
"im_less", /* Name */
|
||||
"in1 less than in2 in value", /* Description */
|
||||
IM_FN_PTOP | IM_FN_PIO, /* Flags */
|
||||
less_vec, /* Dispatch function */
|
||||
IM_NUMBER( two_in_one_out ), /* Size of arg list */
|
||||
two_in_one_out /* Arg list */
|
||||
};
|
||||
|
||||
/* Call im_lessconst via arg vector.
|
||||
*/
|
||||
static int
|
||||
lessconst_vec( im_object *argv )
|
||||
{
|
||||
double c = *((double *) argv[2]);
|
||||
|
||||
return( im_lessconst( argv[0], argv[1], c ) );
|
||||
}
|
||||
|
||||
/* Description of im_lessconst.
|
||||
*/
|
||||
static im_function lessconst_desc = {
|
||||
"im_lessconst", /* Name */
|
||||
"in less than const", /* Description */
|
||||
IM_FN_PTOP | IM_FN_PIO, /* Flags */
|
||||
lessconst_vec, /* Dispatch function */
|
||||
IM_NUMBER( const_in_one_out ), /* Size of arg list */
|
||||
const_in_one_out /* Arg list */
|
||||
};
|
||||
|
||||
/* Call im_less_vec via arg vector.
|
||||
*/
|
||||
static int
|
||||
less_vec_vec( im_object *argv )
|
||||
{
|
||||
im_doublevec_object *rv = (im_doublevec_object *) argv[2];
|
||||
|
||||
return( im_less_vec( argv[0], argv[1], rv->n, rv->vec ) );
|
||||
}
|
||||
|
||||
/* Description of im_less_vec.
|
||||
*/
|
||||
static im_function less_vec_desc = {
|
||||
"im_less_vec", /* Name */
|
||||
"in less than doublevec", /* Description */
|
||||
IM_FN_PTOP | IM_FN_PIO, /* Flags */
|
||||
less_vec_vec, /* Dispatch function */
|
||||
IM_NUMBER( vec_in_one_out ), /* Size of arg list */
|
||||
vec_in_one_out /* Arg list */
|
||||
};
|
||||
|
||||
/* Call im_more via arg vector.
|
||||
*/
|
||||
static int
|
||||
more_vec( im_object *argv )
|
||||
{
|
||||
return( im_more( argv[0], argv[1], argv[2] ) );
|
||||
}
|
||||
|
||||
/* Description of im_more.
|
||||
*/
|
||||
static im_function more_desc = {
|
||||
"im_more", /* Name */
|
||||
"in1 more than in2 in value", /* Description */
|
||||
IM_FN_PTOP | IM_FN_PIO, /* Flags */
|
||||
more_vec, /* Dispatch function */
|
||||
IM_NUMBER( two_in_one_out ), /* Size of arg list */
|
||||
two_in_one_out /* Arg list */
|
||||
};
|
||||
|
||||
/* Call im_moreconst via arg vector.
|
||||
*/
|
||||
static int
|
||||
moreconst_vec( im_object *argv )
|
||||
{
|
||||
double c = *((double *) argv[2]);
|
||||
|
||||
return( im_moreconst( argv[0], argv[1], c ) );
|
||||
}
|
||||
|
||||
/* Description of im_moreconst.
|
||||
*/
|
||||
static im_function moreconst_desc = {
|
||||
"im_moreconst", /* Name */
|
||||
"in more than const", /* Description */
|
||||
IM_FN_PTOP | IM_FN_PIO, /* Flags */
|
||||
moreconst_vec, /* Dispatch function */
|
||||
IM_NUMBER( const_in_one_out ), /* Size of arg list */
|
||||
const_in_one_out /* Arg list */
|
||||
};
|
||||
|
||||
/* Call im_more_vec via arg vector.
|
||||
*/
|
||||
static int
|
||||
more_vec_vec( im_object *argv )
|
||||
{
|
||||
im_doublevec_object *rv = (im_doublevec_object *) argv[2];
|
||||
|
||||
return( im_more_vec( argv[0], argv[1], rv->n, rv->vec ) );
|
||||
}
|
||||
|
||||
/* Description of im_more_vec.
|
||||
*/
|
||||
static im_function more_vec_desc = {
|
||||
"im_more_vec", /* Name */
|
||||
"in more than doublevec", /* Description */
|
||||
IM_FN_PTOP | IM_FN_PIO, /* Flags */
|
||||
more_vec_vec, /* Dispatch function */
|
||||
IM_NUMBER( vec_in_one_out ), /* Size of arg list */
|
||||
vec_in_one_out /* Arg list */
|
||||
};
|
||||
|
||||
/* Call im_moreeq via arg vector.
|
||||
*/
|
||||
static int
|
||||
moreeq_vec( im_object *argv )
|
||||
{
|
||||
return( im_moreeq( argv[0], argv[1], argv[2] ) );
|
||||
}
|
||||
|
||||
/* Description of im_moreeq.
|
||||
*/
|
||||
static im_function moreeq_desc = {
|
||||
"im_moreeq", /* Name */
|
||||
"in1 more than or equal to in2 in value",
|
||||
IM_FN_PTOP | IM_FN_PIO, /* Flags */
|
||||
moreeq_vec, /* Dispatch function */
|
||||
IM_NUMBER( two_in_one_out ), /* Size of arg list */
|
||||
two_in_one_out /* Arg list */
|
||||
};
|
||||
|
||||
/* Call im_moreeqconst via arg vector.
|
||||
*/
|
||||
static int
|
||||
moreeqconst_vec( im_object *argv )
|
||||
{
|
||||
double c = *((double *) argv[2]);
|
||||
|
||||
return( im_moreeqconst( argv[0], argv[1], c ) );
|
||||
}
|
||||
|
||||
/* Description of im_moreeqconst.
|
||||
*/
|
||||
static im_function moreeqconst_desc = {
|
||||
"im_moreeqconst", /* Name */
|
||||
"in more than or equal to const",
|
||||
IM_FN_PTOP | IM_FN_PIO, /* Flags */
|
||||
moreeqconst_vec, /* Dispatch function */
|
||||
IM_NUMBER( const_in_one_out ), /* Size of arg list */
|
||||
const_in_one_out /* Arg list */
|
||||
};
|
||||
|
||||
/* Call im_moreeq_vec via arg vector.
|
||||
*/
|
||||
static int
|
||||
moreeq_vec_vec( im_object *argv )
|
||||
{
|
||||
im_doublevec_object *rv = (im_doublevec_object *) argv[2];
|
||||
|
||||
return( im_moreeq_vec( argv[0], argv[1], rv->n, rv->vec ) );
|
||||
}
|
||||
|
||||
/* Description of im_moreeq_vec.
|
||||
*/
|
||||
static im_function moreeq_vec_desc = {
|
||||
"im_moreeq_vec", /* Name */
|
||||
"in more than or equal to doublevec",
|
||||
IM_FN_PTOP | IM_FN_PIO, /* Flags */
|
||||
moreeq_vec_vec, /* Dispatch function */
|
||||
IM_NUMBER( vec_in_one_out ), /* Size of arg list */
|
||||
vec_in_one_out /* Arg list */
|
||||
};
|
||||
|
||||
/* Call im_lesseq via arg vector.
|
||||
*/
|
||||
static int
|
||||
lesseq_vec( im_object *argv )
|
||||
{
|
||||
return( im_lesseq( argv[0], argv[1], argv[2] ) );
|
||||
}
|
||||
|
||||
/* Description of im_lesseq.
|
||||
*/
|
||||
static im_function lesseq_desc = {
|
||||
"im_lesseq", /* Name */
|
||||
"in1 less than or equal to in2 in value",
|
||||
IM_FN_PTOP | IM_FN_PIO, /* Flags */
|
||||
lesseq_vec, /* Dispatch function */
|
||||
IM_NUMBER( two_in_one_out ), /* Size of arg list */
|
||||
two_in_one_out /* Arg list */
|
||||
};
|
||||
|
||||
/* Call im_lesseqconst via arg vector.
|
||||
*/
|
||||
static int
|
||||
lesseqconst_vec( im_object *argv )
|
||||
{
|
||||
double c = *((double *) argv[2]);
|
||||
|
||||
return( im_lesseqconst( argv[0], argv[1], c ) );
|
||||
}
|
||||
|
||||
/* Description of im_lesseqconst.
|
||||
*/
|
||||
static im_function lesseqconst_desc = {
|
||||
"im_lesseqconst", /* Name */
|
||||
"in less than or equal to const",
|
||||
IM_FN_PTOP | IM_FN_PIO, /* Flags */
|
||||
lesseqconst_vec, /* Dispatch function */
|
||||
IM_NUMBER( const_in_one_out ), /* Size of arg list */
|
||||
const_in_one_out /* Arg list */
|
||||
};
|
||||
|
||||
/* Call im_lesseq_vec via arg vector.
|
||||
*/
|
||||
static int
|
||||
lesseq_vec_vec( im_object *argv )
|
||||
{
|
||||
im_doublevec_object *rv = (im_doublevec_object *) argv[2];
|
||||
|
||||
return( im_lesseq_vec( argv[0], argv[1], rv->n, rv->vec ) );
|
||||
}
|
||||
|
||||
/* Description of im_lesseq_vec.
|
||||
*/
|
||||
static im_function lesseq_vec_desc = {
|
||||
"im_lesseq_vec", /* Name */
|
||||
"in less than or equal to doublevec",
|
||||
IM_FN_PTOP | IM_FN_PIO, /* Flags */
|
||||
lesseq_vec_vec, /* Dispatch function */
|
||||
IM_NUMBER( vec_in_one_out ), /* Size of arg list */
|
||||
vec_in_one_out /* Arg list */
|
||||
};
|
||||
|
||||
/* If-then-else args.
|
||||
*/
|
||||
static im_arg_desc ifthenelse_args[] = {
|
||||
IM_INPUT_IMAGE( "cond" ),
|
||||
IM_INPUT_IMAGE( "in1" ),
|
||||
IM_INPUT_IMAGE( "in2" ),
|
||||
IM_OUTPUT_IMAGE( "out" )
|
||||
};
|
||||
|
||||
/* Call im_blend via arg vector.
|
||||
*/
|
||||
static int
|
||||
blend_vec( im_object *argv )
|
||||
{
|
||||
return( im_blend( argv[0], argv[1], argv[2], argv[3] ) );
|
||||
}
|
||||
|
||||
/* Description of im_blend.
|
||||
*/
|
||||
static im_function blend_desc = {
|
||||
"im_blend", /* Name */
|
||||
"use cond image to blend between images in1 and in2",
|
||||
IM_FN_PTOP | IM_FN_PIO, /* Flags */
|
||||
blend_vec, /* Dispatch function */
|
||||
IM_NUMBER( ifthenelse_args ), /* Size of arg list */
|
||||
ifthenelse_args /* Arg list */
|
||||
};
|
||||
|
||||
/* Call im_ifthenelse via arg vector.
|
||||
*/
|
||||
static int
|
||||
ifthenelse_vec( im_object *argv )
|
||||
{
|
||||
return( im_ifthenelse( argv[0], argv[1], argv[2], argv[3] ) );
|
||||
}
|
||||
|
||||
/* Description of im_ifthenelse.
|
||||
*/
|
||||
static im_function ifthenelse_desc = {
|
||||
"im_ifthenelse", /* Name */
|
||||
"use cond image to choose pels from image in1 or in2",
|
||||
IM_FN_PTOP | IM_FN_PIO, /* Flags */
|
||||
ifthenelse_vec, /* Dispatch function */
|
||||
IM_NUMBER( ifthenelse_args ), /* Size of arg list */
|
||||
ifthenelse_args /* Arg list */
|
||||
};
|
||||
|
||||
/* Package up all these functions.
|
||||
*/
|
||||
static im_function *relational_list[] = {
|
||||
&blend_desc,
|
||||
&equal_desc,
|
||||
&equal_vec_desc,
|
||||
&equalconst_desc,
|
||||
&ifthenelse_desc,
|
||||
&less_desc,
|
||||
&less_vec_desc,
|
||||
&lessconst_desc,
|
||||
&lesseq_desc,
|
||||
&lesseq_vec_desc,
|
||||
&lesseqconst_desc,
|
||||
&more_desc,
|
||||
&more_vec_desc,
|
||||
&moreconst_desc,
|
||||
&moreeq_desc,
|
||||
&moreeq_vec_desc,
|
||||
&moreeqconst_desc,
|
||||
¬equal_desc,
|
||||
¬equal_vec_desc,
|
||||
¬equalconst_desc
|
||||
};
|
||||
|
||||
/* Package of functions.
|
||||
*/
|
||||
im_package im__relational = {
|
||||
"relational",
|
||||
IM_NUMBER( relational_list ),
|
||||
relational_list
|
||||
};
|
Loading…
Reference in New Issue