]> git.sesse.net Git - qscale/commitdiff
Add support for the Mitchell filter kernel.
authorSteinar H. Gunderson <sesse@debian.org>
Sat, 12 Jul 2008 22:02:43 +0000 (00:02 +0200)
committerSteinar H. Gunderson <sesse@debian.org>
Sat, 12 Jul 2008 22:02:43 +0000 (00:02 +0200)
libqscale.c
libqscale.h

index dc040282001c74dd2fcdd644392d35a786902355..b784294def3eedb9f4210bd187675b56dee71393 100644 (file)
@@ -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);
        }
 
index 0d23510c2e9653381dc703f3e4b01017e393eec2..d9e18e7440ed7d8eabb768c02bd54e1e4d0e767b 100644 (file)
@@ -24,6 +24,7 @@ typedef struct {
 
 enum qscale_scaling_filter {
        LANCZOS = 0,
+       MITCHELL = 1,
 };
 
 enum qscale_jpeg_mode {