BlendMode Overview
BlendMode(混合模式)决定了当两个图形重叠时,源图像(Src,即将绘制的内容)的像素如何与目标图像(Dst,画布上已有的内容)的像素进行数学运算与融合。
在 TGFX 中,混合模式不仅涵盖了经典的 Porter-Duff 规则(主要用于处理几何形状的遮罩、裁剪与覆盖关系),还包含了丰富的色彩混合算法(如正片叠底、滤色等,用于模拟光影与材质的物理叠加效果)。
整个混合过程是像素级的精确计算:系统会根据选定的模式公式,结合 Src 与 Dst 的 R、G、B 颜色分量以及 Alpha 透明度通道,最终计算出输出到屏幕上的每一个像素点的颜色。
1. 混合模型基础 (Blend Model Basics)
所有的混合计算都基于以下三个概念:
- Src(源):你当前正在绘制的内容(例如刚刚使用
DrawImage或画笔绘制的新图形)。 - Dst(目标):画布上已经存在的内容(背景)。
- Result(结果):混合计算完成后,输出到画布上的最终像素。
预乘 Alpha (Premultiplied Alpha)
所有的颜色计算都假定颜色通道(RGB)已经预乘了透明度(Alpha)。
即对于 RGBA 颜色,存储的值实际为 (R*A, G*A, B*A, A)。
2. 完整混合模式速查 (Complete BlendModes)
以下列出了 BlendMode 中包含的 30 种枚举类型及其基本表现。每种模式都有对应的效果对比图:左侧为默认的 SrcOver 效果,右侧为当前混合模式的效果。
2.1 基础合成模式 (Porter-Duff Alpha Compositing)
这部分模式主要处理源和目标的几何覆盖关系,由经典的 Porter-Duff 规则定义。
Clear
清除目标,变为空白透明。
公式:$Result = 0$

Src
直接用源替换目标。
公式:$Result = Src$

Dst
保留目标,忽略源。
公式:$Result = Dst$

SrcOver(默认)
源覆盖在目标上方,这是最常用的默认混合模式。
公式:$Result = Src + Dst \times (1 - Src.alpha)$

DstOver
目标覆盖在源上方。
公式:$Result = Dst + Src \times (1 - Dst.alpha)$

SrcIn
仅保留源在目标内部的部分。
公式:$Result = Src \times Dst.alpha$

DstIn
仅保留目标在源内部的部分。
公式:$Result = Dst \times Src.alpha$

SrcOut
仅保留源在目标外部的部分。
公式:$Result = Src \times (1 - Dst.alpha)$

DstOut
仅保留目标在源外部的部分。
公式:$Result = Dst \times (1 - Src.alpha)$

SrcATop
源覆盖目标,但仅限目标范围内。
公式:$Result = Src \times Dst.alpha + Dst \times (1 - Src.alpha)$

DstATop
目标覆盖源,但仅限源范围内。
公式:$Result = Dst \times Src.alpha + Src \times (1 - Dst.alpha)$

Xor
源和目标不重叠的部分保留。
公式:$Result = Src \times (1 - Dst.alpha) + Dst \times (1 - Src.alpha)$

2.2 色彩混合模式 (Advanced Blend Modes)
这部分模式在处理重叠区域时,侧重于 RGB 颜色的数学运算,用于实现阴影、发光、对比度调整等高级特效。
PlusLighter
颜色相加(加色模式)。
公式:$Result = \min(Src + Dst, 1.0)$

PlusDarker
颜色相加并减 1(减色模式)。
公式:$Result = \max(Src + Dst - 1.0, 0)$

Modulate
颜色相乘(预乘 Alpha 直接相乘)。
公式:$Result = Src \times Dst$

Multiply
正片叠底(更符合直觉的相乘)。
公式:$Result = Src \times Dst + Src \times (1-Dst.A) + Dst \times (1-Src.A)$

Screen
滤色(变亮)。
公式:$Result = Src + Dst - Src \times Dst$

Overlay
叠加,根据目标亮度决定使用 Multiply 还是 Screen。

Darken
变暗,取 Src 和 Dst 中较暗的值。

Lighten
变亮,取 Src 和 Dst 中较亮的值。

ColorDodge
颜色减淡,提亮 Dst 以反映 Src。

ColorBurn
颜色加深,变暗 Dst 以反映 Src。

HardLight
强光,根据源亮度决定使用 Multiply 还是 Screen。

SoftLight
柔光,HardLight 的柔和版本。

Difference
差值。
公式:$Result = |Src - Dst|$ (带 Alpha 影响)

Exclusion
排除,Difference 的低对比度版本。

2.3 颜色通道分离模式 (Color Component Modes)
这部分模式将颜色分解为色相(Hue)、饱和度(Saturation)和明度(Luminosity),并分别组合。
Hue
保留源的色相,目标的饱和度与明度。

Saturation
保留源的饱和度,目标的色相与明度。

Color
保留源的色相与饱和度,目标的明度。

Luminosity
保留源的明度,目标的色相与饱和度。

3. 常用模式详解 (Common Modes Detail)
💡 最佳实践提醒: 复杂的混合模式(如
Multiply、Screen等)会作用于当前画布上的所有已有底层像素。在实际开发中,如果不想让某些特效和主画布的复杂背景发生意外混合,强烈建议使用canvas->saveLayer()将相关绘制内容隔离在一个单独的透明图层中处理,完成后再通过canvas->restore()合成到主画布。
这里详细剖析几个在 UI 开发和图形处理中使用频率最高的 BlendMode。
SrcOver (默认模式)
- 表现:最符合真实世界物理直觉的叠加。新画的内容(Src)像一张带透明通道的贴纸,直接贴在已有的画布(Dst)上。
- 应用:99% 的日常绘制(画线、画字、贴图)。
Multiply (正片叠底)
- 表现:将底色和上层颜色相乘。任何颜色与黑色相乘都变黑,与白色相乘保持原色。整体效果会使图像变暗。
- 应用:给物体添加阴影,或在不破坏底图纹理的情况下给底图上色。
Screen (滤色)
- 表现:与
Multiply完全相反。它反转底色和上层色后相乘再反转。与白色混合变白,与黑色混合保持原色。整体效果会使图像变亮。 - 应用:添加高光、发光特效,或者将带有黑色背景的火焰/光斑素材去掉黑底叠加上去。
Overlay (叠加)
- 表现:结合了
Multiply和Screen。如果底色较暗,则执行相乘变暗;如果底色较亮,则执行滤色变亮。它能在改变颜色的同时,极好地保留底图的明暗对比细节。 - 应用:为灰度材质图(如木纹、噪点)进行染色叠加。
DstIn (目标在内)
- 表现:仅保留画布上已有内容(Dst)在新图形(Src)范围内的部分。新图形的 RGB 颜色被完全丢弃,只使用它的 Alpha 通道作为遮罩。
- 注意:局部图形(如文字、圆形)使用
DstIn时,并不会擦除图形轮廓外部的画布内容。若要实现“用某形状精确裁剪出目标”,更推荐使用新建图层(saveLayer)配合SrcIn(见后文案例 1)。 - 应用:图片裁剪、形状交集运算。
SrcATop (源在上)
- 表现:新图形(Src)只会绘制在画布已有图形(Dst)的不透明区域内,且原有图形的透明度不受影响。
- 应用:给已经绘制好的不规则图标“换色”,而不会把颜色画到图标范围外面。
4. 经典应用场景案例 (Classic Use Cases)
案例 1:文字遮罩效果(图片裁剪到文字形状)
使用 SrcIn 结合图层隔离(saveLayer),可以轻松实现图片内容填充到文字形状内部的效果。
具体步骤如下:
- 开启独立图层:使用
saveLayer(nullptr)开启一个透明的隔离图层,防止混合计算影响主画布上的底层元素。 - 绘制遮罩(Dst):使用默认模式(
SrcOver)绘制文字,这段文字的内容将作为后续图片裁剪的“容器”和“目标(Dst)”。 - 设置混合模式:将准备用于绘制图片的
Paint对象的混合模式设为核心的tgfx::BlendMode::SrcIn。 - 绘制图片(Src):使用配置好的画笔绘制图片。在
SrcIn模式下,图片内容(Src)只会保留那些和底层文字(Dst)的 Alpha(透明度)相交的部分,其他没有文字的区域全被裁切丢弃,从而完美实现图片嵌入文字的效果。 - 合并图层:调用
restore(),将图层中已经完美裁剪并混合后的结果,一次性合成并印制回主画布。
canvas->saveLayer(nullptr);
tgfx::Paint textPaint;
canvas->drawTextBlob(myTextBlob, 10, 50, textPaint);
tgfx::Paint imagePaint;
imagePaint.setBlendMode(tgfx::BlendMode::SrcIn);
canvas->drawImage(myPhoto, 0, 0, &imagePaint);
canvas->restore();

案例 2:给黑白素描图或材质上色
使用 Multiply(正片叠底)可以在不掩盖底图阴影或纹理细节的情况下进行上色。
具体步骤如下:
- 绘制材质底图(Dst):首先在画布上绘制带有明暗细节或横纹图案的底图(如笔记本纸张)。
- 设置混合模式:将准备用于覆盖的画笔混合模式设为
tgfx::BlendMode::Multiply。 - 覆盖绘制色块(Src):使用该画笔直接在纹理区域上方覆盖绘制。上方颜色会与底部的像素发生正片叠底相乘,在给纸张染色的同时,完美保留底部的横纹和明暗细节。
canvas->drawImage(paperTexture, 0, 0);
tgfx::Paint paint;
paint.setColor(tgfx::Color::FromRGBA(100, 180, 255, 255)); // 设置颜色
paint.setBlendMode(tgfx::BlendMode::Multiply);
canvas->drawRect(tgfx::Rect::MakeWH(500, 500), paint);

