Line data Source code
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 0 : SkBitmapFilter(float width) : fWidth(width), fInvWidth(1.f/width) {
26 0 : fPrecomputed = false;
27 0 : fLookupMultiplier = this->invWidth() * (SKBITMAP_FILTER_TABLE_SIZE-1);
28 0 : }
29 0 : 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 0 : float width() const { return fWidth; }
41 0 : float invWidth() const { return fInvWidth; }
42 : virtual float evaluate(float x) const = 0;
43 :
44 0 : virtual float evaluate_n(float val, float diff, int count, float* output) const {
45 0 : float sum = 0;
46 0 : for (int index = 0; index < count; index++) {
47 0 : float filterValue = evaluate(val);
48 0 : *output++ = filterValue;
49 0 : sum += filterValue;
50 0 : val += diff;
51 : }
52 0 : 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 0 : class SkMitchellFilter final : public SkBitmapFilter {
76 : public:
77 0 : SkMitchellFilter()
78 0 : : INHERITED(2)
79 : , fB(1.f / 3.f)
80 : , fC(1.f / 3.f)
81 0 : , fA1(-fB - 6*fC)
82 0 : , fB1(6*fB + 30*fC)
83 0 : , fC1(-12*fB - 48*fC)
84 0 : , fD1(8*fB + 24*fC)
85 0 : , fA2(12 - 9*fB - 6*fC)
86 0 : , fB2(-18 + 12*fB + 6*fC)
87 0 : , fD2(6 - 2*fB)
88 0 : {}
89 :
90 0 : float evaluate(float x) const override {
91 0 : x = fabsf(x);
92 0 : if (x > 2.f) {
93 0 : return 0;
94 0 : } else if (x > 1.f) {
95 0 : return (((fA1 * x + fB1) * x + fC1) * x + fD1) * (1.f/6.f);
96 : } else {
97 0 : return ((fA2 * x + fB2) * x*x + fD2) * (1.f/6.f);
98 : }
99 : }
100 :
101 0 : Sk4f evalcore_n(const Sk4f& val) const {
102 0 : Sk4f x = val.abs();
103 0 : Sk4f over2 = x > Sk4f(2);
104 0 : Sk4f over1 = x > Sk4f(1);
105 0 : Sk4f poly1 = (((Sk4f(fA1) * x + Sk4f(fB1)) * x + Sk4f(fC1)) * x + Sk4f(fD1))
106 0 : * Sk4f(1.f/6.f);
107 0 : Sk4f poly0 = ((Sk4f(fA2) * x + Sk4f(fB2)) * x*x + Sk4f(fD2)) * Sk4f(1.f/6.f);
108 0 : return over2.thenElse(Sk4f(0), over1.thenElse(poly1, poly0));
109 : }
110 :
111 0 : float evaluate_n(float val, float diff, int count, float* output) const override {
112 : Sk4f sum(0);
113 0 : while (count >= 4) {
114 0 : float v0 = val;
115 0 : float v1 = val += diff;
116 0 : float v2 = val += diff;
117 0 : float v3 = val += diff;
118 0 : val += diff;
119 0 : Sk4f filterValue = evalcore_n(Sk4f(v0, v1, v2, v3));
120 : filterValue.store(output);
121 0 : output += 4;
122 0 : sum = sum + filterValue;
123 0 : count -= 4;
124 : }
125 : float sums[4];
126 : sum.store(sums);
127 0 : float result = sums[0] + sums[1] + sums[2] + sums[3];
128 0 : result += INHERITED::evaluate_n(val, diff, count, output);
129 0 : 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 0 : class SkTriangleFilter final : public SkBitmapFilter {
156 : public:
157 0 : SkTriangleFilter(float width = 1) : SkBitmapFilter(width) {}
158 :
159 0 : float evaluate(float x) const override {
160 0 : return SkTMax(0.f, fWidth - fabsf(x));
161 : }
162 : };
163 :
164 0 : class SkBoxFilter final : public SkBitmapFilter {
165 : public:
166 0 : SkBoxFilter(float width = 0.5f) : SkBitmapFilter(width) {}
167 :
168 0 : float evaluate(float x) const override {
169 0 : return (x >= -fWidth && x < fWidth) ? 1.0f : 0.0f;
170 : }
171 : };
172 :
173 0 : class SkHammingFilter final : public SkBitmapFilter {
174 : public:
175 0 : SkHammingFilter(float width = 1) : SkBitmapFilter(width) {}
176 :
177 0 : float evaluate(float x) const override {
178 0 : if (x <= -fWidth || x >= fWidth) {
179 0 : return 0.0f; // Outside of the window.
180 : }
181 0 : if (x > -FLT_EPSILON && x < FLT_EPSILON) {
182 0 : return 1.0f; // Special case the sinc discontinuity at the origin.
183 : }
184 0 : const float xpi = x * static_cast<float>(SK_ScalarPI);
185 :
186 0 : return ((sk_float_sin(xpi) / xpi) * // sinc(x)
187 0 : (0.54f + 0.46f * sk_float_cos(xpi / fWidth))); // hamming(x)
188 : }
189 : };
190 :
191 0 : class SkLanczosFilter final : public SkBitmapFilter {
192 : public:
193 0 : SkLanczosFilter(float width = 3.f) : SkBitmapFilter(width) {}
194 :
195 0 : float evaluate(float x) const override {
196 0 : if (x <= -fWidth || x >= fWidth) {
197 0 : return 0.0f; // Outside of the window.
198 : }
199 0 : if (x > -FLT_EPSILON && x < FLT_EPSILON) {
200 0 : return 1.0f; // Special case the discontinuity at the origin.
201 : }
202 0 : float xpi = x * static_cast<float>(SK_ScalarPI);
203 0 : return (sk_float_sin(xpi) / xpi) * // sinc(x)
204 0 : sk_float_sin(xpi / fWidth) / (xpi / fWidth); // sinc(x/fWidth)
205 : }
206 : };
207 :
208 :
209 : #endif
|