diff --git a/ChangeLog b/ChangeLog index cd9c78f6..bbc3cae0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -44,8 +44,9 @@ - renamed im_eor_vec() as im_eorimage_vec() for consistency, also and, or - renamed im_eorconst() as im_eorimage_const() for consistency, also and, or - relational revised: smaller, more general, faster -- im_blend() allows many-band conditional, 1-band then/else -- im_blend() allows band and format to differ between then and else parts +- im_blend()/im_ifthenelse() allows many-band conditional, 1-band then/else +- im_blend()/im_ifthenelse() allows band and format to differ between then + and else parts 25/3/09 started 7.18.0 - revised version numbers diff --git a/TODO b/TODO index 1aaa7b80..1e24ed9d 100644 --- a/TODO +++ b/TODO @@ -1,11 +1,6 @@ -- do im_ifthenelse - - - we have tools/ and contrib/ argh - - - Joe's new defs diff --git a/libvips/include/vips/proto.h b/libvips/include/vips/proto.h index cfbb03ee..370b1f87 100644 --- a/libvips/include/vips/proto.h +++ b/libvips/include/vips/proto.h @@ -136,6 +136,7 @@ int im_isMSBfirst( IMAGE * ); int im_amiMSBfirst( void ); int im_check_uncoded( const char *domain, IMAGE *im ); +int im_check_known_coded( const char *domain, IMAGE *im ); int im_check_bands_1orn( const char *domain, IMAGE *im1, IMAGE *im2 ); int im_check_noncomplex( const char *domain, IMAGE *im ); int im_check_complex( const char *domain, IMAGE *im ); diff --git a/libvips/iofuncs/predicate.c b/libvips/iofuncs/predicate.c index 8c0a1dc7..457fb5f5 100644 --- a/libvips/iofuncs/predicate.c +++ b/libvips/iofuncs/predicate.c @@ -370,6 +370,21 @@ im_check_uncoded( const char *domain, IMAGE *im ) return( 0 ); } +int +im_check_known_coded( const char *domain, IMAGE *im ) +{ + /* These all have codings that extract/ifthenelse/etc can ignore. + */ + if( im->Coding != IM_CODING_NONE && + im->Coding != IM_CODING_LABQ && + im->Coding != IM_CODING_RAD ) { + im_error( domain, "%s", _( "unknown image coding" ) ); + return( -1 ); + } + + return( 0 ); +} + int im_check_bands_1orn( const char *domain, IMAGE *im1, IMAGE *im2 ) { diff --git a/libvips/relational/im_blend.c b/libvips/relational/im_blend.c index a7bd9837..4dad582d 100644 --- a/libvips/relational/im_blend.c +++ b/libvips/relational/im_blend.c @@ -9,6 +9,7 @@ * - gtkdoc comments * - use im_check*() * - allow many-band conditional and single-band a/b + * - allow a/b to differ in format and bands */ /* diff --git a/libvips/relational/im_ifthenelse.c b/libvips/relational/im_ifthenelse.c index 0c6c566a..48c1d138 100644 --- a/libvips/relational/im_ifthenelse.c +++ b/libvips/relational/im_ifthenelse.c @@ -11,6 +11,10 @@ * - 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 */ /* @@ -44,9 +48,8 @@ #endif /*HAVE_CONFIG_H*/ #include -#include - #include +#include #ifdef WITH_DMALLOC #include @@ -143,68 +146,24 @@ ifthenelse_gen( REGION *or, void *seq, void *client1, void *client2 ) return( 0 ); } -/** - * im_ifthenelse: - * @c: condition #IMAGE - * @a: then #IMAGE - * @b: else #IMAGE - * @out: output #IMAGE - * - * This operation scans the condition image @c (which must be unsigned char) - * and uses it to select pixels from either the then image @a or the else - * image @b. Non-zero means @a, 0 means @b. - * - * The conditional image @c can have either 1 band, in which case entire pels - * come either from @a or @b, or n bands, where n is the number of bands in - * both @a and @b, in which case individual band elements are chosen from - * @a and @b. - * - * Images @a and @b must match exactly in size, bands and format. - * - * See also: im_blend(), im_equal(). - * - * Returns: 0 on success, -1 on error - */ -int -im_ifthenelse( IMAGE *c, IMAGE *a, IMAGE *b, IMAGE *out ) +static int +ifthenelse( IMAGE *c, IMAGE *a, IMAGE *b, IMAGE *out ) { IMAGE **in; /* Check args. */ - if( a->Coding != IM_CODING_NONE && a->Coding != IM_CODING_LABQ ) { - im_error( "im_ifthenelse", - "%s", _( "then image must be uncoded or labpack" ) ); - return( -1 ); - } - if( b->Coding != IM_CODING_NONE && b->Coding != IM_CODING_LABQ ) { - im_error( "im_ifthenelse", - "%s", _( "else image must be uncoded or labpack" ) ); - return( -1 ); - } - if( c->Coding != IM_CODING_NONE ) { - im_error( "im_ifthenelse", - "%s", _( "condition image must be uncoded" ) ); - return( -1 ); - } - if( a->BandFmt != b->BandFmt || - a->Bands != b->Bands ) { - im_error( "im_ifthenelse", - "%s", _( "size and format of then and else " - "must match" ) ); - return( -1 ); - } - if( c->BandFmt != IM_BANDFMT_UCHAR ) { - im_error( "im_ifthenelse", - "%s", _( "conditional image must be uchar" ) ); - return( -1 ); - } - if( c->Bands != 1 && c->Bands != a->Bands ) { - im_error( "im_ifthenelse", - "%s", _( "conditional image must be one band or same " - "as then and else images" ) ); - return( -1 ); - } + if( im_check_uncoded( "im_ifthenelse", c ) || + im_check_uchar( "im_ifthenelse", c ) || + im_check_known_coded( "im_ifthenelse", a ) || + im_check_known_coded( "im_ifthenelse", b ) || + im_check_format( "im_ifthenelse", a, b ) || + im_check_bands( "im_ifthenelse", a, b ) || + im_check_bands_1orn( "im_ifthenelse", c, a ) || + im_piocheck( c, out ) || + im_pincheck( a ) || + im_pincheck( b ) ) + return( -1 ); /* Make output image. */ @@ -218,3 +177,47 @@ im_ifthenelse( IMAGE *c, IMAGE *a, IMAGE *b, IMAGE *out ) return( 0 ); } + +/** + * im_ifthenelse: + * @c: condition #IMAGE + * @a: then #IMAGE + * @b: else #IMAGE + * @out: output #IMAGE + * + * This operation scans the condition image @c (which must be unsigned char) + * and uses it to select pixels from either the then image @a or the else + * image @b. Non-zero means @a, 0 means @b. + * + * 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 @a and @b are cast up to the smallest common format. + * + * Images @a and @b must match exactly in size. + * + * See also: im_blend(), im_equal(). + * + * Returns: 0 on success, -1 on error + */ +int +im_ifthenelse( IMAGE *c, IMAGE *a, IMAGE *b, IMAGE *out ) +{ + IMAGE *t[7]; + + if( im_open_local_array( out, t, 7, "im_ifthenelse", "p" ) ) + return( -1 ); + + /* Make a and b match in bands and format. Don't make c match: we + * special-case this in code above ^^^ for speed. + */ + if( im__formatalike( a, b, t[0], t[1] ) || + im__bandalike( t[0], t[1], t[2], t[3] ) ) + return( -1 ); + + if( ifthenelse( c, t[2], t[3], out ) ) + return( -1 ); + + return( 0 ); +}