DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Implementation

Mercurial (d8847129d134)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175

/*
 * Copyright 2013 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */


#ifndef SkBitmapFilter_DEFINED
#define SkBitmapFilter_DEFINED

#include "SkMath.h"

// size of the precomputed bitmap filter tables for high quality filtering.
// Used to precompute the shape of the filter kernel.
// Table size chosen from experiments to see where I could start to see a difference.

#define SKBITMAP_FILTER_TABLE_SIZE 128

class SkBitmapFilter {
  public:
      SkBitmapFilter(float width)
      : fWidth(width), fInvWidth(1.f/width) {
          fPrecomputed = false;
          fLookupMultiplier = this->invWidth() * (SKBITMAP_FILTER_TABLE_SIZE-1);
      }

      SkFixed lookup(float x) const {
          if (!fPrecomputed) {
              precomputeTable();
          }
          int filter_idx = int(sk_float_abs(x * fLookupMultiplier));
          SkASSERT(filter_idx < SKBITMAP_FILTER_TABLE_SIZE);
          return fFilterTable[filter_idx];
      }

      SkScalar lookupScalar(float x) const {
          if (!fPrecomputed) {
              precomputeTable();
          }
          int filter_idx = int(sk_float_abs(x * fLookupMultiplier));
          SkASSERT(filter_idx < SKBITMAP_FILTER_TABLE_SIZE);
          return fFilterTableScalar[filter_idx];
      }

      float width() const { return fWidth; }
      float invWidth() const { return fInvWidth; }
      virtual float evaluate(float x) const = 0;
      virtual ~SkBitmapFilter() {}

      static SkBitmapFilter* Allocate();
  protected:
      float fWidth;
      float fInvWidth;

      float fLookupMultiplier;

      mutable bool fPrecomputed;
      mutable SkFixed fFilterTable[SKBITMAP_FILTER_TABLE_SIZE];
      mutable SkScalar fFilterTableScalar[SKBITMAP_FILTER_TABLE_SIZE];
  private:
      void precomputeTable() const {
          fPrecomputed = true;
          SkFixed *ftp = fFilterTable;
          SkScalar *ftpScalar = fFilterTableScalar;
          for (int x = 0; x < SKBITMAP_FILTER_TABLE_SIZE; ++x) {
              float fx = ((float)x + .5f) * this->width() / SKBITMAP_FILTER_TABLE_SIZE;
              float filter_value = evaluate(fx);
              *ftpScalar++ = filter_value;
              *ftp++ = SkFloatToFixed(filter_value);
          }
      }
};

class SkMitchellFilter: public SkBitmapFilter {
  public:
      SkMitchellFilter(float b, float c, float width=2.0f)
      : SkBitmapFilter(width), B(b), C(c) {
      }

      virtual float evaluate(float x) const SK_OVERRIDE {
          x = fabsf(x);
          if (x > 2.f) {
              return 0;
          } else if (x > 1.f) {
              return ((-B - 6*C) * x*x*x + (6*B + 30*C) * x*x +
                      (-12*B - 48*C) * x + (8*B + 24*C)) * (1.f/6.f);
          } else {
              return ((12 - 9*B - 6*C) * x*x*x +
                      (-18 + 12*B + 6*C) * x*x +
                      (6 - 2*B)) * (1.f/6.f);
          }
      }
  protected:
      float B, C;
};

class SkGaussianFilter: public SkBitmapFilter {
  public:
      SkGaussianFilter(float a, float width=2.0f)
      : SkBitmapFilter(width), alpha(a), expWidth(expf(-alpha * width * width)) {
      }

      virtual float evaluate(float x) const SK_OVERRIDE {
          return SkTMax(0.f, float(expf(-alpha*x*x) - expWidth));
      }
  protected:
      float alpha, expWidth;
};

class SkTriangleFilter: public SkBitmapFilter {
  public:
      SkTriangleFilter(float width=1)
      : SkBitmapFilter(width) {
      }

      virtual float evaluate(float x) const SK_OVERRIDE {
          return SkTMax(0.f, fWidth - fabsf(x));
      }
  protected:
};

class SkBoxFilter: public SkBitmapFilter {
  public:
      SkBoxFilter(float width=0.5f)
      : SkBitmapFilter(width) {
      }

      virtual float evaluate(float x) const SK_OVERRIDE {
          return (x >= -fWidth && x < fWidth) ? 1.0f : 0.0f;
      }
  protected:
};

class SkHammingFilter: public SkBitmapFilter {
public:
    SkHammingFilter(float width=1.f)
    : SkBitmapFilter(width) {
    }
    virtual float evaluate(float x) const SK_OVERRIDE {
        if (x <= -fWidth || x >= fWidth) {
            return 0.0f;  // Outside of the window.
        }
        if (x > -FLT_EPSILON && x < FLT_EPSILON) {
            return 1.0f;  // Special case the sinc discontinuity at the origin.
        }
        const float xpi = x * static_cast<float>(SK_ScalarPI);

        return ((sk_float_sin(xpi) / xpi) *  // sinc(x)
                (0.54f + 0.46f * sk_float_cos(xpi / fWidth)));  // hamming(x)
    }
};

class SkLanczosFilter: public SkBitmapFilter {
  public:
      SkLanczosFilter(float width=3.f)
      : SkBitmapFilter(width) {
      }

      virtual float evaluate(float x) const SK_OVERRIDE {
          if (x <= -fWidth || x >= fWidth) {
              return 0.0f;  // Outside of the window.
          }
          if (x > -FLT_EPSILON && x < FLT_EPSILON) {
              return 1.0f;  // Special case the discontinuity at the origin.
          }
          float xpi = x * static_cast<float>(SK_ScalarPI);
          return (sk_float_sin(xpi) / xpi) *  // sinc(x)
                  sk_float_sin(xpi / fWidth) / (xpi / fWidth);  // sinc(x/fWidth)
      }
};


#endif