/* * 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 "include/core/SkCanvas.h" #include "include/core/SkColorPriv.h" #include "include/core/SkStream.h" #include "include/core/SkString.h" #include "include/core/SkTypes.h" #include "samplecode/DecodeFile.h" #include "samplecode/Sample.h" #include "src/core/SkBlurMask.h" #include "src/core/SkOSFile.h" #include "src/utils/SkOSPath.h" #include "src/utils/SkUTF.h" #include "tools/Resources.h" #include "tools/ToolUtils.h" /** * 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 Sample { public: UnpremulView(SkString res) : fResPath(res) , fPremul(true) , fDecodeSucceeded(false) { this->nextImage(); } protected: SkString name() override { return SkString("unpremul"); } bool onChar(SkUnichar uni) override { char utf8[SkUTF::kMaxBytesInUTF8Sequence]; size_t size = SkUTF::ToUTF8(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 false; } void onDrawBackground(SkCanvas* canvas) override { ToolUtils::draw_checkerboard(canvas, 0xFFCCCCCC, 0xFFFFFFFF, 12); } void onDrawContent(SkCanvas* canvas) override { SkPaint paint; paint.setAntiAlias(true); SkFont font; font.setSize(24); SkScalar height = font.getMetrics(nullptr); 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->drawString(failure, 0, height, font, paint); return; } // Name, size of the file, and whether or not it is premultiplied. SkString header(SkOSPath::Basename(fCurrFile.c_str())); header.appendf(" [%dx%d] %s", fBitmap.width(), fBitmap.height(), (fPremul ? "premultiplied" : "unpremultiplied")); canvas->drawString(header, 0, height, font, paint); canvas->translate(0, height); // Help messages header.printf("Press '%c' to move to the next image.'", fNextImageChar); canvas->drawString(header, 0, height, font, paint); canvas->translate(0, height); header.printf("Press '%c' to toggle premultiplied decode.", fTogglePremulChar); canvas->drawString(header, 0, height, font, paint); // Now draw the image itself. canvas->translate(height * 2, height * 2); if (!fPremul) { // A premultiplied bitmap cannot currently be drawn. // Copy it to a bitmap which can be drawn, converting // to premultiplied: SkBitmap bm; bm.allocN32Pixels(fBitmap.width(), fBitmap.height()); 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::Join(fResPath.c_str(), basename.c_str()); this->decodeCurrFile(); } void decodeCurrFile() { if (fCurrFile.size() == 0) { fDecodeSucceeded = false; return; } fDecodeSucceeded = decode_file(fCurrFile.c_str(), &fBitmap, kN32_SkColorType, !fPremul); } void togglePremul() { fPremul = !fPremul; this->decodeCurrFile(); } using INHERITED = Sample; }; ////////////////////////////////////////////////////////////////////////////// DEF_SAMPLE( return new UnpremulView(GetResourcePath("images")); )