From 115192a9fe4206be3bbe897daf0e5fc3e2561fe8 Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Sun, 13 Jul 2008 00:02:43 +0200 Subject: [PATCH] Add support for the Mitchell filter kernel. --- libqscale.c | 73 ++++++++++++++++++++++++++++++++++++++++++++--------- libqscale.h | 1 + 2 files changed, 62 insertions(+), 12 deletions(-) diff --git a/libqscale.c b/libqscale.c index dc04028..b784294 100644 --- a/libqscale.c +++ b/libqscale.c @@ -172,12 +172,39 @@ static double lanczos_tap(double x) return sinc(x*M_PI) * sinc(x*M_PI / 3.0); } +static double mitchell_tap(double x) +{ + const double b = 1.0 / 3.0; + const double c = 1.0 / 3.0; + const double p0 = ( 6.0 - 2.0*b ) / 6.0; + const double p2 = (-18.0 + 12.0*b + 6.0*c) / 6.0; + const double p3 = ( 12.0 - 9.0*b - 6.0*c) / 6.0; + const double q0 = ( 8.0*b + 24.0*c) / 6.0; + const double q1 = ( - 12.0*b - 48.0*c) / 6.0; + const double q2 = ( 6.0*b + 30.0*c) / 6.0; + const double q3 = ( - b - 6.0*c) / 6.0; + + if (x < -2.0) { + return 0.0; + } else if (x < -1.0) { + return q0 - x * (q1 - x * (q2 - x * q3)); + } else if (x < 0.0) { + return p0 + x * x * (p2 - x * p3); + } else if (x < 1.0) { + return p0 + x * x * (p2 + x * p3); + } else if (x < 2.0) { + return q0 + x * (q1 + x * (q2 + x * q3)); + } else { + return 0.0; + } +} + struct pix_desc { unsigned start, end; unsigned startcoeff; }; -static void hscale(float *pix, unsigned char *npix, unsigned w, unsigned h, unsigned nw, unsigned sstride, unsigned dstride) +static void hscale(float *pix, unsigned char *npix, unsigned w, unsigned h, unsigned nw, unsigned sstride, unsigned dstride, enum qscale_scaling_filter scaling_filter) { struct pix_desc *pd = (struct pix_desc *)malloc(nw * sizeof(struct pix_desc)); int size_coeffs = 8; @@ -185,7 +212,13 @@ static void hscale(float *pix, unsigned char *npix, unsigned w, unsigned h, unsi int num_coeffs = 0; int x, y; double sf = (double)w / (double)nw; - double support = (w > nw) ? (3.0 * sf) : (3.0 / sf); + double support; + + if (scaling_filter == LANCZOS) { + support = (w > nw) ? (3.0 * sf) : (3.0 / sf); + } else { /* Mitchell */ + support = (w > nw) ? (2.0 * sf) : (2.0 / sf); + } /* calculate the filter */ for (x = 0; x < nw; ++x) { @@ -222,7 +255,12 @@ static void hscale(float *pix, unsigned char *npix, unsigned w, unsigned h, unsi for (sx = start; sx <= end; ++sx) { double nd = (w > nw) ? (sx/sf - x) : (sx - x*sf); - double f = lanczos_tap(nd); + double f; + if (scaling_filter == LANCZOS) { + f = lanczos_tap(nd); + } else { /* Mitchell */ + f = mitchell_tap(nd); + } if (num_coeffs == size_coeffs) { size_coeffs <<= 1; coeffs = (float *)realloc(coeffs, size_coeffs * sizeof(float)); @@ -300,7 +338,7 @@ static void hscale(float *pix, unsigned char *npix, unsigned w, unsigned h, unsi } } -static void vscale(unsigned char *pix, float *npix, unsigned w, unsigned h, unsigned nh, unsigned dstride) +static void vscale(unsigned char *pix, float *npix, unsigned w, unsigned h, unsigned nh, unsigned dstride, enum qscale_scaling_filter scaling_filter) { struct pix_desc *pd = (struct pix_desc *)malloc(nh * sizeof(struct pix_desc)); int size_coeffs = 8; @@ -308,7 +346,13 @@ static void vscale(unsigned char *pix, float *npix, unsigned w, unsigned h, unsi int num_coeffs = 0; int x, y, sy; double sf = (double)h / (double)nh; - double support = (h > nh) ? (3.0 * sf) : (3.0 / sf); + double support; + + if (scaling_filter == LANCZOS) { + support = (h > nh) ? (3.0 * sf) : (3.0 / sf); + } else { /* Mitchell */ + support = (h > nh) ? (2.0 * sf) : (2.0 / sf); + } /* calculate the filter */ for (y = 0; y < nh; ++y) { @@ -329,7 +373,12 @@ static void vscale(unsigned char *pix, float *npix, unsigned w, unsigned h, unsi for (sy = start; sy <= end; ++sy) { double nd = (h > nh) ? (sy/sf - y) : (sy - y*sf); - double f = lanczos_tap(nd); + double f; + if (scaling_filter == LANCZOS) { + f = lanczos_tap(nd); + } else { /* Mitchell */ + f = mitchell_tap(nd); + } if (num_coeffs == size_coeffs) { size_coeffs <<= 1; coeffs = (float *)realloc(coeffs, size_coeffs * sizeof(float)); @@ -562,23 +611,23 @@ qscale_img *qscale_scale(qscale_img *src, unsigned width, unsigned height, unsig /* FIXME: handle out-of-memory gracefully */ { float *npix = (float*)memalign(16, sstride0 * dst->h0 * sizeof(float)); - vscale(src->data_y, npix, sstride0, src->h0, dst->h0, sstride0); + vscale(src->data_y, npix, sstride0, src->h0, dst->h0, sstride0, scaling_filter); dst->data_y = (unsigned char *)malloc(dst->h0 * dstride0); - hscale(npix, dst->data_y, src->w0, dst->h0, dst->w0, sstride0, dstride0); + hscale(npix, dst->data_y, src->w0, dst->h0, dst->w0, sstride0, dstride0, scaling_filter); free(npix); } { float *npix = (float*)memalign(16, sstride1 * dst->h1 * sizeof(float)); - vscale(src->data_cr, npix, sstride1, src->h1, dst->h1, sstride1); + vscale(src->data_cr, npix, sstride1, src->h1, dst->h1, sstride1, scaling_filter); dst->data_cr = (unsigned char *)malloc(dst->h1 * dstride1); - hscale(npix, dst->data_cr, src->w1, dst->h1, dst->w1, sstride1, dstride1); + hscale(npix, dst->data_cr, src->w1, dst->h1, dst->w1, sstride1, dstride1, scaling_filter); free(npix); } { float *npix = (float*)memalign(16, sstride2 * dst->h2 * sizeof(float)); - vscale(src->data_cb, npix, sstride2, src->h2, dst->h2, sstride2); + vscale(src->data_cb, npix, sstride2, src->h2, dst->h2, sstride2, scaling_filter); dst->data_cb = (unsigned char *)malloc(dst->h2 * dstride2); - hscale(npix, dst->data_cb, src->w2, dst->h2, dst->w2, sstride2, dstride2); + hscale(npix, dst->data_cb, src->w2, dst->h2, dst->w2, sstride2, dstride2, scaling_filter); free(npix); } diff --git a/libqscale.h b/libqscale.h index 0d23510..d9e18e7 100644 --- a/libqscale.h +++ b/libqscale.h @@ -24,6 +24,7 @@ typedef struct { enum qscale_scaling_filter { LANCZOS = 0, + MITCHELL = 1, }; enum qscale_jpeg_mode { -- 2.39.2