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.
|
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. |