/* * 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 "sk_tool_utils.h" #include "Resources.h" #include "SampleCode.h" #include "SkBlurMask.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; /** * 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 bool onQuery(SkEvent* evt) 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); } void onDrawBackground(SkCanvas* canvas) override { sk_tool_utils::draw_checkerboard(canvas, 0xFFCCCCCC, 0xFFFFFFFF, 12); } void onDrawContent(SkCanvas* canvas) override { SkPaint paint; paint.setAntiAlias(true); paint.setTextSize(SkIntToScalar(24)); SkAutoTUnref<SkDrawLooper> looper( SkBlurDrawLooper::Create(SK_ColorBLUE, SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(2)), 0, 0)); paint.setLooper(looper); SkScalar height = paint.getFontMetrics(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->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::Basename(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.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; } SkFILEStream stream(fCurrFile.c_str()); SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(&stream)); if (nullptr == decoder.get()) { fDecodeSucceeded = false; return; } if (!fPremul) { decoder->setRequireUnpremultipliedColors(true); } fDecodeSucceeded = decoder->decode(&stream, &fBitmap, kN32_SkColorType, SkImageDecoder::kDecodePixels_Mode) != SkImageDecoder::kFailure; this->inval(nullptr); } void togglePremul() { fPremul = !fPremul; this->decodeCurrFile(); } typedef SampleView INHERITED; }; ////////////////////////////////////////////////////////////////////////////// static SkView* MyFactory() { return new UnpremulView(GetResourcePath()); } static SkViewRegister reg(MyFactory);