Skip to content

Commit ac30bad

Browse files
committed
Remove round-to-nearest behaviour
It seems that it generates the same image, with or without this change. Tested with https://github.com/kleisauke/vips-issue-703.
1 parent c0ed106 commit ac30bad

File tree

3 files changed

+31
-41
lines changed

3 files changed

+31
-41
lines changed

libvips/resample/bicubic.cpp

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -79,16 +79,15 @@ typedef VipsInterpolate VipsInterpolateBicubic;
7979
typedef VipsInterpolateClass VipsInterpolateBicubicClass;
8080

8181
/* Precalculated interpolation matrices. int (used for pel
82-
* sizes up to short), and double (for all others). We go to
83-
* scale + 1 so we can round-to-nearest safely.
82+
* sizes up to short), and double (for all others).
8483
*/
8584

8685
/* We could keep a large set of 2d 4x4 matricies, but this actually
8786
* works out slower since for many resizes the thing will no longer
8887
* fit in L1.
8988
*/
90-
static int vips_bicubic_matrixi[VIPS_TRANSFORM_SCALE + 1][4];
91-
static double vips_bicubic_matrixf[VIPS_TRANSFORM_SCALE + 1][4];
89+
static int vips_bicubic_matrixi[VIPS_TRANSFORM_SCALE][4];
90+
static double vips_bicubic_matrixf[VIPS_TRANSFORM_SCALE][4];
9291

9392
/* We need C linkage for this.
9493
*/
@@ -498,19 +497,13 @@ static void
498497
vips_interpolate_bicubic_interpolate( VipsInterpolate *interpolate,
499498
void *out, VipsRegion *in, double x, double y )
500499
{
501-
/* Find the mask index. We round-to-nearest, so we need to generate
502-
* indexes in 0 to VIPS_TRANSFORM_SCALE, 2^n + 1 values. We multiply
503-
* by 2 more than we need to, add one, mask, then shift down again to
504-
* get the extra range.
500+
/* Find the mask index.
505501
*/
506-
const int sx = x * VIPS_TRANSFORM_SCALE * 2;
507-
const int sy = y * VIPS_TRANSFORM_SCALE * 2;
502+
const int sx = x * VIPS_TRANSFORM_SCALE;
503+
const int sy = y * VIPS_TRANSFORM_SCALE;
508504

509-
const int six = sx & (VIPS_TRANSFORM_SCALE * 2 - 1);
510-
const int siy = sy & (VIPS_TRANSFORM_SCALE * 2 - 1);
511-
512-
const int tx = (six + 1) >> 1;
513-
const int ty = (siy + 1) >> 1;
505+
const int tx = sx & (VIPS_TRANSFORM_SCALE - 1);
506+
const int ty = sy & (VIPS_TRANSFORM_SCALE - 1);
514507

515508
/* We know x/y are always positive, so we can just (int) them.
516509
*/
@@ -643,7 +636,7 @@ vips_interpolate_bicubic_class_init( VipsInterpolateBicubicClass *iclass )
643636

644637
/* Build the tables of pre-computed coefficients.
645638
*/
646-
for( int x = 0; x < VIPS_TRANSFORM_SCALE + 1; x++ ) {
639+
for( int x = 0; x < VIPS_TRANSFORM_SCALE; x++ ) {
647640
calculate_coefficients_catmull( vips_bicubic_matrixf[x],
648641
(float) x / VIPS_TRANSFORM_SCALE );
649642

libvips/resample/reduceh.cpp

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
* 6/6/20 kleisauke
1212
* - deprecate @centre option, it's now always on
1313
* - fix pixel shift
14+
* - remove unnecessary round-to-nearest behaviour
1415
*/
1516

1617
/*
@@ -78,11 +79,10 @@ typedef struct _VipsReduceh {
7879
double hoffset;
7980

8081
/* Precalculated interpolation matrices. int (used for pel
81-
* sizes up to short), and double (for all others). We go to
82-
* scale + 1 so we can round-to-nearest safely.
82+
* sizes up to short), and double (for all others).
8383
*/
84-
int *matrixi[VIPS_TRANSFORM_SCALE + 1];
85-
double *matrixf[VIPS_TRANSFORM_SCALE + 1];
84+
int *matrixi[VIPS_TRANSFORM_SCALE];
85+
double *matrixf[VIPS_TRANSFORM_SCALE];
8686

8787
/* Deprecated.
8888
*/
@@ -320,7 +320,7 @@ vips_reduceh_gen( VipsRegion *out_region, void *seq,
320320

321321
VIPS_GATE_START( "vips_reduceh_gen: work" );
322322

323-
for( int y = 0; y < r->height; y ++ ) {
323+
for( int y = 0; y < r->height; y++ ) {
324324
VipsPel *p0;
325325
VipsPel *q;
326326

@@ -346,9 +346,8 @@ vips_reduceh_gen( VipsRegion *out_region, void *seq,
346346
for( int x = 0; x < r->width; x++ ) {
347347
const int ix = (int) X;
348348
VipsPel *p = p0 + ix * ps;
349-
const int sx = X * VIPS_TRANSFORM_SCALE * 2;
350-
const int six = sx & (VIPS_TRANSFORM_SCALE * 2 - 1);
351-
const int tx = (six + 1) >> 1;
349+
const int sx = X * VIPS_TRANSFORM_SCALE;
350+
const int tx = sx & (VIPS_TRANSFORM_SCALE - 1);
352351
const int *cxi = reduceh->matrixi[tx];
353352
const double *cxf = reduceh->matrixf[tx];
354353

@@ -480,7 +479,7 @@ vips_reduceh_build( VipsObject *object )
480479

481480
/* Build the tables of pre-computed coefficients.
482481
*/
483-
for( int x = 0; x < VIPS_TRANSFORM_SCALE + 1; x++ ) {
482+
for( int x = 0; x < VIPS_TRANSFORM_SCALE; x++ ) {
484483
reduceh->matrixf[x] =
485484
VIPS_ARRAY( object, reduceh->n_point, double );
486485
reduceh->matrixi[x] =

libvips/resample/reducev.cpp

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
* - deprecate @centre option, it's now always on
2222
* - fix pixel shift
2323
* - speed up the mask construction for uchar/ushort images
24+
* - remove unnecessary round-to-nearest behaviour
2425
*/
2526

2627
/*
@@ -117,15 +118,14 @@ typedef struct _VipsReducev {
117118
double voffset;
118119

119120
/* Precalculated interpolation matrices. int (used for pel
120-
* sizes up to short), and double (for all others). We go to
121-
* scale + 1 so we can round-to-nearest safely.
121+
* sizes up to short), and double (for all others).
122122
*/
123-
int *matrixi[VIPS_TRANSFORM_SCALE + 1];
124-
double *matrixf[VIPS_TRANSFORM_SCALE + 1];
123+
int *matrixi[VIPS_TRANSFORM_SCALE];
124+
double *matrixf[VIPS_TRANSFORM_SCALE];
125125

126126
/* And another set for orc: we want 2.6 precision.
127127
*/
128-
int *matrixo[VIPS_TRANSFORM_SCALE + 1];
128+
int *matrixo[VIPS_TRANSFORM_SCALE];
129129

130130
/* The passes we generate for this mask.
131131
*/
@@ -154,7 +154,7 @@ vips_reducev_finalize( GObject *gobject )
154154
for( int i = 0; i < reducev->n_pass; i++ )
155155
VIPS_FREEF( vips_vector_free, reducev->pass[i].vector );
156156
reducev->n_pass = 0;
157-
for( int i = 0; i < VIPS_TRANSFORM_SCALE + 1; i++ ) {
157+
for( int i = 0; i < VIPS_TRANSFORM_SCALE; i++ ) {
158158
VIPS_FREE( reducev->matrixf[i] );
159159
VIPS_FREE( reducev->matrixi[i] );
160160
VIPS_FREE( reducev->matrixo[i] );
@@ -550,14 +550,13 @@ vips_reducev_gen( VipsRegion *out_region, void *vseq,
550550
double Y = (r->top + 0.5) * reducev->vshrink - 0.5 -
551551
reducev->voffset;
552552

553-
for( int y = 0; y < r->height; y ++ ) {
553+
for( int y = 0; y < r->height; y++ ) {
554554
VipsPel *q =
555555
VIPS_REGION_ADDR( out_region, r->left, r->top + y );
556556
const int py = (int) Y;
557557
VipsPel *p = VIPS_REGION_ADDR( ir, r->left, py );
558-
const int sy = Y * VIPS_TRANSFORM_SCALE * 2;
559-
const int siy = sy & (VIPS_TRANSFORM_SCALE * 2 - 1);
560-
const int ty = (siy + 1) >> 1;
558+
const int sy = Y * VIPS_TRANSFORM_SCALE;
559+
const int ty = sy & (VIPS_TRANSFORM_SCALE - 1);
561560
const int *cyi = reducev->matrixi[ty];
562561
const double *cyf = reducev->matrixf[ty];
563562
const int lskip = VIPS_REGION_LSKIP( ir );
@@ -675,13 +674,12 @@ vips_reducev_vector_gen( VipsRegion *out_region, void *vseq,
675674
double Y = (r->top + 0.5) * reducev->vshrink - 0.5 -
676675
reducev->voffset;
677676

678-
for( int y = 0; y < r->height; y ++ ) {
677+
for( int y = 0; y < r->height; y++ ) {
679678
VipsPel *q =
680679
VIPS_REGION_ADDR( out_region, r->left, r->top + y );
681680
const int py = (int) Y;
682-
const int sy = Y * VIPS_TRANSFORM_SCALE * 2;
683-
const int siy = sy & (VIPS_TRANSFORM_SCALE * 2 - 1);
684-
const int ty = (siy + 1) >> 1;
681+
const int sy = Y * VIPS_TRANSFORM_SCALE;
682+
const int ty = sy & (VIPS_TRANSFORM_SCALE - 1);
685683
const int *cyo = reducev->matrixo[ty];
686684

687685
#ifdef DEBUG_PIXELS
@@ -742,7 +740,7 @@ vips_reducev_raw( VipsReducev *reducev, VipsImage *in, VipsImage **out )
742740
*/
743741
if( in->BandFmt == VIPS_FORMAT_UCHAR &&
744742
vips_vector_isenabled() )
745-
for( int y = 0; y < VIPS_TRANSFORM_SCALE + 1; y++ ) {
743+
for( int y = 0; y < VIPS_TRANSFORM_SCALE; y++ ) {
746744
reducev->matrixo[y] =
747745
VIPS_ARRAY( NULL, reducev->n_point, int );
748746
if( !reducev->matrixo[y] )
@@ -854,7 +852,7 @@ vips_reducev_build( VipsObject *object )
854852

855853
/* Build the tables of pre-computed coefficients.
856854
*/
857-
for( int y = 0; y < VIPS_TRANSFORM_SCALE + 1; y++ ) {
855+
for( int y = 0; y < VIPS_TRANSFORM_SCALE; y++ ) {
858856
reducev->matrixf[y] =
859857
VIPS_ARRAY( NULL, reducev->n_point, double );
860858
reducev->matrixi[y] =

0 commit comments

Comments
 (0)