skia2/samplecode/SampleUnpremul.cpp
Hal Canary f107a2fd01 SkUTF
Create new header and namespace, `SkUTF` where we are putting all of our
robust, well documented UTF-8, UTF-16, and UTF-32 functions:
`SkUTF::{Count,Next,To}UTF{8,16,32}()`.

SkUTF.h and SkUTF.cpp do not depend on the rest of Skia and are suitable
for re-use in other modules.

Some of the old UTF-{8,16} functions still live in SkUtils.h; their use
will be phased out in future CLs.

Also added more unit testing and cleaned up old tests.

Removed functions that were unused outside of tests or used only once.

Change-Id: Iaa59b8705abccf9c4ba082f855da368a0bad8380
Reviewed-on: https://skia-review.googlesource.com/143306
Reviewed-by: Ben Wagner <bungeman@google.com>
Commit-Queue: Hal Canary <halcanary@google.com>
2018-07-31 20:11:19 +00:00

182 lines
5.5 KiB
C++

/*
* 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 "DecodeFile.h"
#include "Resources.h"
#include "SampleCode.h"
#include "SkBlurMask.h"
#include "SkBlurDrawLooper.h"
#include "SkCanvas.h"
#include "SkColorPriv.h"
#include "SkOSFile.h"
#include "SkOSPath.h"
#include "SkStream.h"
#include "SkString.h"
#include "SkTypes.h"
#include "SkUtils.h"
#include "SkView.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 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[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 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));
auto looper(
SkBlurDrawLooper::Make(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->drawString(failure, 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->drawString(header, 0, height, paint);
canvas->translate(0, height);
// Help messages
header.printf("Press '%c' to move to the next image.'", fNextImageChar);
canvas->drawString(header, 0, height, paint);
canvas->translate(0, height);
header.printf("Press '%c' to toggle premultiplied decode.", fTogglePremulChar);
canvas->drawString(header, 0, height, 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();
}
typedef SampleView INHERITED;
};
//////////////////////////////////////////////////////////////////////////////
static SkView* MyFactory() {
return new UnpremulView(GetResourcePath("images"));
}
static SkViewRegister reg(MyFactory);