From 3b1e3e1841dab816dcf9550bde857423fb57b77f Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Tue, 12 Jun 2018 12:55:10 +0100 Subject: [PATCH] add Mitchell kernel see https://github.com/jcupitt/libvips/issues/966 --- ChangeLog | 1 + libvips/conversion/composite.cpp | 13 +++++++------ libvips/include/vips/resample.h | 1 + libvips/iofuncs/enumtypes.c | 1 + libvips/resample/reduceh.cpp | 10 +++++++++- libvips/resample/resize.c | 1 + libvips/resample/templates.h | 30 +++++++++++++++++++----------- 7 files changed, 39 insertions(+), 18 deletions(-) diff --git a/ChangeLog b/ChangeLog index f333703a..0152fb5c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -28,6 +28,7 @@ - vips7 C++ interface defaults off - make members, getters and operators "const" in cpp API - composite has params for x/y position of sub-images [medakk] +- add Mitchell kernel 12/3/18 started 8.6.4 - better fitting of fonts with overhanging edges [AdriĆ ] diff --git a/libvips/conversion/composite.cpp b/libvips/conversion/composite.cpp index 59e4687d..ce1edff4 100644 --- a/libvips/conversion/composite.cpp +++ b/libvips/conversion/composite.cpp @@ -98,6 +98,13 @@ typedef struct _VipsCompositeBase { */ gboolean premultiplied; + /* The x and y positions for each image in the stack. There are n - 1 + * of these, since image 0 is always positioned at (0, 0). Set by + * subclasses. Can be NULL. + */ + int *x_offset; + int *y_offset; + /* The number of inputs. This can be less than the number of images in * @in. */ @@ -112,12 +119,6 @@ typedef struct _VipsCompositeBase { */ double max_band[MAX_BANDS + 1]; - /* The x and y positions for each image in the stack. There are n - 1 - * of these, since image 0 is always positioned at (0, 0). - */ - int *x_offset; - int *y_offset; - #ifdef HAVE_VECTOR_ARITH /* max_band as a vector, for the RGBA case. */ diff --git a/libvips/include/vips/resample.h b/libvips/include/vips/resample.h index eafe658c..d6ec0d1b 100644 --- a/libvips/include/vips/resample.h +++ b/libvips/include/vips/resample.h @@ -42,6 +42,7 @@ typedef enum { VIPS_KERNEL_NEAREST, VIPS_KERNEL_LINEAR, VIPS_KERNEL_CUBIC, + VIPS_KERNEL_MITCHELL, VIPS_KERNEL_LANCZOS2, VIPS_KERNEL_LANCZOS3, VIPS_KERNEL_LAST diff --git a/libvips/iofuncs/enumtypes.c b/libvips/iofuncs/enumtypes.c index 2ecbaaaa..a23424bc 100644 --- a/libvips/iofuncs/enumtypes.c +++ b/libvips/iofuncs/enumtypes.c @@ -877,6 +877,7 @@ vips_kernel_get_type( void ) {VIPS_KERNEL_NEAREST, "VIPS_KERNEL_NEAREST", "nearest"}, {VIPS_KERNEL_LINEAR, "VIPS_KERNEL_LINEAR", "linear"}, {VIPS_KERNEL_CUBIC, "VIPS_KERNEL_CUBIC", "cubic"}, + {VIPS_KERNEL_MITCHELL, "VIPS_KERNEL_MITCHELL", "mitchell"}, {VIPS_KERNEL_LANCZOS2, "VIPS_KERNEL_LANCZOS2", "lanczos2"}, {VIPS_KERNEL_LANCZOS3, "VIPS_KERNEL_LANCZOS3", "lanczos3"}, {VIPS_KERNEL_LAST, "VIPS_KERNEL_LAST", "last"}, diff --git a/libvips/resample/reduceh.cpp b/libvips/resample/reduceh.cpp index 61be4e38..91c9c613 100644 --- a/libvips/resample/reduceh.cpp +++ b/libvips/resample/reduceh.cpp @@ -104,6 +104,7 @@ vips_reduce_get_points( VipsKernel kernel, double shrink ) return( rint( 2 * shrink ) + 1 ); case VIPS_KERNEL_CUBIC: + case VIPS_KERNEL_MITCHELL: return( rint( 4 * shrink ) + 1 ); case VIPS_KERNEL_LANCZOS2: @@ -135,7 +136,14 @@ vips_reduce_make_mask( double *c, VipsKernel kernel, double shrink, double x ) break; case VIPS_KERNEL_CUBIC: - calculate_coefficients_adaptive_catmull( c, shrink, x ); + /* Catmull-Rom. + */ + calculate_coefficients_cubic( c, shrink, x, 0.0, 0.5 ); + break; + + case VIPS_KERNEL_MITCHELL: + calculate_coefficients_cubic( c, shrink, x, + 1.0 / 3.0, 1.0 / 3.0 ); break; case VIPS_KERNEL_LANCZOS2: diff --git a/libvips/resample/resize.c b/libvips/resample/resize.c index 08eb3ac2..fd5f4c37 100644 --- a/libvips/resample/resize.c +++ b/libvips/resample/resize.c @@ -128,6 +128,7 @@ vips_resize_int_shrink( VipsResize *resize, double scale ) case VIPS_KERNEL_LINEAR: case VIPS_KERNEL_CUBIC: + case VIPS_KERNEL_MITCHELL: case VIPS_KERNEL_LANCZOS2: case VIPS_KERNEL_LANCZOS3: default: diff --git a/libvips/resample/templates.h b/libvips/resample/templates.h index 07f03ab9..e10ea287 100644 --- a/libvips/resample/templates.h +++ b/libvips/resample/templates.h @@ -316,7 +316,8 @@ calculate_coefficients_catmull( double c[4], const double x ) * from the interpolator as well as from the table builder. */ static void inline -calculate_coefficients_triangle( double *c, const double shrink, const double x ) +calculate_coefficients_triangle( double *c, + const double shrink, const double x ) { /* Needs to be in sync with vips_reduce_get_points(). */ @@ -342,11 +343,18 @@ calculate_coefficients_triangle( double *c, const double shrink, const double x c[i] /= sum; } -/* Calculate a catmull kernel for shrinking. +/* Generate a cubic filter. See: + * + * Mitchell and Netravali, Reconstruction Filters in Computer Graphics + * Computer Graphics, Volume 22, Number 4, August 1988. + * + * B = 1, C = 0 - cubic B-spline + * B = 1/3, C = 1/3 - Mitchell + * B = 0, C = 1/2 - Catmull-Rom spline */ static void inline -calculate_coefficients_adaptive_catmull( double *c, - const double shrink, const double x ) +calculate_coefficients_cubic( double *c, + const double shrink, const double x, double B, double C ) { /* Needs to be in sync with vips_reduce_get_points(). */ @@ -361,18 +369,18 @@ calculate_coefficients_adaptive_catmull( double *c, const double axp = VIPS_FABS( xp ); const double axp2 = axp * axp; const double axp3 = axp2 * axp; - const double a = -0.5; double l; if( axp <= 1 ) - l = (a + 2) * axp3 - - (a + 3) * axp2 + 1; + l = ((12 - 9 * B - 6 * C) * axp3 + + (-18 + 12 * B + 6 * C) * axp2 + + (6 - 2 * B)) / 6; else if( axp <= 2 ) - l = a * axp3 - - 5 * a * axp2 + - 8 * a * axp - - 4 * a; + l = ((-B - 6 * C) * axp3 + + (6 * B + 30 * C) * axp2 + + (-12 * B - 48 * C) * axp + + (8 * B + 24 * C)) / 6; else l = 0.0;