aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/effects/SkMatrixConvolutionImageFilter.cpp62
1 files changed, 56 insertions, 6 deletions
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;