Simplified Image Processing in GDI+

With GDI+ coming into its own in the two-dimensional image processing field, image processing was drastically simplified. Those who have become accustomed to traditional GDI may feel a bit puzzled with the image handling introduced in GDI+. Once they grow accustomed to the differences, which should happen quickly, they will probably prefer GDI+. Keep reading to find out why, and to learn GDI+'s image processing methods through several examples. This article is the first of two parts.

Contributed by
Rating: 5 stars5 stars5 stars5 stars5 stars / 2
September 10, 2008
Rate this Article:
MEH MEH++


SEARCH ASP FREE
TOOLS YOU CAN USE

advertisement

Introduction

With GDI+, users of traditional GDI will notice that they can no longer find the troublesome DIB or DDB concepts, nor can they find data structures such as the BMP file header and the BMP-related palette which brought so much trouble to Windows GDI developers. In GDI+, there are almost no absolute limits between various picture files. A typical example is that in GDI+ you may find that you can use almost the same means to manipulate BMP files as you do with JPEG or PNG format files.

Digging deeper into GDI+, you will see that there are three main classes, i.e. Image, Bitmap, and Metafile, introduced to deal with common and typical image processing. The Bitmap class provides methods to load, save, and handle raster images, which to some degree expands the abilities of the Image class. In contrast, the Metafile class has enhanced the Image class by introducing additional methods to record and validate vector images.

There are many concepts as well as higher theories with images. However, we are not going to dwell much on these monotonous and bald doctrines. In this article, I will show you the richer and easier support available in GDI+ to process images through several samples.

Open and Render Images

There are mainly two classes introduced to manipulate and maintain image processing, i.e. Image and Bitmap. The Bitmap class derives from the base class Image. Here we are mainly interested in the Bitmap class.

There are 12 variations of constructor for the Bitmap class. As for rendering an image file, this is typically performed using the DrawImage methods of the Graphics class-there are 30 kinds of definitions for the DrawImage method. There are so many rich invocations for the DrawImage method that you can deal with an image in GDI+ with great ease and flexibility. For example, the functionalities, rotating, and inverting, interpolating with any special angle, that can not be directly accomplished using the API BitBlt() in GDI can now be easily achieved using the DrawImage method in GDI+.

Here we do not plan to list the dozens of variations of the DrawImage method, but summarize what you can do with it:

  1. You can use the DrawImage method to render many kinds of images at the specified locations as well as scaling them.
  2. You can utilize the point information in the screen to describe the location of an image using the DrawImage method to rotate it at any specified angle, which is quite different from what you can achieve using the coordination transformation in the drawing plane.
  3. If the ImageAttributes function is enabled in the DrawImage method, you can validate the color information of an image as well as specify the color-rendering channel.

Meta File Support in GDI+

A meta file, also known as a vector image, is a kind of image which contains a set of drawing instructions and settings. There are two kinds of meta files, i.e. the memory meta file and the disk meta file. The memory meta file is merely stored and manipulated within the memory, mostly to draw or copy images, or share images between processes, while the disk meta file is mostly used to persist the drawn image into a disk and for later replay.

Since a meta file is only a series of drawing instructions, it is not suitable for use under an image process field. On the other hand, the rendering speed of a meta file is much slower than the images of other formats, and it does not adapt to scenarios requiring strict speed. However, a meta file bears the unique advantage of occupying much less disk space than the other formats of images. This is why the meta file is still in use in certain areas.

In GDI+, the following formats of meta file can be rendered:

  • A Windows meta file (WMF)

  • An enhanced meta file (EMF)

  • EMF+


GDI+ mainly uses EMF to describe a meta file, which is a 32 bit extensible meta file developed by Microsoft with the general aim of overcoming the shortcomings of the WMF file introduced in Windows 3.1. In GDI+, a Metafile class is used to handle a meta file, which can be used to record, render, and persist a meta file. Open MSDN, and you will find more than thirty constructors for the Metafile class. Herein, we are only interested in how to record and replay a metafile.

Next, let us take a close look at a related sample application.

Sample One-Record and Replay Metafiles

As is indicated above, to record a meta file is in fact to persist all the drawing instructions into a disk file. In this simple sample, you will learn how to save (record) the drawing instructions and replay them on the screen. Figure 1 shows the running-time snapshot.


Figure 1-the running-time snapshot for sample 1


The following indicates the related key code implementation:

Graphics metagraph=this.CreateGraphics();

//create a new meta file

IntPtr hdc =metagraph.GetHdc();

Metafile metaFile1 = new Metafile("SampMeta1.emf", hdc);

//use the address of the Metafile object as the drawing plane

Graphics graphics=Graphics.FromImage(metaFile1);


//define a red to blue gradient brush

LinearGradientBrush RtoBBrush=new LinearGradientBrush(

new Point(0, 10),

new Point(200, 10),

Color.Red,

Color.Blue);

//define another blue to yellow gradient brush

LinearGradientBrush BtoYBrush=new LinearGradientBrush(

new Point(0, 10),

new Point(200, 10),

Color.Blue,

Color.Yellow);

Pen bluePen=new Pen(Color.Blue);

//draw a ancient Chinese picture of the Eight Diagrams onto the 'screen'

Rectangle ellipseRect=new Rectangle(0, 0, 200, 200);

Rectangle left=new Rectangle(0, 50, 100, 100);

graphics.DrawArc(bluePen,left,180.0f,180.0f);

Rectangle right=new Rectangle(100, 50, 100, 100);

graphics.FillPie(RtoBBrush, ellipseRect,0.0f,180.0f);

graphics.FillPie(BtoYBrush, ellipseRect,180.0f,180.0f);

graphics.FillPie(RtoBBrush, left,180.0f,180.0f);

graphics.FillPie(BtoYBrush, right,0.0f,180.0f);


//render some text

SolidBrush solidBrush=new SolidBrush(Color.Black);

FontFamily fontFamily=new FontFamily("MS Gothic");

Font font=new Font(fontFamily, 27,

FontStyle.Regular, GraphicsUnit.Pixel);

graphics.DrawString("Meta File Test", font, solidBrush,

new PointF(5.0f, 80.0f));

//so far, GDI+ has merely store drawing instruction into the harddisk


//release all the related resources used above

graphics.Dispose();

metaFile1.Dispose();

metagraph.ReleaseHdc(hdc);

metagraph.Dispose();


//replay the drawing info created above

Graphics playbackGraphics=this.CreateGraphics();

playbackGraphics.Clear(Color.White);

//open and render the previously-created meta file

Metafile metaFile2 = new Metafile("SampMeta1.emf");

playbackGraphics.DrawImage(metaFile2,new Point(0,0));

//close the open meta file

metaFile2.Dispose();

There are two crucial steps in the previous sample. The first step is to create an empty meta file named "SampMeta1.emf,"draw images onto the image, and then render text in it. All of the drawing actions are done on a file in a hard disk-you can see nothing on the screen during the first step.

The second step picks up from the last few lines. First create a Graphics object, then open the meta file created in the first step and finally, by using the DrawImage() method of the Graphics object, the true rendering plays on the screen. It is only then that you can visualize the rendering result, i.e. replay the meta file on the screen.

One last word: after running the first sample, you may find a metafile named "SampMeta1.emf," which corresponds to the drawing instructions; without the second step to invoke the DrawImage() method you will not see anything on the screen.

Sample Two-Clipping and Scaling Images

Now, let us shift our attention to another application of the image process supported by GDI+-clipping and scaling images. There is still nothing peculiar here; all functions still rest on the DrawImage() method. As usual, let us first look at the running-time snapshot, as is shown in Figure 2.


Figure 2-the running-time snapshot for sample 2

The following gives the short coding in this sample:

Graphics graphics=this.CreateGraphics();

graphics.Clear(Color.White);


//load the image

Bitmap image=new Bitmap("nemo.bmp");

int width = image.Width;

int height = image.Height;


//enlarge the target area by 1.4 times of the source image

RectangleF destinationRect=new RectangleF(

width+10, 0.0f, 1.4f* width, 1.4f* height);

//first render the source image

graphics.DrawImage(image, 0, 0);


//then draw the bitmap onto the target area

graphics.DrawImage(

image,

destinationRect,

new RectangleF(0, 0, //upper left corner of the source image

0.65f*width, // only render 65% of the width of the source image

0.65f * height), // only render 65% of the height of the source image

GraphicsUnit.Pixel);

Here, we first enlarge the target area 1.4 times and then in the DrawImage() function we shrink the rendering area to 65% of the original image, by which both the clipping and scaling effects are achieved. As is shown is Figure 2, you may find the body of the goldfish becomes bigger, while the mouth of the goldfish is still invisible, which is just the effect accomplished by clipping and scaling. In addition, you will find that in the enlarged image appears some blurring effect, which will be covered in the next topic.

Sample Three-Use Interpolation to Output

Different Qualities of Images

What is interpolation? Interpolation is a kind of mathematic algorithm to compute the middle value of two given endpoints.

In GDI+ you can use Interpolation to adjust the rendering quality of an image. If you want to stretch an image, you have to map each of the pixels in the source image to the corresponding pixel in the larger target one, while achieving a shrink effect requires similar mapping with the smaller target image. As you may image, the selected mapping algorithm will decide the result of the rendered image. To gain better quality requires longer processing time.

An enumeration type, InterpolationMode, is defined in GDI+ to control the different interpolation modes. The following table lists all the values associated with InterpolationMode.


Member name

Description

Invalid

Equivalent to the Invalid element of the QualityMode enumeration.

Default

Specifies default mode.

Low

Specifies low quality interpolation.

High

Specifies high quality interpolation.

Bilinear

Specifies bilinear interpolation. No prefiltering is done. This mode is not suitable for shrinking an image below 50 percent of its original size.

Bicubic

Specifies bicubic interpolation. No prefiltering is done. This mode is not suitable for shrinking an image below 25 percent of its original size.

NearestNeighbor

Specifies nearest-neighbor interpolation.

HighQualityBilinear

Specifies high-quality, bilinear interpolation. Prefiltering is performed to ensure high-quality shrinking.

HighQualityBicubic

Specifies high-quality, bicubic interpolation. Prefiltering is performed to ensure high-quality shrinking. This mode produces the highest quality transformed images.


Now let's look at a sample to see how you can use the different interpolation modes to affect rendering quality. Figure 3 illustrates the running-time snapshot for sample 3, through which you can apparently notice from the head and feature parts of the eagle that different modes of interpolation result in different rendering quality.


Figure 3-the running-time snapshot for sample 3

You can find the final answer in the following code:

private void UsingInterpolationMode_Click(object sender, System.EventArgs e)

{

Graphics graphics=this.CreateGraphics();

graphics.Clear(Color.White);


//load the image

Bitmap image=new Bitmap("eagle.bmp");

int width = image.Width;

int height = image.Height;


//draw the source image

graphics.DrawImage(

image,

new Rectangle(0, 0, width, height), //target area

0, 0, //upper left corner of the source image

width, //width of the source image

height, //height of the source image

GraphicsUnit.Pixel);


//shift to drawing plane to the right

graphics.TranslateTransform( width+10,0);

//use NearestNeighbor (low quality)

graphics.InterpolationMode=InterpolationMode.NearestNeighbor;

graphics.DrawImage(

image,

new RectangleF(0.0f, 0.0f, 0.6f * width, 0.6f * height), //target area

new RectangleF(0, 0, //upper left corner of the source image

width, //width of the source image

height), //height of the source image

GraphicsUnit.Pixel);


//shift to drawing plane to the right

graphics.TranslateTransform( 0.6f*width+10,0);

// use Bicubic mode (high quality)

graphics.InterpolationMode=InterpolationMode.Bicubic;

graphics.DrawImage(

image,

new RectangleF(0, 0, 0.6f * width, 0.6f * height), //target area

new Rectangle(0, 0, //upper left corner of the source image

width, //width of the source image

height), //height of the source image

GraphicsUnit.Pixel);


//shift to drawing plane to the right

graphics.TranslateTransform(0.6f*width+10,0f);

// use the highest quality of HighQualityBicubic mode

graphics.InterpolationMode=InterpolationMode.HighQualityBicubic;

graphics.DrawImage(

image,

new RectangleF(0, 0, 0.6f * width, 0.6f * height), //target area

new Rectangle(0, 0, //upper left corner of the source image

width, //width of the source image

height), //height of the source image

GraphicsUnit.Pixel);

}

There is also one point worth noticing: different modes of interpolation will exhaust different quantities of system resources. And from Figure 3 above you will have concluded that the HighQualityBicubic mode of interpolation will consume the most system resources, which of course corresponds to the slowest rendering speed.

Sample Four-Flipping an Image

Are you familiar with Windows' paintbrush application? It provides support for flipping a specified image 90 degrees or 180 degrees. GDI+'s RotateFlip() function will easily help you to achieve the above and even more effects. Here's the signature for the RotateFlip() function:

public void RotateFlip(RotateFlipType rotateFlipType);

As you may guess, all the secrets hide behind the RotateFlipType parameter. The following table lists all the enumeration values of this parameter, through which you can see the typical flipping support accomplished in any good image processing software.

Member name

Description

RotateNoneFlipNone

Specifies no rotation and no flipping.

Rotate90FlipNone

Specifies a 90-degree rotation without flipping.

Rotate180FlipNone

Specifies a 180-degree rotation without flipping.

Rotate270FlipNone

Specifies a 270-degree rotation without flipping.

RotateNoneFlipX

Specifies no rotation followed by a horizontal flip.

Rotate90FlipX

Specifies a 90-degree rotation followed by a horizontal flip.

Rotate180FlipX

Specifies a 180-degree rotation followed by a horizontal flip.

Rotate270FlipX

Specifies a 270-degree rotation followed by a horizontal flip.

RotateNoneFlipY

Specifies no rotation followed by a vertical flip.

Rotate90FlipY

Specifies a 90-degree rotation followed by a vertical flip.

Rotate180FlipY

Specifies a 180-degree rotation followed by a vertical flip.

Rotate270FlipY

Specifies a 270-degree rotation followed by a vertical flip.

RotateNoneFlipXY

Specifies no rotation followed by a horizontal and vertical flip.

Rotate90FlipXY

Specifies a 90-degree rotation followed by a horizontal and vertical flip.

Rotate180FlipXY

Specifies a 180-degree rotation followed by a horizontal and vertical flip.

Rotate270FlipXY

Specifies a 270-degree rotation followed by a horizontal and vertical flip.


For simplicity, we only construct a sample using the constant RotateNoneFlipX. Figure 4 shows the running-time result of this related sample application.


Figure 4 - the running-time snapshot for sample 4

The following code is already accompanied by enough comments to explain the usage of the RotateFlip() function and the constant RotateNoneFlipX:

private void RotateFlip_Click(object sender, System.EventArgs e)

{

Graphics graphics=this.CreateGraphics();

graphics.Clear(Color.White);

//load the image

Bitmap photo=new Bitmap("nemo2.bmp");


//get the size of the image

int iWidth = photo.Width;

int iHeight = photo.Height;

//render the source image

graphics.DrawImage(photo, 10+photo.Width+2,

10, photo.Width, photo.Height);

//flip the image in horizontal direction

photo.RotateFlip(RotateFlipType.RotateNoneFlipX);

//render the rotated image

graphics.DrawImage( photo, 10, 10, photo.Width, photo.Height);

}

In the next article, our first sample will look at another usage of the DrawImage() function to achieve the reflecting and skewing effect for a given image. You won't want to miss it! 

blog comments powered by Disqus
WINDOWS SCRIPTING ARTICLES

- More Windows Scripting Workarounds from Nilpo
- Overloading Methods and More in VBScript
- Improving MFC for Windows Vista
- Regular Expressions in VBScript
- Working with Dates in WMI
- Completing Calendars with VBScript Date Func...
- Building Calendars with VBScript Date Functi...
- Working With Dates and Times in VBScript
- Designing WCF DataContract Classes Using the...
- Understanding Dates and Times in VBScript
- Working With Arrays in VBScript
- Compressed Folders in WSH
- Using .NET Interops in VBScript
- Nilpo`s Scripting Secrets, Vol I
- Database operations using Silverlight 2.0 WC...

ASP Web Hosting ASP.Net Web Hosting Windows Web Hosting
 
 
 

ASP Free Forums 
 RSS  Tutorials RSS
 RSS  Forums RSS
 RSS  All Feeds
Site Map 
Request Media Kit
Write For Us Get Paid 
Weekly Newsletter
 
Developer Updates  
Free Website Content 
Privacy Policy 
Support 


© 2003-2012 by Developer Shed. All rights reserved. DS Cluster 1 - Follow our Sitemap
Most Popular Topics
All ASP.Net Tutorials