Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright 2013 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #ifndef SkBitmapFilter_DEFINED
      9 #define SkBitmapFilter_DEFINED
     10 
     11 #include "SkFixed.h"
     12 #include "SkMath.h"
     13 #include "SkScalar.h"
     14 
     15 #include "SkNx.h"
     16 
     17 // size of the precomputed bitmap filter tables for high quality filtering.
     18 // Used to precompute the shape of the filter kernel.
     19 // Table size chosen from experiments to see where I could start to see a difference.
     20 
     21 #define SKBITMAP_FILTER_TABLE_SIZE 128
     22 
     23 class SkBitmapFilter {
     24 public:
     25     SkBitmapFilter(float width) : fWidth(width), fInvWidth(1.f/width) {
     26         fPrecomputed = false;
     27         fLookupMultiplier = this->invWidth() * (SKBITMAP_FILTER_TABLE_SIZE-1);
     28     }
     29     virtual ~SkBitmapFilter() {}
     30 
     31     SkScalar lookupScalar(float x) const {
     32         if (!fPrecomputed) {
     33             precomputeTable();
     34         }
     35         int filter_idx = int(sk_float_abs(x * fLookupMultiplier));
     36         SkASSERT(filter_idx < SKBITMAP_FILTER_TABLE_SIZE);
     37         return fFilterTableScalar[filter_idx];
     38     }
     39 
     40     float width() const { return fWidth; }
     41     float invWidth() const { return fInvWidth; }
     42     virtual float evaluate(float x) const = 0;
     43 
     44     virtual float evaluate_n(float val, float diff, int count, float* output) const {
     45         float sum = 0;
     46         for (int index = 0; index < count; index++) {
     47             float filterValue = evaluate(val);
     48             *output++ = filterValue;
     49             sum += filterValue;
     50             val += diff;
     51         }
     52         return sum;
     53     }
     54 
     55 protected:
     56     float fWidth;
     57     float fInvWidth;
     58     float fLookupMultiplier;
     59 
     60     mutable bool fPrecomputed;
     61     mutable SkScalar fFilterTableScalar[SKBITMAP_FILTER_TABLE_SIZE];
     62 
     63 private:
     64     void precomputeTable() const {
     65         fPrecomputed = true;
     66         SkScalar *ftpScalar = fFilterTableScalar;
     67         for (int x = 0; x < SKBITMAP_FILTER_TABLE_SIZE; ++x) {
     68             float fx = ((float)x + .5f) * this->width() / SKBITMAP_FILTER_TABLE_SIZE;
     69             float filter_value = evaluate(fx);
     70             *ftpScalar++ = filter_value;
     71         }
     72     }
     73 };
     74 
     75 class SkMitchellFilter final : public SkBitmapFilter {
     76 public:
     77     SkMitchellFilter()
     78         : INHERITED(2)
     79         , fB(1.f / 3.f)
     80         , fC(1.f / 3.f)
     81         , fA1(-fB - 6*fC)
     82         , fB1(6*fB + 30*fC)
     83         , fC1(-12*fB - 48*fC)
     84         , fD1(8*fB + 24*fC)
     85         , fA2(12 - 9*fB - 6*fC)
     86         , fB2(-18 + 12*fB + 6*fC)
     87         , fD2(6 - 2*fB)
     88     {}
     89 
     90     float evaluate(float x) const override {
     91         x = fabsf(x);
     92         if (x > 2.f) {
     93             return 0;
     94         } else if (x > 1.f) {
     95             return (((fA1 * x + fB1) * x + fC1) * x + fD1) * (1.f/6.f);
     96         } else {
     97             return ((fA2 * x + fB2) * x*x + fD2) * (1.f/6.f);
     98         }
     99     }
    100 
    101     Sk4f evalcore_n(const Sk4f& val) const {
    102         Sk4f x = val.abs();
    103         Sk4f over2 = x > Sk4f(2);
    104         Sk4f over1 = x > Sk4f(1);
    105         Sk4f poly1 = (((Sk4f(fA1) * x + Sk4f(fB1)) * x + Sk4f(fC1)) * x + Sk4f(fD1))
    106                      * Sk4f(1.f/6.f);
    107         Sk4f poly0 = ((Sk4f(fA2) * x + Sk4f(fB2)) * x*x + Sk4f(fD2)) * Sk4f(1.f/6.f);
    108         return over2.thenElse(Sk4f(0), over1.thenElse(poly1, poly0));
    109     }
    110 
    111     float evaluate_n(float val, float diff, int count, float* output) const override {
    112         Sk4f sum(0);
    113         while (count >= 4) {
    114             float v0 = val;
    115             float v1 = val += diff;
    116             float v2 = val += diff;
    117             float v3 = val += diff;
    118             val += diff;
    119             Sk4f filterValue = evalcore_n(Sk4f(v0, v1, v2, v3));
    120             filterValue.store(output);
    121             output += 4;
    122             sum = sum + filterValue;
    123             count -= 4;
    124         }
    125         float sums[4];
    126         sum.store(sums);
    127         float result = sums[0] + sums[1] + sums[2] + sums[3];
    128         result += INHERITED::evaluate_n(val, diff, count, output);
    129         return result;
    130     }
    131 
    132   protected:
    133       float fB, fC;
    134       float fA1, fB1, fC1, fD1;
    135       float fA2, fB2, fD2;
    136 private:
    137     typedef SkBitmapFilter INHERITED;
    138 };
    139 
    140 class SkGaussianFilter final : public SkBitmapFilter {
    141     float fAlpha, fExpWidth;
    142 
    143 public:
    144     SkGaussianFilter(float a, float width = 2)
    145         : SkBitmapFilter(width)
    146         , fAlpha(a)
    147         , fExpWidth(expf(-a * width * width))
    148     {}
    149 
    150     float evaluate(float x) const override {
    151         return SkTMax(0.f, float(expf(-fAlpha*x*x) - fExpWidth));
    152     }
    153 };
    154 
    155 class SkTriangleFilter final : public SkBitmapFilter {
    156 public:
    157     SkTriangleFilter(float width = 1) : SkBitmapFilter(width) {}
    158 
    159     float evaluate(float x) const override {
    160         return SkTMax(0.f, fWidth - fabsf(x));
    161     }
    162 };
    163 
    164 class SkBoxFilter final : public SkBitmapFilter {
    165 public:
    166     SkBoxFilter(float width = 0.5f) : SkBitmapFilter(width) {}
    167 
    168     float evaluate(float x) const override {
    169         return (x >= -fWidth && x < fWidth) ? 1.0f : 0.0f;
    170     }
    171 };
    172 
    173 class SkHammingFilter final : public SkBitmapFilter {
    174 public:
    175     SkHammingFilter(float width = 1) : SkBitmapFilter(width) {}
    176 
    177     float evaluate(float x) const override {
    178         if (x <= -fWidth || x >= fWidth) {
    179             return 0.0f;  // Outside of the window.
    180         }
    181         if (x > -FLT_EPSILON && x < FLT_EPSILON) {
    182             return 1.0f;  // Special case the sinc discontinuity at the origin.
    183         }
    184         const float xpi = x * static_cast<float>(SK_ScalarPI);
    185 
    186         return ((sk_float_sin(xpi) / xpi) *  // sinc(x)
    187                 (0.54f + 0.46f * sk_float_cos(xpi / fWidth)));  // hamming(x)
    188     }
    189 };
    190 
    191 class SkLanczosFilter final : public SkBitmapFilter {
    192 public:
    193     SkLanczosFilter(float width = 3.f) : SkBitmapFilter(width) {}
    194 
    195     float evaluate(float x) const override {
    196         if (x <= -fWidth || x >= fWidth) {
    197             return 0.0f;  // Outside of the window.
    198         }
    199         if (x > -FLT_EPSILON && x < FLT_EPSILON) {
    200             return 1.0f;  // Special case the discontinuity at the origin.
    201         }
    202         float xpi = x * static_cast<float>(SK_ScalarPI);
    203         return (sk_float_sin(xpi) / xpi) *  // sinc(x)
    204                sk_float_sin(xpi / fWidth) / (xpi / fWidth);  // sinc(x/fWidth)
    205     }
    206 };
    207 
    208 
    209 #endif
    210