ONDotNet.com    
 Published on ONDotNet.com (http://www.ondotnet.com/)
 See this if you're having trouble printing code examples


System.Drawing with C#

by Budi Kurniawan
05/20/2002

The System.Drawing namespace, which contains types that help you with drawing, plays an important role in Windows programming. You need its members to draw a custom control user interface and for sending text and graphics to a printer. Even when you are only using standard controls on your form, you have used some of its members, probably without realizing it. Understanding the System.Drawing namespace enables you to write better -- and probably faster -- code. Here is a 10-minute crash course to familiarize you with it.

There are probably only 10 members of the System.Drawing namespace that you use in 99% of your programs. Out of these, the Point, Color, and Size structures are always present in any form-based applications. Let's start with the easiest ones: Point and PointF, structures that represent a location in a two-dimensional plane; and Size and SizeF, two structures that represent a width and a height. We will continue with the Color structure, as well as the Pen and Brush classes. Finally, the Graphics, Font, Image, and Bitmap classes are discussed. Note that all examples in this article assume that System.Drawing is imported; i.e., the following line is added to the beginning of your class or module:


using System.Drawing;

In the next article, I will demonstrate how these classes and structures are used in Windows printing.

The Point and PointF Structures

A Point object represents a coordinate in a two-dimensional plane. The easiest way to construct a Point is to pass two integers as the abscissa and the ordinate parts of the coordinate, such as the following:


Point myPoint = new Point(1,2);

Point is frequently used not only when drawing a shape, but also when writing a form- based application. For example, to adjust the position of a Button control on a form, you can assign a Point object to the button's Location property to indicate the position of the top-left corner of the button on the form. The following code places the button's top-left corner at coordinate (100, 30) in the form -- i.e., 100 pixels from the left edge of the form, and 30 pixels from the upper edge of the form's client area:


button.Location = new Point(100, 30);

Assigning a Point object to a control's Location property is the shortest way of positioning that control in its container. Another way is to use the Left and Top properties of the control, but this approach requires two lines of code instead of one. The Point structure has the X and Y properties, from which you can obtain the abscissa and ordinate of the coordinate a Point object represents. Also, IsEmpty is a read-only property that returns true only when both the X and Y properties of a Point object have the value of zero. (Note, though, that this can be misleading; (0, 0) can represent a valid coordinate for a Point object.)

You can also construct a Point object by passing a Size object. In this case, the Size object's width will become the abscissa of the Point, and the Size object's height will become the ordinate of the Point object. For example:


Size mySize = new Size(13, 133);
Point myPoint = new Point(mySize);
System.Console.WriteLine("X: " + myPoint.X + ", Y: " + myPoint.Y);

produces the following output:


X: 13, Y: 1

For more information on the Size structure, see the "Size and SizeF Structures" section below. The third way of constructing a Point is by passing an Integer. The low-order 16 bits of the integer will become the value of the Point's abscissa, and the high-order 16 bits the value of the Point's ordinate.

If you need more precision in your Point object, you can use the PointF structure. Instead of representing a coordinate with a pair of integers, PointF takes floats as the X and Y parts of a coordinate. PointF has only a single constructor with the following signature :


public PointF (
  float x, float y
);

The Size and SizeF Structures

The Size structure represents the width and height of a rectangular area. The easiest way to construct a Size object is by passing two integers as its width and height, as in the following code:


Size mySize = new Size(10, 30);

The Size object above has a width of 10 pixels and a height of 30 pixels. In a form-based Windows application, the Size structure is often used to set or change the size of a control. The Control class has a Size property to which you can assign a Size object. For instance, the following code sets the size of a button so that it will be 90 pixels wide and 20 pixels tall:


button1.Size = new Size(90, 20);

In addition, you can also construct a Size object by passing a Point object, as in the following code:


Point myPoint = new Point(10, 50);
Size mySize = new Size(myPoint);

In this case, the width and height of the resulting Size object will have the value of X and Y properties of the Point object, respectively. You can obtain the width and height values of a Size object by retrieving the value of its Width and Height properties. Another property, IsEmpty, is a read-only property that returns true only if both the Width and Height properties have the value of zero. The SizeF structure is very similar to Size, except that its width and height are represented by float. You use SizeF if you want more precision in your Size object.

The Color Structure

Related Reading

Programming C#
By Jesse Liberty

The Color Structure represents a color that you can use in drawing shapes or to assign to the BackColor or ForeColor properties of a control. To obtain a Color object, you don't use any constructor, because this structure does not have one. Instead, the structure includes a large number of static properties that represent various colors. For example, the Brown property represents a brown Color object. Because these properties are static, you don't need to instantiate a Color object to use them. The following code shows how to use the Brown property of the Color structure to assign a brown color to the BackColor property of a Button control:


Color myColor = Color.Brown;
button1.BackColor = myColor;

In addition to common colors such as green, blue, yellow, red, white, and black, you can choose more exotic colors such as azure, beige, coral, or powder blue. There are more than 140 properties representing different colors.

If that is not enough, you can compose a custom color by passing the R, G, and B components of an RGB color to the FromArgb static method. Again, since this method is static, you can use it without instantiating a Color object. As an example, the following code constructs a Color object whose R, G, and B components are all 240:


Color myColor = Color.FromArgb(240, 240, 240);

Note that even though the arguments are all integers, the values passed must be in the range of 0 and 255; this will result in a 32-bit color, in which the first eight bits represent the alpha value. In fact, you can also specify all 32 bits of a Color object through another overload of the FromArgb method that accepts four integers:


public static Color From Argb(
  int alpha, int red, int green, int blue
);

You can retrieve the individual alpha, red, green, and blue components of a Color object by calling its toArgb method, which returns an integer representing all of the four components (alpha, red, green, blue). This integer indicates the Color object's color value as follows:

Bits Value
0-7 Blue
8-15 Green
16-23 Red
24-31 Alpha

Another way of constructing a Color object is by using the Color structure's FromName method. For example, the following code constructs a blue color by passing the string blue to the FromName method:


Color myColor = Color.FromName("blue");

The Pen Class

The Pen class represents a pen that you can use for drawing a shape or writing text. A Pen object can have a color, a width, a brush, and other properties. The easiest way to construct a Pen is by passing a Color object to one of its constructors. For instance, the following code creates a yellow pen.


Pen myPen = new Pen(Color.Yellow );

A Pen object constructed using this code has a default width of 1 and a default brush. Another constructor lets you specify a width as well as a color. For example, the following Pen object is yellow with a width of 2:


Pen myPen = new Pen(Color.Yellow, 2);

The Pen class also provides some advanced properties to customize your Pen object. For example, you can create a Pen that draws a dashed line by specifying a value for the DashStyle property, as shown in the following code:


myPen.DashStyle = System.Drawing.Drawing2D.DashStyle.DashDot;

More examples of Pen objects can be found in "The Graphics Class" section later. Note also that the Pens class has static properties that allow you to obtain Pen objects of different colors.

The Brush Class

You use a Pen to draw the lines of a shape or to write text on it. To fill the interior of a shape you draw, you use a brush, which in the .NET Framework Class Library is represented by the Brush class and its five derived classes. The Brush class itself is an abstract class; therefore, it cannot be instantiated. You can, however, instantiate one of its child classes: HatchBrush, LinearGradientBrush, PathGradientBrush, SolidBrush, and TextureBrush. HatchBrush represents a hatch-styled rectangular brush; LinearGradientBrush represents a brush that paints with a linear gradient; PathGradientBrush is used to fill a GraphicPath with a gradient, SolidBrush represents a brush that fills an area evenly, and TextureBrush represents a brush with a texture image to fill an area. For example, here is the code that draws a filled rectangle on a form using a SolidBrush:


// get the Graphics of a form
Graphics g = form.CreateGraphics();
SolidBrush solidBrush = new SolidBrush(Color.Blue);
g.FillRectangle(solidBrush, 10, 20, 100, 100);

Note that the Brushes class contains static properties that allow you to get a Brush object of different colors. For instance, the previous code can be modified as follows.


Graphics g = this.CreateGraphics();
g.FillRectangle(Brushes.Blue, 10, 20, 100, 100);

See how easy it is to obtain a Brush object using the Brushes class?

The Graphics Class

Related Reading

C# Essentials
By Ben Albahari, Peter Drayton, Brad Merrill

The Graphics class represents a rectangular area on which various shapes can be drawn and text can be written. The constructor of this class is private, so there is no way you can instantiate a Graphics class using the new keyword. However, you can obtain a Graphics object that represents some other object, such as a form or a control. Once you obtain a Graphics object, you can use its various methods to draw many different shapes on it. For example, the System.Windows.Forms.Control class has the CreateGraphics method that returns a Graphics object representing that control. This is also the method that you need to call first if you want to draw on a form, as we will see later in this section. The methods of the Graphics class often require you to pass a Pen or a Brush object to create a shape. As one example, the DrawLine method of the Graphics class can be used to draw a line. One of its overloads has the following signature:


public void DrawLine ( 
  Pen pen, 
      int x1,
      int y1,
      int x2,
      int y2,
);

This overload accepts a Pen object and four integers representing the starting coordinate (x1, y1) and the end coordinate (x2, y2) of the line. For example, the following code obtains the Graphics object of a form, creates a Pen object, and passes the Pen object to the DrawLine method to draw a line on the form:


Graphics g = this.CreateGraphics();
Pen pen = new Pen(Color.Yellow, 2);
// set the pen's DashStyle to dash - dot
pen.DashStyle = System.Drawing.Drawing2D.DashStyle.DashDot;
g.DrawLine(pen, 0, 0, 100, 200);

The line is drawn from the coordinate (0, 0) to the coordinate (100, 200).

Graphics Class Methods

The following are some other methods of the Graphics class:

DrawLines

Draws lines that connect a series of points in an array, and is passed as the second parameter to the method. The first parameter is a Pen object. For example, the following code declares and instantiates an array of 4 points and draws lines connecting those points on a form:


Point[] points = new Point[4];
points[0] = new Point(0, 0);
points[1] = new Point(0, 120);
points[2] = new Point(20, 120);
points[3] = new Point(20, 0);
Graphics g = this.CreateGraphics();
Pen pen = new Pen(Color.Yellow, 2);
g.DrawLines(pen, points);

DrawRectangle

Draws a rectangle. For example, the following code draws a rectangle on a form by passing a Pen object and four integers. The first two integers represent the coordinate of the top-left corner of the rectangle, the third coordinate is the width of the rectangle, and the last integer the height of the rectangle.


Graphics g = this.CreateGraphics();
Pen pen = new Pen(Color.Aquamarine, 2);
g.DrawRectangle(pen, 10, 10, 100, 20);

In this example, the top-left corner of the rectangle is at coordinate (10, 10), and it has a width of 100 pixels and a height of 20 pixels.

DrawEllipse

Draws an ellipse within a containing imaginary rectangle. For example, the following code draws an ellipse having a width of 100 pixels and a height of 20. The top-left corner of the imaginary rectangle is at coordinate (10, 10).


Graphics g = this.CreateGraphics();
Pen pen = new Pen(Color.Aquamarine, 2);
g.DrawEllipse(pen, 10, 10, 100, 20);

FillRectangle

Draws a filled rectangle. For example, the following code draws a filled rectangle on a form by passing a SolidBrush object and four integers. The first two integers represent the coordinate of the top-left corner of the rectangle. The rectangle has a width of 100 pixels and a height of 30 pixels.


Graphics g = this.CreateGraphics();
SolidBrush solidBrush = new SolidBrush(Color.DarkCyan);
g.FillRectangle(solidBrush, 10, 10, 100, 30);

FillEllipse

Draws a filled ellipse. This method is similar to DrawEllipse, but the resulting ellipse is filled. Instead of passing a Pen object, the method requires a Brush object. The following code draws a filled ellipse on a form:


Graphics g = this.CreateGraphics();
SolidBrush solidBrush = new SolidBrush(Color.DarkCyan);
g.FillEllipse(solidBrush, 10, 10, 100, 30);

DrawString

Writes a string of text at a specified location on the Graphics object. For an example, see the Font class.

Save

Persists the current Graphics object into a GraphicsState object. Later, you can retrieve the persisted object using the Restore method.

Restore

Restores a previously persisted Graphics object from a System.Drawing.Drawing2D.GraphicState object. For example, the following code saves the state of a Graphics object into a System.Drawing.Drawing2D.GraphicState object and then immediately restores it.


Graphics g = this.CreateGraphics();
// save the state of the current Graphics object
System.Drawing.Drawing2D.GraphicsState graphicsState = g.Save();
// do something here
  .
  .
  .
// restore it
g.Restore(graphicsState);

Graphics Class Properties

The following are some of the most important properties of the Graphics class:

DpiX

The horizontal resolution of the current Graphics object.

DpiY

The vertical resolution of the current Graphics object.

PageUnit

By default, the measurement unit of a Graphics object is pixels. You can change this by setting the PageUnit property. This property takes one of the members of the GraphicsUnit enumeration: Display, Document, Inch, Millimeter, Pixel, Point, or World. For example, the following changes the PageUnit of a Graphics object into inches:


graphics.PageUnit = GraphicsUnit.Inch;

The Font Class

The Font class represents a font. The easiest way to construct a Font object is by passing a string containing the font name and the font size. For instance, the following obtains the Graphics object of a form, creates an Arial font with the size of 14, creates a SolidBrush called "solidBrush," and writes a string on the Graphics object in 14 point Arial:

Graphics g = this.CreateGraphics();
Font font = new Font("Arial", 14);
SolidBrush solidBrush = new SolidBrush(Color.Chartreuse);
g.DrawString("Hello", font, solidBrush, 10, 100);

If the font name passed to the constructor does not correspond to an available font, the default font is used. The Font class has read-only Bold and Italic properties that indicate whether or not the font is bold or italic.

The Image Class

Image is an abstract class that encapsulates functionality to work with a raster image. The Image class is used in drawing, as well as to display an image in a form-based program. The System.Windows.Forms.Control class has a BackgroundImage property that can take an Image object as the background image for that control.

Even though Image is an abstract class, it has static methods that enable you to create an Image object. Those methods are FromFile and FromStream. The FromFile method is used to create an Image object directly from an image file, such as a .bmp or .gif file. For example, the following code creates an Image object using the FromFile method by passing the complete path to a .bmp file and assigns the Image object to the BackgroundImage property of a form:


Image image = Image.FromFile("C:\\TV.bmp");
this.BackgroundImage = image;

Alternatively, you can use the FromStream method to create an Image object by passing a System.IO.Stream object.

Another way to construct an Image object is by instantiating one of its derived classes, Bitmap or Metafile. Bitmap is used more often, and you can find more information on the Bitmap class in the following section.

The Image class has three read-only properties related to its size: Width, Height, and Size. Both Width and Height return an integer. The Size property returns a Size structure, the members of which include Width and Height. Once you have an Image object, you can save it back into a file, as shown in the following code:


Image bitmap = Image.FromFile("C:\\TV.bmp");
bitmap.Save("C:\\TV2.bmp");

Another useful method is RotateFlip, which you can use to rotate and flip an Image object. With this method, you can rotate, flip, or rotate and flip. The method accepts one of the following members of the RotateFlipType enumeration:


Rotate180FlipNone, Rotate180FlipX, Rotate180FlipXY, 
Rotate180FlipY, Rotate270FlipNone, Rotate270FlipX, 
Rotate270FlipXY, Rotate270FlipY, Rotate90FlipNone, 
Rotate90FlipX, Rotate90FlipXY, Rotate90FlipY, 
RotateNoneFlipNone, RotateNoneFlipX, RotateNoneFlipXY, and 
RotateNoneFlipY.

The Bitmap Class

The Bitmap class represents a raster or bitmap-based image. The easiest way to instantiate a Bitmap object is to pass the complete path to a bitmap file. For example, the following code instantiates a Bitmap object from a .bmp file named TV.bmp in the C:\ directory, and assigns the object as the background image of a form:


Image bitmap = new Bitmap("C:\\TV.bmp");
this.BackgroundImage = bitmap;

Because Bitmap is derived from Image, it inherits the Image class's properties and methods. However, the Bitmap class offers much more functionality. For example, there are 12 constructors that give you flexibility in creating a Bitmap object. As you have seen, you can pass in the complete path to a bitmap file. However, you can also pass in a System.IO.Stream object or an Image object, and you can change the size of the image. For instance, the following code takes an Image object and sets the size of the resulting Bitmap to 30, 30, regardless of the image's original size :


Size size = new Size(30, 30);
Image image = Image.FromFile("C:\\TV.bmp");
Bitmap bitmap = new Bitmap(image, size);

You can even create a Bitmap object from a Graphics object by using the following constructor:


public Bitmap (
  int width, int height, Graphics g
);

The power of the Bitmap class also derives from two methods that allow you to manipulate a bitmap pixel by pixel: GetPixel and SetPixel. The GetPixel method returns the Color of a specified pixel at a particular coordinate, and SetPixel allows you to change the color of an individual pixel. For example, the following code removes the green component of a Bitmap object, then assigns the bitmap to a form's BackgroundImage property:


Bitmap bitmap = new Bitmap("C:\\TV2.bmp");
int width = bitmap.Width;
int height = bitmap.Height;

int i, j;
for (i = 0; i< width; i++) 
{
  for (j=0; j<height; j++)
  {
     Color pixelColor = bitmap.GetPixel(i, j);
     int r = pixelColor.R; // the Red component
     int b = pixelColor.B; // the Blue component
     Color newColor = Color.FromArgb(r, 0, b);
     bitmap.SetPixel(i, j, newColor);
    }
}
this.BackgroundImage = bitmap;

Summary

This article presents the most important members of the System.Drawing namespace. Its classes and structures are useful for drawing the user interface of a control as well as for printing. Some of the structures, such as Point, Size, and Color, are always used in Windows forms.

Copyright © 2009 O'Reilly Media, Inc.