From 4469afaeb0ff788dc9fb18eaa1e2b1ff5e31af5f Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Fri, 12 Jun 2020 12:03:15 +0100 Subject: [PATCH] better handling of "nearest" in resize we now use vips_subsample() for this case --- libvips/resample/resize.c | 89 +++++++++++++++------------------------ 1 file changed, 34 insertions(+), 55 deletions(-) diff --git a/libvips/resample/resize.c b/libvips/resample/resize.c index 28235351..22449bb0 100644 --- a/libvips/resample/resize.c +++ b/libvips/resample/resize.c @@ -33,6 +33,8 @@ * affine nearest interpolator is always centre * 7/7/19 [lovell] * - don't let either axis drop below 1px + * 12/7/20 + * - much better handling of "nearest" */ /* @@ -105,45 +107,6 @@ typedef VipsResampleClass VipsResizeClass; G_DEFINE_TYPE( VipsResize, vips_resize, VIPS_TYPE_RESAMPLE ); -/* How much of a scale should be by an integer shrink factor? - * - * This depends on the scale and the kernel we will use for residual resizing. - * For upsizing and nearest-neighbour downsize, we want no shrinking. - * - * The others are adaptive: the size of the kernel changes with the shrink - * factor. We will get the best quality (but be the slowest) if we let - * reduce do all the work. Leave it the final 200 - 300% to do as a compromise - * for efficiency. - * - * FIXME: this is rather ugly. Kernel should be a class and this info should be - * stored in there. - */ -static int -vips_resize_int_shrink( VipsResize *resize, double scale ) -{ - int shrink; - - if( scale > 1.0 ) - shrink = 1; - else - switch( resize->kernel ) { - case VIPS_KERNEL_NEAREST: - shrink = 1; - break; - - case VIPS_KERNEL_LINEAR: - case VIPS_KERNEL_CUBIC: - case VIPS_KERNEL_MITCHELL: - case VIPS_KERNEL_LANCZOS2: - case VIPS_KERNEL_LANCZOS3: - default: - shrink = VIPS_MAX( 1, VIPS_FLOOR( 1.0 / (scale * 2) ) ); - break; - } - - return( shrink ); -} - /* Suggest a VipsInterpolate which corresponds to a VipsKernel. We use * this to pick a thing for affine(). */ @@ -192,10 +155,10 @@ vips_resize_build( VipsObject *object ) else vscale = resize->scale; - /* The int part of our scale. + /* The int part of our scale. Leave the final 200 - 300% to reduce. */ - int_hshrink = vips_resize_int_shrink( resize, hscale ); - int_vshrink = vips_resize_int_shrink( resize, vscale ); + int_hshrink = VIPS_MAX( 1, VIPS_FLOOR( 1.0 / (hscale * 2) ) ); + int_vshrink = VIPS_MAX( 1, VIPS_FLOOR( 1.0 / (vscale * 2) ) ); /* Unpack for processing. */ @@ -203,22 +166,38 @@ vips_resize_build( VipsObject *object ) return( -1 ); in = t[5]; - if( int_vshrink > 1 ) { - g_info( "shrinkv by %d", int_vshrink ); - if( vips_shrinkv( in, &t[0], int_vshrink, NULL ) ) - return( -1 ); - in = t[0]; + if( resize->kernel == VIPS_KERNEL_NEAREST ) { + if( int_vshrink > 1 || + int_hshrink > 1 ) { + g_info( "subsample by %d, %d", + int_hshrink, int_vshrink ); + if( vips_subsample( in, &t[0], + int_hshrink, int_vshrink, NULL ) ) + return( -1 ); + in = t[0]; - vscale *= int_vshrink; - } + hscale *= int_hshrink; + vscale *= int_vshrink; + } + } + else { + if( int_vshrink > 1 ) { + g_info( "shrinkv by %d", int_vshrink ); + if( vips_shrinkv( in, &t[0], int_vshrink, NULL ) ) + return( -1 ); + in = t[0]; - if( int_hshrink > 1 ) { - g_info( "shrinkh by %d", int_hshrink ); - if( vips_shrinkh( in, &t[1], int_hshrink, NULL ) ) - return( -1 ); - in = t[1]; + vscale *= int_vshrink; + } - hscale *= int_hshrink; + if( int_hshrink > 1 ) { + g_info( "shrinkh by %d", int_hshrink ); + if( vips_shrinkh( in, &t[1], int_hshrink, NULL ) ) + return( -1 ); + in = t[1]; + + hscale *= int_hshrink; + } } /* Don't let either axis drop below 1 px.