1
2/*
3 * Copyright 2013 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9
10#ifndef SkBitmapFilter_DEFINED
11#define SkBitmapFilter_DEFINED
12
13#include "SkMath.h"
14
15// size of the precomputed bitmap filter tables for high quality filtering.
16// Used to precompute the shape of the filter kernel.
17// Table size chosen from experiments to see where I could start to see a difference.
18
19#define SKBITMAP_FILTER_TABLE_SIZE 128
20
21class SkBitmapFilter {
22  public:
23      SkBitmapFilter(float width)
24      : fWidth(width), fInvWidth(1.f/width) {
25          fPrecomputed = false;
26          fLookupMultiplier = this->invWidth() * (SKBITMAP_FILTER_TABLE_SIZE-1);
27      }
28
29      SkFixed lookup(float x) const {
30          if (!fPrecomputed) {
31              precomputeTable();
32          }
33          int filter_idx = int(sk_float_abs(x * fLookupMultiplier));
34          SkASSERT(filter_idx < SKBITMAP_FILTER_TABLE_SIZE);
35          return fFilterTable[filter_idx];
36      }
37
38      SkScalar lookupScalar(float x) const {
39          if (!fPrecomputed) {
40              precomputeTable();
41          }
42          int filter_idx = int(sk_float_abs(x * fLookupMultiplier));
43          SkASSERT(filter_idx < SKBITMAP_FILTER_TABLE_SIZE);
44          return fFilterTableScalar[filter_idx];
45      }
46
47      float width() const { return fWidth; }
48      float invWidth() const { return fInvWidth; }
49      virtual float evaluate(float x) const = 0;
50      virtual ~SkBitmapFilter() {}
51
52      static SkBitmapFilter* Allocate();
53  protected:
54      float fWidth;
55      float fInvWidth;
56
57      float fLookupMultiplier;
58
59      mutable bool fPrecomputed;
60      mutable SkFixed fFilterTable[SKBITMAP_FILTER_TABLE_SIZE];
61      mutable SkScalar fFilterTableScalar[SKBITMAP_FILTER_TABLE_SIZE];
62  private:
63      void precomputeTable() const {
64          fPrecomputed = true;
65          SkFixed *ftp = fFilterTable;
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              *ftp++ = SkFloatToFixed(filter_value);
72          }
73      }
74};
75
76class SkMitchellFilter: public SkBitmapFilter {
77  public:
78      SkMitchellFilter(float b, float c, float width=2.0f)
79      : SkBitmapFilter(width), B(b), C(c) {
80      }
81
82      virtual float evaluate(float x) const SK_OVERRIDE {
83          x = fabsf(x);
84          if (x > 2.f) {
85              return 0;
86          } else if (x > 1.f) {
87              return ((-B - 6*C) * x*x*x + (6*B + 30*C) * x*x +
88                      (-12*B - 48*C) * x + (8*B + 24*C)) * (1.f/6.f);
89          } else {
90              return ((12 - 9*B - 6*C) * x*x*x +
91                      (-18 + 12*B + 6*C) * x*x +
92                      (6 - 2*B)) * (1.f/6.f);
93          }
94      }
95  protected:
96      float B, C;
97};
98
99class SkGaussianFilter: public SkBitmapFilter {
100  public:
101      SkGaussianFilter(float a, float width=2.0f)
102      : SkBitmapFilter(width), alpha(a), expWidth(expf(-alpha * width * width)) {
103      }
104
105      virtual float evaluate(float x) const SK_OVERRIDE {
106          return SkTMax(0.f, float(expf(-alpha*x*x) - expWidth));
107      }
108  protected:
109      float alpha, expWidth;
110};
111
112class SkTriangleFilter: public SkBitmapFilter {
113  public:
114      SkTriangleFilter(float width=1)
115      : SkBitmapFilter(width) {
116      }
117
118      virtual float evaluate(float x) const SK_OVERRIDE {
119          return SkTMax(0.f, fWidth - fabsf(x));
120      }
121  protected:
122};
123
124class SkBoxFilter: public SkBitmapFilter {
125  public:
126      SkBoxFilter(float width=0.5f)
127      : SkBitmapFilter(width) {
128      }
129
130      virtual float evaluate(float x) const SK_OVERRIDE {
131          return (x >= -fWidth && x < fWidth) ? 1.0f : 0.0f;
132      }
133  protected:
134};
135
136class SkHammingFilter: public SkBitmapFilter {
137public:
138    SkHammingFilter(float width=1.f)
139    : SkBitmapFilter(width) {
140    }
141    virtual float evaluate(float x) const SK_OVERRIDE {
142        if (x <= -fWidth || x >= fWidth) {
143            return 0.0f;  // Outside of the window.
144        }
145        if (x > -FLT_EPSILON && x < FLT_EPSILON) {
146            return 1.0f;  // Special case the sinc discontinuity at the origin.
147        }
148        const float xpi = x * static_cast<float>(SK_ScalarPI);
149
150        return ((sk_float_sin(xpi) / xpi) *  // sinc(x)
151                (0.54f + 0.46f * sk_float_cos(xpi / fWidth)));  // hamming(x)
152    }
153};
154
155class SkLanczosFilter: public SkBitmapFilter {
156  public:
157      SkLanczosFilter(float width=3.f)
158      : SkBitmapFilter(width) {
159      }
160
161      virtual float evaluate(float x) const SK_OVERRIDE {
162          if (x <= -fWidth || x >= fWidth) {
163              return 0.0f;  // Outside of the window.
164          }
165          if (x > -FLT_EPSILON && x < FLT_EPSILON) {
166              return 1.0f;  // Special case the discontinuity at the origin.
167          }
168          float xpi = x * static_cast<float>(SK_ScalarPI);
169          return (sk_float_sin(xpi) / xpi) *  // sinc(x)
170                  sk_float_sin(xpi / fWidth) / (xpi / fWidth);  // sinc(x/fWidth)
171      }
172};
173
174
175#endif
176