diff options
-rw-r--r-- | include/effects/SkTableMaskFilter.h (renamed from include/effects/SkGammaMaskFilter.h) | 44 | ||||
-rw-r--r-- | samplecode/SampleWarp.cpp | 95 | ||||
-rw-r--r-- | src/effects/SkGammaMaskFilter.cpp | 95 | ||||
-rw-r--r-- | src/effects/SkTableMaskFilter.cpp | 127 |
4 files changed, 238 insertions, 123 deletions
diff --git a/include/effects/SkGammaMaskFilter.h b/include/effects/SkTableMaskFilter.h index fdff43d1e8..a57053d6f3 100644 --- a/include/effects/SkGammaMaskFilter.h +++ b/include/effects/SkTableMaskFilter.h @@ -14,27 +14,45 @@ * limitations under the License. */ -#ifndef SkGammaMaskFilter_DEFINED -#define SkGammaMaskFilter_DEFINED +#ifndef SkTableMaskFilter_DEFINED +#define SkTableMaskFilter_DEFINED #include "SkMaskFilter.h" #include "SkScalar.h" -/** \class SkGammaMaskFilter +/** \class SkTableMaskFilter Applies a table lookup on each of the alpha values in the mask. - An arbitrary table can be assigned, or a gamma (pow) table is computed - based on the specified exponent. + Helper methods create some common tables (e.g. gamma, clipping) */ -class SkGammaMaskFilter : public SkMaskFilter { +class SkTableMaskFilter : public SkMaskFilter { public: - SkGammaMaskFilter(); - SkGammaMaskFilter(SkScalar gamma); - SkGammaMaskFilter(const uint8_t table[256]); - virtual ~SkGammaMaskFilter(); + SkTableMaskFilter(); + SkTableMaskFilter(const uint8_t table[256]); + virtual ~SkTableMaskFilter(); - void setGamma(SkScalar gamma); - void setGammaTable(const uint8_t table[256]); + void setTable(const uint8_t table[256]); + + /** Utility that sets the gamma table + */ + static void MakeGammaTable(uint8_t table[256], SkScalar gamma); + + /** Utility that creates a clipping table: clamps values below min to 0 + and above max to 255, and rescales the remaining into 0..255 + */ + static void MakeClipTable(uint8_t table[256], uint8_t min, uint8_t max); + + static SkTableMaskFilter* CreateGamma(SkScalar gamma) { + uint8_t table[256]; + MakeGammaTable(table, gamma); + return SkNEW_ARGS(SkTableMaskFilter, (table)); + } + + static SkTableMaskFilter* CreateClip(uint8_t min, uint8_t max) { + uint8_t table[256]; + MakeClipTable(table, min, max); + return SkNEW_ARGS(SkTableMaskFilter, (table)); + } // overrides from SkMaskFilter virtual SkMask::Format getFormat(); @@ -45,7 +63,7 @@ public: virtual Factory getFactory(); protected: - SkGammaMaskFilter(SkFlattenableReadBuffer& rb); + SkTableMaskFilter(SkFlattenableReadBuffer& rb); static SkFlattenable* Factory(SkFlattenableReadBuffer&); private: diff --git a/samplecode/SampleWarp.cpp b/samplecode/SampleWarp.cpp index 16c0bc82be..b1b433397b 100644 --- a/samplecode/SampleWarp.cpp +++ b/samplecode/SampleWarp.cpp @@ -8,6 +8,84 @@ #include "SkUtils.h" #include "SkImageDecoder.h" +#include "SkBlurMaskFilter.h" +#include "SkTableMaskFilter.h" + +static void test_bigblur(SkCanvas* canvas) { + canvas->drawColor(SK_ColorBLACK); + + SkBitmap orig, mask; + SkImageDecoder::DecodeFile("/skimages/app_icon.png", &orig); + + SkMaskFilter* mf = SkBlurMaskFilter::Create(8, SkBlurMaskFilter::kNormal_BlurStyle); + SkPaint paint; + paint.setMaskFilter(mf)->unref(); + SkIPoint offset; + orig.extractAlpha(&mask, &paint, &offset); + + paint.setColor(0xFFBB8800); + paint.setColor(SK_ColorWHITE); + + int i; + canvas->save(); + float gamma = 0.8; + for (i = 0; i < 5; i++) { + paint.setMaskFilter(SkTableMaskFilter::CreateGamma(gamma))->unref(); + canvas->drawBitmap(mask, 0, 0, &paint); + paint.setMaskFilter(NULL); + canvas->drawBitmap(orig, -offset.fX, -offset.fY, &paint); + gamma -= 0.1; + canvas->translate(120, 0); + } + canvas->restore(); + canvas->translate(0, 160); + + for (i = 0; i < 5; i++) { + paint.setMaskFilter(SkTableMaskFilter::CreateClip(i*30, 255 - 20))->unref(); + canvas->drawBitmap(mask, 0, 0, &paint); + paint.setMaskFilter(NULL); + canvas->drawBitmap(orig, -offset.fX, -offset.fY, &paint); + canvas->translate(120, 0); + } + +#if 0 + paint.setColor(0xFFFFFFFF); + canvas->drawBitmap(mask, 0, 0, &paint); + paint.setMaskFilter(NULL); + canvas->drawBitmap(orig, -offset.fX, -offset.fY, &paint); + + canvas->translate(120, 0); + + canvas->drawBitmap(mask, 0, 0, &paint); + canvas->drawBitmap(mask, 0, 0, &paint); + canvas->drawBitmap(orig, -offset.fX, -offset.fY, &paint); + + canvas->translate(120, 0); + + canvas->drawBitmap(mask, 0, 0, &paint); + canvas->drawBitmap(mask, 0, 0, &paint); + canvas->drawBitmap(mask, 0, 0, &paint); + canvas->drawBitmap(orig, -offset.fX, -offset.fY, &paint); + + canvas->translate(120, 0); + + canvas->drawBitmap(mask, 0, 0, &paint); + canvas->drawBitmap(mask, 0, 0, &paint); + canvas->drawBitmap(mask, 0, 0, &paint); + canvas->drawBitmap(mask, 0, 0, &paint); + canvas->drawBitmap(orig, -offset.fX, -offset.fY, &paint); + + canvas->translate(120, 0); + + canvas->drawBitmap(mask, 0, 0, &paint); + canvas->drawBitmap(mask, 0, 0, &paint); + canvas->drawBitmap(mask, 0, 0, &paint); + canvas->drawBitmap(mask, 0, 0, &paint); + canvas->drawBitmap(mask, 0, 0, &paint); + canvas->drawBitmap(orig, -offset.fX, -offset.fY, &paint); +#endif +} + #include "SkMeshUtils.h" static SkPoint SkMakePoint(SkScalar x, SkScalar y) { @@ -240,9 +318,6 @@ void Mesh::drawWireframe(SkCanvas* canvas, const SkPaint& paint) { /////////////////////////////////////////////////////////////////////////////// -static SkScalar gScale = 0; -static SkScalar gDScale = 0.02; - class WarpView : public SkView { Mesh fMesh, fOrig; SkBitmap fBitmap; @@ -282,7 +357,8 @@ protected: } virtual void onDraw(SkCanvas* canvas) { - canvas->drawColor(SK_ColorGRAY); + canvas->drawColor(SK_ColorLTGRAY); + // test_bigblur(canvas); return; SkPaint paint; paint.setFilterBitmap(true); @@ -295,18 +371,7 @@ protected: paint.setColor(SK_ColorRED); // fMesh.draw(canvas, paint); -#if 0 - test_patch(canvas, fBitmap, gScale); - gScale += gDScale; - if (gScale > 2) { - gDScale = -gDScale; - } else if (gScale < -2) { - gDScale = -gDScale; - } - this->inval(NULL); -#else test_drag(canvas, fBitmap, fP0, fP1); -#endif } virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) { diff --git a/src/effects/SkGammaMaskFilter.cpp b/src/effects/SkGammaMaskFilter.cpp deleted file mode 100644 index ebf13fcf60..0000000000 --- a/src/effects/SkGammaMaskFilter.cpp +++ /dev/null @@ -1,95 +0,0 @@ -#include "SkGammaMaskFilter.h" - -SkGammaMaskFilter::SkGammaMaskFilter() { - for (int i = 0; i < 256; i++) { - fTable[i] = i; - } -} - -SkGammaMaskFilter::SkGammaMaskFilter(SkScalar gamma) { - this->setGamma(gamma); -} - -SkGammaMaskFilter::SkGammaMaskFilter(const uint8_t table[256]) { - this->setGammaTable(table); -} - -SkGammaMaskFilter::~SkGammaMaskFilter() {} - -void SkGammaMaskFilter::setGamma(SkScalar gamma) { - float x = 0; - const float dx = 1 / 255.0f; - for (int i = 0; i < 256; i++) { - fTable[i] = SkPin32(SkScalarRound(powf(x, gamma) * 255), 0, 255); - x += dx; - } -} - -void SkGammaMaskFilter::setGammaTable(const uint8_t table[256]) { - memcpy(fTable, table, 256); -} - -SkMask::Format SkGammaMaskFilter::getFormat() { - return SkMask::kA8_Format; -} - -bool SkGammaMaskFilter::filterMask(SkMask* dst, const SkMask& src, - const SkMatrix&, SkIPoint* margin) { - if (src.fFormat != SkMask::kA8_Format) { - return false; - } - - dst->fBounds = src.fBounds; - dst->fRowBytes = SkAlign4(dst->fBounds.width()); - dst->fFormat = SkMask::kA8_Format; - dst->fImage = NULL; - - if (src.fImage) { - dst->fImage = SkMask::AllocImage(dst->computeImageSize()); - - const uint8_t* srcP = src.fImage; - uint8_t* dstP = dst->fImage; - const uint8_t* table = fTable; - int dstWidth = dst->fBounds.width(); - int extraZeros = dst->fRowBytes - dstWidth; - - for (int y = dst->fBounds.height() - 1; y >= 0; --y) { - for (int x = dstWidth - 1; x >= 0; --x) { - dstP[x] = table[srcP[x]]; - } - srcP += src.fRowBytes; - // we can't just inc dstP by rowbytes, because if it has any - // padding between its width and its rowbytes, we need to zero those - // so that the bitters can read those safely if that is faster for - // them - dstP += dstWidth; - for (int i = extraZeros - 1; i >= 0; --i) { - *dstP++ = 0; - } - } - } - - if (margin) { - margin->set(0, 0); - } - return true; -} - -void SkGammaMaskFilter::flatten(SkFlattenableWriteBuffer& wb) { - this->INHERITED::flatten(wb); - wb.writePad(fTable, 256); -} - -SkGammaMaskFilter::SkGammaMaskFilter(SkFlattenableReadBuffer& rb) - : INHERITED(rb) { - rb.read(fTable, 256); -} - -SkFlattenable* SkGammaMaskFilter::Factory(SkFlattenableReadBuffer& rb) { - return SkNEW_ARGS(SkGammaMaskFilter, (rb)); -} - -SkFlattenable::Factory SkGammaMaskFilter::getFactory() { - return SkGammaMaskFilter::Factory; -} - diff --git a/src/effects/SkTableMaskFilter.cpp b/src/effects/SkTableMaskFilter.cpp new file mode 100644 index 0000000000..aea939f1c9 --- /dev/null +++ b/src/effects/SkTableMaskFilter.cpp @@ -0,0 +1,127 @@ +#include "SkTableMaskFilter.h" + +SkTableMaskFilter::SkTableMaskFilter() { + for (int i = 0; i < 256; i++) { + fTable[i] = i; + } +} + +SkTableMaskFilter::SkTableMaskFilter(const uint8_t table[256]) { + this->setTable(table); +} + +SkTableMaskFilter::~SkTableMaskFilter() {} + +void SkTableMaskFilter::setTable(const uint8_t table[256]) { + memcpy(fTable, table, 256); +} + +bool SkTableMaskFilter::filterMask(SkMask* dst, const SkMask& src, + const SkMatrix&, SkIPoint* margin) { + if (src.fFormat != SkMask::kA8_Format) { + return false; + } + + dst->fBounds = src.fBounds; + dst->fRowBytes = SkAlign4(dst->fBounds.width()); + dst->fFormat = SkMask::kA8_Format; + dst->fImage = NULL; + + if (src.fImage) { + dst->fImage = SkMask::AllocImage(dst->computeImageSize()); + + const uint8_t* srcP = src.fImage; + uint8_t* dstP = dst->fImage; + const uint8_t* table = fTable; + int dstWidth = dst->fBounds.width(); + int extraZeros = dst->fRowBytes - dstWidth; + + for (int y = dst->fBounds.height() - 1; y >= 0; --y) { + for (int x = dstWidth - 1; x >= 0; --x) { + dstP[x] = table[srcP[x]]; + } + srcP += src.fRowBytes; + // we can't just inc dstP by rowbytes, because if it has any + // padding between its width and its rowbytes, we need to zero those + // so that the bitters can read those safely if that is faster for + // them + dstP += dstWidth; + for (int i = extraZeros - 1; i >= 0; --i) { + *dstP++ = 0; + } + } + } + + if (margin) { + margin->set(0, 0); + } + return true; +} + +SkMask::Format SkTableMaskFilter::getFormat() { + return SkMask::kA8_Format; +} + +void SkTableMaskFilter::flatten(SkFlattenableWriteBuffer& wb) { + this->INHERITED::flatten(wb); + wb.writePad(fTable, 256); +} + +SkTableMaskFilter::SkTableMaskFilter(SkFlattenableReadBuffer& rb) + : INHERITED(rb) { + rb.read(fTable, 256); +} + +SkFlattenable* SkTableMaskFilter::Factory(SkFlattenableReadBuffer& rb) { + return SkNEW_ARGS(SkTableMaskFilter, (rb)); +} + +SkFlattenable::Factory SkTableMaskFilter::getFactory() { + return SkTableMaskFilter::Factory; +} + +/////////////////////////////////////////////////////////////////////////////// + +void SkTableMaskFilter::MakeGammaTable(uint8_t table[256], SkScalar gamma) { + float x = 0; + const float dx = 1 / 255.0f; + for (int i = 0; i < 256; i++) { + table[i] = SkPin32(SkScalarRound(powf(x, gamma) * 255), 0, 255); + x += dx; + } +} + +void SkTableMaskFilter::MakeClipTable(uint8_t table[256], uint8_t min, + uint8_t max) { + if (0 == max) { + max = 1; + } + if (min >= max) { + min = max - 1; + } + SkASSERT(min < max); + + SkFixed scale = (1 << 16) * 255 / (max - min); + memset(table, 0, min + 1); + for (int i = min + 1; i < max; i++) { + int value = SkFixedRound(scale * (i - min)); + SkASSERT(value <= 255); + table[i] = value; + } + memset(table + max, 255, 256 - max); + +#if 0 + int j; + for (j = 0; j < 256; j++) { + if (table[j]) { + break; + } + } + SkDebugf("%d %d start [%d]", min, max, j); + for (; j < 256; j++) { + SkDebugf(" %d", table[j]); + } + SkDebugf("\n\n"); +#endif +} + |