1 2 /* 3 * Copyright 2013 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9 10 #ifndef SkBitmapFilter_DEFINED 11 #define SkBitmapFilter_DEFINED 12 13 #include "SkMath.h" 14 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 19 #define SKBITMAP_FILTER_TABLE_SIZE 128 20 21 class SkBitmapFilter { 22 public: SkBitmapFilter(float width)23 SkBitmapFilter(float width) 24 : fWidth(width), fInvWidth(1.f/width) { 25 fPrecomputed = false; 26 fLookupMultiplier = this->invWidth() * (SKBITMAP_FILTER_TABLE_SIZE-1); 27 } 28 lookup(float x)29 SkFixed lookup(float x) const { 30 if (!fPrecomputed) { 31 precomputeTable(); 32 } 33 int filter_idx = int(sk_float_abs(x * fLookupMultiplier)); 34 SkASSERT(filter_idx < SKBITMAP_FILTER_TABLE_SIZE); 35 return fFilterTable[filter_idx]; 36 } 37 lookupScalar(float x)38 SkScalar lookupScalar(float x) const { 39 if (!fPrecomputed) { 40 precomputeTable(); 41 } 42 int filter_idx = int(sk_float_abs(x * fLookupMultiplier)); 43 SkASSERT(filter_idx < SKBITMAP_FILTER_TABLE_SIZE); 44 return fFilterTableScalar[filter_idx]; 45 } 46 width()47 float width() const { return fWidth; } invWidth()48 float invWidth() const { return fInvWidth; } 49 virtual float evaluate(float x) const = 0; ~SkBitmapFilter()50 virtual ~SkBitmapFilter() {} 51 52 static SkBitmapFilter* Allocate(); 53 protected: 54 float fWidth; 55 float fInvWidth; 56 57 float fLookupMultiplier; 58 59 mutable bool fPrecomputed; 60 mutable SkFixed fFilterTable[SKBITMAP_FILTER_TABLE_SIZE]; 61 mutable SkScalar fFilterTableScalar[SKBITMAP_FILTER_TABLE_SIZE]; 62 private: precomputeTable()63 void precomputeTable() const { 64 fPrecomputed = true; 65 SkFixed *ftp = fFilterTable; 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 *ftp++ = SkFloatToFixed(filter_value); 72 } 73 } 74 }; 75 76 class SkMitchellFilter: public SkBitmapFilter { 77 public: 78 SkMitchellFilter(float b, float c, float width=2.0f) SkBitmapFilter(width)79 : SkBitmapFilter(width), B(b), C(c) { 80 } 81 evaluate(float x)82 float evaluate(float x) const override { 83 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 99 class SkGaussianFilter: public SkBitmapFilter { 100 public: 101 SkGaussianFilter(float a, float width=2.0f) SkBitmapFilter(width)102 : SkBitmapFilter(width), alpha(a), expWidth(expf(-alpha * width * width)) { 103 } 104 evaluate(float x)105 float evaluate(float x) const override { 106 return SkTMax(0.f, float(expf(-alpha*x*x) - expWidth)); 107 } 108 protected: 109 float alpha, expWidth; 110 }; 111 112 class SkTriangleFilter: public SkBitmapFilter { 113 public: 114 SkTriangleFilter(float width=1) SkBitmapFilter(width)115 : SkBitmapFilter(width) { 116 } 117 evaluate(float x)118 float evaluate(float x) const override { 119 return SkTMax(0.f, fWidth - fabsf(x)); 120 } 121 protected: 122 }; 123 124 class SkBoxFilter: public SkBitmapFilter { 125 public: 126 SkBoxFilter(float width=0.5f) SkBitmapFilter(width)127 : SkBitmapFilter(width) { 128 } 129 evaluate(float x)130 float evaluate(float x) const override { 131 return (x >= -fWidth && x < fWidth) ? 1.0f : 0.0f; 132 } 133 protected: 134 }; 135 136 class SkHammingFilter: public SkBitmapFilter { 137 public: 138 SkHammingFilter(float width=1.f) SkBitmapFilter(width)139 : SkBitmapFilter(width) { 140 } evaluate(float x)141 float evaluate(float x) const override { 142 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 } 148 const float xpi = x * static_cast<float>(SK_ScalarPI); 149 150 return ((sk_float_sin(xpi) / xpi) * // sinc(x) 151 (0.54f + 0.46f * sk_float_cos(xpi / fWidth))); // hamming(x) 152 } 153 }; 154 155 class SkLanczosFilter: public SkBitmapFilter { 156 public: 157 SkLanczosFilter(float width=3.f) SkBitmapFilter(width)158 : SkBitmapFilter(width) { 159 } 160 evaluate(float x)161 float evaluate(float x) const override { 162 if (x <= -fWidth || x >= fWidth) { 163 return 0.0f; // Outside of the window. 164 } 165 if (x > -FLT_EPSILON && x < FLT_EPSILON) { 166 return 1.0f; // Special case the discontinuity at the origin. 167 } 168 float xpi = x * static_cast<float>(SK_ScalarPI); 169 return (sk_float_sin(xpi) / xpi) * // sinc(x) 170 sk_float_sin(xpi / fWidth) / (xpi / fWidth); // sinc(x/fWidth) 171 } 172 }; 173 174 175 #endif 176