Contents
C# Graphics Programming
When my editor Bob Elliott asked me if I wanted to write a Wrox Blox about .NET graphics, I felt like a kid in a candy shop! Where should I start? Should I gorge myself on image processing? Or pace myself and work slowly through an assortment of chocolate-covered pens and brushes? Perhaps the metaphor is a bit strained, but .NET provides so many graphics tools that its hard to decide where to start and where to stop. There are so many interesting tools and techniques that theres no way to cover everything in depth in a single Wrox Blox.
To make this as useful as possible to you, Ill cover an assortment of the topics that are most useful in Visual Studio applications. Ill provide enough information to get you going, and Ill even describe some of the more advanced tools such as PathGradientBrushes and custom line end caps. Since I wont be able to cover every tool and technique in as much depth as I would like, at some point youll need to strike out on your own and do some additional research on the Web. If you get stuck on an advanced topic, or if you have questions or comments about the material in this Wrox Blox, e-mail me at , and Ill try to give you some pointers.
Section 1 starts the discussion by describing the basic building blocks of graphics programming in C#: the Graphics , Pen , and Brush classes. You can use these classes to draw and fill lines, curves, ellipses just about everything except images and text.
Section 2 describes advanced Pen and Brush objects that let you produce more advanced effects such as lines with custom end caps and areas filled with color gradients that follow a path.
Section 3 finishes the discussion of fundamental graphical techniques by explaining how to draw text.
Section 4 tells how to draw and manipulate bitmapped images. It shows how to modify or draw images and save the results in a variety of formats such as BMP, GIF, and JPG files.
Section 5 explains an extremely powerful feature provided by .NET graphics: transformations. With a little practice, you can use transformations to build extremely complex graphics relatively simply using the coordinate systems that are easiest for you.
Section 6 shows how to add printouts and print previews to C# applications. Many books dont cover this topic very well, but printing plays an important role in many applications.
Section 7 describes the new Graphics objects that you can use in Windows Presentation Foundation (WPF) applications. By using these objects, you can create graphics declaratively at design time in addition to procedural run time.
Section 8 describes a particularly useful object provided by WPF (Windows Presentation Foundation) graphics: FlowDocument . A FlowDocument object can contain text, images, graphical objects, controls, and other visible objects. It then automatically flows those objects across whatever space is available. The result is a newsletter-like document that is extremely easy to build and view.
Its a lot of material to cover in not so many pages, so grab your favorite caffeinated beverage and lets get started!
Section 1: Using Graphics, Pens, and Brushes
Whenever you draw in C#, you draw on a Graphics object. You can think of this object as representing the canvas or piece of paper on which you will draw. There are several occasions when you may want to draw (when a form refreshes, to update an image, when generating a printout), but they all use the same kind of Graphics object. Thats great news because it means you only need to learn how to draw in one way and you can use the same code to draw on just about anything.
The Pen class determines the characteristics of line-like graphics. This includes straight lines as well as the edges of ellipses, rectangles, arcs, Bezier curves, and other drawn lines. The Pen object determines the lines color, thickness, dash style, lengthwise style (e.g., the line may consist of thin stripes), end caps (the shape of the lines end points), dash caps (the shape of the ends of dashes), and join style.
The Brush class determines the characteristics of filled areas. This includes such items as filled ellipses, rectangles, arcs, and other closed curves. The Brush class also determines how text is filled. The Brush object determines the filled areas color, hatch pattern, color gradient, or fill pattern.
For example, the following code draws on a Graphics object named gr . First the code uses a solid, light blue brush to fill an ellipse that has its upper-left corner at (10, 10), width 200, and height 100. (All units are pixels.) It then draws the same ellipse with a 1-pixel-wide, solid, stock red pen.
gr.FillEllipse( Brushes .LightBlue, 10, 10, 200, 100)
gr.DrawEllipse( Pens .Red, 10, 10, 200, 100)
The following sections describe simple uses of the Graphics , Pen , and Brush classes. Section 2, Using Advanced Pens and Brushes, explains how to use more complicated Pen and Brush objects to produce more sophisticated images.
Getting a Graphics Object
The most common methods for obtaining a Graphics object on which to draw are by:
- Calling a form or other controls CreateGraphics method.
- Calling the Graphics classs FromImage method.
- Using the e.Graphics parameter in a Paint event handler.
- Using the e.Graphics parameter in a PrintDocument objects PrintPage event handler.
The following sections describe each of these methods in some detail.
Using CreateGraphics
The CreateGraphics method returns a Graphics object that you can use to draw immediately on a form or control. Unfortunately, whatever you draw is only safe until that object is refreshed. The UseCreateGraphics example program uses the following code to draw an ellipse on a form:
Graphics gr = this .CreateGraphics();
gr.FillEllipse( Brushes .Yellow, 10, 30, 200, 150);
gr.DrawEllipse( Pens .Orange, 10, 30, 200, 150);
If you cover part of the form with another form and then expose that part again, the part of the ellipse that was covered disappears. Similarly, if you minimize the form and restore it, the entire ellipse disappears. To produce graphics that dont go away like this, you should use some other drawing method such as the Paint event handler described shortly.
Using Graphics.FromImage
The Graphics class provides a static FromImage method that lets you create a Graphics object associated with an image, typically a bitmap. You can then use that object to draw on the bitmap.
The EllipseOnBitmap example program uses the following code. It creates a bitmap and then gets a Graphics object associated with it. It uses that object to draw an ellipse and then displays the bitmap in a PictureBox .
// Create the Bitmap.
Bitmap bm = new Bitmap (200, 100);
// Get a Graphics object associated with the Bitmap.
Graphics gr = Graphics .FromImage(bm);
// Draw on the Bitmap.
gr.FillEllipse( Brushes .Pink, 10, 10, 180, 80);
gr.DrawEllipse( Pens .Black, 10, 10, 180, 80);
// Display the Bitmap in the PictureBox.
picEllipse.Image = bm;
The PictureBox automatically re-displays its image whenever it is refreshed. That means the image doesnt disappear when the control is refreshed as it would be if you used the CreateGraphics method described above. Similarly, you could draw on a bitmap and assign it to a forms BackgroundImage property to tile the form with the image.
Building a bitmap by using the FromImage method is usually the best method for drawing permanent images.
Using e.Graphics in Paint Event Handlers
When a form or other control needs to be refreshed, it raises a Paint event. The event handler takes a parameter e that has a Graphics property. The event handlers code can use that property to draw on the control.