如何实现 Alpha 混合






4.80/5 (16投票s)
2003年9月22日
10分钟阅读

207339

2703
一篇包含如何创建 Alpha 效果(淡入淡出效果)的代码的文章。从将 Alpha 应用于图像开始,到创建 Alpha 动画结束。这与 Windows 中使用的逐像素 Alpha 混合无关。
涵盖的问题
本文解释了
- 什么是 Alpha 效果
- 如何从图像对象创建 Alpha 图像
- 如何应用 Alpha 绘制图形结构(文本、线条、圆弧等)
- 如何创建淡入或淡出 Alpha 动画
- 其他一些需要注意的复杂细节
此外,代码还为您提供了创建 Alpha 图像的示例。
目录
引言
Alpha 效果是您肯定见过,但可能不知情的效果。这是一种简单而有效的视觉效果,图像或文本会淡入或淡出到纯色背景或图像。如果您使用过 Macromedia® Flash®,您可能已经遇到过它。它是一种在电影、电视节目、游戏和几乎任何现有视觉媒体中广泛使用的效果。它如此常见以至于人们都没有注意到。
Alpha 效果通常用作动画。动画需要以快速连续的方式显示离散帧,并在序列中进行渐进式更改。考虑到这一点,本文的第一部分解释了如何从图像对象创建单个 Alpha 图像。接下来,它解释了如何在调用绘图方法(如线条、圆弧、文本等)时创建此效果。然后,本文继续解释如何从所有这些内容创建动画。最后,它指出了一些值得注意的小细节。
代码使用以下附加命名空间
System.Drawing
System.Drawing.2D
System.Drawing.Imaging
将 Alpha 应用于图像
如果您使用 C# 一段时间了,您可能想跳过“第一步”子部分,直接跳到“步骤 1”。“第一步”为您简要介绍了图形编程。
第一步
要在 .NET 中处理图形或格式化文本,您通常依赖 GDI+。GDI+ 只是一个 API(应用程序编程接口),它帮助程序员更好地处理显示设备和图形。
要绘制一些图形,您需要一个要处理的区域。或者更确切地说,一个将绘制图形的表面。这些表面可以是显示设备的一部分,也可以是图像本身的一部分(这就是您以编程方式修改图像的方式)。要表示和操作表面,您可以使用 Graphics
对象(System.Drawing
命名空间)。
因此,应用 Alpha 的第一步是创建要绘制到的表面的 Graphics
对象。
步骤 1:创建 Graphics 对象
如果您要处理的表面是控件的一部分,您调用控件的 CreateGraphics
方法来创建它的 Graphics
对象。例如,假设您的窗体中有一个 PictureBox
控件 pictureBox1
;以下代码将允许您创建它的 Graphics
对象
Graphics gra = pictureBox1.CreateGraphics();
如果您要处理的表面是图像的一部分,您调用静态 Graphics.FromImage
方法来创建图像对象的 Graphics
对象。图像对象由 Bitmap
或 Metafile
类的实例表示,这两个类都派生自抽象的 Image
类。例如,以下代码从文件 logo.jpg 创建一个 Bitmap
对象,然后创建它的 Graphics
对象。
Bitmap logo = new Bitmap("logo.jpg"); Graphics gra = Graphics.FromImage(logo);
Graphics
类包含几种可用于创建基本图形的方法,例如绘制矩形、填充区域等。但是要在图像上应用 Alpha,您需要更多的控制。为此,您将使用两个类:ImageAttributes
和 ColorMatrix
(System.Drawing.Imaging
命名空间)。ImageAttributes
对象允许您通过指定不同的设置(如颜色调整、灰度调整等)来控制图形的渲染方式。ColorMatrix
类可以被视为一个辅助类,其实例是 ImageAttributes
类大多数方法的参数。它包含指定 Alpha、红色、绿色和蓝色通道的值。
因此,下一步是初始化颜色矩阵对象并将其传递给 ImageAttributes
对象的相应方法。
步骤 3:创建 ImageAttributes 和 ColorMatrix 对象
一些基本知识:图像由颜色组成。图像的所有颜色通常由三种原色组成:红色、绿色和蓝色(简称 RGB)。这三种原色的不同组合创建了不同的颜色,这些颜色被称为复合颜色。通常,每种原色都可以取 0 到 255 范围内的任何值。当所有原色都为 0 时,它会创建黑色。当它们都为 255 时,它是白色。通道是图像中存在的实体,可以认为是定义特定原色可见性的东西。例如,如果您关闭红色通道,将不会显示红色(范围 0-255)。此外,一些图像中存在一个 Alpha 通道,它定义了图像的总可见性。因此,图像可能具有 RGBA 作为其通道。原色、原色可以取值的范围、通道等都取决于所使用的图像格式。这与主题无关。
颜色矩阵是包含通道值的矩阵。它是一个 5x5 矩阵,按顺序表示红色、绿色、蓝色、Alpha 通道和另一个元素 w 的值(RGBAw)。
在 ColorMatrix
对象中,矩阵的对角线元素定义了通道值,即 (0,0)、(1,1)、(2,2)、(3,3) 和 (4,4),按前面指定的顺序 - RGBAw。这些值是 float
类型,范围从 0 到 1。元素 w(在 (4,4) 处)始终为 1。
您需要做的是创建一个新的 ColorMatrix
对象并根据需要设置通道值。为此,您访问表示相应矩阵元素的属性。例如,Matrix00
属性允许您访问 (0,0) 处的元素。
初始化 ColorMatrix
对象后,您创建一个新的 ImageAttributes
对象,并将新创建的 ColorMatrix
对象分配给它。这是通过在 ImageAttributes
对象上调用 SetColorMatrix
方法来完成的。例如,以下代码创建一个 ColorMatrix
对象,将其 alpha 值设置为 0.5,然后创建一个新的 ImageAttributes
对象,将其颜色矩阵设置为刚刚创建的那个
ColorMatrix cm = new ColorMatrix();
cm.Matrix33 = 0.5;
ImageAttributes ia = new ImageAttributes();
ia.SetColorMatrix(cm);
最后一步是使用刚刚创建的 ImageAttributes
对象绘制原始图像。使用此 ImageAttributes
对象将以我们在颜色矩阵中设置的 alpha 值绘制原始图像,从而创建 alpha 图像。
步骤 4:绘制 Alpha 图像
要绘制 Alpha 图像,我们在 Graphics
对象上调用 Graphics.DrawImage
方法的其中一个重载。请注意,此重载应该接受一个 ImageAttributes
对象,我们将通过它指定渲染修改。因此,选择适当的重载并调用它。例如,以下代码使用 ImageAttributes
对象 ia
在指定位置绘制图像 ImageBitmap
gra.DrawImage(ImageBitmap,
new Rectangle(0,0,ImageBitmap.Width,ImageBitmap.Height),
0,0,ImageBitmap.Width, ImageBitmap.Height, GraphicsUnit.Pixel,
ia);
以下是我们完成的所有步骤的完整代码列表
// Get a picture box's Graphics object
Graphics gra = pictureBox1.Graphics;
// Create a new color matrix and set the alpha value to 0.5
ColorMatrix cm = new ColorMatrix();
cm.Matrix00 = cm.Matrix11 = cm.Matrix22 = cm.Matrix44 = 1;
cm.Matrix33 = 0.5;
// Create a new image attribute object and set the color matrix to
// the one just created
ImageAttributes ia = new ImageAttributes();
ia.SetColorMatrix(cm);
// Draw the original image with the image attributes specified
gra.DrawImage(ImageBitmap,
new Rectangle(0,0,ImageBitmap.Width, ImageBitmap.Height),
0,0,ImageBitmap.Width, ImageBitmap.Height, GraphicsUnit.Pixel,
ia);
将 Alpha 应用于图形结构
Graphics
类包含几种特定的绘制方法,如线条、圆弧等。当您使用此类方法时,可以直接在它们中使用时应用 Alpha,而不是像前面解释的那样将其完全应用于图像。这无疑会更直接地说明如下
Graphics
类的所有特定图形结构绘制方法(DrawIcon
和 DrawImage
除外)都使用 Pen
或 Brush
对象作为参数。Pen
和 Brush
类都有一个共同的底层元素 - Color
;这意味着这两个类都直接或间接使用 Color
结构。我们利用这一事实来简化 Alpha 的应用。
Color
结构不仅定义了 RGB 通道,还定义了 Alpha 通道。要创建一个同时定义其 Alpha 的新 Color
对象,我们使用 Color.FromArgb
方法
public static Color FromArgb(
int alpha,
int red,
int green,
int blue
);
其中每个元素的取值范围是 0-255。
这里的想法是,用所需的 alpha 值初始化一个 Color
对象,从这个 Color
结构创建适当的 Pen
或 Brush
对象,然后调用特定的绘制方法,传入刚刚创建的 Pen
或 Brush
对象。这将以 Color
结构中设置的 alpha 值绘制图形,并创建与您使用第一种方法获得的相同的 alpha 效果。
要基于 Color
对象创建 Pen
对象,请使用 Pen.Pen(Color)
构造函数。
要基于 Color
对象创建 Brush
对象,请使用 SolidBrush.SolidBrush(Color)
构造函数。SolidBrush
类派生自抽象的 Brush
类。还有其他类派生自 Brush
类,其中一些使用 Color
结构;但这又是另一回事了。
以下代码以黑色绘制字符串“Text”,alpha 值为 100。(请注意,在此过程中 100 不是 100%。这可能不会被注意到。)
gra = e.Graphics; gra.DrawString("Text", new Font("Verdana", 24), new SolidBrush(Color.FromArgb(100,0,0,0)), 0,0 );
以类似的方式,可以对其他结构进行 Alpha 效果。
创建 Alpha 动画
呈现 Alpha 效果的动画通常有两种类型:淡入和淡出。淡入动画通常以黑色背景开始,以实际图像结束。从技术上讲,起始帧的 Alpha 值为零,结束帧的 Alpha 值为 100。淡出动画则完全相反。背景也可以是另一幅图像。
要创建这两种类型中的任何一种动画,您需要创建一整序列的此类 Alpha 图像并按顺序显示它们。
首先,确定您需要的离散 Alpha 图像的数量。为了创建平滑的效果,建议至少使用 15 帧。一旦您确定了数量,就创建一个具有此大小的 Bitmap
数组。然后开始一个循环,并在数组中创建所需 Alpha 值的 Bitmap
对象。最后,根据目标,要么创建一个 Graphics
对象并绘制图像,要么将控件的 Image
属性设置为此对象。这种在内存中创建图像序列然后显示它们的方法称为双缓冲。
以下代码按照上述过程创建图像序列
int FrameCount = 15;
float opacity = 0.0F;
Bitmap original = new Bitmap("logo.jpg");
Bitmap[] frames = new Bitmap[FrameCount];
for(int x=0; x<FrameCount; x++, opacity+=0.1F)
{
Bitmap alpha = new Bitmap(original, original.Size);
Graphics gra = Graphics.FromImage(alpha);
gra.Clear(Color.Transparent);
ColorMatrix cm = new ColorMatrix();
cm.Matrix00 = cm.Matrix11 = cm.Matrix22 = cm.Matrix44 = 1;
cm.Matrix33 = opacity;
ImageAttributes ia = new ImageAttributes();
ia.SetColorMatrix(cm);
gra.DrawImage(original,
new Rectangle(0,0,original.Width,original.Height),
0,0,original.Width, original.Height, GraphicsUnit.Pixel, ia);
frames[x] = alpha;
}
为了显示它们,您可能希望使用计时器,或者控件的唯一绘制处理程序。
杂项
合成模式
当您从表面获取 Graphics
对象时,该表面上可能已经绘制了一些图像。在其顶部以完全 Alpha 绘制新图像会覆盖旧图像。以部分 Alpha 绘制新图像不一定会这样做。在这种情况下存在两种可能性:新图像覆盖旧图像,或者新图像与旧图像混合(旧图像部分显示出来)。要定义新图像的绘制方式,您可以使用 Graphics
类的 CompositingMode
属性。
CompositingMode
,在 System.Drawing.Drawing2D
命名空间中定义,是一个具有两个成员的枚举
SourceCopy
,指定新图像覆盖旧图像SourceOver
,指定新图像与旧图像根据新图像的 alpha 分量进行混合。
因此,一旦您创建了 Graphics
对象,将其 CompositingMode
属性设置为所需的成员并继续。
请注意,当您从控件创建 Graphics
对象时,新图像会自动覆盖旧图像,无论您是否将其 CompositingMode
设置为 SourceCopy
。
另请注意,当您从 Image
对象创建 Graphics
对象时,情况正好相反 - 新图像会与旧图像混合。
除了将 CompositingMode
设置为 SourceCopy
之外,您可以通过在绘制之前使用 Graphics.Clear
方法并传递 Color.Transparent
等颜色来清除表面,从而达到相同的效果。
结论
就这样。去吧!
更新
- 2003/09/22:刚发布。正在考虑在代码中添加动画部分,以及是否还有其他细节需要添加。