diff options
author | scroggo@google.com <scroggo@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2013-06-14 15:33:20 +0000 |
---|---|---|
committer | scroggo@google.com <scroggo@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2013-06-14 15:33:20 +0000 |
commit | 2bbc2c945bb0ecf18fd6473af74ad1a2f5e727a7 (patch) | |
tree | 67d590a01f682d9a821edc8f457dcaa696c7e6d5 /samplecode | |
parent | 99e0d08113738dd8ea8f52af0cdd04c971ff074a (diff) |
Add an option to create unpremultiplied bitmaps.
Currently they cannot be used directly by Skia, but
the pixels can be used elsewhere.
SkImageDecoder:
Add functions to require unpremultiplied output
and query the presence of the requirement
SkImageDecoder_libpng:
SkImageDecoder_libwebp:
SkImageDecoder_WIC:
Respect the requirement for unpremultiplied output.
TODO: Fix SkImageDecoder_CG.
SkScaledBitmapSampler:
Add procs to skip premultiplication and a boolean
parameter to use those procs.
ImageDecodingTest:
Test unpremultiplied bitmap decoding.
SampleUnpremul:
Add a sample which allows visually comparing between the
unpremultiplied version (copied into a premultiplied bitmap,
since drawing unpremultiplied is not currently supported)
and a premultiplied version of image files.
gm.h:
Add a getter for the resource path, so Samples can use it.
As of patch set 13, https://codereview.chromium.org/16816016/
and https://codereview.chromium.org/16983004/, which were
approved separately.
R=reed@google.com
Review URL: https://codereview.chromium.org/16410009
git-svn-id: http://skia.googlecode.com/svn/trunk@9612 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'samplecode')
-rw-r--r-- | samplecode/SampleColorFilter.cpp | 3 | ||||
-rw-r--r-- | samplecode/SampleUnpremul.cpp | 204 |
2 files changed, 206 insertions, 1 deletions
diff --git a/samplecode/SampleColorFilter.cpp b/samplecode/SampleColorFilter.cpp index 41392ac248..126ee4736d 100644 --- a/samplecode/SampleColorFilter.cpp +++ b/samplecode/SampleColorFilter.cpp @@ -84,7 +84,8 @@ static void test_5bits() { SkDebugf("--- trunc: %d %d round: %d %d new: %d %d\n", e0, ae0, e1, ae1, e2, ae2); } -static SkShader* createChecker() { +// No longer marked static, since it is externed in SampleUnpremul. +SkShader* createChecker() { SkBitmap bm; bm.setConfig(SkBitmap::kARGB_8888_Config, 2, 2); bm.allocPixels(); diff --git a/samplecode/SampleUnpremul.cpp b/samplecode/SampleUnpremul.cpp new file mode 100644 index 0000000000..dfdd2accdb --- /dev/null +++ b/samplecode/SampleUnpremul.cpp @@ -0,0 +1,204 @@ +/* + * Copyright 2013 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 "SampleCode.h" +#include "SkBlurDrawLooper.h" +#include "SkCanvas.h" +#include "SkColorPriv.h" +#include "SkForceLinking.h" +#include "SkImageDecoder.h" +#include "SkOSFile.h" +#include "SkStream.h" +#include "SkString.h" +#include "SkSystemEventTypes.h" +#include "SkTypes.h" +#include "SkUtils.h" +#include "SkView.h" + +__SK_FORCE_IMAGE_DECODER_LINKING; + +// Defined in SampleColorFilter.cpp +extern SkShader* createChecker(); + +/** + * Interprets c as an unpremultiplied color, and returns the + * premultiplied equivalent. + */ +static SkPMColor premultiply_unpmcolor(SkPMColor c) { + U8CPU a = SkGetPackedA32(c); + U8CPU r = SkGetPackedR32(c); + U8CPU g = SkGetPackedG32(c); + U8CPU b = SkGetPackedB32(c); + return SkPreMultiplyARGB(a, r, g, b); +} + +class UnpremulView : public SampleView { +public: + UnpremulView(SkString res) + : fResPath(res) + , fPremul(true) + , fDecodeSucceeded(false) { + this->nextImage(); + } + +protected: + // overrides from SkEventSink + virtual bool onQuery(SkEvent* evt) SK_OVERRIDE { + if (SampleCode::TitleQ(*evt)) { + SampleCode::TitleR(evt, "unpremul"); + return true; + } + SkUnichar uni; + if (SampleCode::CharQ(*evt, &uni)) { + char utf8[kMaxBytesInUTF8Sequence]; + size_t size = SkUTF8_FromUnichar(uni, utf8); + // Only consider events for single char keys + if (1 == size) { + switch (utf8[0]) { + case fNextImageChar: + this->nextImage(); + return true; + case fTogglePremulChar: + this->togglePremul(); + return true; + default: + break; + } + } + } + return this->INHERITED::onQuery(evt); + } + + virtual void onDrawBackground(SkCanvas* canvas) SK_OVERRIDE { + SkPaint paint; + SkAutoTUnref<SkShader> shader(createChecker()); + paint.setShader(shader.get()); + canvas->drawPaint(paint); + } + + virtual void onDrawContent(SkCanvas* canvas) SK_OVERRIDE { + SkPaint paint; + paint.setAntiAlias(true); + paint.setTextSize(SkIntToScalar(24)); + SkAutoTUnref<SkBlurDrawLooper> looper(SkNEW_ARGS(SkBlurDrawLooper, + (SkIntToScalar(2), 0, 0, SK_ColorBLUE))); + paint.setLooper(looper); + SkScalar height = paint.getFontMetrics(NULL); + if (!fDecodeSucceeded) { + SkString failure; + if (fResPath.size() == 0) { + failure.printf("resource path is required!"); + } else { + failure.printf("Failed to decode %s", fCurrFile.c_str()); + } + canvas->drawText(failure.c_str(), failure.size(), 0, height, paint); + return; + } + + // Name, size of the file, and whether or not it is premultiplied. + SkString header(SkOSPath::SkBasename(fCurrFile.c_str())); + header.appendf(" [%dx%d] %s", fBitmap.width(), fBitmap.height(), + (fPremul ? "premultiplied" : "unpremultiplied")); + canvas->drawText(header.c_str(), header.size(), 0, height, paint); + canvas->translate(0, height); + + // Help messages + header.printf("Press '%c' to move to the next image.'", fNextImageChar); + canvas->drawText(header.c_str(), header.size(), 0, height, paint); + canvas->translate(0, height); + + header.printf("Press '%c' to toggle premultiplied decode.", fTogglePremulChar); + canvas->drawText(header.c_str(), header.size(), 0, height, paint); + + // Now draw the image itself. + canvas->translate(height * 2, height * 2); + if (!fPremul) { + // A premultiplied bitmap cannot currently be drawn. + SkAutoLockPixels alp(fBitmap); + // Copy it to a bitmap which can be drawn, converting + // to premultiplied: + SkBitmap bm; + bm.setConfig(SkBitmap::kARGB_8888_Config, fBitmap.width(), + fBitmap.height()); + SkASSERT(fBitmap.config() == SkBitmap::kARGB_8888_Config); + if (!bm.allocPixels()) { + SkString errMsg("allocPixels failed"); + canvas->drawText(errMsg.c_str(), errMsg.size(), 0, height, paint); + return; + } + for (int i = 0; i < fBitmap.width(); ++i) { + for (int j = 0; j < fBitmap.height(); ++j) { + *bm.getAddr32(i, j) = premultiply_unpmcolor(*fBitmap.getAddr32(i, j)); + } + } + canvas->drawBitmap(bm, 0, 0); + } else { + canvas->drawBitmap(fBitmap, 0, 0); + } + } + +private: + const SkString fResPath; + SkString fCurrFile; + bool fPremul; + bool fDecodeSucceeded; + SkBitmap fBitmap; + SkOSFile::Iter fFileIter; + + static const char fNextImageChar = 'j'; + static const char fTogglePremulChar = 'h'; + + void nextImage() { + if (fResPath.size() == 0) { + return; + } + SkString basename; + if (!fFileIter.next(&basename)) { + fFileIter.reset(fResPath.c_str()); + if (!fFileIter.next(&basename)) { + // Perhaps this should draw some error message? + return; + } + } + fCurrFile = SkOSPath::SkPathJoin(fResPath.c_str(), basename.c_str()); + this->decodeCurrFile(); + } + + void decodeCurrFile() { + if (fCurrFile.size() == 0) { + fDecodeSucceeded = false; + return; + } + SkFILEStream stream(fCurrFile.c_str()); + SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(&stream)); + if (NULL == decoder.get()) { + fDecodeSucceeded = false; + return; + } + if (!fPremul) { + decoder->setRequireUnpremultipliedColors(true); + } + fDecodeSucceeded = decoder->decode(&stream, &fBitmap, + SkBitmap::kARGB_8888_Config, + SkImageDecoder::kDecodePixels_Mode); + this->inval(NULL); + } + + void togglePremul() { + fPremul = !fPremul; + this->decodeCurrFile(); + } + + typedef SampleView INHERITED; +}; + +////////////////////////////////////////////////////////////////////////////// + +static SkView* MyFactory() { + return new UnpremulView(skiagm::GM::GetResourcePath()); +} +static SkViewRegister reg(MyFactory); |