混合文本,由 FreeType 以颜色和 alpha 渲染
Blending text, rendered by FreeType in color and alpha
我正在使用 FreeType 渲染一些文本。
我要绘制文本的表面是格式为 ARGB、预乘 alpha 的位图图像。
需要的文字颜色也是ARGB。
呈现的 FT_Bitmap 具有格式 FT_PIXEL_MODE_LCD - 这是因为文本在黑色背景上以白色呈现,具有子像素抗锯齿。
所以,对于每个像素,我有 3 个数字:
Da, Dr, Dg, Db
- 目标像素 ARGB(背景图像)。
Fr, Fg, Fb
- FreeType 渲染像素(FT_Bitmap 用 FT_RENDER_MODE_LCD 渲染)
Ca, Cr, Cg, Cb
- 我要使用的文本颜色。
所以,问题是:如何正确组合这 3 个数字以获得结果位图像素。
理论上的答案还可以,甚至比代码示例还要好。
不是将 FreeType 数据解释为实际的 RGB 颜色(这些 'raw' 值用于以黑色绘制文本)而是作为目标文本颜色的 强度。
所以每个 F
颜色分量的完整强度是 F*C/255
。但是,由于您的 C
还包含一个 alpha 分量,因此强度会按比例缩放:
s' = F*C*A/(255 * 255)
当然,假设 F
、C
和 A
在 0..255 的通常范围内。 A
是分数A/255
,二次除法是把F*C
带回目标范围。 s'
现在是 派生的 源颜色。
开始策划。对于每个颜色分量,新颜色会添加到 D
,而 D
又会因源的 alpha 255-A
(缩放)而变暗。
这导致总和
D' = D*(255-A)/255 + F*C*A/(255 * 255)
等于(向右移动一个值)
D' = (D*(255-A) + F*C*A/255)/255
对于 D
、F
、C
和 A
的每个单独通道 r、g、b。最后一个,alpha,也需要对每个通道单独计算,因为你的FreeType输出数据returns这种格式。
如果计算速度太慢,您可以将视觉结果与 FreeType 的非 LCD 优化灰度输出进行比较。我怀疑特别是在 'busy'(不是完全单色)背景上,额外的计算根本不值得。
纯灰度输入的数值优势在于,您只需为每个 RGB 颜色三元组计算一次 A
和 1-A
。
"background" 也有一个 alpha 通道,但是要绘制文本 "on" 您可以将其视为 'unused'。将透明项目绘制到另一个透明项目上通常不会改变其固有透明度。
经过一番探索,我找到了正确的答案。这是令人失望的。
无法在RGBA格式的透明图片上绘制子像素渲染图形(包括字体)。
为了正确呈现此类图形,必须使用支持每种颜色的单独 Alpha 通道的格式。
例如每像素 48 位:RrGgBg,其中 r、g 和 b 分别是红色、绿色和蓝色颜色通道的 Alpha 通道。
我正在使用 FreeType 渲染一些文本。
我要绘制文本的表面是格式为 ARGB、预乘 alpha 的位图图像。
需要的文字颜色也是ARGB。
呈现的 FT_Bitmap 具有格式 FT_PIXEL_MODE_LCD - 这是因为文本在黑色背景上以白色呈现,具有子像素抗锯齿。
所以,对于每个像素,我有 3 个数字:
Da, Dr, Dg, Db
- 目标像素 ARGB(背景图像)。
Fr, Fg, Fb
- FreeType 渲染像素(FT_Bitmap 用 FT_RENDER_MODE_LCD 渲染)
Ca, Cr, Cg, Cb
- 我要使用的文本颜色。
所以,问题是:如何正确组合这 3 个数字以获得结果位图像素。
理论上的答案还可以,甚至比代码示例还要好。
不是将 FreeType 数据解释为实际的 RGB 颜色(这些 'raw' 值用于以黑色绘制文本)而是作为目标文本颜色的 强度。
所以每个 F
颜色分量的完整强度是 F*C/255
。但是,由于您的 C
还包含一个 alpha 分量,因此强度会按比例缩放:
s' = F*C*A/(255 * 255)
当然,假设 F
、C
和 A
在 0..255 的通常范围内。 A
是分数A/255
,二次除法是把F*C
带回目标范围。 s'
现在是 派生的 源颜色。
开始策划。对于每个颜色分量,新颜色会添加到 D
,而 D
又会因源的 alpha 255-A
(缩放)而变暗。
这导致总和
D' = D*(255-A)/255 + F*C*A/(255 * 255)
等于(向右移动一个值)
D' = (D*(255-A) + F*C*A/255)/255
对于 D
、F
、C
和 A
的每个单独通道 r、g、b。最后一个,alpha,也需要对每个通道单独计算,因为你的FreeType输出数据returns这种格式。
如果计算速度太慢,您可以将视觉结果与 FreeType 的非 LCD 优化灰度输出进行比较。我怀疑特别是在 'busy'(不是完全单色)背景上,额外的计算根本不值得。
纯灰度输入的数值优势在于,您只需为每个 RGB 颜色三元组计算一次 A
和 1-A
。
"background" 也有一个 alpha 通道,但是要绘制文本 "on" 您可以将其视为 'unused'。将透明项目绘制到另一个透明项目上通常不会改变其固有透明度。
经过一番探索,我找到了正确的答案。这是令人失望的。
无法在RGBA格式的透明图片上绘制子像素渲染图形(包括字体)。
为了正确呈现此类图形,必须使用支持每种颜色的单独 Alpha 通道的格式。
例如每像素 48 位:RrGgBg,其中 r、g 和 b 分别是红色、绿色和蓝色颜色通道的 Alpha 通道。