65.9K
CodeProject 正在变化。 阅读更多。
Home

如何实现 Alpha 混合

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.80/5 (16投票s)

2003年9月22日

10分钟阅读

viewsIcon

207339

downloadIcon

2703

一篇包含如何创建 Alpha 效果(淡入淡出效果)的代码的文章。从将 Alpha 应用于图像开始,到创建 Alpha 动画结束。这与 Windows 中使用的逐像素 Alpha 混合无关。

Sample Image - alphafx.gif

涵盖的问题

本文解释了

  • 什么是 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 对象。图像对象由 BitmapMetafile 类的实例表示,这两个类都派生自抽象的 Image 类。例如,以下代码从文件 logo.jpg 创建一个 Bitmap 对象,然后创建它的 Graphics 对象。

Bitmap logo = new Bitmap("logo.jpg");
Graphics gra = Graphics.FromImage(logo);

Graphics 类包含几种可用于创建基本图形的方法,例如绘制矩形、填充区域等。但是要在图像上应用 Alpha,您需要更多的控制。为此,您将使用两个类:ImageAttributesColorMatrixSystem.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 类的所有特定图形结构绘制方法(DrawIconDrawImage 除外)都使用 PenBrush 对象作为参数。PenBrush 类都有一个共同的底层元素 - 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 结构创建适当的 PenBrush 对象,然后调用特定的绘制方法,传入刚刚创建的 PenBrush 对象。这将以 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:刚发布。正在考虑在代码中添加动画部分,以及是否还有其他细节需要添加。
© . All rights reserved.