diff --git a/ChangeLog b/ChangeLog index ac131143..3f4dc8a5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -38,6 +38,7 @@ - close callbacks now happen *after* images have closed resources (such as open files) ... this lets them delete temps and stuff. Expect breakage :( - added vips_interpolate_get_window_offset() +- boolean revised: smaller, more general, faster 25/3/09 started 7.18.0 - revised version numbers diff --git a/libvips/arithmetic/im_add.c b/libvips/arithmetic/im_add.c index e6e8f25a..da1c7879 100644 --- a/libvips/arithmetic/im_add.c +++ b/libvips/arithmetic/im_add.c @@ -186,7 +186,7 @@ im__format_common( IMAGE *in1, IMAGE *in2 ) /* Make an n-band image. Input 1 or n bands. */ -static int +int im__bandup( IMAGE *in, IMAGE *out, int n ) { IMAGE *bands[256]; diff --git a/libvips/arithmetic/im_remainder.c b/libvips/arithmetic/im_remainder.c index 6ed5f084..16c178cb 100644 --- a/libvips/arithmetic/im_remainder.c +++ b/libvips/arithmetic/im_remainder.c @@ -50,7 +50,6 @@ #include #include #include -#include #include #include @@ -61,26 +60,26 @@ /* Integer remainder-after-division. */ -#define ILOOP( IN, OUT ) { \ - IN *p1 = (IN *) in[0]; \ - IN *p2 = (IN *) in[1]; \ - OUT *q = (OUT *) out; \ +#define IREMAINDER( TYPE ) { \ + TYPE *p1 = (TYPE *) in[0]; \ + TYPE *p2 = (TYPE *) in[1]; \ + TYPE *q = (TYPE *) out; \ \ - for( x = 0; x < sz; x++ ) \ + for( x = 0; x < ne; x++ ) \ if( p2[x] ) \ - q[x] = (int) p1[x] % (int) p2[x]; \ + q[x] = p1[x] % p2[x]; \ else \ q[x] = -1; \ } /* Float remainder-after-division. */ -#define FLOOP( IN, OUT ) { \ - IN *p1 = (IN *) in[0]; \ - IN *p2 = (IN *) in[1]; \ - OUT *q = (OUT *) out; \ +#define FREMAINDER( TYPE ) { \ + TYPE *p1 = (TYPE *) in[0]; \ + TYPE *p2 = (TYPE *) in[1]; \ + TYPE *q = (TYPE *) out; \ \ - for( x = 0; x < sz; x++ ) { \ + for( x = 0; x < ne; x++ ) { \ double a = p1[x]; \ double b = p2[x]; \ \ @@ -94,21 +93,22 @@ static void remainder_buffer( PEL **in, PEL *out, int width, IMAGE *im ) { + const int ne = width * im->Bands; + int x; - int sz = width * im->Bands; switch( im->BandFmt ) { - case IM_BANDFMT_CHAR: ILOOP( signed char, signed char ); break; - case IM_BANDFMT_UCHAR: ILOOP( unsigned char, unsigned char ); break; - case IM_BANDFMT_SHORT: ILOOP( signed short, signed short ); break; - case IM_BANDFMT_USHORT: ILOOP( unsigned short, unsigned short ); break; - case IM_BANDFMT_INT: ILOOP( signed int, signed int ); break; - case IM_BANDFMT_UINT: ILOOP( unsigned int, unsigned int ); break; - case IM_BANDFMT_FLOAT: FLOOP( float, float ); break; - case IM_BANDFMT_DOUBLE: FLOOP( double, double ); break; + case IM_BANDFMT_CHAR: IREMAINDER( signed char ); break; + case IM_BANDFMT_UCHAR: IREMAINDER( unsigned char ); break; + case IM_BANDFMT_SHORT: IREMAINDER( signed short ); break; + case IM_BANDFMT_USHORT: IREMAINDER( unsigned short ); break; + case IM_BANDFMT_INT: IREMAINDER( signed int ); break; + case IM_BANDFMT_UINT: IREMAINDER( unsigned int ); break; + case IM_BANDFMT_FLOAT: FREMAINDER( float ); break; + case IM_BANDFMT_DOUBLE: FREMAINDER( double ); break; default: - assert( 0 ); + g_assert( 0 ); } } @@ -125,8 +125,7 @@ remainder_buffer( PEL **in, PEL *out, int width, IMAGE *im ) #define D IM_BANDFMT_DOUBLE #define DX IM_BANDFMT_DPCOMPLEX -/* Type promotion for remainder. Same as input, except float/complex which are - * signed int. Keep in sync with remainder_buffer() above. +/* Type promotion for remainder. Keep in sync with remainder_buffer() above. */ static int bandfmt_remainder[10] = { /* UC C US S UI I F X D DX */ @@ -141,8 +140,8 @@ static int bandfmt_remainder[10] = { * * This operation calculates @in1 % @in2 (remainder after division) and writes * the result to @out. The images must be the same size. They may have any - * non-complex format. For float types, im_remainder() calculates a - b * - * floor (a / b). + * non-complex format. For float formats, im_remainder() calculates @in1 - + * @in2 * floor (@in1 / @in2). * * 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 @@ -161,6 +160,10 @@ static int bandfmt_remainder[10] = { int im_remainder( IMAGE *in1, IMAGE *in2, IMAGE *out ) { + if( im_check_noncomplex( "im_remainder", in1 ) || + im_check_noncomplex( "im_remainder", in2 ) ) + return( -1 ); + return( im__arith_binary( "im_remainder", in1, in2, out, bandfmt_remainder, @@ -176,7 +179,19 @@ im_remainder( IMAGE *in1, IMAGE *in2, IMAGE *out ) tq[i] = (TYPE) p[i]; \ } -/* Make a pixel of output type from a realvec. +/* Cast a vector of double to a complex vector of TYPE. + */ +#define CASTC( TYPE ) { \ + TYPE *tq = (TYPE *) q; \ + \ + for( i = 0; i < n; i++ ) { \ + tq[0] = (TYPE) p[i]; \ + tq[1] = 0; \ + tq += 2; \ + } \ +} + +/* Cast a vector of double to the type of IMAGE. */ static PEL * make_pixel( IMAGE *out, int n, double *p ) @@ -184,9 +199,7 @@ make_pixel( IMAGE *out, int n, double *p ) PEL *q; int i; - g_assert( n == out->Bands ); - - if( !(q = IM_ARRAY( out, IM_IMAGE_SIZEOF_PEL( out ), PEL )) ) + if( !(q = IM_ARRAY( out, n * IM_IMAGE_SIZEOF_ELEMENT( out ), PEL )) ) return( NULL ); switch( out->BandFmt ) { @@ -196,6 +209,10 @@ make_pixel( IMAGE *out, int n, double *p ) case IM_BANDFMT_USHORT: CAST( unsigned short ); break; case IM_BANDFMT_INT: CAST( signed int ); break; case IM_BANDFMT_UINT: CAST( unsigned int ); break; + case IM_BANDFMT_FLOAT: CAST( float ); break; + case IM_BANDFMT_DOUBLE: CAST( double ); break; + case IM_BANDFMT_COMPLEX: CASTC( float ); break; + case IM_BANDFMT_DPCOMPLEX: CASTC( double ); break; default: g_assert( 0 ); @@ -208,10 +225,10 @@ int im__arith_binary_const( const char *name, IMAGE *in, IMAGE *out, int n, double *c, int format_table[10], - im_wrapone_fn fn, void *a ) + im_wrapone_fn fn1, im_wrapone_fn fnn ) { - int i; PEL *vector; + IMAGE *t; if( im_piocheck( in, out ) || im_check_vector( name, n, in ) || @@ -224,88 +241,127 @@ im__arith_binary_const( const char *name, /* Cast vector to output type. */ - - /* - need to handle case where vector == 1 but bands == (eg.) 3 - */ - if( !(vector = make_pixel( out, n, c )) ) return( -1 ); - if( im_wrapone( in, out, fn, a, vector ) ) + /* Band-up the input image for the case where we have a >1 vector and + * a 1-band image. + */ + if( !(t = im_open_local( out, "im__arith_binary_const", "p" )) || + im__bandup( in, t, n ) ) return( -1 ); + if( n == 1 ) { + if( im_wrapone( t, out, fn1, vector, t ) ) + return( -1 ); + } + else { + if( im_wrapone( t, out, fnn, vector, t ) ) + return( -1 ); + } + return( 0 ); } - -/* Parameters saved here. +/* Integer remainder-after-divide, single constant. */ -typedef struct _Remainderconst { - IMAGE *in; - IMAGE *out; - int n; - int *c; -} Remainderconst; - -/* Integer remainder-after-divide. - */ -#define ICONST1LOOP( TYPE ) { \ +#define IREMAINDERCONST1( TYPE ) { \ TYPE *p = (TYPE *) in; \ TYPE *q = (TYPE *) out; \ + TYPE c = *((TYPE *) vector); \ \ - for( x = 0; x < sz; x++ ) \ + for( x = 0; x < ne; x++ ) \ q[x] = p[x] % c; \ } +/* Float remainder-after-divide, single constant. + */ +#define FREMAINDERCONST1( TYPE ) { \ + TYPE *p = (TYPE *) in; \ + TYPE *q = (TYPE *) out; \ + TYPE c = *((TYPE *) vector); \ + \ + for( x = 0; x < ne; x++ ) { \ + double a = p[x]; \ + \ + if( c ) \ + q[x] = a - c * floor (a / c); \ + else \ + q[x] = -1; \ + } \ +} + static void -remainderconst1_buffer( PEL *in, PEL *out, int width, Remainderconst *rc ) +remainderconst1_buffer( PEL *in, PEL *out, int width, PEL *vector, IMAGE *im ) { - IMAGE *im = rc->in; - int sz = width * im->Bands; - int c = rc->c[0]; + const int ne = width * im->Bands; + int x; switch( im->BandFmt ) { - case IM_BANDFMT_CHAR: ICONST1LOOP( signed char ); break; - case IM_BANDFMT_UCHAR: ICONST1LOOP( unsigned char ); break; - case IM_BANDFMT_SHORT: ICONST1LOOP( signed short ); break; - case IM_BANDFMT_USHORT: ICONST1LOOP( unsigned short ); break; - case IM_BANDFMT_INT: ICONST1LOOP( signed int ); break; - case IM_BANDFMT_UINT: ICONST1LOOP( unsigned int ); break; + case IM_BANDFMT_CHAR: IREMAINDERCONST1( signed char ); break; + case IM_BANDFMT_UCHAR: IREMAINDERCONST1( unsigned char ); break; + case IM_BANDFMT_SHORT: IREMAINDERCONST1( signed short ); break; + case IM_BANDFMT_USHORT: IREMAINDERCONST1( unsigned short ); break; + case IM_BANDFMT_INT: IREMAINDERCONST1( signed int ); break; + case IM_BANDFMT_UINT: IREMAINDERCONST1( unsigned int ); break; + case IM_BANDFMT_FLOAT: FREMAINDERCONST1( float ); break; + case IM_BANDFMT_DOUBLE: FREMAINDERCONST1( double ); break; default: - assert( 0 ); + g_assert( 0 ); } } -#define ICONSTLOOP( TYPE ) { \ +/* Integer remainder-after-divide, per-band constant. + */ +#define IREMAINDERCONSTN( TYPE ) { \ TYPE *p = (TYPE *) in; \ TYPE *q = (TYPE *) out; \ + TYPE *c = (TYPE *) vector; \ \ for( i = 0, x = 0; x < width; x++ ) \ for( k = 0; k < b; k++, i++ ) \ q[i] = p[i] % c[k]; \ } +/* Float remainder-after-divide, per-band constant. + */ +#define FREMAINDERCONSTN( TYPE ) { \ + TYPE *p = (TYPE *) in; \ + TYPE *q = (TYPE *) out; \ + TYPE *c = (TYPE *) vector; \ + \ + for( i = 0, x = 0; x < width; x++ ) \ + for( k = 0; k < b; k++, i++ ) { \ + double a = p[i]; \ + double b = c[k]; \ + \ + if( b ) \ + q[i] = a - b * floor (a / b); \ + else \ + q[i] = -1; \ + } \ +} + static void -remainderconst_buffer( PEL *in, PEL *out, int width, Remainderconst *rc ) +remainderconst_buffer( PEL *in, PEL *out, int width, PEL *vector, IMAGE *im ) { - IMAGE *im = rc->in; int b = im->Bands; - int *c = rc->c; int i, x, k; switch( im->BandFmt ) { - case IM_BANDFMT_CHAR: ICONSTLOOP( signed char ); break; - case IM_BANDFMT_UCHAR: ICONSTLOOP( unsigned char ); break; - case IM_BANDFMT_SHORT: ICONSTLOOP( signed short ); break; - case IM_BANDFMT_USHORT: ICONSTLOOP( unsigned short ); break; - case IM_BANDFMT_INT: ICONSTLOOP( signed int ); break; - case IM_BANDFMT_UINT: ICONSTLOOP( unsigned int ); break; + case IM_BANDFMT_CHAR: IREMAINDERCONSTN( signed char ); break; + case IM_BANDFMT_UCHAR: IREMAINDERCONSTN( unsigned char ); break; + case IM_BANDFMT_SHORT: IREMAINDERCONSTN( signed short ); break; + case IM_BANDFMT_USHORT: IREMAINDERCONSTN( unsigned short ); break; + case IM_BANDFMT_INT: IREMAINDERCONSTN( signed int ); break; + case IM_BANDFMT_UINT: IREMAINDERCONSTN( unsigned int ); break; + case IM_BANDFMT_FLOAT: FREMAINDERCONSTN( float ); break; + case IM_BANDFMT_DOUBLE: FREMAINDERCONSTN( double ); break; default: - assert( 0 ); + g_assert( 0 ); } } @@ -317,70 +373,31 @@ remainderconst_buffer( PEL *in, PEL *out, int width, Remainderconst *rc ) * @c: array of constants * * This operation calculates @in % @c (remainder after division by constant) - * and writes the result to @out. The image must be one of the integer types. + * and writes the result to @out. + * The image may have any + * non-complex format. For float formats, im_remainder() calculates @in - + * @c * floor (@in / @c). * - * If the array of constants has one element, that constant is used for each - * image band. If the array has more than one element, it must have the same - * number of elements as there are bands in the image, and one array element - * is used for each band. + * If the number of image bands end array elements differs, one of them + * must have one band. Either the image is up-banded by joining n copies of + * the one-band image together, or the array is upbanded by copying the single + * element n times. * - * See also: im_remainder(), im_divide(). + * See also: im_remainder(), im_remainderconst(), im_divide(). * * Returns: 0 on success, -1 on error */ int im_remainderconst_vec( IMAGE *in, IMAGE *out, int n, double *c ) { - Remainderconst *rc; - int i; - - /* Basic checks. - */ - if( im_piocheck( in, out ) || - im_check_vector( "im_remainder", n, in ) || - im_check_uncoded( "im_remainder", in ) || - im_check_int( "im_remainder", in ) ) - return( -1 ); - if( im_cp_desc( out, in ) ) + if( im_check_noncomplex( "im_remainder", in ) ) return( -1 ); - /* Take a copy of the parameters. - */ - if( !(rc = IM_NEW( out, Remainderconst )) || - !(rc->c = IM_ARRAY( out, n, int )) ) - return( -1 ); - rc->in = in; - rc->out = out; - rc->n = n; - for( i = 0; i < n; i++ ) { - /* Cast down to int ... we pass in double for consistency with - * the other _vec functions. - */ - if( c[i] != (int) c[i] ) - im_warn( "im_remainderconst_vec", - _( "float constant %g truncated to integer" ), - c[i] ); - rc->c[i] = c[i]; - - if( rc->c[i] == 0 ) { - im_error( "im_remainderconst_vec", - "%s", _( "division by zero" ) ); - return( -1 ); - } - } - - if( n == 1 ) { - if( im_wrapone( in, out, - (im_wrapone_fn) remainderconst1_buffer, rc, NULL ) ) - return( -1 ); - } - else { - if( im_wrapone( in, out, - (im_wrapone_fn) remainderconst_buffer, rc, NULL ) ) - return( -1 ); - } - - return( 0 ); + return( im__arith_binary_const( "im_remainder", + in, out, n, c, + bandfmt_remainder, + (im_wrapone_fn) remainderconst1_buffer, + (im_wrapone_fn) remainderconst_buffer ) ); } /** diff --git a/libvips/boolean/boolean.c b/libvips/boolean/boolean.c index 089f02e5..b02c0729 100644 --- a/libvips/boolean/boolean.c +++ b/libvips/boolean/boolean.c @@ -43,6 +43,9 @@ * 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 */ /* @@ -80,190 +83,12 @@ #include #include +#include #ifdef WITH_DMALLOC #include #endif /*WITH_DMALLOC*/ -/* A selection of main loops. Only implement monotype operations, ie. input - * type == output type. Float types are cast to int before we come here. - */ -#define AND2( TYPE ) { \ - TYPE *tq = (TYPE *) q; \ - TYPE *tp1 = (TYPE *) p[0]; \ - TYPE *tp2 = (TYPE *) p[1]; \ - \ - for( x = 0; x < ne; x++ ) \ - tq[x] = tp1[x] & tp2[x]; \ -} - -#define OR2( TYPE ) { \ - TYPE *tq = (TYPE *) q; \ - TYPE *tp1 = (TYPE *) p[0]; \ - TYPE *tp2 = (TYPE *) p[1]; \ - \ - for( x = 0; x < ne; x++ ) \ - tq[x] = tp1[x] | tp2[x]; \ -} - -#define EOR2( TYPE ) { \ - TYPE *tq = (TYPE *) q; \ - TYPE *tp1 = (TYPE *) p[0]; \ - TYPE *tp2 = (TYPE *) p[1]; \ - \ - for( x = 0; x < ne; x++ ) \ - tq[x] = tp1[x] ^ tp2[x]; \ -} - -#define ANDCONST( TYPE ) { \ - TYPE *tq = (TYPE *) q; \ - TYPE *tp = (TYPE *) p; \ - TYPE *tc = (TYPE *) c; \ - \ - for( i = 0, x = 0; x < n; x++ ) \ - for( b = 0; b < bands; b++, i++ ) \ - tq[i] = tp[i] & tc[b]; \ -} - -#define ORCONST( TYPE ) { \ - TYPE *tq = (TYPE *) q; \ - TYPE *tp = (TYPE *) p; \ - TYPE *tc = (TYPE *) c; \ - \ - for( i = 0, x = 0; x < n; x++ ) \ - for( b = 0; b < bands; b++, i++ ) \ - tq[i] = tp[i] | tc[b]; \ -} - -#define EORCONST( TYPE ) { \ - TYPE *tq = (TYPE *) q; \ - TYPE *tp = (TYPE *) p; \ - TYPE *tc = (TYPE *) c; \ - \ - for( i = 0, x = 0; x < n; x++ ) \ - for( b = 0; b < bands; b++, i++ ) \ - tq[i] = tp[i] ^ tc[b]; \ -} - -/* The above, wrapped up as buffer processing functions. - */ -static void -and_buffer( PEL **p, PEL *q, int n, IMAGE *im ) -{ - const int ne = n * im->Bands; - - int x; - - switch( im->BandFmt ) { - case IM_BANDFMT_CHAR: AND2( signed char ); break; - case IM_BANDFMT_UCHAR: AND2( unsigned char ); break; - case IM_BANDFMT_SHORT: AND2( signed short ); break; - case IM_BANDFMT_USHORT: AND2( unsigned short ); break; - case IM_BANDFMT_INT: AND2( signed int ); break; - case IM_BANDFMT_UINT: AND2( unsigned int ); break; - - default: - g_assert( 0 ); - } -} - -static void -or_buffer( PEL **p, PEL *q, int n, IMAGE *im ) -{ - const int ne = n * im->Bands; - - int x; - - switch( im->BandFmt ) { - case IM_BANDFMT_CHAR: OR2( signed char ); break; - case IM_BANDFMT_UCHAR: OR2( unsigned char ); break; - case IM_BANDFMT_SHORT: OR2( signed short ); break; - case IM_BANDFMT_USHORT: OR2( unsigned short ); break; - case IM_BANDFMT_INT: OR2( signed int ); break; - case IM_BANDFMT_UINT: OR2( unsigned int ); break; - - default: - g_assert( 0 ); - } -} - -static void -eor_buffer( PEL **p, PEL *q, int n, IMAGE *in1 ) -{ - const int ne = n * im->Bands; - - int x; - - switch( im->BandFmt ) { - case IM_BANDFMT_CHAR: EOR2( signed char ); break; - case IM_BANDFMT_UCHAR: EOR2( unsigned char ); break; - case IM_BANDFMT_SHORT: EOR2( signed short ); break; - case IM_BANDFMT_USHORT: EOR2( unsigned short ); break; - case IM_BANDFMT_INT: EOR2( signed int ); break; - case IM_BANDFMT_UINT: EOR2( unsigned int ); break; - - default: - g_assert( 0 ); - } -} - -static void -andconst_buffer( PEL *p, PEL *q, int n, IMAGE *in, PEL *c ) -{ - int x, i, b; - int bands = in->Bands; - - switch( in->BandFmt ) { - case IM_BANDFMT_CHAR: ANDCONST( signed char ); break; - case IM_BANDFMT_UCHAR: ANDCONST( unsigned char ); break; - case IM_BANDFMT_SHORT: ANDCONST( signed short ); break; - case IM_BANDFMT_USHORT: ANDCONST( unsigned short ); break; - case IM_BANDFMT_INT: ANDCONST( signed int ); break; - case IM_BANDFMT_UINT: ANDCONST( unsigned int ); break; - - default: - g_assert( 0 ); - } -} - -static void -orconst_buffer( PEL *p, PEL *q, int n, IMAGE *in, PEL *c ) -{ - int x, i, b; - int bands = in->Bands; - - switch( in->BandFmt ) { - case IM_BANDFMT_CHAR: ORCONST( signed char ); break; - case IM_BANDFMT_UCHAR: ORCONST( unsigned char ); break; - case IM_BANDFMT_SHORT: ORCONST( signed short ); break; - case IM_BANDFMT_USHORT: ORCONST( unsigned short ); break; - case IM_BANDFMT_INT: ORCONST( signed int ); break; - case IM_BANDFMT_UINT: ORCONST( unsigned int ); break; - - default: - g_assert( 0 ); - } -} - -static void -eorconst_buffer( PEL *p, PEL *q, int n, IMAGE *in, PEL *c ) -{ - int x, i, b; - int bands = in->Bands; - - switch( in->BandFmt ) { - case IM_BANDFMT_CHAR: EORCONST( signed char ); break; - case IM_BANDFMT_UCHAR: EORCONST( unsigned char ); break; - case IM_BANDFMT_SHORT: EORCONST( signed short ); break; - case IM_BANDFMT_USHORT: EORCONST( unsigned short ); break; - case IM_BANDFMT_INT: EORCONST( signed int ); break; - case IM_BANDFMT_UINT: EORCONST( unsigned int ); break; - - default: - g_assert( 0 ); - } -} - /* Save a bit of typing. */ #define UC IM_BANDFMT_UCHAR @@ -277,252 +102,298 @@ eorconst_buffer( PEL *p, PEL *q, int n, IMAGE *in, PEL *c ) */ 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 }, + UC, C, US, S, UI, I, I, I, I, I, }; -/* The above, wrapped up as im_*() functions. - */ +#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, & ) + 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 ) ); + (im_wrapmany_fn) AND_buffer, NULL ) ); } +BINARY_BUFFER( OR, | ) + 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 ) ); + (im_wrapmany_fn) OR_buffer, NULL ) ); } +BINARY_BUFFER( EOR, ^ ) + 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 ) ); + (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, & ) + +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 ) ); +} + +CONST1_BUFFER( OR, | ) + +CONSTN_BUFFER( OR, | ) + +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 ) ); +} + +CONST1_BUFFER( EOR, ^ ) + +CONSTN_BUFFER( EOR, ^ ) + +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 ) ); +} + +CONST1_BUFFER( SHIFTL, << ) + +CONSTN_BUFFER( SHIFTL, << ) + +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 ) ); +} + +CONST1_BUFFER( SHIFTR, >> ) + +CONSTN_BUFFER( SHIFTR, >> ) + +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 ) ); } int im_and_vec( IMAGE *in, IMAGE *out, int n, double *c ) { - IMAGE *invec[2]; - PEL *cb; - - invec[0] = in; invec[1] = NULL; - if( check( invec, out ) ) - return( -1 ); - in = invec[0]; - if( n != in->Bands ) { - im_error( "im_and_vec", - "%s", _( "vec size does not match bands" ) ); - return( -1 ); - } - if( !(cb = make_pixel( out, in->BandFmt, c )) ) - return( -1 ); - - if( im_wrapone( in, out, - (im_wrapone_fn) andconst_buffer, (void *) in, (void *) cb ) ) - return( -1 ); - - return( 0 ); + return( im_andimage_vec( in, out, n, c ) ); } int im_or_vec( IMAGE *in, IMAGE *out, int n, double *c ) { - IMAGE *invec[2]; - PEL *cb; - - invec[0] = in; invec[1] = NULL; - if( check( invec, out ) ) - return( -1 ); - in = invec[0]; - if( n != in->Bands ) { - im_error( "im_or_vec", - "%s", _( "vec size does not match bands" ) ); - return( -1 ); - } - if( !(cb = make_pixel( out, in->BandFmt, c )) ) - return( -1 ); - - if( im_wrapone( in, out, - (im_wrapone_fn) orconst_buffer, (void *) in, (void *) cb ) ) - return( -1 ); - - return( 0 ); + return( im_orimage_vec( in, out, n, c ) ); } int im_eor_vec( IMAGE *in, IMAGE *out, int n, double *c ) { - IMAGE *invec[2]; - PEL *cb; - - invec[0] = in; invec[1] = NULL; - if( check( invec, out ) ) - return( -1 ); - in = invec[0]; - if( n != in->Bands ) { - im_error( "im_eor_vec", - "%s", _( "vec size does not match bands" ) ); - return( -1 ); - } - if( !(cb = make_pixel( out, in->BandFmt, c )) ) - return( -1 ); - - if( im_wrapone( in, out, - (im_wrapone_fn) eorconst_buffer, (void *) in, (void *) cb ) ) - return( -1 ); - - return( 0 ); -} - -/* Cast a double to a vector of TYPE. - */ -#define CCAST( TYPE ) { \ - TYPE *tq = (TYPE *) q; \ - \ - for( i = 0; i < in->Bands; i++ ) \ - tq[i] = (TYPE) p; \ -} - -/* Make a pixel of output type from a single double. - */ -static double * -make_pixel_const( IMAGE *in, IMAGE *out, double p ) -{ - double *q; - int i; - - if( !(q = IM_ARRAY( out, in->Bands, double )) ) - return( NULL ); - for( i = 0; i < in->Bands; i++ ) - q[i] = p; - - return( q ); + return( im_eorimage_vec( in, out, n, c ) ); } int im_andconst( IMAGE *in, IMAGE *out, double c ) { - double *v = make_pixel_const( in, out, c ); - - return( !v || im_and_vec( in, out, in->Bands, v ) ); + return( im_andimage_vec( in, out, 1, &c ) ); } int im_orconst( IMAGE *in, IMAGE *out, double c ) { - double *v = make_pixel_const( in, out, c ); - - return( !v || im_or_vec( in, out, in->Bands, v ) ); + return( im_orimage_vec( in, out, 1, &c ) ); } int im_eorconst( IMAGE *in, IMAGE *out, double c ) { - double *v = make_pixel_const( in, out, c ); - - return( !v || im_eor_vec( in, out, in->Bands, v ) ); + return( im_eorimage_vec( in, out, 1, &c ) ); } -/* Assorted shift operations. - */ -#define SHIFTL( TYPE ) { \ - TYPE *pt = (TYPE *) p;\ - TYPE *qt = (TYPE *) q;\ - \ - for( x = 0; x < ne; x++ )\ - qt[x] = pt[x] << n;\ -} - -/* The above as buffer ops. - */ -static void -shiftleft_buffer( PEL *p, PEL *q, int len, IMAGE *in, int n ) -{ - int x; - int ne = len * in->Bands; - - switch( in->BandFmt ) { - case IM_BANDFMT_UCHAR: SHIFTL( unsigned char ); break; - case IM_BANDFMT_CHAR: SHIFTL( signed char ); break; - case IM_BANDFMT_USHORT: SHIFTL( unsigned short ); break; - case IM_BANDFMT_SHORT: SHIFTL( signed short ); break; - case IM_BANDFMT_UINT: SHIFTL( unsigned int ); break; - case IM_BANDFMT_INT: SHIFTL( signed int ); break; - - default: - g_assert( 0 ); - } -} - -/* The above as im_*() functions. - */ int im_shiftleft( IMAGE *in, IMAGE *out, int n ) { - IMAGE *invec[2]; + double c = n; - invec[0] = in; invec[1] = NULL; - if( check( invec, out ) ) - return( -1 ); - in = invec[0]; - - if( im_wrapone( in, out, - (im_wrapone_fn) shiftleft_buffer, in, GINT_TO_POINTER( n ) ) ) - return( -1 ); - - return( 0 ); -} - -#define SHIFTR( TYPE ) { \ - TYPE *pt = (TYPE *) p; \ - TYPE *qt = (TYPE *) q; \ - \ - for( x = 0; x < ne; x++ ) \ - qt[x] = pt[x] >> n; \ -} - -static void -shiftright_buffer( PEL *p, PEL *q, int len, IMAGE *in, int n ) -{ - int x; - int ne = len * in->Bands; - - switch( in->BandFmt ) { - case IM_BANDFMT_UCHAR: SHIFTR( unsigned char ); break; - case IM_BANDFMT_CHAR: SHIFTR( signed char ); break; - case IM_BANDFMT_USHORT: SHIFTR( unsigned short ); break; - case IM_BANDFMT_SHORT: SHIFTR( signed short ); break; - case IM_BANDFMT_UINT: SHIFTR( unsigned int ); break; - case IM_BANDFMT_INT: SHIFTR( signed int ); break; - - default: - g_assert( 0 ); - } + return( im_shiftleft_vec( in, out, 1, &c ) ); } int im_shiftright( IMAGE *in, IMAGE *out, int n ) { - IMAGE *invec[2]; + double c = n; - invec[0] = in; invec[1] = NULL; - if( check( invec, out ) ) - return( -1 ); - in = invec[0]; - - if( im_wrapone( in, out, - (im_wrapone_fn) shiftright_buffer, in, GINT_TO_POINTER( n ) ) ) - return( -1 ); - - return( 0 ); + return( im_shiftright_vec( in, out, 1, &c ) ); } + diff --git a/libvips/format/im_png2vips.c b/libvips/format/im_png2vips.c index 64f12c5d..45cd1285 100644 --- a/libvips/format/im_png2vips.c +++ b/libvips/format/im_png2vips.c @@ -285,7 +285,7 @@ png2vips( Read *read, int header_only ) */ if( read->pInfo->bit_depth < 8 ) { png_set_packing( read->pPng ); - png_set_shift( read->pPng, 2 ); + png_set_shift( read->pPng, &(read->pInfo->sig_bit) ); } /* If we're an INTEL byte order machine and this is 16bits, we need diff --git a/libvips/include/vips/internal.h b/libvips/include/vips/internal.h index 50b01a27..62bbb049 100644 --- a/libvips/include/vips/internal.h +++ b/libvips/include/vips/internal.h @@ -131,10 +131,15 @@ char *im__gslist_gvalue_get( const GSList *list ); void im__buffer_init( void ); +int im__bandup( IMAGE *in, IMAGE *out, int n ); int im__arith_binary( const char *name, IMAGE *in1, IMAGE *in2, IMAGE *out, int format_table[10], im_wrapmany_fn fn, void *a ); +int im__arith_binary_const( const char *name, + IMAGE *in, IMAGE *out, int n, double *c, + int format_table[10], + im_wrapone_fn fn1, im_wrapone_fn fnn ); int im__math( const char *name, IMAGE *in, IMAGE *out, im_wrapone_fn gen ); int im__value( IMAGE *im, double *value ); typedef int (*im__wrapscan_fn)( void *p, int n, void *seq, void *a, void *b );