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