Advanced Imaging in GDI+


This article has been excerpted from book "Graphics Programming with GDI+".

We discussed the imaging functionality defined in the System.Drawing namespace. This article will cover the advanced imaging functionality defined in the System.Drawing.Imaging namespace. We will explore how to implement this functionality in our applications. The topic will include:

  • Understanding LockBits and UnlockBits
  • Working with metafiles and metafile enhancements
  • Working with the color matrix, color map, and color palette
  • Using the Encoder and EncoderCollection classes
  • An overview of tagged data in TIFF files
  • Converting metafiles

Rendering Partial Bitmaps

The Bitmap class provides the LockBits and UnlockBits methods, but we didn't get to use them. LockBits and UnlockBits and unlock bitmap pixel in system memory. Each call to LockBits should be followed by a call to UnlockBits.

Why might you want to lock bitmap pixels? Rendering (painting) bitmaps and images is a resource-consuming operation, and it is one of the most frequently performed graphics operations. Suppose you want to change the color or intensity level of a bitmap. You could always loop through the bitmap pixel by pixel and use SetPixel to modify its properties, but that is a huge time- and resource-consuming operation. 

Note: The code used in this article uses classes defined in the System.Drawing.Imaging namespace, so be sure to add a reference to this namespace in your applications.

A better option would be using LockBits and UnlockBits. These methods allow you to control any part of the bitmap by specifying a range of pixels, eliminating the need to loop through each pixel of the bitmap.

To use this option, first call LockBits, which returns the BitmapData object. BitmapData specifies the attributes of a bitmap. Before we examine the members of the BitmapData class, let's take a look at the LockBits and UnlockBits methods. The LockBits method is defined as follows:

        public BitmapData LockBits ( Rectangle rect ImageLockMode flags, PixelFormat format);

LockBits takes three parameters of type Rectangle, ImageLockMode enumeration, and PixelFormat enumeration, and it returns an object of type BitmapData. The rectangle defines the portion of the bitmap to be locked in system memory.

UnlockBits takes a single parameter of type BitmapData, which was returned by LockBits. This method is defined as follows:

        public void UnlockBits(BitmapData bitmapdata);

The ImageLockMode enumeration used in LockBits provides the access level to the data. Table 8.1 describes the members of ImageLockMode.

The pixel format defines the number of bits of memory associated with one pixel of data, as well as the order of the color components within a single pixel. Generally the number of bits per pixel is directly proportional to the quality of the image because the pixel can store more colors.

TABLE 8.1: ImageLockMode members

Member

Description

ReadOnly

The locked portion of the bitmap is for reading only.

ReadWrite

The locked portion of the bitmap is for reading or writing.

UserInputBuffer

The buffer used for reading or writing pixel data is allocated by the user.

WriteOnly

The locked portion of the bitmap is for writing only.

The PixelFormat enumeration represents the pixel, which is useful when you need to change the format of a bitmap or a portion of it. The members of the PixelFormat enumeration are described in Table 8.2.

Drawing Grayscale or Other Color Images

To demonstrate the use of LockBits and UnlockBits, we will change the pixels of a bitmap using the GetPixel and SetPixel methods. An application can use GetPixel and SetPixel to get and set the colors of each pixel of a bitmap. To set a bitmap color to grayscale or other colors, and application reads the current color using GetPixel, calculates the grayscale value, and calls SetPixel to apply the new color.

In the following code snippet we read the color of a pixel; calculate the grayscale value by applying a formula to the red, green, and blue components; and call SetPixel to set the pixel's new grayscale color.

        Color curColor = curBitmap.GetPixel (i,j);

        int ret = (curColor.R + curColor.G + curColor.B) / 3;

        curBitmap.SetPixel (i,j, Color.FromArgb (ret, ret, ret));

Listing 8.1 draws an image with its original color settings and later redraw it in grayscale. The Width and Height properties of the Bitmap class are used to loop through each pixel of the bitmap, and SetPixel is used to set the pixel's color to grayscale.

TABLE 8.2: PixelFormat members

Member

Description

Alpha

The pixel data contains alpha values that are not pre-multiplied.

DontCare

No pixel format is specified.

Format1bppIndexed

1 bit per pixel, using indexed color. The color table therefore has two colors in it.

Format4bppIndexed

4 bits per pixel, using indexed color.

Format8bppIndexed

8 bits per pixel, using indexed color.

Format16bppArgb1555

16 bits per pixel, giving 32,768 colors; 5 bits each are used for red, green, and blue and 1 bit is used for alpha.

Format16bppGrayScale

16 bits per pixel, giving 65,536 shades of gray.

Format16bppRgb555

16 bits per pixel; 5bits each are used for red, green, and blue. The last bit is not used.

Format16bppRgb565

16 bits per pixel; 5 bits are used for red, 6 bits for green, and 5 bits for blue.

Format24bppRgb

24 bits per pixel; 8 bits each are used for red, green, and blue.

Format32bppArgb

32 bits per pixel; 8 bits each are used for alpha, red, green, and blue. This is the default GDI+ color combination.

Format32bppPArgb

32 bits per pixel; 8 bits each are used for alpha, red, green, and blue. The red, green and blue components are premultiplied according to the alpha component.

Format32bppRgb

32 bits per pixel; 8 bits each are used for red, green, and blue. The last 8 bits are not used.

Format48bppRgb

48 bits per pixel; 16 bits each are used for red, green, and blue.

Format64bppArgb

64 bits per pixel; 16 bits each are used for alpha, red, green and blue.

Format64bppPArgb

64 bits per pixel; 16 bits each are used for alpha, red, green, and blue. The red, green and blue components are premultiplied according to the alpha component.

Gdi

GDI colors.

Indexed

Color-indexed values, which are an index to colors in the system color table, as opposed to individual color values.

Max

The maximum value for this enumeration.

PAlpha

The format contains premultiplied alpha values.

Undefined

The format is undefined.

LISTING 8.1: Using SetPixel to change the color scale of a bitmap

            // Create a Graphics object from a button
            // or menu click event handler
            Graphics g = this.CreateGraphics();
            g.Clear(this.BackColor);

            // Create a Bitmap object
            Bitmap curBitmap = new Bitmap("roses.jpg");

            // Draw bitmap in its original color
             g.DrawImage(curBitmap, 0, 0, curBitmap.Width, curBitmap.Height);

            // Set each pixel to grayscale using GetPixel and SetPixel
            for (int i = 0; i < curBitmap.Width; i++)
            {
                for (int j = 0; j < curBitmap.Height; j++)
                {
                    Color curColor = curBitmap.GetPixel(i, j);
                    int ret = (curColor.R + curColor.G + curColor.B) / 3;
                     curBitmap.SetPixel(i, j,
                    Color.FromArgb(ret, ret, ret));
                }
            }

            // Draw bitmap again with gray settings
             g.DrawImage(curBitmap, 0, 0, curBitmap.Width, curBitmap.Height);

            // dispose of object
            g.Dispose();

Conclusion

Hope the article would have helped you in understanding advanced Imaging in GDI+. Read other articles on GDI+ on the website.

bookGDI.jpg
This book teaches .NET developers how to work with GDI+ as they develop applications that include graphics, or that interact with monitors or printers. It begins by explaining the difference between GDI and GDI+, and covering the basic concepts of graphics programming in Windows.

erver'>