SkMatrixConvolutionImageFilter.cpp revision 8640d5024d57da5508bdf7585849e3b1f1cb365b
1/* 2 * Copyright 2012 The Android Open Source Project 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#include "SkMatrixConvolutionImageFilter.h" 9#include "SkBitmap.h" 10#include "SkColorPriv.h" 11#include "SkFlattenableBuffers.h" 12#include "SkRect.h" 13#include "SkUnPreMultiply.h" 14 15SkMatrixConvolutionImageFilter::SkMatrixConvolutionImageFilter(const SkISize& kernelSize, const SkScalar* kernel, SkScalar gain, SkScalar bias, const SkIPoint& target, TileMode tileMode, bool convolveAlpha, SkImageFilter* input) 16 : INHERITED(input), 17 fKernelSize(kernelSize), 18 fGain(gain), 19 fBias(bias), 20 fTarget(target), 21 fTileMode(tileMode), 22 fConvolveAlpha(convolveAlpha) { 23 uint32_t size = fKernelSize.fWidth * fKernelSize.fHeight; 24 fKernel = SkNEW_ARRAY(SkScalar, size); 25 memcpy(fKernel, kernel, size * sizeof(SkScalar)); 26 SkASSERT(target.fX >= 0 && target.fX < kernelSize.fWidth); 27 SkASSERT(target.fY >= 0 && target.fY < kernelSize.fHeight); 28} 29 30SkMatrixConvolutionImageFilter::SkMatrixConvolutionImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) { 31 fKernelSize.fWidth = buffer.readInt(); 32 fKernelSize.fHeight = buffer.readInt(); 33 uint32_t size = fKernelSize.fWidth * fKernelSize.fHeight; 34 fKernel = SkNEW_ARRAY(SkScalar, size); 35 uint32_t readSize = buffer.readScalarArray(fKernel); 36 SkASSERT(readSize == size); 37 fGain = buffer.readScalar(); 38 fBias = buffer.readScalar(); 39 fTarget.fX = buffer.readScalar(); 40 fTarget.fY = buffer.readScalar(); 41 fTileMode = (TileMode) buffer.readInt(); 42 fConvolveAlpha = buffer.readBool(); 43} 44 45void SkMatrixConvolutionImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const { 46 this->INHERITED::flatten(buffer); 47 buffer.writeInt(fKernelSize.fWidth); 48 buffer.writeInt(fKernelSize.fHeight); 49 buffer.writeScalarArray(fKernel, fKernelSize.fWidth * fKernelSize.fHeight); 50 buffer.writeScalar(fGain); 51 buffer.writeScalar(fBias); 52 buffer.writeScalar(fTarget.fX); 53 buffer.writeScalar(fTarget.fY); 54 buffer.writeInt((int) fTileMode); 55 buffer.writeBool(fConvolveAlpha); 56} 57 58SkMatrixConvolutionImageFilter::~SkMatrixConvolutionImageFilter() { 59 delete[] fKernel; 60} 61 62class UncheckedPixelFetcher { 63public: 64 static inline SkPMColor fetch(const SkBitmap& src, int x, int y) { 65 return *src.getAddr32(x, y); 66 } 67}; 68 69class ClampPixelFetcher { 70public: 71 static inline SkPMColor fetch(const SkBitmap& src, int x, int y) { 72 x = SkClampMax(x, src.width() - 1); 73 y = SkClampMax(y, src.height() - 1); 74 return *src.getAddr32(x, y); 75 } 76}; 77 78class RepeatPixelFetcher { 79public: 80 static inline SkPMColor fetch(const SkBitmap& src, int x, int y) { 81 x %= src.width(); 82 y %= src.height(); 83 if (x < 0) { 84 x += src.width(); 85 } 86 if (y < 0) { 87 y += src.height(); 88 } 89 return *src.getAddr32(x, y); 90 } 91}; 92 93class ClampToBlackPixelFetcher { 94public: 95 static inline SkPMColor fetch(const SkBitmap& src, int x, int y) { 96 if (x < 0 || x >= src.width() || y < 0 || y >= src.height()) { 97 return 0; 98 } else { 99 return *src.getAddr32(x, y); 100 } 101 } 102}; 103 104template<class PixelFetcher, bool convolveAlpha> 105void SkMatrixConvolutionImageFilter::filterPixels(const SkBitmap& src, SkBitmap* result, const SkIRect& rect) { 106 for (int y = rect.fTop; y < rect.fBottom; ++y) { 107 SkPMColor* dptr = result->getAddr32(rect.fLeft, y); 108 for (int x = rect.fLeft; x < rect.fRight; ++x) { 109 SkScalar sumA = 0, sumR = 0, sumG = 0, sumB = 0; 110 for (int cy = 0; cy < fKernelSize.fHeight; cy++) { 111 for (int cx = 0; cx < fKernelSize.fWidth; cx++) { 112 SkPMColor s = PixelFetcher::fetch(src, x + cx - fTarget.fX, y + cy - fTarget.fY); 113 SkScalar k = fKernel[cy * fKernelSize.fWidth + cx]; 114 if (convolveAlpha) { 115 sumA += SkScalarMul(SkIntToScalar(SkGetPackedA32(s)), k); 116 } 117 sumR += SkScalarMul(SkIntToScalar(SkGetPackedR32(s)), k); 118 sumG += SkScalarMul(SkIntToScalar(SkGetPackedG32(s)), k); 119 sumB += SkScalarMul(SkIntToScalar(SkGetPackedB32(s)), k); 120 } 121 } 122 int a = convolveAlpha 123 ? SkClampMax(SkScalarFloorToInt(SkScalarMul(sumA, fGain) + fBias), 255) 124 : SkGetPackedA32(PixelFetcher::fetch(src, x, y)); 125 int r = SkClampMax(SkScalarFloorToInt(SkScalarMul(sumR, fGain) + fBias), a); 126 int g = SkClampMax(SkScalarFloorToInt(SkScalarMul(sumG, fGain) + fBias), a); 127 int b = SkClampMax(SkScalarFloorToInt(SkScalarMul(sumB, fGain) + fBias), a); 128 if (!convolveAlpha) { 129 *dptr++ = SkPreMultiplyARGB(a, r, g, b); 130 } else { 131 *dptr++ = SkPackARGB32(a, r, g, b); 132 } 133 } 134 } 135} 136 137template<class PixelFetcher> 138void SkMatrixConvolutionImageFilter::filterPixels(const SkBitmap& src, SkBitmap* result, const SkIRect& rect) { 139 if (fConvolveAlpha) { 140 filterPixels<PixelFetcher, true>(src, result, rect); 141 } else { 142 filterPixels<PixelFetcher, false>(src, result, rect); 143 } 144} 145 146void SkMatrixConvolutionImageFilter::filterInteriorPixels(const SkBitmap& src, SkBitmap* result, const SkIRect& rect) { 147 filterPixels<UncheckedPixelFetcher>(src, result, rect); 148} 149 150void SkMatrixConvolutionImageFilter::filterBorderPixels(const SkBitmap& src, SkBitmap* result, const SkIRect& rect) { 151 switch (fTileMode) { 152 case kClamp_TileMode: 153 filterPixels<ClampPixelFetcher>(src, result, rect); 154 break; 155 case kRepeat_TileMode: 156 filterPixels<RepeatPixelFetcher>(src, result, rect); 157 break; 158 case kClampToBlack_TileMode: 159 filterPixels<ClampToBlackPixelFetcher>(src, result, rect); 160 break; 161 } 162} 163 164// FIXME: This should be refactored to SkSingleInputImageFilter for 165// use by other filters. For now, we assume the input is always 166// premultiplied and unpremultiply it 167static SkBitmap unpremultiplyBitmap(const SkBitmap& src) 168{ 169 SkAutoLockPixels alp(src); 170 if (!src.getPixels()) { 171 return SkBitmap(); 172 } 173 SkBitmap result; 174 result.setConfig(src.config(), src.width(), src.height()); 175 result.allocPixels(); 176 if (!result.getPixels()) { 177 return SkBitmap(); 178 } 179 for (int y = 0; y < src.height(); ++y) { 180 const uint32_t* srcRow = src.getAddr32(0, y); 181 uint32_t* dstRow = result.getAddr32(0, y); 182 for (int x = 0; x < src.width(); ++x) { 183 dstRow[x] = SkUnPreMultiply::PMColorToColor(srcRow[x]); 184 } 185 } 186 return result; 187} 188 189bool SkMatrixConvolutionImageFilter::onFilterImage(Proxy* proxy, 190 const SkBitmap& source, 191 const SkMatrix& matrix, 192 SkBitmap* result, 193 SkIPoint* loc) { 194 SkBitmap src = this->getInputResult(proxy, source, matrix, loc); 195 if (src.config() != SkBitmap::kARGB_8888_Config) { 196 return false; 197 } 198 199 if (!fConvolveAlpha && !src.isOpaque()) { 200 src = unpremultiplyBitmap(src); 201 } 202 203 SkAutoLockPixels alp(src); 204 if (!src.getPixels()) { 205 return false; 206 } 207 208 result->setConfig(src.config(), src.width(), src.height()); 209 result->allocPixels(); 210 211 SkIRect interior = SkIRect::MakeXYWH(fTarget.fX, fTarget.fY, 212 src.width() - fKernelSize.fWidth + 1, 213 src.height() - fKernelSize.fHeight + 1); 214 SkIRect top = SkIRect::MakeWH(src.width(), fTarget.fY); 215 SkIRect bottom = SkIRect::MakeLTRB(0, interior.bottom(), 216 src.width(), src.height()); 217 SkIRect left = SkIRect::MakeXYWH(0, interior.top(), 218 fTarget.fX, interior.height()); 219 SkIRect right = SkIRect::MakeLTRB(interior.right(), interior.top(), 220 src.width(), interior.bottom()); 221 filterBorderPixels(src, result, top); 222 filterBorderPixels(src, result, left); 223 filterInteriorPixels(src, result, interior); 224 filterBorderPixels(src, result, right); 225 filterBorderPixels(src, result, bottom); 226 return true; 227} 228