aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--bench/MatrixConvolutionBench.cpp12
-rw-r--r--gm/matrixconvolution.cpp14
-rw-r--r--include/effects/SkMatrixConvolutionImageFilter.h8
-rw-r--r--src/effects/SkMatrixConvolutionImageFilter.cpp62
4 files changed, 78 insertions, 18 deletions
diff --git a/bench/MatrixConvolutionBench.cpp b/bench/MatrixConvolutionBench.cpp
index 1f6a004270..dfa05dbd35 100644
--- a/bench/MatrixConvolutionBench.cpp
+++ b/bench/MatrixConvolutionBench.cpp
@@ -15,7 +15,7 @@ class MatrixConvolutionBench : public SkBenchmark {
SkMatrixConvolutionImageFilter::TileMode fTileMode;
public:
- MatrixConvolutionBench(void* param, SkMatrixConvolutionImageFilter::TileMode tileMode)
+ MatrixConvolutionBench(void* param, SkMatrixConvolutionImageFilter::TileMode tileMode, bool convolveAlpha)
: INHERITED(param), fName("matrixconvolution") {
SkISize kernelSize = SkISize::Make(3, 3);
SkScalar kernel[9] = {
@@ -25,7 +25,7 @@ public:
};
SkScalar gain = SkFloatToScalar(0.3f), bias = SkIntToScalar(100);
SkIPoint target = SkIPoint::Make(1, 1);
- fFilter = new SkMatrixConvolutionImageFilter(kernelSize, kernel, gain, bias, target, tileMode);
+ fFilter = new SkMatrixConvolutionImageFilter(kernelSize, kernel, gain, bias, target, tileMode, convolveAlpha);
}
~MatrixConvolutionBench() {
@@ -56,10 +56,12 @@ private:
SkString fName;
};
-static SkBenchmark* Fact00(void* p) { return new MatrixConvolutionBench(p, SkMatrixConvolutionImageFilter::kClamp_TileMode); }
-static SkBenchmark* Fact01(void* p) { return new MatrixConvolutionBench(p, SkMatrixConvolutionImageFilter::kRepeat_TileMode); }
-static SkBenchmark* Fact02(void* p) { return new MatrixConvolutionBench(p, SkMatrixConvolutionImageFilter::kClampToBlack_TileMode); }
+static SkBenchmark* Fact00(void* p) { return new MatrixConvolutionBench(p, SkMatrixConvolutionImageFilter::kClamp_TileMode, true); }
+static SkBenchmark* Fact01(void* p) { return new MatrixConvolutionBench(p, SkMatrixConvolutionImageFilter::kRepeat_TileMode, true); }
+static SkBenchmark* Fact02(void* p) { return new MatrixConvolutionBench(p, SkMatrixConvolutionImageFilter::kClampToBlack_TileMode, true); }
+static SkBenchmark* Fact03(void* p) { return new MatrixConvolutionBench(p, SkMatrixConvolutionImageFilter::kClampToBlack_TileMode, false); }
static BenchRegistry gReg00(Fact00);
static BenchRegistry gReg01(Fact01);
static BenchRegistry gReg02(Fact02);
+static BenchRegistry gReg03(Fact03);
diff --git a/gm/matrixconvolution.cpp b/gm/matrixconvolution.cpp
index 6c69fac485..0a0afa492d 100644
--- a/gm/matrixconvolution.cpp
+++ b/gm/matrixconvolution.cpp
@@ -36,10 +36,10 @@ protected:
}
virtual SkISize onISize() {
- return make_isize(300, 300);
+ return make_isize(400, 300);
}
- void draw(SkCanvas* canvas, int x, int y, const SkIPoint& target, SkMatrixConvolutionImageFilter::TileMode tileMode) {
+ void draw(SkCanvas* canvas, int x, int y, const SkIPoint& target, SkMatrixConvolutionImageFilter::TileMode tileMode, bool convolveAlpha) {
SkScalar kernel[9] = {
SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
SkIntToScalar( 1), SkIntToScalar(-7), SkIntToScalar( 1),
@@ -48,7 +48,7 @@ protected:
SkISize kernelSize = SkISize::Make(3, 3);
SkScalar gain = SkFloatToScalar(0.3f), bias = SkIntToScalar(100);
SkPaint paint;
- SkAutoTUnref<SkImageFilter> filter(SkNEW_ARGS(SkMatrixConvolutionImageFilter, (kernelSize, kernel, gain, bias, target, tileMode)));
+ SkAutoTUnref<SkImageFilter> filter(SkNEW_ARGS(SkMatrixConvolutionImageFilter, (kernelSize, kernel, gain, bias, target, tileMode, convolveAlpha)));
paint.setImageFilter(filter);
canvas->drawSprite(fBitmap, x, y, &paint);
}
@@ -62,10 +62,12 @@ protected:
SkIPoint target = SkIPoint::Make(1, 1);
for (target.fY = 0; target.fY < 3; ++target.fY) {
int y = target.fY * 100 + 10;
- draw(canvas, 10, y, target, SkMatrixConvolutionImageFilter::kClamp_TileMode);
- draw(canvas, 110, y, target, SkMatrixConvolutionImageFilter::kClampToBlack_TileMode);
- draw(canvas, 210, y, target, SkMatrixConvolutionImageFilter::kRepeat_TileMode);
+ draw(canvas, 10, y, target, SkMatrixConvolutionImageFilter::kClamp_TileMode, true);
+ draw(canvas, 110, y, target, SkMatrixConvolutionImageFilter::kClampToBlack_TileMode, true);
+ draw(canvas, 210, y, target, SkMatrixConvolutionImageFilter::kRepeat_TileMode, true);
}
+ target.fY = 1;
+ draw(canvas, 310, 10, target, SkMatrixConvolutionImageFilter::kClamp_TileMode, false);
}
private:
diff --git a/include/effects/SkMatrixConvolutionImageFilter.h b/include/effects/SkMatrixConvolutionImageFilter.h
index 035b863a55..a938fd0b26 100644
--- a/include/effects/SkMatrixConvolutionImageFilter.h
+++ b/include/effects/SkMatrixConvolutionImageFilter.h
@@ -42,11 +42,14 @@ public:
target of {1, 1}).
@param tileMode How accesses outside the image are treated. (@see
TileMode).
+ @param convolveAlpha If true, all channels are convolved. If false,
+ only the RGB channels are convolved, and
+ alpha is copied from the source image.
@param input The input image filter. If NULL, the src bitmap
passed to filterImage() is used instead.
*/
- SkMatrixConvolutionImageFilter(const SkISize& kernelSize, const SkScalar* kernel, SkScalar gain, SkScalar bias, const SkIPoint& target, TileMode tileMode, SkImageFilter* input = NULL);
+ SkMatrixConvolutionImageFilter(const SkISize& kernelSize, const SkScalar* kernel, SkScalar gain, SkScalar bias, const SkIPoint& target, TileMode tileMode, bool convolveAlpha, SkImageFilter* input = NULL);
virtual ~SkMatrixConvolutionImageFilter();
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkMatrixConvolutionImageFilter)
@@ -65,8 +68,11 @@ private:
SkScalar fBias;
SkIPoint fTarget;
TileMode fTileMode;
+ bool fConvolveAlpha;
typedef SkSingleInputImageFilter INHERITED;
+ template <class PixelFetcher, bool convolveAlpha>
+ void filterPixels(const SkBitmap& src, SkBitmap* result, const SkIRect& rect);
template <class PixelFetcher>
void filterPixels(const SkBitmap& src, SkBitmap* result, const SkIRect& rect);
void filterInteriorPixels(const SkBitmap& src, SkBitmap* result, const SkIRect& rect);
diff --git a/src/effects/SkMatrixConvolutionImageFilter.cpp b/src/effects/SkMatrixConvolutionImageFilter.cpp
index 852412bb91..1c6f980b41 100644
--- a/src/effects/SkMatrixConvolutionImageFilter.cpp
+++ b/src/effects/SkMatrixConvolutionImageFilter.cpp
@@ -10,14 +10,16 @@
#include "SkColorPriv.h"
#include "SkFlattenableBuffers.h"
#include "SkRect.h"
+#include "SkUnPreMultiply.h"
-SkMatrixConvolutionImageFilter::SkMatrixConvolutionImageFilter(const SkISize& kernelSize, const SkScalar* kernel, SkScalar gain, SkScalar bias, const SkIPoint& target, TileMode tileMode, SkImageFilter* input)
+SkMatrixConvolutionImageFilter::SkMatrixConvolutionImageFilter(const SkISize& kernelSize, const SkScalar* kernel, SkScalar gain, SkScalar bias, const SkIPoint& target, TileMode tileMode, bool convolveAlpha, SkImageFilter* input)
: INHERITED(input),
fKernelSize(kernelSize),
fGain(gain),
fBias(bias),
fTarget(target),
- fTileMode(tileMode) {
+ fTileMode(tileMode),
+ fConvolveAlpha(convolveAlpha) {
uint32_t size = fKernelSize.fWidth * fKernelSize.fHeight;
fKernel = SkNEW_ARRAY(SkScalar, size);
memcpy(fKernel, kernel, size * sizeof(SkScalar));
@@ -37,6 +39,7 @@ SkMatrixConvolutionImageFilter::SkMatrixConvolutionImageFilter(SkFlattenableRead
fTarget.fX = buffer.readScalar();
fTarget.fY = buffer.readScalar();
fTileMode = (TileMode) buffer.readInt();
+ fConvolveAlpha = buffer.readBool();
}
void SkMatrixConvolutionImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
@@ -49,6 +52,7 @@ void SkMatrixConvolutionImageFilter::flatten(SkFlattenableWriteBuffer& buffer) c
buffer.writeScalar(fTarget.fX);
buffer.writeScalar(fTarget.fY);
buffer.writeInt((int) fTileMode);
+ buffer.writeBool(fConvolveAlpha);
}
SkMatrixConvolutionImageFilter::~SkMatrixConvolutionImageFilter() {
@@ -97,7 +101,7 @@ public:
}
};
-template<class PixelFetcher>
+template<class PixelFetcher, bool convolveAlpha>
void SkMatrixConvolutionImageFilter::filterPixels(const SkBitmap& src, SkBitmap* result, const SkIRect& rect) {
for (int y = rect.fTop; y < rect.fBottom; ++y) {
SkPMColor* dptr = result->getAddr32(rect.fLeft, y);
@@ -107,21 +111,38 @@ void SkMatrixConvolutionImageFilter::filterPixels(const SkBitmap& src, SkBitmap*
for (int cx = 0; cx < fKernelSize.fWidth; cx++) {
SkPMColor s = PixelFetcher::fetch(src, x + cx - fTarget.fX, y + cy - fTarget.fY);
SkScalar k = fKernel[cy * fKernelSize.fWidth + cx];
- sumA += SkScalarMul(SkIntToScalar(SkGetPackedA32(s)), k);
+ if (convolveAlpha) {
+ sumA += SkScalarMul(SkIntToScalar(SkGetPackedA32(s)), k);
+ }
sumR += SkScalarMul(SkIntToScalar(SkGetPackedR32(s)), k);
sumG += SkScalarMul(SkIntToScalar(SkGetPackedG32(s)), k);
sumB += SkScalarMul(SkIntToScalar(SkGetPackedB32(s)), k);
}
}
- int a = SkClampMax(SkScalarFloorToInt(SkScalarMul(sumA, fGain) + fBias), 255);
+ int a = convolveAlpha
+ ? SkClampMax(SkScalarFloorToInt(SkScalarMul(sumA, fGain) + fBias), 255)
+ : SkGetPackedA32(PixelFetcher::fetch(src, x, y));
int r = SkClampMax(SkScalarFloorToInt(SkScalarMul(sumR, fGain) + fBias), a);
int g = SkClampMax(SkScalarFloorToInt(SkScalarMul(sumG, fGain) + fBias), a);
int b = SkClampMax(SkScalarFloorToInt(SkScalarMul(sumB, fGain) + fBias), a);
- *dptr++ = SkPackARGB32(a, r, g, b);
+ if (!convolveAlpha) {
+ *dptr++ = SkPreMultiplyARGB(a, r, g, b);
+ } else {
+ *dptr++ = SkPackARGB32(a, r, g, b);
+ }
}
}
}
+template<class PixelFetcher>
+void SkMatrixConvolutionImageFilter::filterPixels(const SkBitmap& src, SkBitmap* result, const SkIRect& rect) {
+ if (fConvolveAlpha) {
+ filterPixels<PixelFetcher, true>(src, result, rect);
+ } else {
+ filterPixels<PixelFetcher, false>(src, result, rect);
+ }
+}
+
void SkMatrixConvolutionImageFilter::filterInteriorPixels(const SkBitmap& src, SkBitmap* result, const SkIRect& rect) {
filterPixels<UncheckedPixelFetcher>(src, result, rect);
}
@@ -140,6 +161,31 @@ void SkMatrixConvolutionImageFilter::filterBorderPixels(const SkBitmap& src, SkB
}
}
+// FIXME: This should be refactored to SkSingleInputImageFilter for
+// use by other filters. For now, we assume the input is always
+// premultiplied and unpremultiply it
+static SkBitmap unpremultiplyBitmap(const SkBitmap& src)
+{
+ SkAutoLockPixels alp(src);
+ if (!src.getPixels()) {
+ return SkBitmap();
+ }
+ SkBitmap result;
+ result.setConfig(src.config(), src.width(), src.height());
+ result.allocPixels();
+ if (!result.getPixels()) {
+ return SkBitmap();
+ }
+ for (int y = 0; y < src.height(); ++y) {
+ const uint32_t* srcRow = src.getAddr32(0, y);
+ uint32_t* dstRow = result.getAddr32(0, y);
+ for (int x = 0; x < src.width(); ++x) {
+ dstRow[x] = SkUnPreMultiply::PMColorToColor(srcRow[x]);
+ }
+ }
+ return result;
+}
+
bool SkMatrixConvolutionImageFilter::onFilterImage(Proxy* proxy,
const SkBitmap& source,
const SkMatrix& matrix,
@@ -150,6 +196,10 @@ bool SkMatrixConvolutionImageFilter::onFilterImage(Proxy* proxy,
return false;
}
+ if (!fConvolveAlpha && !src.isOpaque()) {
+ src = unpremultiplyBitmap(src);
+ }
+
SkAutoLockPixels alp(src);
if (!src.getPixels()) {
return false;