SkConvolver.h (6247B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 // Copyright (c) 2011-2016 Google Inc. 4 // Use of this source code is governed by a BSD-style license that can be 5 // found in the gfx/skia/LICENSE file. 6 7 #ifndef MOZILLA_GFX_SKCONVOLVER_H_ 8 #define MOZILLA_GFX_SKCONVOLVER_H_ 9 10 #include <cfloat> 11 #include <cmath> 12 #include "mozilla/Vector.h" 13 #include "Types.h" 14 15 namespace skia { 16 17 class SkBitmapFilter { 18 public: 19 explicit SkBitmapFilter(float width) : fWidth(width) {} 20 virtual ~SkBitmapFilter() = default; 21 22 float width() const { return fWidth; } 23 virtual float evaluate(float x) const = 0; 24 25 protected: 26 float fWidth; 27 }; 28 29 class SkBoxFilter final : public SkBitmapFilter { 30 public: 31 explicit SkBoxFilter(float width = 0.5f) : SkBitmapFilter(width) {} 32 33 float evaluate(float x) const override { 34 return (x >= -fWidth && x < fWidth) ? 1.0f : 0.0f; 35 } 36 }; 37 38 class SkLanczosFilter final : public SkBitmapFilter { 39 public: 40 explicit SkLanczosFilter(float width = 3.0f) : SkBitmapFilter(width) {} 41 42 float evaluate(float x) const override { 43 if (x <= -fWidth || x >= fWidth) { 44 return 0.0f; // Outside of the window. 45 } 46 if (x > -FLT_EPSILON && x < FLT_EPSILON) { 47 return 1.0f; // Special case the discontinuity at the origin. 48 } 49 float xpi = x * float(M_PI); 50 return (sinf(xpi) / xpi) * // sinc(x) 51 sinf(xpi / fWidth) / (xpi / fWidth); // sinc(x/fWidth) 52 } 53 }; 54 55 // Represents a filter in one dimension. Each output pixel has one entry in this 56 // object for the filter values contributing to it. You build up the filter 57 // list by calling AddFilter for each output pixel (in order). 58 // 59 // We do 2-dimensional convolution by first convolving each row by one 60 // SkConvolutionFilter1D, then convolving each column by another one. 61 // 62 // Entries are stored in ConvolutionFixed point, shifted left by kShiftBits. 63 class SkConvolutionFilter1D { 64 public: 65 using ConvolutionFixed = short; 66 67 // The number of bits that ConvolutionFixed point values are shifted by. 68 enum { kShiftBits = 14 }; 69 70 SkConvolutionFilter1D(); 71 ~SkConvolutionFilter1D(); 72 73 // Convert between floating point and our ConvolutionFixed point 74 // representation. 75 static ConvolutionFixed ToFixed(float f) { 76 return static_cast<ConvolutionFixed>(f * (1 << kShiftBits)); 77 } 78 79 // Returns the maximum pixel span of a filter. 80 int maxFilter() const { return fMaxFilter; } 81 82 // Returns the number of filters in this filter. This is the dimension of the 83 // output image. 84 int numValues() const { return static_cast<int>(fFilters.length()); } 85 86 bool reserveAdditional(int filterCount, int filterValueCount) { 87 return fFilters.reserve(fFilters.length() + filterCount) && 88 fFilterValues.reserve(fFilterValues.length() + filterValueCount); 89 } 90 91 // Appends the given list of scaling values for generating a given output 92 // pixel. |filterOffset| is the distance from the edge of the image to where 93 // the scaling factors start. The scaling factors apply to the source pixels 94 // starting from this position, and going for the next |filterLength| pixels. 95 // 96 // You will probably want to make sure your input is normalized (that is, 97 // all entries in |filterValuesg| sub to one) to prevent affecting the overall 98 // brighness of the image. 99 // 100 // The filterLength must be > 0. 101 bool AddFilter(int filterOffset, const ConvolutionFixed* filterValues, 102 int filterLength); 103 104 // Retrieves a filter for the given |valueOffset|, a position in the output 105 // image in the direction we're convolving. The offset and length of the 106 // filter values are put into the corresponding out arguments (see AddFilter 107 // above for what these mean), and a pointer to the first scaling factor is 108 // returned. There will be |filterLength| values in this array. 109 inline const ConvolutionFixed* FilterForValue(int valueOffset, 110 int* filterOffset, 111 int* filterLength) const { 112 const FilterInstance& filter = fFilters[valueOffset]; 113 *filterOffset = filter.fOffset; 114 *filterLength = filter.fTrimmedLength; 115 if (filter.fTrimmedLength == 0) { 116 return nullptr; 117 } 118 return &fFilterValues[filter.fDataLocation]; 119 } 120 121 bool ComputeFilterValues(const SkBitmapFilter& aBitmapFilter, 122 int32_t aSrcSize, int32_t aDstSize); 123 124 private: 125 struct FilterInstance { 126 // Offset within filterValues for this instance of the filter. 127 int fDataLocation; 128 129 // Distance from the left of the filter to the center. IN PIXELS 130 int fOffset; 131 132 // Number of values in this filter instance. 133 int fTrimmedLength; 134 135 // Filter length as specified. Note that this may be different from 136 // 'trimmed_length' if leading/trailing zeros of the original floating 137 // point form were clipped differently on each tail. 138 int fLength; 139 }; 140 141 // Stores the information for each filter added to this class. 142 mozilla::Vector<FilterInstance> fFilters; 143 144 // We store all the filter values in this flat list, indexed by 145 // |FilterInstance.data_location| to avoid the mallocs required for storing 146 // each one separately. 147 mozilla::Vector<ConvolutionFixed> fFilterValues; 148 149 // The maximum size of any filter we've added. 150 int fMaxFilter; 151 }; 152 153 void convolve_horizontally(const unsigned char* srcData, 154 const SkConvolutionFilter1D& filter, 155 unsigned char* outRow, 156 mozilla::gfx::SurfaceFormat format); 157 158 void convolve_vertically( 159 const SkConvolutionFilter1D::ConvolutionFixed* filterValues, 160 int filterLength, unsigned char* const* sourceDataRows, int pixelWidth, 161 unsigned char* outRow, mozilla::gfx::SurfaceFormat format); 162 163 bool BGRAConvolve2D(const unsigned char* sourceData, int sourceByteRowStride, 164 mozilla::gfx::SurfaceFormat format, 165 const SkConvolutionFilter1D& filterX, 166 const SkConvolutionFilter1D& filterY, 167 int outputByteRowStride, unsigned char* output); 168 169 } // namespace skia 170 171 #endif /* MOZILLA_GFX_SKCONVOLVER_H_ */