1b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com
2b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com/*
3b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com * Copyright 2013 Google Inc.
4b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com *
5b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com * Use of this source code is governed by a BSD-style license that can be
6b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com * found in the LICENSE file.
7b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com */
8b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com
9b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com
10b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com#ifndef SkBitmapFilter_DEFINED
11b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com#define SkBitmapFilter_DEFINED
12b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com
13b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com#include "SkMath.h"
14b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com
15b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com// size of the precomputed bitmap filter tables for high quality filtering.
16b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com// Used to precompute the shape of the filter kernel.
17b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com// Table size chosen from experiments to see where I could start to see a difference.
18b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com
1987fbf4fc735a61f7d0bd48843d48a9e85e8ab746humper@google.com#define SKBITMAP_FILTER_TABLE_SIZE 128
20b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com
21b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.comclass SkBitmapFilter {
22b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com  public:
23b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com      SkBitmapFilter(float width)
24b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com      : fWidth(width), fInvWidth(1.f/width) {
259c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com          fPrecomputed = false;
269c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com          fLookupMultiplier = this->invWidth() * (SKBITMAP_FILTER_TABLE_SIZE-1);
27b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com      }
289e1ec1a52985cce9db3a0d0e8d448b82a32e70cbskia.committer@gmail.com
29138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com      SkFixed lookup(float x) const {
309c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com          if (!fPrecomputed) {
31b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com              precomputeTable();
32b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com          }
339c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com          int filter_idx = int(sk_float_abs(x * fLookupMultiplier));
349c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com          SkASSERT(filter_idx < SKBITMAP_FILTER_TABLE_SIZE);
35138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com          return fFilterTable[filter_idx];
369e1ec1a52985cce9db3a0d0e8d448b82a32e70cbskia.committer@gmail.com      }
379e1ec1a52985cce9db3a0d0e8d448b82a32e70cbskia.committer@gmail.com
38138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com      SkScalar lookupScalar(float x) const {
399c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com          if (!fPrecomputed) {
40b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com              precomputeTable();
41b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com          }
429c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com          int filter_idx = int(sk_float_abs(x * fLookupMultiplier));
439c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com          SkASSERT(filter_idx < SKBITMAP_FILTER_TABLE_SIZE);
44138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com          return fFilterTableScalar[filter_idx];
459e1ec1a52985cce9db3a0d0e8d448b82a32e70cbskia.committer@gmail.com      }
469e1ec1a52985cce9db3a0d0e8d448b82a32e70cbskia.committer@gmail.com
47b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com      float width() const { return fWidth; }
48b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com      float invWidth() const { return fInvWidth; }
49b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com      virtual float evaluate(float x) const = 0;
50b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com      virtual ~SkBitmapFilter() {}
511f3c73825b8a1752abc6b74fbce978a430de6473skia.committer@gmail.com
52138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com      static SkBitmapFilter* Allocate();
53b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com  protected:
54b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com      float fWidth;
55b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com      float fInvWidth;
56fa1bd5f86ceea6cfa8303594730125ad2853d87bskia.committer@gmail.com
579c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com      float fLookupMultiplier;
589c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com
599c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com      mutable bool fPrecomputed;
60b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com      mutable SkFixed fFilterTable[SKBITMAP_FILTER_TABLE_SIZE];
619c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com      mutable SkScalar fFilterTableScalar[SKBITMAP_FILTER_TABLE_SIZE];
62b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com  private:
63b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com      void precomputeTable() const {
649c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com          fPrecomputed = true;
65b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com          SkFixed *ftp = fFilterTable;
669c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com          SkScalar *ftpScalar = fFilterTableScalar;
67b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com          for (int x = 0; x < SKBITMAP_FILTER_TABLE_SIZE; ++x) {
68b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com              float fx = ((float)x + .5f) * this->width() / SKBITMAP_FILTER_TABLE_SIZE;
69b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com              float filter_value = evaluate(fx);
704b413c8bb123e42ca4b9c7bfa6bc2167283cb84ccommit-bot@chromium.org              *ftpScalar++ = filter_value;
71b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com              *ftp++ = SkFloatToFixed(filter_value);
72b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com          }
73b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com      }
74b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com};
75b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com
76b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.comclass SkMitchellFilter: public SkBitmapFilter {
77b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com  public:
78b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com      SkMitchellFilter(float b, float c, float width=2.0f)
799e1ec1a52985cce9db3a0d0e8d448b82a32e70cbskia.committer@gmail.com      : SkBitmapFilter(width), B(b), C(c) {
80b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com      }
819e1ec1a52985cce9db3a0d0e8d448b82a32e70cbskia.committer@gmail.com
8236352bf5e38f45a70ee4f4fc132a38048d38206dmtklein      float evaluate(float x) const override {
83b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com          x = fabsf(x);
84b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com          if (x > 2.f) {
85b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com              return 0;
86b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com          } else if (x > 1.f) {
87b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com              return ((-B - 6*C) * x*x*x + (6*B + 30*C) * x*x +
88b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com                      (-12*B - 48*C) * x + (8*B + 24*C)) * (1.f/6.f);
89b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com          } else {
90b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com              return ((12 - 9*B - 6*C) * x*x*x +
91b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com                      (-18 + 12*B + 6*C) * x*x +
92b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com                      (6 - 2*B)) * (1.f/6.f);
93b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com          }
94b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com      }
95b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com  protected:
96b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com      float B, C;
97b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com};
98b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com
99b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.comclass SkGaussianFilter: public SkBitmapFilter {
100b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com  public:
101b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com      SkGaussianFilter(float a, float width=2.0f)
1029e1ec1a52985cce9db3a0d0e8d448b82a32e70cbskia.committer@gmail.com      : SkBitmapFilter(width), alpha(a), expWidth(expf(-alpha * width * width)) {
103b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com      }
1049e1ec1a52985cce9db3a0d0e8d448b82a32e70cbskia.committer@gmail.com
10536352bf5e38f45a70ee4f4fc132a38048d38206dmtklein      float evaluate(float x) const override {
106b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com          return SkTMax(0.f, float(expf(-alpha*x*x) - expWidth));
107b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com      }
108b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com  protected:
109b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com      float alpha, expWidth;
110b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com};
111b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com
112b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.comclass SkTriangleFilter: public SkBitmapFilter {
113b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com  public:
114b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com      SkTriangleFilter(float width=1)
1159e1ec1a52985cce9db3a0d0e8d448b82a32e70cbskia.committer@gmail.com      : SkBitmapFilter(width) {
116b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com      }
1179e1ec1a52985cce9db3a0d0e8d448b82a32e70cbskia.committer@gmail.com
11836352bf5e38f45a70ee4f4fc132a38048d38206dmtklein      float evaluate(float x) const override {
119b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com          return SkTMax(0.f, fWidth - fabsf(x));
120b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com      }
121b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com  protected:
122b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com};
123b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com
124b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.comclass SkBoxFilter: public SkBitmapFilter {
125b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com  public:
126b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com      SkBoxFilter(float width=0.5f)
1279e1ec1a52985cce9db3a0d0e8d448b82a32e70cbskia.committer@gmail.com      : SkBitmapFilter(width) {
128b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com      }
1299e1ec1a52985cce9db3a0d0e8d448b82a32e70cbskia.committer@gmail.com
13036352bf5e38f45a70ee4f4fc132a38048d38206dmtklein      float evaluate(float x) const override {
131138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com          return (x >= -fWidth && x < fWidth) ? 1.0f : 0.0f;
132b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com      }
133b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com  protected:
134b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com};
135b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com
136138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.comclass SkHammingFilter: public SkBitmapFilter {
137138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.compublic:
138138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com    SkHammingFilter(float width=1.f)
139138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com    : SkBitmapFilter(width) {
140138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com    }
14136352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    float evaluate(float x) const override {
142138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com        if (x <= -fWidth || x >= fWidth) {
143138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com            return 0.0f;  // Outside of the window.
144138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com        }
145138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com        if (x > -FLT_EPSILON && x < FLT_EPSILON) {
146138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com            return 1.0f;  // Special case the sinc discontinuity at the origin.
147138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com        }
14816acf75151ae9d2d367ddbb54f39b86606bc6fb3humper@google.com        const float xpi = x * static_cast<float>(SK_ScalarPI);
149138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com
150138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com        return ((sk_float_sin(xpi) / xpi) *  // sinc(x)
151138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com                (0.54f + 0.46f * sk_float_cos(xpi / fWidth)));  // hamming(x)
152138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com    }
153138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com};
154b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com
155138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.comclass SkLanczosFilter: public SkBitmapFilter {
156b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com  public:
157138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com      SkLanczosFilter(float width=3.f)
158138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com      : SkBitmapFilter(width) {
159b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com      }
1609e1ec1a52985cce9db3a0d0e8d448b82a32e70cbskia.committer@gmail.com
16136352bf5e38f45a70ee4f4fc132a38048d38206dmtklein      float evaluate(float x) const override {
162138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com          if (x <= -fWidth || x >= fWidth) {
163138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com              return 0.0f;  // Outside of the window.
164138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com          }
1651f3c73825b8a1752abc6b74fbce978a430de6473skia.committer@gmail.com          if (x > -FLT_EPSILON && x < FLT_EPSILON) {
166138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com              return 1.0f;  // Special case the discontinuity at the origin.
167138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com          }
16816acf75151ae9d2d367ddbb54f39b86606bc6fb3humper@google.com          float xpi = x * static_cast<float>(SK_ScalarPI);
169138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com          return (sk_float_sin(xpi) / xpi) *  // sinc(x)
170138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com                  sk_float_sin(xpi / fWidth) / (xpi / fWidth);  // sinc(x/fWidth)
1711f3c73825b8a1752abc6b74fbce978a430de6473skia.committer@gmail.com      }
172b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com};
173b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com
174b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com
175b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com#endif
176