зеркало из https://github.com/mozilla/moz-skia.git
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:
Родитель
6c31d9d9b4
Коммит
ae814c7476
|
@ -19,9 +19,7 @@
|
||||||
'../gm/gradients.cpp',
|
'../gm/gradients.cpp',
|
||||||
'../gm/gradtext.cpp',
|
'../gm/gradtext.cpp',
|
||||||
'../gm/hairmodes.cpp',
|
'../gm/hairmodes.cpp',
|
||||||
# commented out until SkPicture support for SkImageFilter is complete
|
'../gm/imageblur.cpp',
|
||||||
# See http://code.google.com/p/skia/issues/detail?id=391
|
|
||||||
# '../gm/imageblur.cpp',
|
|
||||||
'../gm/lcdtext.cpp',
|
'../gm/lcdtext.cpp',
|
||||||
'../gm/linepaths.cpp',
|
'../gm/linepaths.cpp',
|
||||||
'../gm/movepaths.cpp',
|
'../gm/movepaths.cpp',
|
||||||
|
|
|
@ -19,6 +19,9 @@ public:
|
||||||
return SkNEW_ARGS(SkBlurImageFilter, (buffer));
|
return SkNEW_ARGS(SkBlurImageFilter, (buffer));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual bool onFilterImage(const SkBitmap& src, const SkMatrix&,
|
||||||
|
SkBitmap* result, SkIPoint* offset);
|
||||||
|
|
||||||
SK_DECLARE_FLATTENABLE_REGISTRAR()
|
SK_DECLARE_FLATTENABLE_REGISTRAR()
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "SkBlurImageFilter.h"
|
#include "SkBlurImageFilter.h"
|
||||||
|
#include "SkColorPriv.h"
|
||||||
|
|
||||||
SkBlurImageFilter::SkBlurImageFilter(SkFlattenableReadBuffer& buffer)
|
SkBlurImageFilter::SkBlurImageFilter(SkFlattenableReadBuffer& buffer)
|
||||||
: INHERITED(buffer) {
|
: INHERITED(buffer) {
|
||||||
|
@ -29,4 +30,153 @@ void SkBlurImageFilter::flatten(SkFlattenableWriteBuffer& buffer) {
|
||||||
buffer.writeScalar(fSigma.fHeight);
|
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)
|
SK_DEFINE_FLATTENABLE_REGISTRAR(SkBlurImageFilter)
|
||||||
|
|
Загрузка…
Ссылка в новой задаче