cb92744d3d
https://docs.google.com/document/d/1z9ZODlZX4XXbfOjh2t1-1Z7FJcCCcOfbrEjiFzPE4vg/edit?usp=sharing&resourcekey=0-Io-07D1zm1yKMQN2UAiYBw This approach lets us write color filters that want to work in particular color spaces and alpha formats and adapt them to our normal pipeline. It should work with pre-canned and runtime effects, and we can do the same sort of thing for shaders too. Some features are designed for using this with the high-contrast filter: - ability to change working tf and gamut separately: as written the HC effect only wants to work in linear space without changing gamut, which is I bet will be a common desired mode. But other effects may want to fully change the working color space, e.g. to sRGB or XYZ. - adapting the alpha type to unpremul is mostly a flourish: you could do it yourself in sksl, but we might as well do it if doing other transforms anyway (it's cheaper this way than doing it yourself), and this may make it easier to adapt non-runtime effects. (I bet most color filters actually want to be unpremul.) I briefly also included a knob to control how this effect treats a nullptr dst color space, but I've come back around to that not being a parameter. I think this is a situation where we know best. New GM to demo. Cq-Include-Trybots: luci.chromium.try:linux-blink-rel Change-Id: I420e3a2aa648f314c019a98bfdcd44e810a3dac6 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/368336 Commit-Queue: Mike Klein <mtklein@google.com> Reviewed-by: Mike Reed <reed@google.com>
203 lines
6.5 KiB
C++
203 lines
6.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/gm.h"
|
|
#include "include/core/SkBlendMode.h"
|
|
#include "include/core/SkCanvas.h"
|
|
#include "include/core/SkColor.h"
|
|
#include "include/core/SkColorFilter.h"
|
|
#include "include/core/SkFont.h"
|
|
#include "include/core/SkFontTypes.h"
|
|
#include "include/core/SkPaint.h"
|
|
#include "include/core/SkPoint.h"
|
|
#include "include/core/SkRect.h"
|
|
#include "include/core/SkRefCnt.h"
|
|
#include "include/core/SkScalar.h"
|
|
#include "include/core/SkShader.h"
|
|
#include "include/core/SkSize.h"
|
|
#include "include/core/SkString.h"
|
|
#include "include/core/SkTileMode.h"
|
|
#include "include/core/SkTypeface.h"
|
|
#include "include/core/SkTypes.h"
|
|
#include "include/effects/SkGradientShader.h"
|
|
#include "include/effects/SkLumaColorFilter.h"
|
|
#include "include/effects/SkRuntimeEffect.h"
|
|
#include "tools/Resources.h"
|
|
#include "tools/ToolUtils.h"
|
|
|
|
#include <string.h>
|
|
|
|
static SkScalar kSize = 80;
|
|
static SkScalar kInset = 10;
|
|
static SkColor kColor1 = SkColorSetARGB(0xff, 0xff, 0xff, 0);
|
|
static SkColor kColor2 = SkColorSetARGB(0xff, 0x82, 0xff, 0);
|
|
|
|
static void draw_label(SkCanvas* canvas, const char* label,
|
|
const SkPoint& offset) {
|
|
SkFont font(ToolUtils::create_portable_typeface());
|
|
font.setEdging(SkFont::Edging::kAlias);
|
|
|
|
size_t len = strlen(label);
|
|
|
|
SkScalar width = font.measureText(label, len, SkTextEncoding::kUTF8);
|
|
canvas->drawSimpleText(label, len, SkTextEncoding::kUTF8, offset.x() - width / 2, offset.y(),
|
|
font, SkPaint());
|
|
}
|
|
|
|
static void draw_scene(SkCanvas* canvas, const sk_sp<SkColorFilter>& filter, SkBlendMode mode,
|
|
const sk_sp<SkShader>& s1, const sk_sp<SkShader>& s2) {
|
|
SkPaint paint;
|
|
paint.setAntiAlias(true);
|
|
SkRect r, c, bounds = SkRect::MakeWH(kSize, kSize);
|
|
|
|
c = bounds;
|
|
c.fRight = bounds.centerX();
|
|
paint.setARGB(0x20, 0, 0, 0xff);
|
|
canvas->drawRect(bounds, paint);
|
|
|
|
canvas->saveLayer(&bounds, nullptr);
|
|
|
|
r = bounds;
|
|
r.inset(kInset, 0);
|
|
paint.setShader(s1);
|
|
paint.setColor(s1 ? SK_ColorBLACK : SkColorSetA(kColor1, 0x80));
|
|
canvas->drawOval(r, paint);
|
|
if (!s1) {
|
|
canvas->save();
|
|
canvas->clipRect(c);
|
|
paint.setColor(kColor1);
|
|
canvas->drawOval(r, paint);
|
|
canvas->restore();
|
|
}
|
|
|
|
SkPaint xferPaint;
|
|
xferPaint.setBlendMode(mode);
|
|
canvas->saveLayer(&bounds, &xferPaint);
|
|
|
|
r = bounds;
|
|
r.inset(0, kInset);
|
|
paint.setShader(s2);
|
|
paint.setColor(s2 ? SK_ColorBLACK : SkColorSetA(kColor2, 0x80));
|
|
paint.setColorFilter(filter);
|
|
canvas->drawOval(r, paint);
|
|
if (!s2) {
|
|
canvas->save();
|
|
canvas->clipRect(c);
|
|
paint.setColor(kColor2);
|
|
canvas->drawOval(r, paint);
|
|
canvas->restore();
|
|
}
|
|
|
|
canvas->restore();
|
|
canvas->restore();
|
|
}
|
|
|
|
class LumaFilterGM : public skiagm::GM {
|
|
protected:
|
|
void onOnceBeforeDraw() override {
|
|
SkColor g1Colors[] = { kColor1, SkColorSetA(kColor1, 0x20) };
|
|
SkColor g2Colors[] = { kColor2, SkColorSetA(kColor2, 0x20) };
|
|
SkPoint g1Points[] = { { 0, 0 }, { 0, 100 } };
|
|
SkPoint g2Points[] = { { 0, 0 }, { kSize, 0 } };
|
|
SkScalar pos[] = { 0.2f, 1.0f };
|
|
|
|
fFilter = SkLumaColorFilter::Make();
|
|
fGr1 = SkGradientShader::MakeLinear(g1Points, g1Colors, pos, SK_ARRAY_COUNT(g1Colors),
|
|
SkTileMode::kClamp);
|
|
fGr2 = SkGradientShader::MakeLinear(g2Points, g2Colors, pos, SK_ARRAY_COUNT(g2Colors),
|
|
SkTileMode::kClamp);
|
|
}
|
|
|
|
SkString onShortName() override {
|
|
return SkString("lumafilter");
|
|
}
|
|
|
|
SkISize onISize() override {
|
|
return SkISize::Make(600, 420);
|
|
}
|
|
|
|
void onDraw(SkCanvas* canvas) override {
|
|
SkBlendMode modes[] = {
|
|
SkBlendMode::kSrcOver,
|
|
SkBlendMode::kDstOver,
|
|
SkBlendMode::kSrcATop,
|
|
SkBlendMode::kDstATop,
|
|
SkBlendMode::kSrcIn,
|
|
SkBlendMode::kDstIn,
|
|
};
|
|
struct {
|
|
const sk_sp<SkShader>& fShader1;
|
|
const sk_sp<SkShader>& fShader2;
|
|
} shaders[] = {
|
|
{ nullptr, nullptr },
|
|
{ nullptr, fGr2 },
|
|
{ fGr1, nullptr },
|
|
{ fGr1, fGr2 },
|
|
};
|
|
|
|
SkScalar gridStep = kSize + 2 * kInset;
|
|
for (size_t i = 0; i < SK_ARRAY_COUNT(modes); ++i) {
|
|
draw_label(canvas, SkBlendMode_Name(modes[i]),
|
|
SkPoint::Make(gridStep * (0.5f + i), 20));
|
|
}
|
|
|
|
for (size_t i = 0; i < SK_ARRAY_COUNT(shaders); ++i) {
|
|
canvas->save();
|
|
canvas->translate(kInset, gridStep * i + 30);
|
|
for (size_t m = 0; m < SK_ARRAY_COUNT(modes); ++m) {
|
|
draw_scene(canvas, fFilter, modes[m], shaders[i].fShader1,
|
|
shaders[i].fShader2);
|
|
canvas->translate(gridStep, 0);
|
|
}
|
|
canvas->restore();
|
|
}
|
|
}
|
|
|
|
private:
|
|
sk_sp<SkColorFilter> fFilter;
|
|
sk_sp<SkShader> fGr1, fGr2;
|
|
|
|
using INHERITED = skiagm::GM;
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
DEF_GM(return new LumaFilterGM;)
|
|
|
|
DEF_SIMPLE_GM(AlternateLuma, canvas, 384,128) {
|
|
sk_sp<SkImage> img = GetResourceAsImage("images/mandrill_128.png");
|
|
if (!img) {
|
|
return;
|
|
}
|
|
|
|
// Normal luma colorfilter on the left.
|
|
SkPaint paint;
|
|
paint.setColorFilter(SkLumaColorFilter::Make());
|
|
canvas->drawImage(img, 0,0, SkSamplingOptions{}, &paint);
|
|
canvas->translate(128,0);
|
|
|
|
// Original image in the middle for reference.
|
|
canvas->drawImage(img, 0,0);
|
|
canvas->translate(128,0);
|
|
|
|
// Splatting the Y channel of XYZ on the right should result in (near) greyscale.
|
|
auto [effect, err] = SkRuntimeEffect::Make(SkString{
|
|
"uniform shader input; half4 main() { return sample(input).yyya; }"});
|
|
SkASSERT(effect && err.isEmpty());
|
|
|
|
sk_sp<SkColorFilter> input = nullptr,
|
|
filter = effect->makeColorFilter(SkData::MakeEmpty(), &input, 1);
|
|
SkASSERT(filter);
|
|
|
|
SkAlphaType unpremul = kUnpremul_SkAlphaType;
|
|
paint.setColorFilter(SkColorFilters::WithWorkingFormat(std::move(filter),
|
|
&SkNamedTransferFn::kLinear,
|
|
&SkNamedGamut::kXYZ,
|
|
&unpremul));
|
|
canvas->drawImage(img, 0,0, SkSamplingOptions{}, &paint);
|
|
}
|