A software implementation of the Gaussian blur filter, using 3 box blurs. Also
re-enable the imageblur GM test, since the SkPicture path now works. Review URL: http://codereview.appspot.com/5413048/ git-svn-id: http://skia.googlecode.com/svn/trunk@2905 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
6c31d9d9b4
commit
ae814c7476
@ -19,9 +19,7 @@
|
||||
'../gm/gradients.cpp',
|
||||
'../gm/gradtext.cpp',
|
||||
'../gm/hairmodes.cpp',
|
||||
# commented out until SkPicture support for SkImageFilter is complete
|
||||
# See http://code.google.com/p/skia/issues/detail?id=391
|
||||
# '../gm/imageblur.cpp',
|
||||
'../gm/imageblur.cpp',
|
||||
'../gm/lcdtext.cpp',
|
||||
'../gm/linepaths.cpp',
|
||||
'../gm/movepaths.cpp',
|
||||
|
@ -19,6 +19,9 @@ public:
|
||||
return SkNEW_ARGS(SkBlurImageFilter, (buffer));
|
||||
}
|
||||
|
||||
virtual bool onFilterImage(const SkBitmap& src, const SkMatrix&,
|
||||
SkBitmap* result, SkIPoint* offset);
|
||||
|
||||
SK_DECLARE_FLATTENABLE_REGISTRAR()
|
||||
|
||||
protected:
|
||||
|
@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
#include "SkBlurImageFilter.h"
|
||||
#include "SkColorPriv.h"
|
||||
|
||||
SkBlurImageFilter::SkBlurImageFilter(SkFlattenableReadBuffer& buffer)
|
||||
: INHERITED(buffer) {
|
||||
@ -29,4 +30,153 @@ void SkBlurImageFilter::flatten(SkFlattenableWriteBuffer& buffer) {
|
||||
buffer.writeScalar(fSigma.fHeight);
|
||||
}
|
||||
|
||||
static void boxBlurX(const SkBitmap& src, SkBitmap* dst, int kernelSize,
|
||||
int leftOffset, int rightOffset)
|
||||
{
|
||||
int width = src.width(), height = src.height();
|
||||
int rightBorder = SkMin32(rightOffset + 1, width);
|
||||
for (int y = 0; y < height; ++y) {
|
||||
int sumA = 0, sumR = 0, sumG = 0, sumB = 0;
|
||||
SkPMColor* p = src.getAddr32(0, y);
|
||||
for (int i = 0; i < rightBorder; ++i) {
|
||||
sumA += SkGetPackedA32(*p);
|
||||
sumR += SkGetPackedR32(*p);
|
||||
sumG += SkGetPackedG32(*p);
|
||||
sumB += SkGetPackedB32(*p);
|
||||
p++;
|
||||
}
|
||||
|
||||
const SkColor* sptr = src.getAddr32(0, y);
|
||||
SkColor* dptr = dst->getAddr32(0, y);
|
||||
for (int x = 0; x < width; ++x) {
|
||||
*dptr = SkPackARGB32(sumA / kernelSize,
|
||||
sumR / kernelSize,
|
||||
sumG / kernelSize,
|
||||
sumB / kernelSize);
|
||||
if (x >= leftOffset) {
|
||||
SkColor l = *(sptr - leftOffset);
|
||||
sumA -= SkGetPackedA32(l);
|
||||
sumR -= SkGetPackedR32(l);
|
||||
sumG -= SkGetPackedG32(l);
|
||||
sumB -= SkGetPackedB32(l);
|
||||
}
|
||||
if (x + rightOffset + 1 < width) {
|
||||
SkColor r = *(sptr + rightOffset + 1);
|
||||
sumA += SkGetPackedA32(r);
|
||||
sumR += SkGetPackedR32(r);
|
||||
sumG += SkGetPackedG32(r);
|
||||
sumB += SkGetPackedB32(r);
|
||||
}
|
||||
sptr++;
|
||||
dptr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void boxBlurY(const SkBitmap& src, SkBitmap* dst, int kernelSize,
|
||||
int topOffset, int bottomOffset)
|
||||
{
|
||||
int width = src.width(), height = src.height();
|
||||
int bottomBorder = SkMin32(bottomOffset + 1, height);
|
||||
int srcStride = src.rowBytesAsPixels();
|
||||
int dstStride = dst->rowBytesAsPixels();
|
||||
for (int x = 0; x < width; ++x) {
|
||||
int sumA = 0, sumR = 0, sumG = 0, sumB = 0;
|
||||
SkColor* p = src.getAddr32(x, 0);
|
||||
for (int i = 0; i < bottomBorder; ++i) {
|
||||
sumA += SkGetPackedA32(*p);
|
||||
sumR += SkGetPackedR32(*p);
|
||||
sumG += SkGetPackedG32(*p);
|
||||
sumB += SkGetPackedB32(*p);
|
||||
p += srcStride;
|
||||
}
|
||||
|
||||
const SkColor* sptr = src.getAddr32(x, 0);
|
||||
SkColor* dptr = dst->getAddr32(x, 0);
|
||||
for (int y = 0; y < height; ++y) {
|
||||
*dptr = SkPackARGB32(sumA / kernelSize,
|
||||
sumR / kernelSize,
|
||||
sumG / kernelSize,
|
||||
sumB / kernelSize);
|
||||
if (y >= topOffset) {
|
||||
SkColor l = *(sptr - topOffset * srcStride);
|
||||
sumA -= SkGetPackedA32(l);
|
||||
sumR -= SkGetPackedR32(l);
|
||||
sumG -= SkGetPackedG32(l);
|
||||
sumB -= SkGetPackedB32(l);
|
||||
}
|
||||
if (y + bottomOffset + 1 < height) {
|
||||
SkColor r = *(sptr + (bottomOffset + 1) * srcStride);
|
||||
sumA += SkGetPackedA32(r);
|
||||
sumR += SkGetPackedR32(r);
|
||||
sumG += SkGetPackedG32(r);
|
||||
sumB += SkGetPackedB32(r);
|
||||
}
|
||||
sptr += srcStride;
|
||||
dptr += dstStride;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void getBox3Params(SkScalar s, int *kernelSize, int* kernelSize3, int *lowOffset, int *highOffset)
|
||||
{
|
||||
int d = static_cast<int>(floorf(SkScalarToFloat(s) * 3.0f * sqrtf(2.0f * M_PI) / 4.0f + 0.5f));
|
||||
*kernelSize = d;
|
||||
if (d % 2 == 1) {
|
||||
*lowOffset = *highOffset = (d - 1) / 2;
|
||||
*kernelSize3 = d;
|
||||
} else {
|
||||
*highOffset = d / 2;
|
||||
*lowOffset = *highOffset - 1;
|
||||
*kernelSize3 = d + 1;
|
||||
}
|
||||
}
|
||||
|
||||
bool SkBlurImageFilter::onFilterImage(const SkBitmap& src, const SkMatrix&,
|
||||
SkBitmap* dst, SkIPoint*) {
|
||||
if (src.config() != SkBitmap::kARGB_8888_Config) {
|
||||
return false;
|
||||
}
|
||||
|
||||
dst->setConfig(src.config(), src.width(), src.height());
|
||||
dst->allocPixels();
|
||||
int kernelSizeX, kernelSizeX3, lowOffsetX, highOffsetX;
|
||||
int kernelSizeY, kernelSizeY3, lowOffsetY, highOffsetY;
|
||||
getBox3Params(fSigma.width(), &kernelSizeX, &kernelSizeX3, &lowOffsetX, &highOffsetX);
|
||||
getBox3Params(fSigma.height(), &kernelSizeY, &kernelSizeY3, &lowOffsetY, &highOffsetY);
|
||||
|
||||
if (kernelSizeX < 0 || kernelSizeY < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (kernelSizeX == 0 && kernelSizeY == 0) {
|
||||
src.copyTo(dst, dst->config());
|
||||
return true;
|
||||
}
|
||||
|
||||
SkBitmap temp;
|
||||
temp.setConfig(dst->config(), dst->width(), dst->height());
|
||||
if (!temp.allocPixels()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (kernelSizeX > 0 && kernelSizeY > 0) {
|
||||
boxBlurX(src, &temp, kernelSizeX, lowOffsetX, highOffsetX);
|
||||
boxBlurY(temp, dst, kernelSizeY, lowOffsetY, highOffsetY);
|
||||
boxBlurX(*dst, &temp, kernelSizeX, highOffsetX, lowOffsetX);
|
||||
boxBlurY(temp, dst, kernelSizeY, highOffsetY, lowOffsetY);
|
||||
boxBlurX(*dst, &temp, kernelSizeX3, highOffsetX, highOffsetX);
|
||||
boxBlurY(temp, dst, kernelSizeY3, highOffsetY, highOffsetY);
|
||||
} else if (kernelSizeX > 0) {
|
||||
boxBlurX(src, dst, kernelSizeX, lowOffsetX, highOffsetX);
|
||||
boxBlurX(*dst, &temp, kernelSizeX, highOffsetX, lowOffsetX);
|
||||
boxBlurX(temp, dst, kernelSizeX3, highOffsetX, highOffsetX);
|
||||
} else if (kernelSizeY > 0) {
|
||||
boxBlurY(src, dst, kernelSizeY, lowOffsetY, highOffsetY);
|
||||
boxBlurY(*dst, &temp, kernelSizeY, highOffsetY, lowOffsetY);
|
||||
boxBlurY(temp, dst, kernelSizeY3, highOffsetY, highOffsetY);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
SK_DEFINE_FLATTENABLE_REGISTRAR(SkBlurImageFilter)
|
||||
|
Loading…
Reference in New Issue
Block a user