boolean revised

This commit is contained in:
John Cupitt 2009-09-17 15:47:40 +00:00
parent c6418893eb
commit 4e2cb87524
6 changed files with 384 additions and 490 deletions

View File

@ -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

View File

@ -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];

View File

@ -50,7 +50,6 @@
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <assert.h>
#include <vips/vips.h>
#include <vips/internal.h>
@ -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 ) );
}
/**

View File

@ -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 <math.h>
#include <vips/vips.h>
#include <vips/internal.h>
#ifdef WITH_DMALLOC
#include <dmalloc.h>
#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 ) );
}

View File

@ -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

View File

@ -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 );