From db4fe60405a8937e5c55cdd9a03608458fc4b17d Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Mon, 17 Dec 2018 12:42:34 +0000 Subject: [PATCH] fix mapim offsets pixels were not being offset by the stencil origin, so interpolators like bicubic could fail thanks @erdmann https://github.com/libvips/libvips/issues/1180 --- ChangeLog | 3 +++ configure.ac | 6 +++--- libvips/resample/bicubic.cpp | 10 +++++----- libvips/resample/mapim.c | 13 +++++++++---- test/test-suite/test_resample.py | 8 ++++++++ 5 files changed, 28 insertions(+), 12 deletions(-) diff --git a/ChangeLog b/ChangeLog index d4ffb172..76be267e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,6 @@ +17/12/18 started 8.7.4 +- mapim was not offsetting by window offset [erdmann] + 21/11/18 started 8.7.3 - fix infinite loop for autofit with non-scaleable font diff --git a/configure.ac b/configure.ac index 329a438d..29a371da 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # also update the version number in the m4 macros below -AC_INIT([vips], [8.7.3], [vipsip@jiscmail.ac.uk]) +AC_INIT([vips], [8.7.4], [vipsip@jiscmail.ac.uk]) # required for gobject-introspection AC_PREREQ(2.62) @@ -18,7 +18,7 @@ AC_CONFIG_MACRO_DIR([m4]) # user-visible library versioning m4_define([vips_major_version], [8]) m4_define([vips_minor_version], [7]) -m4_define([vips_micro_version], [3]) +m4_define([vips_micro_version], [4]) m4_define([vips_version], [vips_major_version.vips_minor_version.vips_micro_version]) @@ -38,7 +38,7 @@ VIPS_VERSION_STRING=$VIPS_VERSION-`date -u -r ChangeLog` # binary interface changes not backwards compatible?: reset age to 0 LIBRARY_CURRENT=51 -LIBRARY_REVISION=3 +LIBRARY_REVISION=4 LIBRARY_AGE=9 # patched into include/vips/version.h diff --git a/libvips/resample/bicubic.cpp b/libvips/resample/bicubic.cpp index bdd612f8..f247ec29 100644 --- a/libvips/resample/bicubic.cpp +++ b/libvips/resample/bicubic.cpp @@ -533,17 +533,17 @@ vips_interpolate_bicubic_interpolate( VipsInterpolate *interpolate, const int bands = in->im->Bands; const int lskip = VIPS_REGION_LSKIP( in ); - g_assert( ix - 1 >= in->valid.left ); - g_assert( iy - 1 >= in->valid.top ); - g_assert( ix + 2 < VIPS_RECT_RIGHT( &in->valid ) ); - g_assert( iy + 2 < VIPS_RECT_BOTTOM( &in->valid ) ); - /* Confirm that absolute_x and absolute_y are >= 1, because of * window_offset. */ g_assert( x >= 1.0 ); g_assert( y >= 1.0 ); + g_assert( ix - 1 >= in->valid.left ); + g_assert( iy - 1 >= in->valid.top ); + g_assert( ix + 2 < VIPS_RECT_RIGHT( &in->valid ) ); + g_assert( iy + 2 < VIPS_RECT_BOTTOM( &in->valid ) ); + #ifdef DEBUG printf( "vips_interpolate_bicubic_interpolate: %g %g\n", x, y ); printf( "\tleft=%d, top=%d, width=%d, height=%d\n", diff --git a/libvips/resample/mapim.c b/libvips/resample/mapim.c index 9e0b30f7..b82960fa 100644 --- a/libvips/resample/mapim.c +++ b/libvips/resample/mapim.c @@ -5,6 +5,8 @@ * 12/8/18 * - prevent float->int overflow * - a bit quicker + * 17/12/18 + * - we were not offsetting pixel fetches by window_offset */ /* @@ -229,8 +231,8 @@ vips_mapim_region_minmax( VipsRegion *region, VipsRect *r, VipsRect *bounds ) TYPE * restrict p1 = (TYPE *) p; \ \ for( x = 0; x < r->width; x++ ) { \ - TYPE px = p1[0]; \ - TYPE py = p1[1]; \ + TYPE px = p1[0] + window_offset; \ + TYPE py = p1[1] + window_offset; \ \ if( px >= clip_width || \ py >= clip_height ) { \ @@ -249,8 +251,8 @@ vips_mapim_region_minmax( VipsRegion *region, VipsRect *r, VipsRect *bounds ) TYPE * restrict p1 = (TYPE *) p; \ \ for( x = 0; x < r->width; x++ ) { \ - TYPE px = p1[0]; \ - TYPE py = p1[1]; \ + TYPE px = p1[0] + window_offset; \ + TYPE py = p1[1] + window_offset; \ \ if( px < 0 || \ px >= clip_width || \ @@ -278,6 +280,8 @@ vips_mapim_gen( VipsRegion *or, void *seq, void *a, void *b, gboolean *stop ) const VipsImage *in = in_array[0]; const int window_size = vips_interpolate_get_window_size( mapim->interpolate ); + const int window_offset = + vips_interpolate_get_window_offset( mapim->interpolate ); const VipsInterpolateMethod interpolate = vips_interpolate_get_method( mapim->interpolate ); const int ps = VIPS_IMAGE_SIZEOF_PEL( in ); @@ -310,6 +314,7 @@ vips_mapim_gen( VipsRegion *or, void *seq, void *a, void *b, gboolean *stop ) /* The bounding box of that area is what we will need from @in. Add * enough for the interpolation stencil as well. + * */ bounds.width += window_size - 1; bounds.height += window_size - 1; diff --git a/test/test-suite/test_resample.py b/test/test-suite/test_resample.py index 4e4713ae..1375718b 100644 --- a/test/test-suite/test_resample.py +++ b/test/test-suite/test_resample.py @@ -198,6 +198,14 @@ class TestResample: b = im.crop(50, 0, im.width - 50, im.height).gaussblur(2) assert (a - b).abs().max() < 20 + # this was a bug at one point, strangely, if executed with debug + # enabled + mp = pyvips.Image.xyz(100, 100) + interp = pyvips.Interpolate.new('bicubic') + assert im.mapim(mp, interpolate=interp).avg() == \ + im.crop(0, 0, 100, 100).avg() + + if __name__ == '__main__': pytest.main()