initial impl of SkImageFilters : virtual signature will change!

Do not invest too much in other subclasses until this API solidifies.



git-svn-id: http://skia.googlecode.com/svn/trunk@2903 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
reed@google.com 2011-12-20 16:19:00 +00:00
Родитель 3287949868
Коммит 32d25b6f5f
8 изменённых файлов: 726 добавлений и 7 удалений

117
gm/testimagefilters.cpp Normal file
Просмотреть файл

@ -0,0 +1,117 @@
/*
* Copyright 2011 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "gm.h"
#include "SkCanvas.h"
#include "SkColorFilter.h"
#include "SkColorPriv.h"
#include "SkShader.h"
#include "SkTestImageFilters.h"
#define FILTER_WIDTH SkIntToScalar(150)
#define FILTER_HEIGHT SkIntToScalar(200)
static SkImageFilter* make0() { return new SkDownSampleImageFilter(SK_Scalar1 / 5); }
static SkImageFilter* make1() { return new SkOffsetImageFilter(SkIntToScalar(16), SkIntToScalar(16)); }
static SkImageFilter* make2() {
SkColorFilter* cf = SkColorFilter::CreateModeFilter(SK_ColorBLUE,
SkXfermode::kSrcIn_Mode);
SkAutoUnref aur(cf);
return new SkColorFilterImageFilter(cf);
}
static SkImageFilter* make3() {
SkImageFilter* outer = new SkOffsetImageFilter(SkIntToScalar(16), SkIntToScalar(16));
SkImageFilter* inner = new SkDownSampleImageFilter(SK_Scalar1 / 5);
SkAutoUnref aur0(outer);
SkAutoUnref aur1(inner);
return new SkComposeImageFilter(outer, inner);
}
static SkImageFilter* make4() {
SkImageFilter* first = new SkOffsetImageFilter(SkIntToScalar(16), SkIntToScalar(16));
SkImageFilter* second = new SkDownSampleImageFilter(SK_Scalar1 / 5);
SkAutoUnref aur0(first);
SkAutoUnref aur1(second);
return new SkMergeImageFilter(first, second);
}
static SkImageFilter* make5() {
SkImageFilter* outer = new SkOffsetImageFilter(SkIntToScalar(16), SkIntToScalar(16));
SkImageFilter* inner = new SkDownSampleImageFilter(SK_Scalar1 / 5);
SkAutoUnref aur0(outer);
SkAutoUnref aur1(inner);
SkImageFilter* compose = new SkComposeImageFilter(outer, inner);
SkAutoUnref aur2(compose);
SkColorFilter* cf = SkColorFilter::CreateModeFilter(0x880000FF,
SkXfermode::kSrcIn_Mode);
SkAutoUnref aur3(cf);
SkImageFilter* blue = new SkColorFilterImageFilter(cf);
SkAutoUnref aur4(blue);
return new SkMergeImageFilter(compose, blue);
}
static void draw0(SkCanvas* canvas) {
SkPaint p;
p.setAntiAlias(true);
SkRect r = SkRect::MakeWH(FILTER_WIDTH, FILTER_HEIGHT);
r.inset(SK_Scalar1, SK_Scalar1);
p.setColor(SK_ColorRED);
canvas->drawOval(r, p);
}
class TestImageFiltersGM : public skiagm::GM {
public:
TestImageFiltersGM () {}
protected:
virtual SkString onShortName() {
return SkString("testimagefilters");
}
virtual SkISize onISize() { return SkISize::Make(640, 480); }
virtual void onDraw(SkCanvas* canvas) {
static SkImageFilter* (*gFilterProc[])() = {
make0, make1, make2, make3, make4, make5
};
const SkRect bounds = SkRect::MakeWH(FILTER_WIDTH, FILTER_HEIGHT);
const SkScalar dx = bounds.width() * 8 / 7;
const SkScalar dy = bounds.height() * 8 / 7;
for (size_t i = 0; i < SK_ARRAY_COUNT(gFilterProc); ++i) {
int ix = i % 3;
int iy = i / 3;
SkPaint paint;
paint.setImageFilter(gFilterProc[i]())->unref();
SkAutoCanvasRestore acr(canvas, true);
canvas->translate(ix * dx, iy * dy);
SkPaint p;
p.setColor(0xFFCCCCCC);
canvas->drawRect(bounds, p);
canvas->saveLayer(&bounds, &paint);
draw0(canvas);
}
}
private:
typedef GM INHERITED;
};
//////////////////////////////////////////////////////////////////////////////
static skiagm::GM* MyFactory(void*) { return new TestImageFiltersGM; }
static skiagm::GMRegistry reg(MyFactory);

Просмотреть файл

@ -69,6 +69,7 @@
'../src/effects/SkPorterDuff.cpp',
'../src/effects/SkRadialGradient_Table.h',
'../src/effects/SkRectShape.cpp',
'../src/effects/SkTestImageFilters.cpp',
'../src/effects/SkTransparentShader.cpp',
],
'direct_dependent_settings': {

Просмотреть файл

@ -36,6 +36,7 @@
'../gm/shapes.cpp',
'../gm/strokerects.cpp',
'../gm/strokes.cpp',
'../gm/testimagefilters.cpp',
'../gm/texdata.cpp',
'../gm/tilemodes.cpp',
'../gm/tinybitmap.cpp',

Просмотреть файл

@ -23,7 +23,17 @@ struct SkPoint;
* then be handed to the imagefilter, who in turn creates a new bitmap which
* is what will finally be drawn to the device (using the original xfermode).
*
* If the imagefilter returns false, nothing is drawn.
* THIS SIGNATURE IS TEMPORARY
*
* There are several weaknesses in this function signature:
* 1. Does not expose the destination/target device, so filters that can draw
* directly to it are unable to take advantage of that optimization.
* 2. Does not expose a way to create a "compabitible" image (i.e. gpu -> gpu)
* 3. As with #1, the filter is unable to "read" the dest (which would be slow)
*
* Therefore, we should not create any real dependencies on this API yet -- it
* is being checked in as a check-point so we can explore these and other
* considerations.
*/
class SK_API SkImageFilter : public SkFlattenable {
public:
@ -41,9 +51,15 @@ public:
* If the result image cannot be created, return false, in which case both
* the result and offset parameters will be ignored by the caller.
*/
bool filterImage(const SkBitmap& src, const SkMatrix&,
bool filterImage(const SkBitmap& src, const SkMatrix& ctm,
SkBitmap* result, SkIPoint* offset);
/**
* Given the src bounds of an image, this returns the bounds of the result
* image after the filter has been applied.
*/
bool filterBounds(const SkIRect& src, const SkMatrix& ctm, SkIRect* dst);
/**
* Experimental.
*
@ -55,8 +71,12 @@ public:
protected:
SkImageFilter() {}
explicit SkImageFilter(SkFlattenableReadBuffer& rb) : INHERITED(rb) {}
// Default impl returns false
virtual bool onFilterImage(const SkBitmap& src, const SkMatrix&,
SkBitmap* result, SkIPoint* offset);
// Default impl copies src into dst and returns true
virtual bool onFilterBounds(const SkIRect&, const SkMatrix&, SkIRect*);
private:
typedef SkFlattenable INHERITED;

Просмотреть файл

@ -0,0 +1,157 @@
#ifndef _SkTestImageFilters_h
#define _SkTestImageFilters_h
#include "SkImageFilter.h"
class SkOffsetImageFilter : public SkImageFilter {
public:
SkOffsetImageFilter(SkScalar dx, SkScalar dy) {
fOffset.set(dx, dy);
}
static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
return SkNEW_ARGS(SkOffsetImageFilter, (buffer));
}
protected:
SkOffsetImageFilter(SkFlattenableReadBuffer& buffer);
virtual bool onFilterImage(const SkBitmap& src, const SkMatrix&,
SkBitmap* result, SkIPoint* loc) SK_OVERRIDE;
virtual bool onFilterBounds(const SkIRect&, const SkMatrix&, SkIRect*) SK_OVERRIDE;
// overrides from SkFlattenable
virtual void flatten(SkFlattenableWriteBuffer&) SK_OVERRIDE;
virtual Factory getFactory() SK_OVERRIDE;
private:
SkVector fOffset;
typedef SkImageFilter INHERITED;
};
class SkComposeImageFilter : public SkImageFilter {
public:
SkComposeImageFilter(SkImageFilter* outer, SkImageFilter* inner) {
fOuter = outer;
fInner = inner;
SkSafeRef(outer);
SkSafeRef(inner);
}
virtual ~SkComposeImageFilter();
static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
return SkNEW_ARGS(SkComposeImageFilter, (buffer));
}
protected:
SkComposeImageFilter(SkFlattenableReadBuffer& buffer);
virtual bool onFilterImage(const SkBitmap& src, const SkMatrix&,
SkBitmap* result, SkIPoint* loc) SK_OVERRIDE;
virtual bool onFilterBounds(const SkIRect&, const SkMatrix&, SkIRect*) SK_OVERRIDE;
// overrides from SkFlattenable
virtual void flatten(SkFlattenableWriteBuffer&) SK_OVERRIDE;
virtual Factory getFactory() SK_OVERRIDE;
private:
SkImageFilter* fOuter;
SkImageFilter* fInner;
typedef SkImageFilter INHERITED;
};
#include "SkXfermode.h"
class SkMergeImageFilter : public SkImageFilter {
public:
SkMergeImageFilter(SkImageFilter* first, SkImageFilter* second,
SkXfermode::Mode = SkXfermode::kSrcOver_Mode);
SkMergeImageFilter(SkImageFilter* const filters[], int count,
const SkXfermode::Mode modes[] = NULL);
virtual ~SkMergeImageFilter();
static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
return SkNEW_ARGS(SkMergeImageFilter, (buffer));
}
protected:
SkMergeImageFilter(SkFlattenableReadBuffer& buffer);
virtual bool onFilterImage(const SkBitmap& src, const SkMatrix&,
SkBitmap* result, SkIPoint* loc) SK_OVERRIDE;
virtual bool onFilterBounds(const SkIRect&, const SkMatrix&, SkIRect*) SK_OVERRIDE;
// overrides from SkFlattenable
virtual void flatten(SkFlattenableWriteBuffer&) SK_OVERRIDE;
virtual Factory getFactory() SK_OVERRIDE;
private:
SkImageFilter** fFilters;
uint8_t* fModes; // SkXfermode::Mode
int fCount;
// private storage, to avoid dynamically allocating storage for our copy
// of the filters and modes (unless fCount is so large we can't fit).
intptr_t fStorage[16];
void initAlloc(int count, bool hasModes);
void init(SkImageFilter* const [], int count, const SkXfermode::Mode []);
typedef SkImageFilter INHERITED;
};
class SkColorFilter;
class SkColorFilterImageFilter : public SkImageFilter {
public:
SkColorFilterImageFilter(SkColorFilter* cf) : fColorFilter(cf) {
SkSafeRef(cf);
}
virtual ~SkColorFilterImageFilter();
static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
return SkNEW_ARGS(SkColorFilterImageFilter, (buffer));
}
protected:
SkColorFilterImageFilter(SkFlattenableReadBuffer& buffer);
virtual bool onFilterImage(const SkBitmap& src, const SkMatrix&,
SkBitmap* result, SkIPoint* loc) SK_OVERRIDE;
// overrides from SkFlattenable
virtual void flatten(SkFlattenableWriteBuffer&) SK_OVERRIDE;
virtual Factory getFactory() SK_OVERRIDE;
private:
SkColorFilter* fColorFilter;
typedef SkImageFilter INHERITED;
};
///////////////////////////////////////////////////////////////////////////////
// Fun mode that scales down (only) and then scales back up to look pixelated
class SkDownSampleImageFilter : public SkImageFilter {
public:
SkDownSampleImageFilter(SkScalar scale) : fScale(scale) {}
static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
return SkNEW_ARGS(SkDownSampleImageFilter, (buffer));
}
protected:
SkDownSampleImageFilter(SkFlattenableReadBuffer& buffer);
virtual bool onFilterImage(const SkBitmap& src, const SkMatrix&,
SkBitmap* result, SkIPoint* loc) SK_OVERRIDE;
// overrides from SkFlattenable
virtual void flatten(SkFlattenableWriteBuffer&) SK_OVERRIDE;
virtual Factory getFactory() SK_OVERRIDE;
private:
SkScalar fScale;
typedef SkImageFilter INHERITED;
};
#endif

Просмотреть файл

@ -7,6 +7,7 @@
*/
#include "SkDevice.h"
#include "SkDraw.h"
#include "SkImageFilter.h"
#include "SkMetaData.h"
#include "SkRect.h"
@ -353,7 +354,20 @@ void SkDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
void SkDevice::drawDevice(const SkDraw& draw, SkDevice* device,
int x, int y, const SkPaint& paint) {
draw.drawSprite(device->accessBitmap(false), x, y, paint);
SkBitmap output;
const SkBitmap* src = &device->accessBitmap(false);
SkImageFilter* filter = paint.getImageFilter();
if (filter) {
SkIPoint loc;
loc.set(x, y);
if (filter->filterImage(*src, *draw.fMatrix, &output, &loc)) {
src = &output;
x = loc.fX;
y = loc.fY;
}
}
draw.drawSprite(*src, x, y, paint);
}
///////////////////////////////////////////////////////////////////////////////

Просмотреть файл

@ -1976,17 +1976,30 @@ bool SkPaint::nothingToDraw() const {
//////////// Move these to their own file soon.
bool SkImageFilter::filterImage(const SkBitmap& src, const SkMatrix& matrix,
SkBitmap* result, SkIPoint* offset) {
SkBitmap* result, SkIPoint* loc) {
SkASSERT(result);
SkASSERT(offset);
return this->onFilterImage(src, matrix, result, offset);
SkASSERT(loc);
return this->onFilterImage(src, matrix, result, loc);
}
bool SkImageFilter::filterBounds(const SkIRect& src, const SkMatrix& ctm,
SkIRect* dst) {
SkASSERT(&src);
SkASSERT(dst);
return this->onFilterBounds(src, ctm, dst);
}
bool SkImageFilter::onFilterImage(const SkBitmap& src, const SkMatrix&,
SkBitmap* result, SkIPoint* offset) {
SkBitmap*, SkIPoint*) {
return false;
}
bool SkImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
SkIRect* dst) {
*dst = src;
return true;
}
bool SkImageFilter::asABlur(SkSize* sigma) const {
return false;
}

Просмотреть файл

@ -0,0 +1,396 @@
#include "SkTestImageFilters.h"
#include "SkCanvas.h"
bool SkOffsetImageFilter::onFilterImage(const SkBitmap& src,
const SkMatrix& matrix,
SkBitmap* result,
SkIPoint* loc) {
SkVector vec;
matrix.mapVectors(&vec, &fOffset, 1);
loc->fX += SkScalarRoundToInt(vec.fX);
loc->fY += SkScalarRoundToInt(vec.fY);
*result = src;
return true;
}
bool SkOffsetImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
SkIRect* dst) {
SkVector vec;
ctm.mapVectors(&vec, &fOffset, 1);
*dst = src;
dst->offset(SkScalarRoundToInt(vec.fX), SkScalarRoundToInt(vec.fY));
return true;
}
void SkOffsetImageFilter::flatten(SkFlattenableWriteBuffer& buffer) {
this->INHERITED::flatten(buffer);
buffer.writeScalar(fOffset.x());
buffer.writeScalar(fOffset.y());
}
SkOffsetImageFilter::SkOffsetImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
fOffset.fX = buffer.readScalar();
fOffset.fY = buffer.readScalar();
}
SkFlattenable::Factory SkOffsetImageFilter::getFactory() {
return CreateProc;
}
///////////////////////////////////////////////////////////////////////////////
SkComposeImageFilter::~SkComposeImageFilter() {
SkSafeUnref(fInner);
SkSafeUnref(fOuter);
}
bool SkComposeImageFilter::onFilterImage(const SkBitmap& src,
const SkMatrix& ctm,
SkBitmap* result,
SkIPoint* loc) {
if (!fOuter && !fInner) {
return false;
}
if (!fOuter || !fInner) {
return (fOuter ? fOuter : fInner)->filterImage(src, ctm, result, loc);
}
SkBitmap tmp;
return fInner->filterImage(src, ctm, &tmp, loc) &&
fOuter->filterImage(tmp, ctm, result, loc);
}
bool SkComposeImageFilter::onFilterBounds(const SkIRect& src,
const SkMatrix& ctm,
SkIRect* dst) {
if (!fOuter && !fInner) {
return false;
}
if (!fOuter || !fInner) {
return (fOuter ? fOuter : fInner)->filterBounds(src, ctm, dst);
}
SkIRect tmp;
return fInner->filterBounds(src, ctm, &tmp) &&
fOuter->filterBounds(tmp, ctm, dst);
}
void SkComposeImageFilter::flatten(SkFlattenableWriteBuffer& buffer) {
this->INHERITED::flatten(buffer);
buffer.writeFlattenable(fOuter);
buffer.writeFlattenable(fInner);
}
SkComposeImageFilter::SkComposeImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
fOuter = (SkImageFilter*)buffer.readFlattenable();
fInner = (SkImageFilter*)buffer.readFlattenable();
}
SkFlattenable::Factory SkComposeImageFilter::getFactory() {
return CreateProc;
}
///////////////////////////////////////////////////////////////////////////////
template <typename T> T* SkSafeRefReturn(T* obj) {
SkSafeRef(obj);
return obj;
}
void SkMergeImageFilter::initAlloc(int count, bool hasModes) {
if (count < 1) {
fFilters = NULL;
fModes = NULL;
fCount = 0;
} else {
int modeCount = hasModes ? count : 0;
size_t size = sizeof(SkImageFilter*) * count + sizeof(uint8_t) * modeCount;
if (size <= sizeof(fStorage)) {
fFilters = SkTCast<SkImageFilter**>(fStorage);
} else {
fFilters = SkTCast<SkImageFilter**>(sk_malloc_throw(size));
}
fModes = hasModes ? SkTCast<uint8_t*>(fFilters + count) : NULL;
fCount = count;
}
}
void SkMergeImageFilter::init(SkImageFilter* const filters[], int count,
const SkXfermode::Mode modes[]) {
this->initAlloc(count, !!modes);
for (int i = 0; i < count; ++i) {
fFilters[i] = SkSafeRefReturn(filters[i]);
if (modes) {
fModes[i] = SkToU8(modes[i]);
}
}
}
SkMergeImageFilter::SkMergeImageFilter(SkImageFilter* first, SkImageFilter* second,
SkXfermode::Mode mode) {
SkImageFilter* filters[] = { first, second };
SkXfermode::Mode modes[] = { mode, mode };
this->init(filters, 2, SkXfermode::kSrcOver_Mode == mode ? NULL : modes);
}
SkMergeImageFilter::SkMergeImageFilter(SkImageFilter* const filters[], int count,
const SkXfermode::Mode modes[]) {
this->init(filters, count, modes);
}
SkMergeImageFilter::~SkMergeImageFilter() {
for (int i = 0; i < fCount; ++i) {
SkSafeUnref(fFilters[i]);
}
if (fFilters != SkTCast<SkImageFilter**>(fStorage)) {
sk_free(fFilters);
// fModes is allocated in the same block as fFilters, so no need to
// separately free it.
}
}
bool SkMergeImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
SkIRect* dst) {
if (fCount < 1) {
return false;
}
SkIRect totalBounds;
for (int i = 0; i < fCount; ++i) {
SkImageFilter* filter = fFilters[i];
SkIRect r;
if (filter) {
if (!filter->filterBounds(src, ctm, &r)) {
return false;
}
} else {
r = src;
}
if (0 == i) {
totalBounds = r;
} else {
totalBounds.join(r);
}
}
// don't modify dst until now, so we don't accidentally change it in the
// loop, but then return false on the next filter.
*dst = totalBounds;
return true;
}
bool SkMergeImageFilter::onFilterImage(const SkBitmap& src, const SkMatrix& ctm,
SkBitmap* result, SkIPoint* loc) {
if (fCount < 1) {
return false;
}
const SkIRect srcBounds = SkIRect::MakeXYWH(loc->x(), loc->y(),
src.width(), src.height());
SkIRect bounds;
if (!this->filterBounds(srcBounds, ctm, &bounds)) {
return false;
}
const int x0 = bounds.left();
const int y0 = bounds.top();
SkBitmap dst;
dst.setConfig(SkBitmap::kARGB_8888_Config, bounds.width(), bounds.height());
dst.allocPixels();
dst.eraseColor(0);
SkCanvas canvas(dst);
SkPaint paint;
for (int i = 0; i < fCount; ++i) {
SkBitmap tmp;
const SkBitmap* srcPtr;
SkIPoint pos = *loc;
SkImageFilter* filter = fFilters[i];
if (filter) {
if (!filter->filterImage(src, ctm, &tmp, &pos)) {
return false;
}
srcPtr = &tmp;
} else {
srcPtr = &src;
}
if (fModes) {
paint.setXfermodeMode((SkXfermode::Mode)fModes[i]);
} else {
paint.setXfermode(NULL);
}
canvas.drawSprite(*srcPtr, pos.x() - x0, pos.y() - y0, &paint);
}
loc->set(bounds.left(), bounds.top());
result->swap(dst);
return true;
}
void SkMergeImageFilter::flatten(SkFlattenableWriteBuffer& buffer) {
this->INHERITED::flatten(buffer);
int storedCount = fCount;
if (fModes) {
// negative count signals we have modes
storedCount = -storedCount;
}
buffer.write32(storedCount);
if (fCount) {
for (int i = 0; i < fCount; ++i) {
buffer.writeFlattenable(fFilters[i]);
}
if (fModes) {
buffer.write(fModes, fCount * sizeof(fModes[0]));
}
}
}
SkMergeImageFilter::SkMergeImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
int storedCount = buffer.readS32();
this->initAlloc(SkAbs32(storedCount), storedCount < 0);
for (int i = 0; i < fCount; ++i) {
fFilters[i] = (SkImageFilter*)buffer.readFlattenable();
}
if (fModes) {
SkASSERT(storedCount < 0);
buffer.read(fModes, fCount * sizeof(fModes[0]));
} else {
SkASSERT(storedCount >= 0);
}
}
SkFlattenable::Factory SkMergeImageFilter::getFactory() {
return CreateProc;
}
///////////////////////////////////////////////////////////////////////////////
#include "SkColorFilter.h"
SkColorFilterImageFilter::~SkColorFilterImageFilter() {
SkSafeUnref(fColorFilter);
}
bool SkColorFilterImageFilter::onFilterImage(const SkBitmap& src,
const SkMatrix& matrix,
SkBitmap* result,
SkIPoint* loc) {
if (SkBitmap::kARGB_8888_Config != src.config()) {
return false;
}
SkColorFilter* cf = fColorFilter;
if (NULL == cf) {
*result = src;
return true;
}
SkAutoLockPixels alpsrc(src);
if (!src.readyToDraw()) {
return false;
}
SkBitmap dst(src);
dst.allocPixels();
if (!dst.readyToDraw()) {
return false;
}
for (int y = 0; y < src.height(); ++y) {
cf->filterSpan(src.getAddr32(0, y), src.width(), dst.getAddr32(0, y));
}
result->swap(dst);
return true;
}
void SkColorFilterImageFilter::flatten(SkFlattenableWriteBuffer& buffer) {
this->INHERITED::flatten(buffer);
buffer.writeFlattenable(fColorFilter);
}
SkColorFilterImageFilter::SkColorFilterImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
fColorFilter = (SkColorFilter*)buffer.readFlattenable();
}
SkFlattenable::Factory SkColorFilterImageFilter::getFactory() {
return CreateProc;
}
///////////////////////////////////////////////////////////////////////////////
bool SkDownSampleImageFilter::onFilterImage(const SkBitmap& src,
const SkMatrix& matrix,
SkBitmap* result, SkIPoint*) {
SkScalar scale = fScale;
if (scale > SK_Scalar1 || scale <= 0) {
return false;
}
int dstW = SkScalarRoundToInt(src.width() * scale);
int dstH = SkScalarRoundToInt(src.height() * scale);
if (dstW < 1) {
dstW = 1;
}
if (dstH < 1) {
dstH = 1;
}
SkBitmap dst;
dst.setConfig(SkBitmap::kARGB_8888_Config, dstW, dstH);
dst.allocPixels();
dst.eraseColor(0);
// downsample
{
SkPaint paint;
paint.setFilterBitmap(true);
SkCanvas canvas(dst);
canvas.scale(scale, scale);
canvas.drawBitmap(src, 0, 0, &paint);
}
result->setConfig(SkBitmap::kARGB_8888_Config, src.width(), src.height());
result->allocPixels();
result->eraseColor(0);
// upscale
{
SkRect r = SkRect::MakeWH(SkIntToScalar(result->width()),
SkIntToScalar(result->height()));
SkCanvas canvas(*result);
canvas.drawBitmapRect(dst, NULL, r, NULL);
}
return true;
}
void SkDownSampleImageFilter::flatten(SkFlattenableWriteBuffer& buffer) {
this->INHERITED::flatten(buffer);
buffer.writeScalar(fScale);
}
SkDownSampleImageFilter::SkDownSampleImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
fScale = buffer.readScalar();
}
SkFlattenable::Factory SkDownSampleImageFilter::getFactory() {
return CreateProc;
}