Implement crop rect for the dilate and erode (morphology) filters. This provoked some cleanup on the GPU side: apply_morphology() now deals with SkBitmaps, rather than GrTextures. There's still a clear opportunity for more refactoring between the two filters.
Note: this adds some test cases to the morphology GM, so it will require a rebaseline. R=bsalomon@google.com, reed@google.com Review URL: https://codereview.chromium.org/23892011 git-svn-id: http://skia.googlecode.com/svn/trunk@11313 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
ef45a646a7
commit
8fcad98791
@ -8,8 +8,8 @@
|
||||
#include "gm.h"
|
||||
#include "SkMorphologyImageFilter.h"
|
||||
|
||||
#define WIDTH 640
|
||||
#define HEIGHT 480
|
||||
#define WIDTH 700
|
||||
#define HEIGHT 560
|
||||
|
||||
namespace skiagm {
|
||||
|
||||
@ -44,6 +44,16 @@ protected:
|
||||
virtual SkISize onISize() {
|
||||
return make_isize(WIDTH, HEIGHT);
|
||||
}
|
||||
|
||||
void drawClippedBitmap(SkCanvas* canvas, const SkPaint& paint, int x, int y) {
|
||||
canvas->save();
|
||||
canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
|
||||
canvas->clipRect(SkRect::MakeWH(
|
||||
SkIntToScalar(fBitmap.width()), SkIntToScalar(fBitmap.height())));
|
||||
canvas->drawBitmap(fBitmap, 0, 0, &paint);
|
||||
canvas->restore();
|
||||
}
|
||||
|
||||
virtual void onDraw(SkCanvas* canvas) {
|
||||
if (!fOnce) {
|
||||
make_bitmap();
|
||||
@ -60,26 +70,25 @@ protected:
|
||||
{ 24, 24, 25, 25 },
|
||||
};
|
||||
SkPaint paint;
|
||||
for (unsigned j = 0; j < 2; ++j) {
|
||||
SkIRect cropRect = SkIRect::MakeXYWH(25, 20, 100, 80);
|
||||
|
||||
for (unsigned j = 0; j < 4; ++j) {
|
||||
for (unsigned i = 0; i < SK_ARRAY_COUNT(samples); ++i) {
|
||||
SkScalar x = SkIntToScalar(i * 140), y = SkIntToScalar(j * 140);
|
||||
if (j) {
|
||||
const SkIRect* cr = j & 0x02 ? &cropRect : NULL;
|
||||
if (j & 0x01) {
|
||||
paint.setImageFilter(new SkErodeImageFilter(
|
||||
samples[i].fRadiusX,
|
||||
samples[i].fRadiusY))->unref();
|
||||
samples[i].fRadiusY,
|
||||
NULL,
|
||||
cr))->unref();
|
||||
} else {
|
||||
paint.setImageFilter(new SkDilateImageFilter(
|
||||
samples[i].fRadiusX,
|
||||
samples[i].fRadiusY))->unref();
|
||||
samples[i].fRadiusY,
|
||||
NULL,
|
||||
cr))->unref();
|
||||
}
|
||||
SkRect bounds = SkRect::MakeXYWH(
|
||||
x,
|
||||
y,
|
||||
SkIntToScalar(samples[i].fWidth),
|
||||
SkIntToScalar(samples[i].fHeight));
|
||||
canvas->saveLayer(&bounds, &paint);
|
||||
canvas->drawBitmap(fBitmap, x, y);
|
||||
canvas->restore();
|
||||
drawClippedBitmap(canvas, paint, i * 140, j * 140);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@
|
||||
|
||||
class SK_API SkMorphologyImageFilter : public SkImageFilter {
|
||||
public:
|
||||
SkMorphologyImageFilter(int radiusX, int radiusY, SkImageFilter* input);
|
||||
SkMorphologyImageFilter(int radiusX, int radiusY, SkImageFilter* input, const SkIRect* cropRect);
|
||||
|
||||
protected:
|
||||
SkMorphologyImageFilter(SkFlattenableReadBuffer& buffer);
|
||||
@ -32,8 +32,10 @@ private:
|
||||
|
||||
class SK_API SkDilateImageFilter : public SkMorphologyImageFilter {
|
||||
public:
|
||||
SkDilateImageFilter(int radiusX, int radiusY, SkImageFilter* input = NULL)
|
||||
: INHERITED(radiusX, radiusY, input) {}
|
||||
SkDilateImageFilter(int radiusX, int radiusY,
|
||||
SkImageFilter* input = NULL,
|
||||
const SkIRect* cropRect = NULL)
|
||||
: INHERITED(radiusX, radiusY, input, cropRect) {}
|
||||
|
||||
virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
|
||||
SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
|
||||
@ -53,8 +55,10 @@ private:
|
||||
|
||||
class SK_API SkErodeImageFilter : public SkMorphologyImageFilter {
|
||||
public:
|
||||
SkErodeImageFilter(int radiusX, int radiusY, SkImageFilter* input = NULL)
|
||||
: INHERITED(radiusX, radiusY, input) {}
|
||||
SkErodeImageFilter(int radiusX, int radiusY,
|
||||
SkImageFilter* input = NULL,
|
||||
const SkIRect* cropRect = NULL)
|
||||
: INHERITED(radiusX, radiusY, input, cropRect) {}
|
||||
|
||||
virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
|
||||
SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
|
||||
|
@ -26,8 +26,8 @@ SkMorphologyImageFilter::SkMorphologyImageFilter(SkFlattenableReadBuffer& buffer
|
||||
fRadius.fHeight = buffer.readInt();
|
||||
}
|
||||
|
||||
SkMorphologyImageFilter::SkMorphologyImageFilter(int radiusX, int radiusY, SkImageFilter* input)
|
||||
: INHERITED(input), fRadius(SkISize::Make(radiusX, radiusY)) {
|
||||
SkMorphologyImageFilter::SkMorphologyImageFilter(int radiusX, int radiusY, SkImageFilter* input, const SkIRect* cropRect)
|
||||
: INHERITED(input, cropRect), fRadius(SkISize::Make(radiusX, radiusY)) {
|
||||
}
|
||||
|
||||
|
||||
@ -71,17 +71,17 @@ static void erode(const SkPMColor* src, SkPMColor* dst,
|
||||
}
|
||||
}
|
||||
|
||||
static void erodeX(const SkBitmap& src, SkBitmap* dst, int radiusX)
|
||||
static void erodeX(const SkBitmap& src, SkBitmap* dst, int radiusX, const SkIRect& bounds)
|
||||
{
|
||||
erode(src.getAddr32(0, 0), dst->getAddr32(0, 0),
|
||||
radiusX, src.width(), src.height(),
|
||||
erode(src.getAddr32(bounds.left(), bounds.top()), dst->getAddr32(0, 0),
|
||||
radiusX, bounds.width(), bounds.height(),
|
||||
1, src.rowBytesAsPixels(), 1, dst->rowBytesAsPixels());
|
||||
}
|
||||
|
||||
static void erodeY(const SkBitmap& src, SkBitmap* dst, int radiusY)
|
||||
static void erodeY(const SkBitmap& src, SkBitmap* dst, int radiusY, const SkIRect& bounds)
|
||||
{
|
||||
erode(src.getAddr32(0, 0), dst->getAddr32(0, 0),
|
||||
radiusY, src.height(), src.width(),
|
||||
erode(src.getAddr32(bounds.left(), bounds.top()), dst->getAddr32(0, 0),
|
||||
radiusY, bounds.height(), bounds.width(),
|
||||
src.rowBytesAsPixels(), 1, dst->rowBytesAsPixels(), 1);
|
||||
}
|
||||
|
||||
@ -119,17 +119,17 @@ static void dilate(const SkPMColor* src, SkPMColor* dst,
|
||||
}
|
||||
}
|
||||
|
||||
static void dilateX(const SkBitmap& src, SkBitmap* dst, int radiusX)
|
||||
static void dilateX(const SkBitmap& src, SkBitmap* dst, int radiusX, const SkIRect& bounds)
|
||||
{
|
||||
dilate(src.getAddr32(0, 0), dst->getAddr32(0, 0),
|
||||
radiusX, src.width(), src.height(),
|
||||
dilate(src.getAddr32(bounds.left(), bounds.top()), dst->getAddr32(0, 0),
|
||||
radiusX, bounds.width(), bounds.height(),
|
||||
1, src.rowBytesAsPixels(), 1, dst->rowBytesAsPixels());
|
||||
}
|
||||
|
||||
static void dilateY(const SkBitmap& src, SkBitmap* dst, int radiusY)
|
||||
static void dilateY(const SkBitmap& src, SkBitmap* dst, int radiusY, const SkIRect& bounds)
|
||||
{
|
||||
dilate(src.getAddr32(0, 0), dst->getAddr32(0, 0),
|
||||
radiusY, src.height(), src.width(),
|
||||
dilate(src.getAddr32(bounds.left(), bounds.top()), dst->getAddr32(0, 0),
|
||||
radiusY, bounds.height(), bounds.width(),
|
||||
src.rowBytesAsPixels(), 1, dst->rowBytesAsPixels(), 1);
|
||||
}
|
||||
|
||||
@ -145,12 +145,18 @@ bool SkErodeImageFilter::onFilterImage(Proxy* proxy,
|
||||
return false;
|
||||
}
|
||||
|
||||
SkIRect bounds;
|
||||
src.getBounds(&bounds);
|
||||
if (!this->applyCropRect(&bounds, ctm)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SkAutoLockPixels alp(src);
|
||||
if (!src.getPixels()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
dst->setConfig(src.config(), src.width(), src.height());
|
||||
dst->setConfig(src.config(), bounds.width(), bounds.height());
|
||||
dst->allocPixels();
|
||||
|
||||
int width = radius().width();
|
||||
@ -161,7 +167,9 @@ bool SkErodeImageFilter::onFilterImage(Proxy* proxy,
|
||||
}
|
||||
|
||||
if (width == 0 && height == 0) {
|
||||
src.copyTo(dst, dst->config());
|
||||
src.extractSubset(dst, bounds);
|
||||
offset->fX += bounds.left();
|
||||
offset->fY += bounds.top();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -172,13 +180,16 @@ bool SkErodeImageFilter::onFilterImage(Proxy* proxy,
|
||||
}
|
||||
|
||||
if (width > 0 && height > 0) {
|
||||
erodeX(src, &temp, width);
|
||||
erodeY(temp, dst, height);
|
||||
erodeX(src, &temp, width, bounds);
|
||||
SkIRect tmpBounds = SkIRect::MakeWH(bounds.width(), bounds.height());
|
||||
erodeY(temp, dst, height, tmpBounds);
|
||||
} else if (width > 0) {
|
||||
erodeX(src, dst, width);
|
||||
erodeX(src, dst, width, bounds);
|
||||
} else if (height > 0) {
|
||||
erodeY(src, dst, height);
|
||||
erodeY(src, dst, height, bounds);
|
||||
}
|
||||
offset->fX += bounds.left();
|
||||
offset->fY += bounds.top();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -193,12 +204,18 @@ bool SkDilateImageFilter::onFilterImage(Proxy* proxy,
|
||||
return false;
|
||||
}
|
||||
|
||||
SkIRect bounds;
|
||||
src.getBounds(&bounds);
|
||||
if (!this->applyCropRect(&bounds, ctm)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SkAutoLockPixels alp(src);
|
||||
if (!src.getPixels()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
dst->setConfig(src.config(), src.width(), src.height());
|
||||
dst->setConfig(src.config(), bounds.width(), bounds.height());
|
||||
dst->allocPixels();
|
||||
|
||||
int width = radius().width();
|
||||
@ -209,7 +226,9 @@ bool SkDilateImageFilter::onFilterImage(Proxy* proxy,
|
||||
}
|
||||
|
||||
if (width == 0 && height == 0) {
|
||||
src.copyTo(dst, dst->config());
|
||||
src.extractSubset(dst, bounds);
|
||||
offset->fX += bounds.left();
|
||||
offset->fY += bounds.top();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -220,13 +239,16 @@ bool SkDilateImageFilter::onFilterImage(Proxy* proxy,
|
||||
}
|
||||
|
||||
if (width > 0 && height > 0) {
|
||||
dilateX(src, &temp, width);
|
||||
dilateY(temp, dst, height);
|
||||
dilateX(src, &temp, width, bounds);
|
||||
SkIRect tmpBounds = SkIRect::MakeWH(bounds.width(), bounds.height());
|
||||
dilateY(temp, dst, height, tmpBounds);
|
||||
} else if (width > 0) {
|
||||
dilateX(src, dst, width);
|
||||
dilateX(src, dst, width, bounds);
|
||||
} else if (height > 0) {
|
||||
dilateY(src, dst, height);
|
||||
dilateY(src, dst, height, bounds);
|
||||
}
|
||||
offset->fX += bounds.left();
|
||||
offset->fY += bounds.top();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -446,7 +468,8 @@ namespace {
|
||||
|
||||
void apply_morphology_pass(GrContext* context,
|
||||
GrTexture* texture,
|
||||
const SkIRect& rect,
|
||||
const SkIRect& srcRect,
|
||||
const SkIRect& dstRect,
|
||||
int radius,
|
||||
GrMorphologyEffect::MorphologyType morphType,
|
||||
Gr1DKernelEffect::Direction direction) {
|
||||
@ -455,15 +478,19 @@ void apply_morphology_pass(GrContext* context,
|
||||
direction,
|
||||
radius,
|
||||
morphType))->unref();
|
||||
context->drawRect(paint, SkRect::MakeFromIRect(rect));
|
||||
context->drawRectToRect(paint, SkRect::MakeFromIRect(dstRect), SkRect::MakeFromIRect(srcRect));
|
||||
}
|
||||
|
||||
GrTexture* apply_morphology(GrTexture* srcTexture,
|
||||
const SkIRect& rect,
|
||||
GrMorphologyEffect::MorphologyType morphType,
|
||||
SkISize radius) {
|
||||
bool apply_morphology(const SkBitmap& input,
|
||||
const SkIRect& rect,
|
||||
GrMorphologyEffect::MorphologyType morphType,
|
||||
SkISize radius,
|
||||
SkBitmap* dst) {
|
||||
GrTexture* srcTexture = input.getTexture();
|
||||
SkASSERT(NULL != srcTexture);
|
||||
GrContext* context = srcTexture->getContext();
|
||||
srcTexture->ref();
|
||||
SkAutoTUnref<GrTexture> src(srcTexture);
|
||||
|
||||
GrContext::AutoMatrix am;
|
||||
am.setIdentity(context);
|
||||
@ -471,62 +498,101 @@ GrTexture* apply_morphology(GrTexture* srcTexture,
|
||||
GrContext::AutoClip acs(context, SkRect::MakeWH(SkIntToScalar(srcTexture->width()),
|
||||
SkIntToScalar(srcTexture->height())));
|
||||
|
||||
SkIRect dstRect = SkIRect::MakeWH(rect.width(), rect.height());
|
||||
GrTextureDesc desc;
|
||||
desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
|
||||
desc.fWidth = rect.width();
|
||||
desc.fHeight = rect.height();
|
||||
desc.fConfig = kSkia8888_GrPixelConfig;
|
||||
SkIRect srcRect = rect;
|
||||
|
||||
if (radius.fWidth > 0) {
|
||||
GrAutoScratchTexture ast(context, desc);
|
||||
GrContext::AutoRenderTarget art(context, ast.texture()->asRenderTarget());
|
||||
apply_morphology_pass(context, srcTexture, rect, radius.fWidth,
|
||||
apply_morphology_pass(context, src, srcRect, dstRect, radius.fWidth,
|
||||
morphType, Gr1DKernelEffect::kX_Direction);
|
||||
SkIRect clearRect = SkIRect::MakeXYWH(rect.fLeft, rect.fBottom,
|
||||
rect.width(), radius.fHeight);
|
||||
SkIRect clearRect = SkIRect::MakeXYWH(dstRect.fLeft, dstRect.fBottom,
|
||||
dstRect.width(), radius.fHeight);
|
||||
context->clear(&clearRect, 0x0);
|
||||
srcTexture->unref();
|
||||
srcTexture = ast.detach();
|
||||
src.reset(ast.detach());
|
||||
srcRect = dstRect;
|
||||
}
|
||||
if (radius.fHeight > 0) {
|
||||
GrAutoScratchTexture ast(context, desc);
|
||||
GrContext::AutoRenderTarget art(context, ast.texture()->asRenderTarget());
|
||||
apply_morphology_pass(context, srcTexture, rect, radius.fHeight,
|
||||
apply_morphology_pass(context, src, srcRect, dstRect, radius.fHeight,
|
||||
morphType, Gr1DKernelEffect::kY_Direction);
|
||||
srcTexture->unref();
|
||||
srcTexture = ast.detach();
|
||||
src.reset(ast.detach());
|
||||
}
|
||||
return srcTexture;
|
||||
return SkImageFilterUtils::WrapTexture(src, rect.width(), rect.height(), dst);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
bool SkDilateImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const SkMatrix& ctm,
|
||||
SkBitmap* result, SkIPoint* offset) {
|
||||
SkBitmap inputBM;
|
||||
if (!SkImageFilterUtils::GetInputResultGPU(getInput(0), proxy, src, ctm, &inputBM, offset)) {
|
||||
SkBitmap input;
|
||||
if (!SkImageFilterUtils::GetInputResultGPU(getInput(0), proxy, src, ctm, &input, offset)) {
|
||||
return false;
|
||||
}
|
||||
GrTexture* input = inputBM.getTexture();
|
||||
SkIRect bounds;
|
||||
src.getBounds(&bounds);
|
||||
SkAutoTUnref<GrTexture> resultTex(apply_morphology(input, bounds,
|
||||
GrMorphologyEffect::kDilate_MorphologyType, radius()));
|
||||
return SkImageFilterUtils::WrapTexture(resultTex, src.width(), src.height(), result);
|
||||
if (!this->applyCropRect(&bounds, ctm)) {
|
||||
return false;
|
||||
}
|
||||
int width = radius().width();
|
||||
int height = radius().height();
|
||||
|
||||
if (width < 0 || height < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (width == 0 && height == 0) {
|
||||
src.extractSubset(result, bounds);
|
||||
offset->fX += bounds.left();
|
||||
offset->fY += bounds.top();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!apply_morphology(input, bounds, GrMorphologyEffect::kDilate_MorphologyType, radius(), result)) {
|
||||
return false;
|
||||
}
|
||||
offset->fX += bounds.left();
|
||||
offset->fY += bounds.top();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SkErodeImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const SkMatrix& ctm,
|
||||
SkBitmap* result, SkIPoint* offset) {
|
||||
SkBitmap inputBM;
|
||||
if (!SkImageFilterUtils::GetInputResultGPU(getInput(0), proxy, src, ctm, &inputBM, offset)) {
|
||||
SkBitmap input;
|
||||
if (!SkImageFilterUtils::GetInputResultGPU(getInput(0), proxy, src, ctm, &input, offset)) {
|
||||
return false;
|
||||
}
|
||||
GrTexture* input = inputBM.getTexture();
|
||||
SkIRect bounds;
|
||||
src.getBounds(&bounds);
|
||||
SkAutoTUnref<GrTexture> resultTex(apply_morphology(input, bounds,
|
||||
GrMorphologyEffect::kErode_MorphologyType, radius()));
|
||||
return SkImageFilterUtils::WrapTexture(resultTex, src.width(), src.height(), result);
|
||||
if (!this->applyCropRect(&bounds, ctm)) {
|
||||
return false;
|
||||
}
|
||||
int width = radius().width();
|
||||
int height = radius().height();
|
||||
|
||||
if (width < 0 || height < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (width == 0 && height == 0) {
|
||||
src.extractSubset(result, bounds);
|
||||
offset->fX += bounds.left();
|
||||
offset->fY += bounds.top();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!apply_morphology(input, bounds, GrMorphologyEffect::kErode_MorphologyType, radius(), result)) {
|
||||
return false;
|
||||
}
|
||||
offset->fX += bounds.left();
|
||||
offset->fY += bounds.top();
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user