better handling of overflow in vips_flatten()

This commit is contained in:
John Cupitt 2014-02-05 09:30:24 +00:00
parent c5d5fd515d
commit 8e1ae0c6ec

View File

@ -76,8 +76,8 @@ G_DEFINE_TYPE( VipsFlatten, vips_flatten, VIPS_TYPE_CONVERSION );
/* Flatten with black background. /* Flatten with black background.
*/ */
#define VIPS_FLATTEN_BLACK( TYPE, MAX ) { \ #define VIPS_FLATTEN_BLACK( TYPE, MAX ) { \
TYPE *p = (TYPE *) in; \ TYPE * restrict p = (TYPE *) in; \
TYPE *q = (TYPE *) out; \ TYPE * restrict q = (TYPE *) out; \
\ \
for( x = 0; x < width; x++ ) { \ for( x = 0; x < width; x++ ) { \
TYPE alpha = p[bands - 1]; \ TYPE alpha = p[bands - 1]; \
@ -94,13 +94,13 @@ G_DEFINE_TYPE( VipsFlatten, vips_flatten, VIPS_TYPE_CONVERSION );
/* Flatten with any background. /* Flatten with any background.
*/ */
#define VIPS_FLATTEN( TYPE, MAX ) { \ #define VIPS_FLATTEN( TYPE, MAX ) { \
TYPE *p = (TYPE *) in; \ TYPE * restrict p = (TYPE *) in; \
TYPE *q = (TYPE *) out; \ TYPE * restrict q = (TYPE *) out; \
\ \
for( x = 0; x < width; x++ ) { \ for( x = 0; x < width; x++ ) { \
TYPE alpha = p[bands - 1]; \ TYPE alpha = p[bands - 1]; \
TYPE nalpha = (MAX) - alpha; \ TYPE nalpha = (MAX) - alpha; \
TYPE *bg = (TYPE *) flatten->ink; \ TYPE * restrict bg = (TYPE *) flatten->ink; \
int b; \ int b; \
\ \
for( b = 0; b < bands - 1; b++ ) \ for( b = 0; b < bands - 1; b++ ) \
@ -112,6 +112,44 @@ G_DEFINE_TYPE( VipsFlatten, vips_flatten, VIPS_TYPE_CONVERSION );
} \ } \
} }
/* Same, but with float arithmetic. Necessary for int/uint to prevent
* overflow.
*/
#define VIPS_FLATTEN_BLACK_FLOAT( TYPE, MAX ) { \
TYPE * restrict p = (TYPE *) in; \
TYPE * restrict q = (TYPE *) out; \
\
for( x = 0; x < width; x++ ) { \
TYPE alpha = p[bands - 1]; \
int b; \
\
for( b = 0; b < bands - 1; b++ ) \
q[b] = ((double) p[b] * alpha) / (MAX); \
\
p += bands; \
q += bands - 1; \
} \
}
#define VIPS_FLATTEN_FLOAT( TYPE, MAX ) { \
TYPE * restrict p = (TYPE *) in; \
TYPE * restrict q = (TYPE *) out; \
\
for( x = 0; x < width; x++ ) { \
TYPE alpha = p[bands - 1]; \
TYPE nalpha = (MAX) - alpha; \
TYPE * restrict bg = (TYPE *) flatten->ink; \
int b; \
\
for( b = 0; b < bands - 1; b++ ) \
q[b] = ((double) p[b] * alpha) / (MAX) + \
((double) bg[b] * nalpha) / (MAX); \
\
p += bands; \
q += bands - 1; \
} \
}
static int static int
vips_flatten_black_gen( VipsRegion *or, void *vseq, void *a, void *b, vips_flatten_black_gen( VipsRegion *or, void *vseq, void *a, void *b,
gboolean *stop ) gboolean *stop )
@ -151,19 +189,19 @@ vips_flatten_black_gen( VipsRegion *or, void *vseq, void *a, void *b,
break; break;
case VIPS_FORMAT_UINT: case VIPS_FORMAT_UINT:
VIPS_FLATTEN_BLACK( unsigned int, UINT_MAX ); VIPS_FLATTEN_BLACK_FLOAT( unsigned int, UINT_MAX );
break; break;
case VIPS_FORMAT_INT: case VIPS_FORMAT_INT:
VIPS_FLATTEN_BLACK( signed int, INT_MAX ); VIPS_FLATTEN_BLACK_FLOAT( signed int, INT_MAX );
break; break;
case VIPS_FORMAT_FLOAT: case VIPS_FORMAT_FLOAT:
VIPS_FLATTEN_BLACK( float, 1.0 ); VIPS_FLATTEN_BLACK_FLOAT( float, 1.0 );
break; break;
case VIPS_FORMAT_DOUBLE: case VIPS_FORMAT_DOUBLE:
VIPS_FLATTEN_BLACK( double, 1.0 ); VIPS_FLATTEN_BLACK_FLOAT( double, 1.0 );
break; break;
case VIPS_FORMAT_COMPLEX: case VIPS_FORMAT_COMPLEX:
@ -217,19 +255,19 @@ vips_flatten_gen( VipsRegion *or, void *vseq, void *a, void *b,
break; break;
case VIPS_FORMAT_UINT: case VIPS_FORMAT_UINT:
VIPS_FLATTEN( unsigned int, UINT_MAX ); VIPS_FLATTEN_FLOAT( unsigned int, UINT_MAX );
break; break;
case VIPS_FORMAT_INT: case VIPS_FORMAT_INT:
VIPS_FLATTEN( signed int, INT_MAX ); VIPS_FLATTEN_FLOAT( signed int, INT_MAX );
break; break;
case VIPS_FORMAT_FLOAT: case VIPS_FORMAT_FLOAT:
VIPS_FLATTEN( float, 1.0 ); VIPS_FLATTEN_FLOAT( float, 1.0 );
break; break;
case VIPS_FORMAT_DOUBLE: case VIPS_FORMAT_DOUBLE:
VIPS_FLATTEN( double, 1.0 ); VIPS_FLATTEN_FLOAT( double, 1.0 );
break; break;
case VIPS_FORMAT_COMPLEX: case VIPS_FORMAT_COMPLEX: