Skia---常用的颜色过滤器

阴影

Skia为绘制路径的阴影提供了一个工具函数,如下代码所示:

// #include "include/utils/SkShadowUtils.h"
// #include "include/core/SkPoint3.h"

void drawPathShadow(SkCanvas* canvas) {
    SkPath path;
    path.addRect(SkRect::MakeLTRB(80, 80, w - 80, h - 80));
    auto zPlaneParams = SkPoint3::Make(0, 0, 80);
    auto lightPos = SkPoint3::Make(0, 0, 0);
    SkShadowUtils::DrawShadow(canvas, path, zPlaneParams, lightPos, 80.f, 0xFF00FFFF, SK_ColorTRANSPARENT);
}

SkShadowUtils::DrawShadow 方法用于绘制阴影,第三个参数为阴影与 z 平面的关系。第四个参数为光源的位置和半径。第五个参数是阴影的模糊半径。第六个参数为阴影的起始颜色。第七个参数为阴影的终止颜色。

程序最终运行的效果图如下所示:

阴影.png

除此之外,你还可以用 SkImageFilters 来绘制阴影,如下代码所示:

void drawPathShadow2(SkCanvas* canvas) {
    SkPaint paint;
    paint.setStroke(false);
    paint.setColor(0xFF00FFFF);
    sk_sp<SkImageFilter> dropShadowFilter = SkImageFilters::DropShadow(
        0, 0, // 阴影偏移 (dx, dy)
        18.0f, 18.0f, // 模糊半径 (sigmaX, sigmaY)
        0xffffffff, // 阴影颜色
        nullptr // 输入图像过滤器
    );
    paint.setImageFilter(dropShadowFilter); 
    auto rect = SkRect::MakeXYWH(w / 2 - 100, h / 2 - 100, 200, 200);
    SkVector radii[4]{
        {16, 16},  // 矩形左上角圆角尺寸;
        {16, 16},  // 矩形右上角圆角尺寸;
        {16, 16},  // 矩形右下角圆角尺寸;
        {16, 16}   // 矩形左下角圆角尺寸;
    };
    SkRRect rr;
    rr.setRectRadii(rect, radii);
    canvas->drawRRect(rr, paint);
}

这段代码中使用 SkImageFilters::DropShadow 方法创建了一个 SkImageFilter 对象,并使用这个对象来绘制阴影。

此方法前两个参数分别是阴影在 x 和 y 方向上的偏移量,第三、四个参数为阴影的模糊半径,第五个参数是阴影的颜色。第六个参数也是一个图像过滤器,用于叠加两个过滤器效果,我们暂时不需要这个参数,所以输入一个空指针。

我们通过 paint.setImageFilter 方法把这个 SkImageFilter 对象设置给 paint 对象。

程序运行的结果如下图所示:

阴影2.png

模糊

Skia为绘制模糊颜色也提供了支持,如下代码所示:

// #include "include/core/SkMaskFilter.h"
// #include "include/core/SkBlurTypes.h"

void drawBlur(SkCanvas* canvas) {
    SkPaint paint;
    paint.setAntiAlias(true);
    paint.setColor(0xFF00FFFF);
    auto filter = SkMaskFilter::MakeBlur(SkBlurStyle::kNormal_SkBlurStyle, 8);
    paint.setMaskFilter(filter);
    auto r = std::min(w / 2 - 60, h / 2 - 60);
    canvas->drawCircle(w / 2, h / 2, r, paint);
}

SkMaskFilter::MakeBlur 方法用于创建一个 SkMaskFilter 对象,方法的第一个参数是模糊类型,这里我们使用默认的模糊类型(路径内部外部同时模糊)。第二个参数为高斯模糊的标准偏差。参数必须为大于0。

我们通过 paint.setMaskFilter 方法把这个 SkMaskFilter 对象设置给 paint 对象。

程序最终的运行结果如下图所示:

模糊.png

SkMaskFilter 可以用于绘制模糊的几何图形,但无法用于绘制模糊的图像,要想让一个图像变得模糊,应该使用SkImageFilter 对象,如下代码所示:

void blurImg(SkCanvas* canvas) {
    canvas->clear(0xFFFFFFFF);
    auto img = getImg();
    auto rect = SkRect::MakeXYWH(0, 0, w, h);
    SkSamplingOptions imgOption{ SkFilterMode::kLinear, SkMipmapMode::kLinear };
    SkPaint paint;
    sk_sp<SkImageFilter> filter = SkImageFilters::Blur(10, 10, nullptr, {});
    paint.setImageFilter(filter);
    canvas->drawImageRect(img, rect, imgOption, &paint);
}

在这段代码中,使用 SkImageFilters::Blur 方法创建了一个 SkImageFilter 对象

此方法的前两个参数分别是水平和垂直方向上的模糊值(高斯模糊),第三个参数是图像模糊滤镜,如果不设置则使用源图像;第四个参数是一个可选的矩形区域,用于限定模糊效果的应用范围,示例中我们的模糊效果应用于整个图像。

运行程序,结果如下图所示:

模糊图像.png

滤色

绘制图像时,可以使用颜色合成模式来控制图像的像素,如下代码所示:

void imgBlendColor(SkCanvas* canvas) {
    canvas->clear(0xFFFFFFFF);
    auto img = getImg();
    auto rect = SkRect::MakeXYWH(0, 0, w, h);
    SkSamplingOptions imgOption{ SkFilterMode::kLinear, SkMipmapMode::kLinear };
    SkPaint paint;
    sk_sp<SkColorFilter> filter = SkColorFilters::Blend(0xff000000, SkBlendMode::kSrcATop);  //SkBlendMode::kXor
    paint.setColorFilter(filter);
    canvas->drawImageRect(img, rect, imgOption, &paint);
}

在这段代码中,使用 SkColorFilters::Blend 方法创建了一个 SkColorFilter 对象,

这个方法的第一个参数为源颜色,此处设置为黑色(0xff000000),第二个参数(SkBlendMode::kSrcATop)将源颜色与目标颜色(图像里的颜色)混合,结果颜色的 Alpha 值取决于源颜色的 Alpha 值。

程序运行得结果如下图所示:

图像Blend.png

颜色矩阵

SkColorMatrix 用于表示颜色矩阵。 通过设置颜色矩阵中的值,可以实现各种颜色效果,比如调整亮度、对比度、饱和度,或者将颜色转换为灰度。

SkColorMatrix 内置一个 5x4 的矩阵,用于定义颜色变换。每个颜色通道(红、绿、蓝、透明度)都可以通过矩阵变换进行独立调整。如下代码所示:

void colorFilter(SkCanvas* canvas) {
    SkPaint paint;
    auto x = w / 2;
    auto y = h / 2;
    //绘制锥型渐变的代码
    SkColor colors[6]{ 0xFF00FFFF, 0xFFFFFF66, 0xFFFF00FF, 0xFF66FFFF, 0xFFFFFF00, 0xFFFF66FF };
    auto shader = SkGradientShader::MakeTwoPointConical(SkPoint::Make(x, y), y, SkPoint::Make(x, 60.0f), 20.0f,
        colors, nullptr, 6, SkTileMode::kClamp);
    paint.setShader(shader);
    //颜色矩阵
    SkColorMatrix colorMatrix;
    colorMatrix.setSaturation(0);
    auto filter = SkColorFilters::Matrix(colorMatrix);
    paint.setColorFilter(filter);
    canvas->drawPaint(paint);
}

在上述代码中 colorMatrix.setSaturation(0) 是将颜色矩阵的饱和度设置为 0(0:完全灰度,1:原始饱和度),这意味着它会将图像转换为灰度。

设置饱和度为 0 的意义在于去除颜色信息,只保留亮度信息。换句话说,图像中的每个像素都将变成其对应的灰度值。

颜色过滤器.png

如果你想更细致得控制图像的渲染效果,那么你也可以使用颜色矩阵来完成工作,如下代码所示:

void imgColorFilter(SkCanvas* canvas) {
    canvas->clear(0xFFFFFFFF);
    auto img = getImg();
    auto rect = SkRect::MakeXYWH(0, 0, w, h);
    SkSamplingOptions imgOption{ SkFilterMode::kLinear, SkMipmapMode::kLinear };
    SkPaint paint;
    SkScalar colorMatrix[20] = {
    0, 0, 1, 0, 0,
    0, 1, 0, 0, 0,
    1, 0, 0, 0, 0,
    0, 0, 0, 1, 0 }; // mix G and A.
    sk_sp<SkColorFilter> filter = SkColorFilters::Matrix(colorMatrix);
    paint.setColorFilter(filter);
    canvas->drawImageRect(img, rect, imgOption, &paint);
}

colorMatrix 是一个颜色矩阵(二位数组),这个矩阵每一列对应于输入颜色的一个分量R、G、B、A,最后一列是一个常数列。每一行则对应于输出颜色的一个分量,四行分别是输出颜色的:R、G、B、A。

比如,第一行的五个值控制着输出颜色红色分量的值,它由输入颜色的R、G、B、A分量以及一个常数偏移量决定。。

这种布局允许你处理颜色空间的转换,包括但不限于亮度调整、对比度调整、灰度化、色相旋转、饱和度调整等。

程序运行的结果如下图所示:

颜色矩阵2.png

噪声颜色

噪声颜色并不是过滤器,而是一种着色器,常用于绘制某一具体事物的表面纹理或背景,如下代码所示:

// #include "include/effects/SkPerlinNoiseShader.h"

void drawNoiseColor(SkCanvas* canvas) {
    canvas->clear(SK_ColorWHITE);
    SkPaint paint;
    auto shader = SkShaders::MakeFractalNoise(0.1f, 0.1f, 6, 0.0f, nullptr);
    //auto shader = SkShaders::MakeTurbulence(0.1f, 0.1f, 6, 0.0f, nullptr);
    paint.setShader(shader);
    canvas->drawPaint(paint);
}

SkShaders::MakeFractalNoise 方法负责创建噪声颜色的着色器。

此方法的前两个参数用于描述噪声颜色在水平向和垂直方向上的频率,它们决定了噪声图案的粒度。较高的值会产生较小、较精细的噪声,而较低的值会产生较大、较粗糙的噪声,这两个值的取值范围应该在0-1之间。

第三个参数为 八度数量,增加八度数量可以提高噪声的频率和复杂性,从而产生更多细节。减少八度数量将产生较平滑的结果,此值应小于255。第四个参数用于初始化噪声生成器的随机状态。

程序运行结果如下图所示:

噪声色.png

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

liulun

如果文章真帮到了你,谢谢您打赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值