aboutsummaryrefslogtreecommitdiffhomepage
path: root/samplecode
diff options
context:
space:
mode:
authorGravatar scroggo@google.com <scroggo@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-06-14 15:33:20 +0000
committerGravatar scroggo@google.com <scroggo@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-06-14 15:33:20 +0000
commit2bbc2c945bb0ecf18fd6473af74ad1a2f5e727a7 (patch)
tree67d590a01f682d9a821edc8f457dcaa696c7e6d5 /samplecode
parent99e0d08113738dd8ea8f52af0cdd04c971ff074a (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.cpp3
-rw-r--r--samplecode/SampleUnpremul.cpp204
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);