RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Manipulating Images with .NET Programs

Many image processing techniques are simpler than you might expect and can be implemented easily in C# or Visual Basic.

With a cheap digital camera you can take a picture, transfer it to your computer, and inflict it on your friends and relatives in a matter of minutes. Sometimes, however, the results aren't quite perfect. Images may be too bright or dark, washed out, or may suffer from red-eye. The first part of this two-part series explains ways you adjust pictures to fix these problems and generally make them look better.

These days you can buy a fairly nice digital camera for under $100. Depending on what you want to do with the picture, however, you may need to do more than just say "cheese" and press a button.

For portraits you may want to perform red-eye reduction or insert an image of your favorite movie star into the picture. I've seen high-end group portraits where the photographer has copied one person's open eyes from one picture into another picture where that person blinked. You may also want to adjust the image's brightness, contrast, or color levels, and add a filter to make the image look softer.

When you're building user interfaces, you might want to add drop shadows, glow, or embossed effects. With scientific images you may want to highlight sharp edges or compare two pictures of the same scene (that's a good way to discover comets, asteroids, supernovas, and other astronomical phenomena that appear, disappear, or move quickly).

All of these are image processing techniques. Many of these techniques are much simpler than you might expect and you can implement them easily in C# or Visual Basic.

In this two-part article, I'll explain how you can implement some of these techniques. The first part of this article explains point processes: techniques that modify images one pixel at a time. Some of these techniques include brightness and contrast adjustment, image subtraction, and converting images to gray scale. The second part of this article will explain area processes such as blurring, sharpening, beveling, and embossing techniques.

Before I explain point processing techniques, however, you should learn a few things about loading, saving, and manipulating images in .NET programs.

Loading Images

One easy way to load images in a .NET program is to create a new Bitmap object, passing its constructor the name of the file you want to load. For example, the LoadImageLocked example program, uses the following code to display an image when you use the File menu's Open command. (All of the examples in this article are available for download in C# and Visual Basic versions.) This code calls the Bitmap class's constructor, passing it the name of the file you selected in the ofdFile OpenFileDialog control.
// Load and display the file.
picResult.Image = new Bitmap(ofdFile.FileName);
There are two important things to note about this code. First, the picResult PictureBox uses this Bitmap whenever it needs to redraw itself. That means you cannot call the Bitmap's Dispose method to free its resources. If you do, the program crashes the next time it needs to refresh the PictureBox.

Not calling the Bitmap's Dispose method is easy enough but it leads to the second important thing to note: until you dispose of the Bitmap, it keeps the image file locked. If you try to delete or rename the file while the Bitmap still exists, you'll get the error "The action can't be completed because the file is open in another program."

One way around this problem is to load the Bitmap, copy it into a new Bitmap in memory, and then dispose of the original Bitmap. The new Bitmap holds everything it needs to know in memory so it doesn't need to keep the image file locked. After you call the first Bitmap's Dispose method, the file is unlocked so the program won't interfere with other programs that need to use the file, for example if you try to delete the file in Windows Explorer.

To make this operation and some others easier, I created an ImageMethods class in the file ImageStuff.cs. This class holds static methods that make working with images easier. The LoadBitmap method shown in the following code uses this technique of loading a file into a Bitmap, creating a copy of the Bitmap, and then disposing of the original (with a using statement).
// Load the image without leaving the file locked.
public static Bitmap LoadBitmap(string file_name)
    using (Bitmap bm = new Bitmap(file_name))
        return new Bitmap(bm);
If you open the LoadImageLocked program's File menu and select Open Unlocked, the program uses the following code to invoke the LoadBitmap method. This loads the image but doesn't lock the file.
// Load and display the file.
picResult.Image = ImageMethods.LoadBitmap(ofdFile.FileName);

Saving Images

The Bitmap class provides a useful Save method for saving image files. An optional second parameter tells Save what format to give the file. This value can be Bmp, Emf, Exit, Gif, Icon, Jpeg, MemoryBmp, Png, Tiff, and Wmf. For example, the following code saves the Bitmap named bm as a PNG file. (Lately I've come to like PNG files a lot because they provide pretty good compression without losing any of the image's data the way the GIF and JPEG formats do.)
bm.Save(filename, ImageFormat.Png);
The Save method doesn't really care what extension the file name has so you should be sure it matches the format that you use. For example, you could make a file named Happy.bmp that is saved in the JPEG format. The Save method doesn't care but that could lead to confusion.

To make saving images in the correct format easier, I added the following SaveBitmapUsingExtension method to the ImageMethods class.
// Save the file with the appropriate format.
// Throw a NotSupportedException if the file
// has an unknown extension.
public static void SaveBitmapUsingExtension(
    Bitmap bm, string filename)
    string extension = Path.GetExtension(filename);
    switch (extension.ToLower())
        case ".bmp":
            bm.Save(filename, ImageFormat.Bmp);
        case ".exif":
            bm.Save(filename, ImageFormat.Exif);
        case ".gif":
            bm.Save(filename, ImageFormat.Gif);
        case ".jpg":
        case ".jpeg":
            bm.Save(filename, ImageFormat.Jpeg);
        case ".png":
            bm.Save(filename, ImageFormat.Png);
        case ".tif":
        case ".tiff":
            bm.Save(filename, ImageFormat.Tiff);
            throw new NotSupportedException(
                "Unknown file extension " + extension);
This method uses a file name's extension to figure out which format is appropriate and then saves the image appropriately. That makes it easier to accommodate users who select different file formats.

Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date