From 43d69e74e7938dae3d1c477be60c78806a17af96 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Thu, 13 Dec 2012 14:10:52 +0000 Subject: [PATCH] use corner convention everywhere all interpolators use corner convention --- ChangeLog | 4 +-- TODO | 2 +- libvips/resample/bicubic.cpp | 32 +++++++++---------- libvips/resample/im_affine.c | 54 ++++++++++++++++---------------- libvips/resample/interpolate.c | 36 +++++++++++----------- libvips/resample/lbb.cpp | 56 ++++++++++++++++------------------ libvips/resample/nohalo.cpp | 53 ++++++++++++++++---------------- libvips/resample/vsqbs.cpp | 55 ++++++++++++++++----------------- 8 files changed, 144 insertions(+), 148 deletions(-) diff --git a/ChangeLog b/ChangeLog index 64a3b0fb..61a4ef4d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -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 diff --git a/TODO b/TODO index a41a4a88..4a4432be 100644 --- a/TODO +++ b/TODO @@ -4,7 +4,7 @@ dx/dy displace output -- switch to corner convention everywhere +- make affinei into a class diff --git a/libvips/resample/bicubic.cpp b/libvips/resample/bicubic.cpp index ddbb01a5..65a3e5df 100644 --- a/libvips/resample/bicubic.cpp +++ b/libvips/resample/bicubic.cpp @@ -105,7 +105,7 @@ G_DEFINE_TYPE( VipsInterpolateBicubic, vips_interpolate_bicubic, */ template 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 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 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( 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( out, p, bands, lskip, cxi, cyi ); break; - case IM_BANDFMT_USHORT: + case VIPS_FORMAT_USHORT: bicubic_int_tab( out, p, bands, lskip, cxi, cyi ); break; - case IM_BANDFMT_SHORT: + case VIPS_FORMAT_SHORT: bicubic_int_tab( out, p, bands, lskip, cxi, cyi ); break; - case IM_BANDFMT_UINT: + case VIPS_FORMAT_UINT: bicubic_float_tab( out, p, bands, lskip, cxf, cyf ); break; - case IM_BANDFMT_INT: + case VIPS_FORMAT_INT: bicubic_float_tab( out, p, bands, lskip, cxf, cyf ); break; - case IM_BANDFMT_FLOAT: + case VIPS_FORMAT_FLOAT: bicubic_float_tab( out, p, bands, lskip, cxf, cyf ); break; - case IM_BANDFMT_DOUBLE: + case VIPS_FORMAT_DOUBLE: bicubic_notab( out, p, bands, lskip, x - ix, y - iy ); break; - case IM_BANDFMT_COMPLEX: + case VIPS_FORMAT_COMPLEX: bicubic_float_tab( out, p, bands * 2, lskip, cxf, cyf ); break; - case IM_BANDFMT_DPCOMPLEX: + case VIPS_FORMAT_DPCOMPLEX: bicubic_notab( out, p, bands * 2, lskip, x - ix, y - iy ); break; diff --git a/libvips/resample/im_affine.c b/libvips/resample/im_affine.c index 9df7c7e0..dce250bb 100644 --- a/libvips/resample/im_affine.c +++ b/libvips/resample/im_affine.c @@ -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 ) ); diff --git a/libvips/resample/interpolate.c b/libvips/resample/interpolate.c index 7a1431cd..4dd1c93e 100644 --- a/libvips/resample/interpolate.c +++ b/libvips/resample/interpolate.c @@ -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; diff --git a/libvips/resample/lbb.cpp b/libvips/resample/lbb.cpp index ec3ae8af..6eeda4f2 100644 --- a/libvips/resample/lbb.cpp +++ b/libvips/resample/lbb.cpp @@ -581,8 +581,8 @@ lbbicubic( const double c00, */ #define LBB_CONVERSION( conversion ) \ template 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; diff --git a/libvips/resample/nohalo.cpp b/libvips/resample/nohalo.cpp index cbf75937..251a3789 100644 --- a/libvips/resample/nohalo.cpp +++ b/libvips/resample/nohalo.cpp @@ -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; diff --git a/libvips/resample/vsqbs.cpp b/libvips/resample/vsqbs.cpp index d0002e9a..9973ad41 100644 --- a/libvips/resample/vsqbs.cpp +++ b/libvips/resample/vsqbs.cpp @@ -178,8 +178,8 @@ typedef struct _VipsInterpolateVsqbsClass { */ #define VSQBS_CONVERSION( conversion ) \ template 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;