• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
SkBitmapFilter(float width)25     SkBitmapFilter(float width) : fWidth(width), fInvWidth(1.f/width) {
26         fPrecomputed = false;
27         fLookupMultiplier = this->invWidth() * (SKBITMAP_FILTER_TABLE_SIZE-1);
28     }
~SkBitmapFilter()29     virtual ~SkBitmapFilter() {}
30 
lookupScalar(float x)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 
width()40     float width() const { return fWidth; }
invWidth()41     float invWidth() const { return fInvWidth; }
42     virtual float evaluate(float x) const = 0;
43 
evaluate_n(float val,float diff,int count,float * output)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:
precomputeTable()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:
SkMitchellFilter()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 
evaluate(float x)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 
evalcore_n(const Sk4f & val)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 
evaluate_n(float val,float diff,int count,float * output)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)
SkBitmapFilter(width)145         : SkBitmapFilter(width)
146         , fAlpha(a)
147         , fExpWidth(expf(-a * width * width))
148     {}
149 
evaluate(float x)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:
SkBitmapFilter(width)157     SkTriangleFilter(float width = 1) : SkBitmapFilter(width) {}
158 
evaluate(float x)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:
SkBitmapFilter(width)166     SkBoxFilter(float width = 0.5f) : SkBitmapFilter(width) {}
167 
evaluate(float x)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:
SkBitmapFilter(width)175     SkHammingFilter(float width = 1) : SkBitmapFilter(width) {}
176 
evaluate(float x)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:
SkBitmapFilter(width)193     SkLanczosFilter(float width = 3.f) : SkBitmapFilter(width) {}
194 
evaluate(float x)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