SkMatrixConvolutionImageFilter.cpp revision 5faa2dc266ec933b3961f985e5718236f1ecbe47
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 14SkMatrixConvolutionImageFilter::SkMatrixConvolutionImageFilter(const SkISize& kernelSize, const SkScalar* kernel, SkScalar gain, SkScalar bias, const SkIPoint& target, TileMode tileMode, SkImageFilter* input) 15 : INHERITED(input), 16 fKernelSize(kernelSize), 17 fGain(gain), 18 fBias(bias), 19 fTarget(target), 20 fTileMode(tileMode) { 21 uint32_t size = fKernelSize.fWidth * fKernelSize.fHeight; 22 fKernel = SkNEW_ARRAY(SkScalar, size); 23 memcpy(fKernel, kernel, size * sizeof(SkScalar)); 24 SkASSERT(target.fX >= 0 && target.fX < kernelSize.fWidth); 25 SkASSERT(target.fY >= 0 && target.fY < kernelSize.fHeight); 26} 27 28SkMatrixConvolutionImageFilter::SkMatrixConvolutionImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) { 29 fKernelSize.fWidth = buffer.readInt(); 30 fKernelSize.fHeight = buffer.readInt(); 31 uint32_t size = fKernelSize.fWidth * fKernelSize.fHeight; 32 fKernel = SkNEW_ARRAY(SkScalar, size); 33 uint32_t readSize = buffer.readScalarArray(fKernel); 34 SkASSERT(readSize == size); 35 fGain = buffer.readScalar(); 36 fBias = buffer.readScalar(); 37 fTarget.fX = buffer.readScalar(); 38 fTarget.fY = buffer.readScalar(); 39 fTileMode = (TileMode) buffer.readInt(); 40} 41 42void SkMatrixConvolutionImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const { 43 this->INHERITED::flatten(buffer); 44 buffer.writeInt(fKernelSize.fWidth); 45 buffer.writeInt(fKernelSize.fHeight); 46 buffer.writeScalarArray(fKernel, fKernelSize.fWidth * fKernelSize.fHeight); 47 buffer.writeScalar(fGain); 48 buffer.writeScalar(fBias); 49 buffer.writeScalar(fTarget.fX); 50 buffer.writeScalar(fTarget.fY); 51 buffer.writeInt((int) fTileMode); 52} 53 54SkMatrixConvolutionImageFilter::~SkMatrixConvolutionImageFilter() { 55 delete[] fKernel; 56} 57 58class UncheckedPixelFetcher { 59public: 60 static inline SkPMColor fetch(const SkBitmap& src, int x, int y) { 61 return *src.getAddr32(x, y); 62 } 63}; 64 65class ClampPixelFetcher { 66public: 67 static inline SkPMColor fetch(const SkBitmap& src, int x, int y) { 68 x = SkClampMax(x, src.width() - 1); 69 y = SkClampMax(y, src.height() - 1); 70 return *src.getAddr32(x, y); 71 } 72}; 73 74class RepeatPixelFetcher { 75public: 76 static inline SkPMColor fetch(const SkBitmap& src, int x, int y) { 77 x %= src.width(); 78 y %= src.height(); 79 if (x < 0) { 80 x += src.width(); 81 } 82 if (y < 0) { 83 y += src.height(); 84 } 85 return *src.getAddr32(x, y); 86 } 87}; 88 89class ClampToBlackPixelFetcher { 90public: 91 static inline SkPMColor fetch(const SkBitmap& src, int x, int y) { 92 if (x < 0 || x >= src.width() || y < 0 || y >= src.height()) { 93 return 0; 94 } else { 95 return *src.getAddr32(x, y); 96 } 97 } 98}; 99 100template<class PixelFetcher> 101void SkMatrixConvolutionImageFilter::filterPixels(const SkBitmap& src, SkBitmap* result, const SkIRect& rect) { 102 for (int y = rect.fTop; y < rect.fBottom; ++y) { 103 SkPMColor* dptr = result->getAddr32(rect.fLeft, y); 104 for (int x = rect.fLeft; x < rect.fRight; ++x) { 105 SkScalar sumA = 0, sumR = 0, sumG = 0, sumB = 0; 106 for (int cy = 0; cy < fKernelSize.fHeight; cy++) { 107 for (int cx = 0; cx < fKernelSize.fWidth; cx++) { 108 SkPMColor s = PixelFetcher::fetch(src, x + cx - fTarget.fX, y + cy - fTarget.fY); 109 SkScalar k = fKernel[cy * fKernelSize.fWidth + cx]; 110 sumA += SkScalarMul(SkIntToScalar(SkGetPackedA32(s)), k); 111 sumR += SkScalarMul(SkIntToScalar(SkGetPackedR32(s)), k); 112 sumG += SkScalarMul(SkIntToScalar(SkGetPackedG32(s)), k); 113 sumB += SkScalarMul(SkIntToScalar(SkGetPackedB32(s)), k); 114 } 115 } 116 int a = SkScalarFloorToInt(SkScalarMul(sumA, fGain) + fBias); 117 int r = SkScalarFloorToInt(SkScalarMul(sumR, fGain) + fBias); 118 int g = SkScalarFloorToInt(SkScalarMul(sumG, fGain) + fBias); 119 int b = SkScalarFloorToInt(SkScalarMul(sumB, fGain) + fBias); 120 *dptr++ = SkPackARGB32(SkClampMax(a, 255), 121 SkClampMax(r, 255), 122 SkClampMax(g, 255), 123 SkClampMax(b, 255)); 124 } 125 } 126} 127 128void SkMatrixConvolutionImageFilter::filterInteriorPixels(const SkBitmap& src, SkBitmap* result, const SkIRect& rect) { 129 filterPixels<UncheckedPixelFetcher>(src, result, rect); 130} 131 132void SkMatrixConvolutionImageFilter::filterBorderPixels(const SkBitmap& src, SkBitmap* result, const SkIRect& rect) { 133 switch (fTileMode) { 134 case kClamp_TileMode: 135 filterPixels<ClampPixelFetcher>(src, result, rect); 136 break; 137 case kRepeat_TileMode: 138 filterPixels<RepeatPixelFetcher>(src, result, rect); 139 break; 140 case kClampToBlack_TileMode: 141 filterPixels<ClampToBlackPixelFetcher>(src, result, rect); 142 break; 143 } 144} 145 146bool SkMatrixConvolutionImageFilter::onFilterImage(Proxy* proxy, 147 const SkBitmap& source, 148 const SkMatrix& matrix, 149 SkBitmap* result, 150 SkIPoint* loc) { 151 SkBitmap src = this->getInputResult(proxy, source, matrix, loc); 152 if (src.config() != SkBitmap::kARGB_8888_Config) { 153 return false; 154 } 155 156 SkAutoLockPixels alp(src); 157 if (!src.getPixels()) { 158 return false; 159 } 160 161 result->setConfig(src.config(), src.width(), src.height()); 162 result->allocPixels(); 163 164 SkIRect interior = SkIRect::MakeXYWH(fTarget.fX, fTarget.fY, 165 src.width() - fKernelSize.fWidth + 1, 166 src.height() - fKernelSize.fHeight + 1); 167 SkIRect top = SkIRect::MakeWH(src.width(), fTarget.fY); 168 SkIRect bottom = SkIRect::MakeLTRB(0, interior.bottom(), 169 src.width(), src.height()); 170 SkIRect left = SkIRect::MakeXYWH(0, interior.top(), 171 fTarget.fX, interior.height()); 172 SkIRect right = SkIRect::MakeLTRB(interior.right(), interior.top(), 173 src.width(), interior.bottom()); 174 filterBorderPixels(src, result, top); 175 filterBorderPixels(src, result, left); 176 filterInteriorPixels(src, result, interior); 177 filterBorderPixels(src, result, right); 178 filterBorderPixels(src, result, bottom); 179 return true; 180} 181 182SK_DEFINE_FLATTENABLE_REGISTRAR(SkMatrixConvolutionImageFilter) 183 184