use corner convention everywhere

all interpolators use corner convention
This commit is contained in:
John Cupitt 2012-12-13 14:10:52 +00:00
parent 823068a282
commit 43d69e74e7
8 changed files with 144 additions and 148 deletions

View File

@ -22,8 +22,6 @@
- vipsthumbnail -o allows absolute file names
- much better exif handling for jpg images (thanks Gary)
- preserve jpeg app13 (photoshop ipct)
- nearest neighbour goes back to round down ... round to nearest caused a
range of annoying problems, such as strange half-pixels along edges
- vips_max() / _min() track the top n maxima / minima
- deprecate im_maxpos_avg(): too specialised to be worth maintaining
- deprecate im_linreg(): easily done by combining other operators
@ -32,6 +30,8 @@
- added vips_bandbool(), with vips_bandand(), _bandor(), _bandeor() as
convenience functions
- added scRGB colourspace, linear light float space with sRGB primaries
- all interpolators use corner convention ... we had round-to-nearest in
several of them before, causing a range of annoying problems
14/11/12 started 7.30.6
- capture tiff warnings earlier

2
TODO
View File

@ -4,7 +4,7 @@
dx/dy displace output
- switch to corner convention everywhere
- make affinei into a class

View File

@ -105,7 +105,7 @@ G_DEFINE_TYPE( VipsInterpolateBicubic, vips_interpolate_bicubic,
*/
template <typename T, int min_value, int max_value>
static void inline
bicubic_int_tab( void *pout, const PEL *pin,
bicubic_int_tab( void *pout, const VipsPel *pin,
const int bands, const int lskip,
const int *cx, const int *cy )
{
@ -173,7 +173,7 @@ bicubic_int_tab( void *pout, const PEL *pin,
*/
template <typename T>
static void inline
bicubic_float_tab( void *pout, const PEL *pin,
bicubic_float_tab( void *pout, const VipsPel *pin,
const int bands, const int lskip,
const double *cx, const double *cy )
{
@ -236,7 +236,7 @@ bicubic_float_tab( void *pout, const PEL *pin,
*/
template <typename T>
static void inline
bicubic_notab( void *pout, const PEL *pin,
bicubic_notab( void *pout, const VipsPel *pin,
const int bands, const int lskip,
double x, double y )
{
@ -303,7 +303,7 @@ bicubic_notab( void *pout, const PEL *pin,
static void
vips_interpolate_bicubic_interpolate( VipsInterpolate *interpolate,
void *out, REGION *in, double x, double y )
void *out, VipsRegion *in, double x, double y )
{
/* Find the mask index. We round-to-nearest, so we need to generate
* indexes in 0 to VIPS_TRANSFORM_SCALE, 2^n + 1 values. We multiply
@ -326,7 +326,7 @@ vips_interpolate_bicubic_interpolate( VipsInterpolate *interpolate,
/* Back and up one to get the top-left of the 4x4.
*/
const PEL *p = (PEL *) IM_REGION_ADDR( in, ix - 1, iy - 1 );
const VipsPel *p = VIPS_REGION_ADDR( in, ix - 1, iy - 1 );
/* Look up the tables we need.
*/
@ -338,7 +338,7 @@ vips_interpolate_bicubic_interpolate( VipsInterpolate *interpolate,
/* Pel size and line size.
*/
const int bands = in->im->Bands;
const int lskip = IM_REGION_LSKIP( in );
const int lskip = VIPS_REGION_LSKIP( in );
#ifdef DEBUG
printf( "vips_interpolate_bicubic_interpolate: %g %g\n", x, y );
@ -348,7 +348,7 @@ vips_interpolate_bicubic_interpolate( VipsInterpolate *interpolate,
#endif /*DEBUG*/
switch( in->im->BandFmt ) {
case IM_BANDFMT_UCHAR:
case VIPS_FORMAT_UCHAR:
bicubic_int_tab<unsigned char, 0, UCHAR_MAX>(
out, p, bands, lskip,
cxi, cyi );
@ -366,50 +366,50 @@ vips_interpolate_bicubic_interpolate( VipsInterpolate *interpolate,
*/
break;
case IM_BANDFMT_CHAR:
case VIPS_FORMAT_CHAR:
bicubic_int_tab<signed char, SCHAR_MIN, SCHAR_MAX>(
out, p, bands, lskip,
cxi, cyi );
break;
case IM_BANDFMT_USHORT:
case VIPS_FORMAT_USHORT:
bicubic_int_tab<unsigned short, 0, USHRT_MAX>(
out, p, bands, lskip,
cxi, cyi );
break;
case IM_BANDFMT_SHORT:
case VIPS_FORMAT_SHORT:
bicubic_int_tab<signed short, SHRT_MIN, SHRT_MAX>(
out, p, bands, lskip,
cxi, cyi );
break;
case IM_BANDFMT_UINT:
case VIPS_FORMAT_UINT:
bicubic_float_tab<unsigned int>( out, p, bands, lskip,
cxf, cyf );
break;
case IM_BANDFMT_INT:
case VIPS_FORMAT_INT:
bicubic_float_tab<signed int>( out, p, bands, lskip,
cxf, cyf );
break;
case IM_BANDFMT_FLOAT:
case VIPS_FORMAT_FLOAT:
bicubic_float_tab<float>( out, p, bands, lskip,
cxf, cyf );
break;
case IM_BANDFMT_DOUBLE:
case VIPS_FORMAT_DOUBLE:
bicubic_notab<double>( out, p, bands, lskip,
x - ix, y - iy );
break;
case IM_BANDFMT_COMPLEX:
case VIPS_FORMAT_COMPLEX:
bicubic_float_tab<float>( out, p, bands * 2, lskip,
cxf, cyf );
break;
case IM_BANDFMT_DPCOMPLEX:
case VIPS_FORMAT_DPCOMPLEX:
bicubic_notab<double>( out, p, bands * 2, lskip,
x - ix, y - iy );
break;

View File

@ -150,8 +150,8 @@
/* Per-call state.
*/
typedef struct _Affine {
IMAGE *in;
IMAGE *out;
VipsImage *in;
VipsImage *out;
VipsInterpolate *interpolate;
Transformation trn;
} Affine;
@ -159,7 +159,7 @@ typedef struct _Affine {
static int
affine_free( Affine *affine )
{
IM_FREEF( g_object_unref, affine->interpolate );
VIPS_FREEF( g_object_unref, affine->interpolate );
return( 0 );
}
@ -171,7 +171,7 @@ affine_free( Affine *affine )
*
* 2. This is embedded in a larger image to provide borders for the
* interpolator. iarea->left/top give the offset. These are the coordinates we
* pass to IM_REGION_ADDR()/im_prepare() for the input image.
* pass to VIPS_REGION_ADDR()/im_prepare() for the input image.
*
* The borders are sized by the interpolator's window_size property and offset
* by the interpolator's window_offset property. For example,
@ -190,15 +190,15 @@ affine_free( Affine *affine )
* can be negative, since a rotated image can go up and left of the origin.
*
* 5. Output image space. This is the wh of the xywh passed to im_affine()
* below. These are the coordinates we pass to IM_REGION_ADDR() for the
* below. These are the coordinates we pass to VIPS_REGION_ADDR() for the
* output image, and that affinei_gen() is asked for.
*/
static int
affinei_gen( REGION *or, void *seq, void *a, void *b )
affinei_gen( VipsRegion *or, void *seq, void *a, void *b )
{
REGION *ir = (REGION *) seq;
const IMAGE *in = (IMAGE *) a;
VipsRegion *ir = (VipsRegion *) seq;
const VipsImage *in = (VipsImage *) a;
const Affine *affine = (Affine *) b;
const int window_size =
vips_interpolate_get_window_size( affine->interpolate );
@ -211,14 +211,14 @@ affinei_gen( REGION *or, void *seq, void *a, void *b )
*/
const Rect *r = &or->valid;
const int le = r->left;
const int ri = IM_RECT_RIGHT( r );
const int ri = VIPS_RECT_RIGHT( r );
const int to = r->top;
const int bo = IM_RECT_BOTTOM( r );
const int bo = VIPS_RECT_BOTTOM( r );
const Rect *iarea = &affine->trn.iarea;
const Rect *oarea = &affine->trn.oarea;
int ps = IM_IMAGE_SIZEOF_PEL( in );
int ps = VIPS_IMAGE_SIZEOF_PEL( in );
int x, y, z;
Rect image, want, need, clipped;
@ -327,7 +327,7 @@ affinei_gen( REGION *or, void *seq, void *a, void *b )
ix += iarea->left;
iy += iarea->top;
q = IM_REGION_ADDR( or, le, y );
q = VIPS_REGION_ADDR( or, le, y );
for( x = le; x < ri; x++ ) {
int fx, fy;
@ -356,7 +356,7 @@ affinei_gen( REGION *or, void *seq, void *a, void *b )
}
static int
affinei( IMAGE *in, IMAGE *out,
affinei( VipsImage *in, VipsImage *out,
VipsInterpolate *interpolate, Transformation *trn )
{
Affine *affine;
@ -370,7 +370,7 @@ affinei( IMAGE *in, IMAGE *out,
/* Need a copy of the params for the lifetime of out.
*/
if( !(affine = IM_NEW( out, Affine )) )
if( !(affine = VIPS_NEW( out, Affine )) )
return( -1 );
affine->interpolate = NULL;
if( im_add_close_callback( out,
@ -391,11 +391,11 @@ affinei( IMAGE *in, IMAGE *out,
/* Normally SMALLTILE ... except if this is a size up/down affine.
*/
if( affine->trn.b == 0.0 && affine->trn.c == 0.0 ) {
if( im_demand_hint( out, IM_FATSTRIP, in, NULL ) )
if( im_demand_hint( out, VIPS_DEMAND_STYLE_FATSTRIP, in, NULL ) )
return( -1 );
}
else {
if( im_demand_hint( out, IM_SMALLTILE, in, NULL ) )
if( im_demand_hint( out, VIPS_DEMAND_STYLE_SMALLTILE, in, NULL ) )
return( -1 );
}
@ -404,8 +404,8 @@ affinei( IMAGE *in, IMAGE *out,
*/
edge = INT_MAX / VIPS_TRANSFORM_SCALE;
if( affine->trn.oarea.left < -edge || affine->trn.oarea.top < -edge ||
IM_RECT_RIGHT( &affine->trn.oarea ) > edge ||
IM_RECT_BOTTOM( &affine->trn.oarea ) > edge ) {
VIPS_RECT_RIGHT( &affine->trn.oarea ) > edge ||
VIPS_RECT_BOTTOM( &affine->trn.oarea ) > edge ) {
im_error( "im_affinei",
"%s", _( "output coordinates out of range" ) );
return( -1 );
@ -420,13 +420,13 @@ affinei( IMAGE *in, IMAGE *out,
return( 0 );
}
/* As above, but do IM_CODING_LABQ too. And embed the input.
/* As above, but do VIPS_CODING_LABQ too. And embed the input.
*/
static int
im__affinei( IMAGE *in, IMAGE *out,
im__affinei( VipsImage *in, VipsImage *out,
VipsInterpolate *interpolate, Transformation *trn )
{
IMAGE *t3 = im_open_local( out, "im_affine:3", "p" );
VipsImage *t3 = im_open_local( out, "im_affine:3", "p" );
const int window_size =
vips_interpolate_get_window_size( interpolate );
const int window_offset =
@ -452,8 +452,8 @@ im__affinei( IMAGE *in, IMAGE *out,
im__transform_print( &trn2 );
#endif /*DEBUG_GEOMETRY*/
if( in->Coding == IM_CODING_LABQ ) {
IMAGE *t[2];
if( in->Coding == VIPS_CODING_LABQ ) {
VipsImage *t[2];
if( im_open_local_array( out, t, 2, "im_affine:2", "p" ) ||
im_LabQ2LabS( t3, t[0] ) ||
@ -461,7 +461,7 @@ im__affinei( IMAGE *in, IMAGE *out,
im_LabS2LabQ( t[1], out ) )
return( -1 );
}
else if( in->Coding == IM_CODING_NONE ) {
else if( in->Coding == VIPS_CODING_NONE ) {
if( affinei( t3, out, interpolate, &trn2 ) )
return( -1 );
}
@ -514,7 +514,7 @@ im__affinei( IMAGE *in, IMAGE *out,
* Returns: 0 on success, -1 on error
*/
int
im_affinei( IMAGE *in, IMAGE *out, VipsInterpolate *interpolate,
im_affinei( VipsImage *in, VipsImage *out, VipsInterpolate *interpolate,
double a, double b, double c, double d, double dx, double dy,
int ox, int oy, int ow, int oh )
{
@ -560,7 +560,7 @@ im_affinei( IMAGE *in, IMAGE *out, VipsInterpolate *interpolate,
* Returns: 0 on success, -1 on error
*/
int
im_affinei_all( IMAGE *in, IMAGE *out, VipsInterpolate *interpolate,
im_affinei_all( VipsImage *in, VipsImage *out, VipsInterpolate *interpolate,
double a, double b, double c, double d, double dx, double dy )
{
Transformation trn;
@ -584,7 +584,7 @@ im_affinei_all( IMAGE *in, IMAGE *out, VipsInterpolate *interpolate,
/* Still needed by some parts of mosaic.
*/
int
im__affine( IMAGE *in, IMAGE *out, Transformation *trn )
im__affine( VipsImage *in, VipsImage *out, Transformation *trn )
{
return( im__affinei( in, out,
vips_interpolate_bilinear_static(), trn ) );

View File

@ -78,7 +78,7 @@ G_DEFINE_ABSTRACT_TYPE( VipsInterpolate, vips_interpolate, VIPS_TYPE_OBJECT );
* @y: interpolate value at this position
*
* An interpolation function. It should read source pixels from @in with
* IM_REGION_ADDR(), it can look left and up from (x, y) by @window_offset
* VIPS_REGION_ADDR(), it can look left and up from (x, y) by @window_offset
* pixels and it can access pixels in a window of size @window_size.
*
* The interpolated value should be written to the pixel pointed to by @out.
@ -159,7 +159,7 @@ vips_interpolate_real_get_window_offset( VipsInterpolate *interpolate )
/* Don't go -ve, of course, for window_size 1.
*/
return( IM_MAX( 0, window_size / 2 - 1 ) );
return( VIPS_MAX( 0, window_size / 2 - 1 ) );
}
}
@ -211,7 +211,7 @@ vips_interpolate_init( VipsInterpolate *interpolate )
*/
void
vips_interpolate( VipsInterpolate *interpolate,
void *out, REGION *in, double x, double y )
void *out, VipsRegion *in, double x, double y )
{
VipsInterpolateClass *class = VIPS_INTERPOLATE_GET_CLASS( interpolate );
@ -329,14 +329,14 @@ G_DEFINE_TYPE( VipsInterpolateNearest, vips_interpolate_nearest,
static void
vips_interpolate_nearest_interpolate( VipsInterpolate *interpolate,
void *out, REGION *in, double x, double y )
void *out, VipsRegion *in, double x, double y )
{
const int ps = IM_IMAGE_SIZEOF_PEL( in->im );
const int ps = VIPS_IMAGE_SIZEOF_PEL( in->im );
const int xi = (int) x;
const int yi = (int) y;
const VipsPel *p = IM_REGION_ADDR( in, xi, yi );
const VipsPel *p = VIPS_REGION_ADDR( in, xi, yi );
VipsPel *q = (VipsPel *) out;
int z;
@ -479,14 +479,14 @@ G_DEFINE_TYPE( VipsInterpolateBilinear, vips_interpolate_bilinear,
*/
#define SWITCH_INTERPOLATE( FMT, INT, FLOAT ) { \
switch( (FMT) ) { \
case IM_BANDFMT_UCHAR: INT( unsigned char ); break; \
case IM_BANDFMT_CHAR: INT( char ); break; \
case IM_BANDFMT_USHORT: INT( unsigned short ); break; \
case IM_BANDFMT_SHORT: INT( short ); break; \
case IM_BANDFMT_UINT: FLOAT( unsigned int ); break; \
case IM_BANDFMT_INT: FLOAT( int ); break; \
case IM_BANDFMT_FLOAT: FLOAT( float ); break; \
case IM_BANDFMT_DOUBLE: FLOAT( double ); break; \
case VIPS_FORMAT_UCHAR: INT( unsigned char ); break; \
case VIPS_FORMAT_CHAR: INT( char ); break; \
case VIPS_FORMAT_USHORT:INT( unsigned short ); break; \
case VIPS_FORMAT_SHORT: INT( short ); break; \
case VIPS_FORMAT_UINT: FLOAT( unsigned int ); break; \
case VIPS_FORMAT_INT: FLOAT( int ); break; \
case VIPS_FORMAT_FLOAT: FLOAT( float ); break; \
case VIPS_FORMAT_DOUBLE:FLOAT( double ); break; \
default: \
g_assert( FALSE ); \
} \
@ -494,18 +494,18 @@ G_DEFINE_TYPE( VipsInterpolateBilinear, vips_interpolate_bilinear,
static void
vips_interpolate_bilinear_interpolate( VipsInterpolate *interpolate,
void *out, REGION *in, double x, double y )
void *out, VipsRegion *in, double x, double y )
{
/* Pel size and line size.
*/
const int ps = IM_IMAGE_SIZEOF_PEL( in->im );
const int ls = IM_REGION_LSKIP( in );
const int ps = VIPS_IMAGE_SIZEOF_PEL( in->im );
const int ls = VIPS_REGION_LSKIP( in );
const int b = in->im->Bands;
const int ix = (int) x;
const int iy = (int) y;
const VipsPel *p1 = IM_REGION_ADDR( in, ix, iy );
const VipsPel *p1 = VIPS_REGION_ADDR( in, ix, iy );
const VipsPel *p2 = p1 + ps;
const VipsPel *p3 = p1 + ls;
const VipsPel *p4 = p3 + ps;

View File

@ -581,8 +581,8 @@ lbbicubic( const double c00,
*/
#define LBB_CONVERSION( conversion ) \
template <typename T> static void inline \
lbb_ ## conversion( void* restrict pout, \
const PEL* restrict pin, \
lbb_ ## conversion( void* restrict pout, \
const VipsPel* restrict pin, \
const int bands, \
const int lskip, \
const double relative_x, \
@ -764,32 +764,24 @@ G_DEFINE_TYPE( VipsInterpolateLbb, vips_interpolate_lbb,
static void
vips_interpolate_lbb_interpolate( VipsInterpolate* restrict interpolate,
void* restrict out,
REGION* restrict in,
VipsRegion* restrict in,
double absolute_x,
double absolute_y )
{
/*
* Floor's surrogate FAST_PSEUDO_FLOOR is used to make sure that the
* transition through 0 is smooth. If it is known that absolute_x
* and absolute_y will never be less than 0, plain cast---that is,
* const int ix = absolute_x---should be used instead. Actually,
* any function which agrees with floor for non-integer values, and
* picks one of the two possibilities for integer values, can be
* used. FAST_PSEUDO_FLOOR fits the bill.
/* absolute_x and absolute_y are always >= 1.0 (see double-check assert
* below), so we don't need floor().
*
* Then, x is the x-coordinate of the sampling point relative to the
* position of the top left corner of the convex hull of the 2x2
* block of closest pixels. Similarly for y. Range of values: [0,1).
* It's 1 not 0 since have a window_offset of 1.
*/
const int ix = FAST_PSEUDO_FLOOR( absolute_x );
const int iy = FAST_PSEUDO_FLOOR( absolute_y );
const int ix = (int) absolute_x;
const int iy = (int) absolute_y;
/*
* Move the pointer to (the first band of) the top/left pixel of the
* 2x2 group of pixel centers which contains the sampling location
* in its convex hull:
*/
const PEL* restrict p = (PEL *) IM_REGION_ADDR( in, ix, iy );
const VipsPel* restrict p = VIPS_REGION_ADDR( in, ix, iy );
const double relative_x = absolute_x - ix;
const double relative_y = absolute_y - iy;
@ -797,50 +789,56 @@ vips_interpolate_lbb_interpolate( VipsInterpolate* restrict interpolate,
/*
* VIPS versions of Nicolas's pixel addressing values.
*/
const int actual_bands = in->im->Bands;
const int lskip = IM_REGION_LSKIP( in ) / IM_IMAGE_SIZEOF_ELEMENT( in->im );
const int lskip = VIPS_REGION_LSKIP( in ) /
VIPS_IMAGE_SIZEOF_ELEMENT( in->im );
/*
* Double the bands for complex images to account for the real and
* imaginary parts being computed independently:
*/
const int actual_bands = in->im->Bands;
const int bands =
vips_bandfmt_iscomplex( in->im->BandFmt ) ? 2 * actual_bands : actual_bands;
/* Confirm that absolute_x and absolute_y are >= 1, see above.
*/
g_assert( absolute_x >= 1.0 );
g_assert( absolute_y >= 1.0 );
switch( in->im->BandFmt ) {
case IM_BANDFMT_UCHAR:
case VIPS_FORMAT_UCHAR:
CALL( unsigned char, nosign );
break;
case IM_BANDFMT_CHAR:
case VIPS_FORMAT_CHAR:
CALL( signed char, withsign );
break;
case IM_BANDFMT_USHORT:
case VIPS_FORMAT_USHORT:
CALL( unsigned short, nosign );
break;
case IM_BANDFMT_SHORT:
case VIPS_FORMAT_SHORT:
CALL( signed short, withsign );
break;
case IM_BANDFMT_UINT:
case VIPS_FORMAT_UINT:
CALL( unsigned int, nosign );
break;
case IM_BANDFMT_INT:
case VIPS_FORMAT_INT:
CALL( signed int, withsign );
break;
/*
* Complex images are handled by doubling of bands.
*/
case IM_BANDFMT_FLOAT:
case IM_BANDFMT_COMPLEX:
case VIPS_FORMAT_FLOAT:
case VIPS_FORMAT_COMPLEX:
CALL( float, fptypes );
break;
case IM_BANDFMT_DOUBLE:
case IM_BANDFMT_DPCOMPLEX:
case VIPS_FORMAT_DOUBLE:
case VIPS_FORMAT_DPCOMPLEX:
CALL( double, fptypes );
break;

View File

@ -1480,32 +1480,24 @@ G_DEFINE_TYPE( VipsInterpolateNohalo, vips_interpolate_nohalo,
static void
vips_interpolate_nohalo_interpolate( VipsInterpolate* restrict interpolate,
void* restrict out,
REGION* restrict in,
VipsRegion* restrict in,
double absolute_x,
double absolute_y )
{
/*
* Floor's surrogate FAST_PSEUDO_FLOOR is used to make sure that the
* transition through 0 is smooth. If it is known that absolute_x
* and absolute_y will never be less than 0, plain cast---that is,
* const int ix = absolute_x---should be used instead. Actually,
* any function which agrees with floor for non-integer values, and
* picks one of the two possibilities for integer values, can be
* used. FAST_PSEUDO_FLOOR fits the bill.
/* absolute_x and absolute_y are always >= 2.0 (see double-check assert
* below), so we don't need floor().
*
* Then, x is the x-coordinate of the sampling point relative to the
* position of the center of the convex hull of the 2x2 block of
* closest pixels. Similarly for y. Range of values: [-.5,.5).
* It's 2 not 0 since we ask for a window_offset of 2 at the bottom.
*/
const int ix = FAST_PSEUDO_FLOOR( absolute_x + .5 );
const int iy = FAST_PSEUDO_FLOOR( absolute_y + .5 );
const int ix = (int) absolute_x;
const int iy = (int) absolute_y;
/*
* Move the pointer to (the first band of) the top/left pixel of the
* 2x2 group of pixel centers which contains the sampling location
* in its convex hull:
*/
const PEL* restrict p = (PEL *) IM_REGION_ADDR( in, ix, iy );
const VipsPel* restrict p = VIPS_REGION_ADDR( in, ix, iy );
const double relative_x = absolute_x - ix;
const double relative_y = absolute_y - iy;
@ -1513,50 +1505,57 @@ vips_interpolate_nohalo_interpolate( VipsInterpolate* restrict interpolate,
/*
* VIPS versions of Nicolas's pixel addressing values.
*/
const int actual_bands = in->im->Bands;
const int lskip = IM_REGION_LSKIP( in ) / IM_IMAGE_SIZEOF_ELEMENT( in->im );
const int lskip = VIPS_REGION_LSKIP( in ) /
VIPS_IMAGE_SIZEOF_ELEMENT( in->im );
/*
* Double the bands for complex images to account for the real and
* imaginary parts being computed independently:
*/
const int actual_bands = in->im->Bands;
const int bands =
vips_bandfmt_iscomplex( in->im->BandFmt ) ? 2 * actual_bands : actual_bands;
/* Confirm that absolute_x and absolute_y are >= 2, see above.
*/
g_assert( absolute_x >= 2.0 );
g_assert( absolute_y >= 2.0 );
switch( in->im->BandFmt ) {
case IM_BANDFMT_UCHAR:
case VIPS_FORMAT_UCHAR:
CALL( unsigned char, nosign );
break;
case IM_BANDFMT_CHAR:
case VIPS_FORMAT_CHAR:
CALL( signed char, withsign );
break;
case IM_BANDFMT_USHORT:
case VIPS_FORMAT_USHORT:
CALL( unsigned short, nosign );
break;
case IM_BANDFMT_SHORT:
case VIPS_FORMAT_SHORT:
CALL( signed short, withsign );
break;
case IM_BANDFMT_UINT:
case VIPS_FORMAT_UINT:
CALL( unsigned int, nosign );
break;
case IM_BANDFMT_INT:
case VIPS_FORMAT_INT:
CALL( signed int, withsign );
break;
/*
* Complex images are handled by doubling of bands.
*/
case IM_BANDFMT_FLOAT:
case IM_BANDFMT_COMPLEX:
case VIPS_FORMAT_FLOAT:
case VIPS_FORMAT_COMPLEX:
CALL( float, fptypes );
break;
case IM_BANDFMT_DOUBLE:
case IM_BANDFMT_DPCOMPLEX:
case VIPS_FORMAT_DOUBLE:
case VIPS_FORMAT_DPCOMPLEX:
CALL( double, fptypes );
break;

View File

@ -178,8 +178,8 @@ typedef struct _VipsInterpolateVsqbsClass {
*/
#define VSQBS_CONVERSION( conversion ) \
template <typename T> static void inline \
vsqbs_ ## conversion( void* restrict pout, \
const PEL* restrict pin, \
vsqbs_ ## conversion( void* restrict pout, \
const VipsPel* restrict pin, \
const int bands, \
const int lskip, \
const double x_0, \
@ -308,28 +308,20 @@ vips_interpolate_vsqbs_interpolate( VipsInterpolate* restrict interpolate,
double absolute_x,
double absolute_y )
{
/*
* Floor's surrogate FAST_PSEUDO_FLOOR is used to make sure that the
* transition through 0 is smooth. If it is known that absolute_x
* and absolute_y will never be less than 0, plain cast---that is,
* const int ix = absolute_x---should be used instead. Actually,
* any function which agrees with floor for non-integer values, and
* picks one of the two possibilities for integer values, can be
* used. FAST_PSEUDO_FLOOR fits the bill.
/* absolute_x and absolute_y are always >= 1.0 (see double-check assert
* below), so we don't need floor().
*
* Then, x is the x-coordinate of the sampling point relative to the
* position of the center of the convex hull of the 2x2 block of
* closest pixels. Similarly for y. Range of values: [-.5,.5).
* It's 1 not 0 since we ask for a window_offset of 1 at the bottom.
*/
const int ix = FAST_PSEUDO_FLOOR( absolute_x + .5 );
const int iy = FAST_PSEUDO_FLOOR( absolute_y + .5 );
const int ix = (int) absolute_x;
const int iy = (int) absolute_y;
/*
* Move the pointer to (the first band of) the top/left pixel of the
* 2x2 group of pixel centers which contains the sampling location
* in its convex hull:
*/
const PEL* restrict p = (PEL *) IM_REGION_ADDR( in, ix, iy );
const VipsPel* restrict p = VIPS_REGION_ADDR( in, ix, iy );
const double relative_x = absolute_x - ix;
const double relative_y = absolute_y - iy;
@ -337,50 +329,57 @@ vips_interpolate_vsqbs_interpolate( VipsInterpolate* restrict interpolate,
/*
* VIPS versions of Nicolas's pixel addressing values.
*/
const int actual_bands = in->im->Bands;
const int lskip = IM_REGION_LSKIP( in ) / IM_IMAGE_SIZEOF_ELEMENT( in->im );
const int lskip = VIPS_REGION_LSKIP( in ) /
VIPS_IMAGE_SIZEOF_ELEMENT( in->im );
/*
* Double the bands for complex images to account for the real and
* imaginary parts being computed independently:
*/
const int actual_bands = in->im->Bands;
const int bands =
vips_bandfmt_iscomplex( in->im->BandFmt ) ? 2 * actual_bands : actual_bands;
/* Confirm that absolute_x and absolute_y are >= 1, see above.
*/
g_assert( absolute_x >= 1.0 );
g_assert( absolute_y >= 1.0 );
switch( in->im->BandFmt ) {
case IM_BANDFMT_UCHAR:
case VIPS_FORMAT_UCHAR:
CALL( unsigned char, nosign );
break;
case IM_BANDFMT_CHAR:
case VIPS_FORMAT_CHAR:
CALL( signed char, withsign );
break;
case IM_BANDFMT_USHORT:
case VIPS_FORMAT_USHORT:
CALL( unsigned short, nosign );
break;
case IM_BANDFMT_SHORT:
case VIPS_FORMAT_SHORT:
CALL( signed short, withsign );
break;
case IM_BANDFMT_UINT:
case VIPS_FORMAT_UINT:
CALL( unsigned int, nosign );
break;
case IM_BANDFMT_INT:
case VIPS_FORMAT_INT:
CALL( signed int, withsign );
break;
/*
* Complex images are handled by doubling bands:
*/
case IM_BANDFMT_FLOAT:
case IM_BANDFMT_COMPLEX:
case VIPS_FORMAT_FLOAT:
case VIPS_FORMAT_COMPLEX:
CALL( float, fptypes );
break;
case IM_BANDFMT_DOUBLE:
case IM_BANDFMT_DPCOMPLEX:
case VIPS_FORMAT_DOUBLE:
case VIPS_FORMAT_DPCOMPLEX:
CALL( double, fptypes );
break;