From 3cfda413a2eadedc1ef9db3c980e78f4d415d6dc Mon Sep 17 00:00:00 2001 From: "reed@android.com" Date: Thu, 29 Oct 2009 15:19:10 +0000 Subject: [PATCH] add gamma maskfilter, especially nice when applied after a blur git-svn-id: http://skia.googlecode.com/svn/trunk@411 2bbb7eff-a529-9590-31e7-b0007b416f81 --- include/effects/SkGammaMaskFilter.h | 58 ++++++++++++++++++++++ src/effects/SkGammaMaskFilter.cpp | 95 +++++++++++++++++++++++++++++++++++++ 2 files changed, 153 insertions(+) create mode 100644 include/effects/SkGammaMaskFilter.h create mode 100644 src/effects/SkGammaMaskFilter.cpp diff --git a/include/effects/SkGammaMaskFilter.h b/include/effects/SkGammaMaskFilter.h new file mode 100644 index 0000000..fdff43d --- /dev/null +++ b/include/effects/SkGammaMaskFilter.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkGammaMaskFilter_DEFINED +#define SkGammaMaskFilter_DEFINED + +#include "SkMaskFilter.h" +#include "SkScalar.h" + +/** \class SkGammaMaskFilter + + 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. + */ +class SkGammaMaskFilter : public SkMaskFilter { +public: + SkGammaMaskFilter(); + SkGammaMaskFilter(SkScalar gamma); + SkGammaMaskFilter(const uint8_t table[256]); + virtual ~SkGammaMaskFilter(); + + void setGamma(SkScalar gamma); + void setGammaTable(const uint8_t table[256]); + + // overrides from SkMaskFilter + virtual SkMask::Format getFormat(); + virtual bool filterMask(SkMask*, const SkMask&, const SkMatrix&, SkIPoint*); + + // overrides from SkFlattenable + virtual void flatten(SkFlattenableWriteBuffer& wb); + virtual Factory getFactory(); + +protected: + SkGammaMaskFilter(SkFlattenableReadBuffer& rb); + static SkFlattenable* Factory(SkFlattenableReadBuffer&); + +private: + uint8_t fTable[256]; + + typedef SkMaskFilter INHERITED; +}; + +#endif + diff --git a/src/effects/SkGammaMaskFilter.cpp b/src/effects/SkGammaMaskFilter.cpp new file mode 100644 index 0000000..ebf13fc --- /dev/null +++ b/src/effects/SkGammaMaskFilter.cpp @@ -0,0 +1,95 @@ +#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; +} + -- 2.7.4