Issues covered
This article explains:
- what the Alpha effect is
- how to create alpha images out of image objects
- how to draw graphic constructs (text, lines, arcs etc.) applying alpha
- how to create a fade-in or fade-out alpha animation
- some other intricacies to be noted
Additionally, the code gives you an example on creating alpha images.
Table of contents
Introduction
An Alpha effect is something that you definitely have seen, though may be unknowingly. It's a simple but effective visual effect where images or text fade in or out to a solid background or an image. You probably have come across it if you have used Macromedia® Flash®. It's an effect that has been used extensively in movies, television programs, games and almost any visual media that exists. It's so common that it goes unnoticed.
An alpha effect is usually employed as an animation. And animations require discrete frames to be displayed in quick succession with progressive alterations in sequence. Keeping this in mind, the first part of this article explains how to create a single alpha image out of image objects. Next, it explains how you could create this effect when calling drawing methods like that of lines, arcs, text etc. The article then goes on to explain how to create an animation out of all that. Finally, it points out some little details worth to be noted.
The code uses the following additional namespaces:
System.Drawing
System.Drawing.2D
System.Drawing.Imaging
Applying alpha on images
If you have been working in C# for some time, you might want to skip the subsection 'The first steps' and proceed to 'Step 1'. 'The first steps' gives you a small introduction to graphics programming.
The first steps
To work with graphics or with formatted text in .NET, you usually rely on GDI+. GDI+ is simply an API (Application Programming Interface) that helps programmers work with display devices and graphics better.
To draw some graphics, you need an area where you want to work upon. Or in better words, a surface where the graphics will be drawn. These surfaces can be portions of display devices or of images themselves (this is how you modify an image programmatically). To represent a surface and to work on it, you use a Graphics
object (System.Drawing
namespace).
So, the first step in applying alpha is to create a Graphics
object of the surface you want to draw onto.
Step 1: Creating a Graphics object
If the surface you want to work upon is a portion of a control, you call the control's CreateGraphics
method to create it's Graphics
object. For example, suppose you have a PictureBox
control, pictureBox1
in your form; the following code will let you create it's Graphics
object:
Graphics gra = pictureBox1.CreateGraphics();
If the surface you want to work upon is a portion of an image, you call the static Graphics.FromImage
method to create the image object's Graphics
object. Image objects are represented by instances of either the Bitmap
or the Metafile
class, both of which derive from the abstract Image
class. For example, the following code creates a Bitmap
object from a file logo.jpg, and then creates it's Graphics
object.
Bitmap logo = new Bitmap("logo.jpg");
Graphics gra = Graphics.FromImage(logo);
The Graphics
class contains several methods you can use to create basic graphics like drawing rectangles, filling regions and so on. But to apply alpha on images, you need more control. For this, you will use two classes: ImageAttributes
and ColorMatrix
(System.Drawing.Imaging
namespace). An ImageAttributes
object lets you control the way graphics is rendered by letting you specify different settings like color adjustment, grayscale adjustment and more. The ColorMatrix
class can be considered as a helper class whose instances are parameters in most of the methods of the ImageAttributes
class. It contains values specifying the Alpha, Red, Green and Blue channels.
So, the next step is to initialize a color matrix object and pass it to the appropriate method of an ImageAttributes
object.
Step 3: Creating the ImageAttributes and ColorMatrix objects
A few basics: An image is composed of colors. All the colors of an image is usually made up of three primary colors: Red, Green and Blue (RGB in short). Different combinations of these three primary colors create different colors which are known as composite colors. Normally, each primary color can take any value in the range of 0 to 255. When all the primary colors have the value 0, then it creates the color black. When all of them are 255, it's white. A Channel is an entity present in images, which can be thought of as what defines the visibility of a specific primary color. For example, if you cut off the Red channel, no Red color (of range 0-255) will be displayed. Additionally, an Alpha channel exists in some images, which defines the total visibility of the image. Hence, an image may have RGBA as it's channels. The primary colors, the range of values a primary color can take, the channels, etc. are all dependent on the image format used. That is off-track.
A color matrix is a matrix that contains values for channels. It's a 5x5 matrix which represents values for the Red, Green, Blue, Alpha channels and another element w, in that order (RGBAw).
In a ColorMatrix
object, the diagonal elements of the matrix define the channel values viz. (0,0), (1,1), (2,2), (3,3), and (4,4), in the order as specified before - RGBAw. The values are of type float
, and range from 0 to 1. The element w (at (4,4) ) is always 1.
What you have to do is to create a new ColorMatrix
object and set the channel values as required. To do this, you access the properties representing the respective matrix elements. For example, the Matrix00
property lets you access the element at (0,0).
Once you initialize the ColorMatrix
object, you create a new ImageAttributes
object, and assign the newly created ColorMatrix
object to it. This is done by calling the SetColorMatrix
method on the ImageAttributes
object. For example, the following code creates a ColorMatrix
object, sets it's alpha value to 0.5, and creates a new ImageAttributes
object, setting it's color matrix to the one just created:
ColorMatrix cm = new ColorMatrix();
cm.Matrix33 = 0.5;
ImageAttributes ia = new ImageAttributes();
ia.SetColorMatrix(cm);
The final step is to draw the original image with the ImageAttributes
object just created. Using this ImageAttributes
object would draw the original image with the alpha value we set in the color matrix, creating the alpha image.
Step 4: Drawing the alpha image
To draw the alpha image, we call one of the overloads of the Graphics.DrawImage
method on the Graphics
object. Note that this overload should accept an ImageAttributes
object with which we would specify the render modifications. So select an appropriate overload and call it. For example, the following code draws the image ImageBitmap
at the location specified, with the ImageAttributes
object ia
:
gra.DrawImage(ImageBitmap,
new Rectangle(0,0,ImageBitmap.Width,ImageBitmap.Height),
0,0,ImageBitmap.Width, ImageBitmap.Height, GraphicsUnit.Pixel,
ia);
The following is a complete code listing for the whole set of steps we went through:
Graphics gra = pictureBox1.Graphics;
ColorMatrix cm = new ColorMatrix();
cm.Matrix00 = cm.Matrix11 = cm.Matrix22 = cm.Matrix44 = 1;
cm.Matrix33 = 0.5;
ImageAttributes ia = new ImageAttributes();
ia.SetColorMatrix(cm);
gra.DrawImage(ImageBitmap,
new Rectangle(0,0,ImageBitmap.Width, ImageBitmap.Height),
0,0,ImageBitmap.Width, ImageBitmap.Height, GraphicsUnit.Pixel,
ia);
Applying alpha on graphic constructs
The Graphics
class consists of several specific draw methods like that of lines, arcs etc. When you use such methods, it is possible to apply alpha right when you use them, rather than applying it to the image in total as explained above. This would undoubtedly be more straightforward illustrated as follows:
All the specific graphic construct draw methods of the Graphics
class (except DrawIcon
and DrawImage
) makes use of either a Pen
or a Brush
object as an argument. Both the Pen
and Brush
classes have a common underlying element - Color
; which means that both these classes use a Color
structure either directly or indirectly. We make use of this fact to make the application of alpha simpler.
A Color
structure defines not only the RGB channels, but also the Alpha channel. To create a new Color
object together defining it's alpha, we use the Color.FromArgb
method:
public static Color FromArgb(
int alpha,
int red,
int green,
int blue
);
where the value range of each element is 0-255.
The idea here is, to initialize a Color
object with the desired alpha value, to create the appropriate Pen
or Brush
objects from this Color
structure, and to call the specific draw method passing the Pen
or Brush
object just created. This would draw the graphic with the alpha value set in the Color
structure, and would create the same alpha effect as you would have obtained using the first procedure.
To create a Pen
object on the basis of a Color
object, use the Pen.Pen(Color)
constructor.
To create a Brush
object on the basis of a Color
object, use the SolidBrush.SolidBrush(Color)
constructor. The SolidBrush
class is derived from the abstract Brush
class. There are other classes derived from the Brush
class some of which use the Color
structure; but that's a different story.
The following code draws a string 'Text' in black with alpha 100. (Note that 100 is not 100% in this procedure. This is likely to go unnoticed.)
gra = e.Graphics;
gra.DrawString("Text", new Font("Verdana", 24),
new SolidBrush(Color.FromArgb(100,0,0,0)), 0,0 );
In a similar manner, alpha effect on other constructs can be carried out.
Creating an alpha animation
An animation exhibiting alpha effect is usually of two types: fade-in and fade-out. A fade-in animation starts with a black (usually) background and ends with the actual image. Technically, the starting frame is of alpha zero, and the ending frame is of alpha 100. A fade-out animation is the exact opposite. The background may also be another image.
To create an animation of either of the two types, you need to create a whole sequence of such alpha images and display them in order.
First, decide on the number of discrete alpha images you need. To create a smooth effect, a minimum of fifteen frames is recommended. Once you have decided on the number, create a Bitmap
array with this size. Then start a loop, and create Bitmap
objects of the required alpha value within the array. Finally, depending on the destination, either create a Graphics
object and draw the image, or set the control's Image
property to this object. This method of creating an image sequence in the memory and then displaying them is known as Double Buffering.
The following code creates an image sequence in the procedure as mentioned above:
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;
}
For displaying them, you might want to use a timer, or the control's unique paint handler.
Miscellaneous stuff
Compositing mode
When you obtain a Graphics
object from a surface, there may be some image already drawn on that same surface. Drawing a new image with full alpha on top of it overwrites the old image. Drawing a new image with partial alpha won't do so necessarily. Two possibilities exist in this case: either the new image overwrites the old image, or the new image blends with the old image (the old image shows through partially). To define the way the new image is to be drawn, you use the CompositingMode
property of the Graphics
class.
CompositingMode
, defined in the System.Drawing.Drawing2D
namespace, is an enumeration with two members:
SourceCopy
, which specifies that new images overwrite old images
SourceOver
, which specifies that new images are blended with old images with respect to the alpha component of the new image.
So, once you create a Graphics
object, set it's CompositingMode
property to the required member and proceed.
Note that when you are creating a Graphics
object from a control, the new image automatically overwrites the old image regardless of whether you set it's CompositingMode
to SourceCopy
or not.
Also note that it's the opposite when you create a Graphics
object from an Image
object - new images are blended to the old ones.
Instead of setting CompositingMode
to SourceCopy
, you could attain the same effect by clearing the surface with the Graphics.Clear
method passing some color like Color.Transparent
before drawing.
Conclusion
That's all. Go!
Updates
- 22/09/2003: Just posted. Thinking about adding an animation portion within the code, and about whether there are other details to be added.