blob: eb327d716c7082748a1eb6abf3ccd3a543070aa6 [file] [log] [blame]
humper@google.comb0889472013-07-09 21:37:14 +00001/*
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
humper@google.comb0889472013-07-09 21:37:14 +00008#ifndef SkBitmapFilter_DEFINED
9#define SkBitmapFilter_DEFINED
10
bungemand3ebb482015-08-05 13:57:49 -070011#include "SkFixed.h"
humper@google.comb0889472013-07-09 21:37:14 +000012#include "SkMath.h"
bungemand3ebb482015-08-05 13:57:49 -070013#include "SkScalar.h"
humper@google.comb0889472013-07-09 21:37:14 +000014
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
humper@google.com87fbf4f2013-07-10 21:49:29 +000019#define SKBITMAP_FILTER_TABLE_SIZE 128
humper@google.comb0889472013-07-09 21:37:14 +000020
21class SkBitmapFilter {
22 public:
23 SkBitmapFilter(float width)
24 : fWidth(width), fInvWidth(1.f/width) {
humper@google.com9c96d4b2013-07-14 01:44:59 +000025 fPrecomputed = false;
26 fLookupMultiplier = this->invWidth() * (SKBITMAP_FILTER_TABLE_SIZE-1);
humper@google.comb0889472013-07-09 21:37:14 +000027 }
skia.committer@gmail.com9e1ec1a2013-07-10 07:00:58 +000028
humper@google.com138ebc32013-07-19 20:20:04 +000029 SkFixed lookup(float x) const {
humper@google.com9c96d4b2013-07-14 01:44:59 +000030 if (!fPrecomputed) {
humper@google.comb0889472013-07-09 21:37:14 +000031 precomputeTable();
32 }
humper@google.com9c96d4b2013-07-14 01:44:59 +000033 int filter_idx = int(sk_float_abs(x * fLookupMultiplier));
34 SkASSERT(filter_idx < SKBITMAP_FILTER_TABLE_SIZE);
humper@google.com138ebc32013-07-19 20:20:04 +000035 return fFilterTable[filter_idx];
skia.committer@gmail.com9e1ec1a2013-07-10 07:00:58 +000036 }
37
humper@google.com138ebc32013-07-19 20:20:04 +000038 SkScalar lookupScalar(float x) const {
humper@google.com9c96d4b2013-07-14 01:44:59 +000039 if (!fPrecomputed) {
humper@google.comb0889472013-07-09 21:37:14 +000040 precomputeTable();
41 }
humper@google.com9c96d4b2013-07-14 01:44:59 +000042 int filter_idx = int(sk_float_abs(x * fLookupMultiplier));
43 SkASSERT(filter_idx < SKBITMAP_FILTER_TABLE_SIZE);
humper@google.com138ebc32013-07-19 20:20:04 +000044 return fFilterTableScalar[filter_idx];
skia.committer@gmail.com9e1ec1a2013-07-10 07:00:58 +000045 }
46
humper@google.comb0889472013-07-09 21:37:14 +000047 float width() const { return fWidth; }
48 float invWidth() const { return fInvWidth; }
49 virtual float evaluate(float x) const = 0;
50 virtual ~SkBitmapFilter() {}
skia.committer@gmail.com1f3c7382013-07-20 07:00:58 +000051
humper@google.com138ebc32013-07-19 20:20:04 +000052 static SkBitmapFilter* Allocate();
humper@google.comb0889472013-07-09 21:37:14 +000053 protected:
54 float fWidth;
55 float fInvWidth;
skia.committer@gmail.comfa1bd5f2013-07-13 07:00:56 +000056
humper@google.com9c96d4b2013-07-14 01:44:59 +000057 float fLookupMultiplier;
58
59 mutable bool fPrecomputed;
humper@google.comb0889472013-07-09 21:37:14 +000060 mutable SkFixed fFilterTable[SKBITMAP_FILTER_TABLE_SIZE];
humper@google.com9c96d4b2013-07-14 01:44:59 +000061 mutable SkScalar fFilterTableScalar[SKBITMAP_FILTER_TABLE_SIZE];
humper@google.comb0889472013-07-09 21:37:14 +000062 private:
63 void precomputeTable() const {
humper@google.com9c96d4b2013-07-14 01:44:59 +000064 fPrecomputed = true;
humper@google.comb0889472013-07-09 21:37:14 +000065 SkFixed *ftp = fFilterTable;
humper@google.com9c96d4b2013-07-14 01:44:59 +000066 SkScalar *ftpScalar = fFilterTableScalar;
humper@google.comb0889472013-07-09 21:37:14 +000067 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);
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +000070 *ftpScalar++ = filter_value;
humper@google.comb0889472013-07-09 21:37:14 +000071 *ftp++ = SkFloatToFixed(filter_value);
72 }
73 }
74};
75
76class SkMitchellFilter: public SkBitmapFilter {
77 public:
78 SkMitchellFilter(float b, float c, float width=2.0f)
skia.committer@gmail.com9e1ec1a2013-07-10 07:00:58 +000079 : SkBitmapFilter(width), B(b), C(c) {
humper@google.comb0889472013-07-09 21:37:14 +000080 }
skia.committer@gmail.com9e1ec1a2013-07-10 07:00:58 +000081
mtklein36352bf2015-03-25 18:17:31 -070082 float evaluate(float x) const override {
humper@google.comb0889472013-07-09 21:37:14 +000083 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)
skia.committer@gmail.com9e1ec1a2013-07-10 07:00:58 +0000102 : SkBitmapFilter(width), alpha(a), expWidth(expf(-alpha * width * width)) {
humper@google.comb0889472013-07-09 21:37:14 +0000103 }
skia.committer@gmail.com9e1ec1a2013-07-10 07:00:58 +0000104
mtklein36352bf2015-03-25 18:17:31 -0700105 float evaluate(float x) const override {
humper@google.comb0889472013-07-09 21:37:14 +0000106 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)
skia.committer@gmail.com9e1ec1a2013-07-10 07:00:58 +0000115 : SkBitmapFilter(width) {
humper@google.comb0889472013-07-09 21:37:14 +0000116 }
skia.committer@gmail.com9e1ec1a2013-07-10 07:00:58 +0000117
mtklein36352bf2015-03-25 18:17:31 -0700118 float evaluate(float x) const override {
humper@google.comb0889472013-07-09 21:37:14 +0000119 return SkTMax(0.f, fWidth - fabsf(x));
120 }
121 protected:
122};
123
124class SkBoxFilter: public SkBitmapFilter {
125 public:
126 SkBoxFilter(float width=0.5f)
skia.committer@gmail.com9e1ec1a2013-07-10 07:00:58 +0000127 : SkBitmapFilter(width) {
humper@google.comb0889472013-07-09 21:37:14 +0000128 }
skia.committer@gmail.com9e1ec1a2013-07-10 07:00:58 +0000129
mtklein36352bf2015-03-25 18:17:31 -0700130 float evaluate(float x) const override {
humper@google.com138ebc32013-07-19 20:20:04 +0000131 return (x >= -fWidth && x < fWidth) ? 1.0f : 0.0f;
humper@google.comb0889472013-07-09 21:37:14 +0000132 }
133 protected:
134};
135
humper@google.com138ebc32013-07-19 20:20:04 +0000136class SkHammingFilter: public SkBitmapFilter {
137public:
138 SkHammingFilter(float width=1.f)
139 : SkBitmapFilter(width) {
140 }
mtklein36352bf2015-03-25 18:17:31 -0700141 float evaluate(float x) const override {
humper@google.com138ebc32013-07-19 20:20:04 +0000142 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 }
humper@google.com16acf752013-07-19 21:12:08 +0000148 const float xpi = x * static_cast<float>(SK_ScalarPI);
humper@google.comb0889472013-07-09 21:37:14 +0000149
humper@google.com138ebc32013-07-19 20:20:04 +0000150 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 {
humper@google.comb0889472013-07-09 21:37:14 +0000156 public:
humper@google.com138ebc32013-07-19 20:20:04 +0000157 SkLanczosFilter(float width=3.f)
158 : SkBitmapFilter(width) {
humper@google.comb0889472013-07-09 21:37:14 +0000159 }
skia.committer@gmail.com9e1ec1a2013-07-10 07:00:58 +0000160
mtklein36352bf2015-03-25 18:17:31 -0700161 float evaluate(float x) const override {
humper@google.com138ebc32013-07-19 20:20:04 +0000162 if (x <= -fWidth || x >= fWidth) {
163 return 0.0f; // Outside of the window.
164 }
skia.committer@gmail.com1f3c7382013-07-20 07:00:58 +0000165 if (x > -FLT_EPSILON && x < FLT_EPSILON) {
humper@google.com138ebc32013-07-19 20:20:04 +0000166 return 1.0f; // Special case the discontinuity at the origin.
167 }
humper@google.com16acf752013-07-19 21:12:08 +0000168 float xpi = x * static_cast<float>(SK_ScalarPI);
humper@google.com138ebc32013-07-19 20:20:04 +0000169 return (sk_float_sin(xpi) / xpi) * // sinc(x)
170 sk_float_sin(xpi / fWidth) / (xpi / fWidth); // sinc(x/fWidth)
skia.committer@gmail.com1f3c7382013-07-20 07:00:58 +0000171 }
humper@google.comb0889472013-07-09 21:37:14 +0000172};
173
174
175#endif