预乘 Alpha

在计算机图形中,有两种不同的方法来表示颜色值的不透明度。 Win2D 使用这两种方法。 本文介绍区别,以及用于何处。

直 alpha

使用直线(也称为线性)时,alpha:

  • RGB 值指定所绘制内容的颜色
  • alpha 值指定它的实心程度

在这个世界中,RGB 和 alpha 是独立的。 可以在不影响另一个的情况下更改其中一个。 若要使对象淡出,应逐渐减小其 alpha 值,同时保持 RGB 不变。

在使用直 alpha 格式的两种颜色之间执行源间混合:

result = (source.RGB * source.A) + (dest.RGB * (1 - source.A))

预乘 Alpha

使用预乘 alpha 时:

  • RGB 指定所绘制内容对输出的贡献颜色
  • alpha 值指定它遮盖它背后的任何东西的量

在这个世界中,RGB 和 alpha 是链接的。 若要使对象透明,必须减小其 RGB (以减少颜色) ,同时降低其 alpha (,以在) 少遮挡其背后的任何内容。 完全透明的对象不再具有任何颜色,因此只有一个值表示 100% 透明度:RGB 和 alpha 全部为零。

若要在使用预乘 alpha 格式的两种颜色之间执行源间混合,请执行以下操作:

result = source.RGB + (dest.RGB * (1 - source.A))

预乘 alpha 用于图形呈现,因为在筛选图像或组合不同图层时,预乘 alpha 提供比直 alpha 更好的结果。 有关详细信息,请参阅以下文章:

Win2D 中的 Alpha

Win2D 在其 API 图面中使用直 alpha,但预乘 alpha 用于内部呈现操作。

Windows.UI.Color 值使用直 alpha。 每当将颜色传递给 Draw*Fill* 方法、设置画笔的颜色或清除为颜色值时,此颜色都使用直 alpha 指定。

存储在位图或呈现目标中的像素值,以及在这些图面上运行的绘图或混合操作,使用预乘的 alpha。 从文件加载位图时,其内容会自动转换为预乘格式。 调用 Win2D 绘图方法时,在实际绘图发生之前,其颜色参数将从直接转换为预乘。

Win2D 图像效果使用直线和预乘 alpha 的混合。 某些效果对一种格式运行,另一些效果对另一种格式进行操作,有些效果提供属性以供选择。 每种效果类型的文档介绍了它使用哪种 alpha 模式。 始终假定效果输入数据是预乘的,因此当效果需要使用直 alpha 时,它将首先应用非多乘转换,计算效果,然后重新预乘输出。

位图 API GetPixelBytesSetPixelBytesGetPixelColorsSetPixelColors执行任何 alpha 格式转换。 它们只是直接将位值传输到基础 GPU 纹理或从基础 GPU 纹理传输位值。 这允许你观察 Win2D 在内部使用的 alpha 格式:

  • 在呈现目标上创建绘图会话
  • 调用 drawingSession.Clear(Colors.Tranparent)
  • Colors.Tranparent 定义为 R = 255、G = 255、B = 255、A = 0
  • Win2D 会将此值转换为预乘格式,产生 R = 0、G = 0、B = 0、A = 0
  • 使用 GetPixelColors 读回呈现目标的内容
  • 请注意,它包含预乘格式 RGB = 0,而不是 RGB = 255,就像原始的直 alpha 值一 Colors.Tranparent

在 alpha 格式之间转换

若要将直 alpha 颜色值转换为预乘格式,请将其 R、G 和 B 值乘以 A。若要将预乘转换为直数,请将 R、G 和 B 除以 A。

请注意,颜色信息通常表示为范围从 0 到 255 (例如, Windows.UI.Color 结构由 4 个字节) 组成。 此表示形式按 255 的系数纵向扩展,因此字节值 255 实际上意味着 1,而 128 是一半强度。 在格式转换期间必须考虑到缩放系数,因此,若要将 从直接转换为 Windows.UI.Color 预乘:

premultiplied.R = (byte)(straight.R * straight.A / 255);
premultiplied.G = (byte)(straight.G * straight.A / 255);
premultiplied.B = (byte)(straight.B * straight.A / 255);
premultiplied.A = straight.A;

如果图像数据使用错误的 alpha 格式, PremultiplyEffectUnPremultiplyEffect 可用于转换它。