Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

EnhancedImage Project

0.00/5 (No votes)
1 Sep 2005 1  
An article about how to enhance current image characteristics.

Sample Image - EnhancedImagePrj.jpg

Introduction

As we all know, raster images cannot scale very well. If you try to scale the image, you will run into jagged pixelization. Of course, you can use vector images to overcome this problem. However, we still need to deal with raster images as well. Now, enter the EnhancedImage project: it simply helps us to scale the image gracefully by introducing Insets concept.

I have been asked many times how to do scaling of raster images. I believe, programmers who have worked in web-based development have already run into similar cases like that. And probably many times they must have come up with quick and dirty solutions by writing custom code for a customized look and feel. I will use a well known technique to accomplish the desired effect. In this approach, the idea is quite simple: divide the picture into several regions and draw them separately. And here is the key: draw some of them as is, and let the others be stretched to satisfy the required image dimension.

Now, let's take a look at the following image. As you can see, the image is divided into 9 regions. I call them, NW, N, NE, W, Center, E, SW, S, and SE, where N: North, S: South, E: East and W: West.

In order to scale well, we will draw all corner images as-is. However the regions in the middle (such as N, W, E, S, and Center) will be all scaled (stretched). Therefore L1, L3, L4 and L6 are constant, on the other side L2 and L5 should be calculated properly. At this point, let me introduce the Insets class to you. It is a simple class that just holds the left, top, bottom and right values. In the previous image, the Insets object required at the constructor of the EnhancedImage class will be the borders of the center region. The following code provides a good detail of information about the usage of the Insets.

In short, the EnhancedImage class simply accomplishes this graceful scaling effect. Also, developers will be able to adjust the opacity of the image as well. A few things that I need to explain here. As you may know, the Image in .NET is an abstract base class. However, it is defined as an internal class in the System.Drawing namespace. That means, we cannot simply derive a new class based on it. It does provide functionality for System.Drawing.Bitmap and System.Drawing.Imaging.Metafile. Guess what? These two concrete classes are also sealed and therefore cannot be extended! Wow! What are we going to do? All that means is that we cannot establish a 'IS-A' relationship, but there is nothing that can stop us establishing a 'HAS-A' relationship. And that's really what we are going to do here. In my implementation, I have a private data member called mPeer to represent a base image for me.

The most interesting part of the code is the PrepareRegions() method:

//----------------- Regions -----------------

// 0,0 ----- L,0 -------------- R,0 ---- W,0

//  |         |                  |        | 

//  |   NW    |       N          |   NE   |

//  |         |                  |        |

// 0,T ----- L,T -------------- R,T ---- W,T

//  |         |                  |        |

//  |   W     |       C          |   E    |

//  |         |                  |        |

// 0,B ----- L,B -------------- R,B ---- W,B

//  |         |                  |        |

//  |   SW    |       S          |   SE   |

//  |         |                  |        |

// 0,H ----- L,H -------------- R,H ---- W,H

//--------------------------------------------            

Insets sourceNW = new Insets(0, 0, L, T); // North West

Insets sourceN  = new Insets(L, 0, R, T); // North

Insets sourceNE = new Insets(R, 0, W, T); // North East

Insets sourceW  = new Insets(0, T, L, B); // West

Insets sourceC  = new Insets(L, T, R, B); // Center

Insets sourceE  = new Insets(R, T, W, B); // East

Insets sourceSW = new Insets(0, B, L, H); // South West

Insets sourceS  = new Insets(L, B, R, H); // South

Insets sourceSE = new Insets(R, B, W, H); // South East


// Update values for destination regions

// (some values don't need to be changed!)

W = Width;               // Width  (EnhacedImage)

H = Height;              // Height (EnhacedImage)

R = W - sourceSE.Width;  // Right

B = H - sourceSE.Height; // Bottom 

    
Insets destinationNW = new Insets(0, 0, L, T); // North West

Insets destinationN  = new Insets(L, 0, R, T); // North

Insets destinationNE = new Insets(R, 0, W, T); // North East

Insets destinationW  = new Insets(0, T, L, B); // West

Insets destinationC  = new Insets(L, T, R, B); // Center

Insets destinationE  = new Insets(R, T, W, B); // East

Insets destinationSW = new Insets(0, B, L, H); // South West

Insets destinationS  = new Insets(L, B, R, H); // South

Insets destinationSE = new Insets(R, B, W, H); // South East


// Now, let's draw all regional pairs one by one...

DrawInsetsOn(g, sourceNW, destinationNW); // North West 

DrawInsetsOn(g, sourceN, destinationN);   // North 

DrawInsetsOn(g, sourceNE, destinationNE); // North East

DrawInsetsOn(g, sourceW, destinationW);   // West

DrawInsetsOn(g, sourceE, destinationE);   // East

DrawInsetsOn(g, sourceSW, destinationSW); // South West

DrawInsetsOn(g, sourceS, destinationS);   // South 

DrawInsetsOn(g, sourceSE, destinationSE); // South East


// Should we draw the center piece?

if (mDrawCenter)
    DrawInsetsOn(g, sourceC, destinationC); // Center


  .
  .
  .

If you are interested with the details, I would recommend that you take a good look at that part of the code.

Using the code

OK, how do we use the new class? Actually it is quite simple. First, create your enhanced image based on a base image, provide the insets, the desired width and height of the your enhanced image, and of course the opacity value. And voila! It is there for you to use :)

Insets insets = new Insets(left, top, right, bottom);
EnhacedImage enhancedImage = new EnhancedImage(baseImage, 
                                 width, height, insets, opacity);
.
.
.

// Let's draw the image somewhere in our program

Graphics g; // Obtain a graphics object here


// We need to obtain the regular representation

// of the enhanced image here

Image reqularImage = enhancedImage.RegularImage;
// And draw it just like any other image.

g.DrawImage(regularImage, x, y); // Draw it as usual at x, y.

Points of Interest

Now it is time to take a look at the provided program. It has quite a few knobs for you to play with. You can change the inset points visually by using the Insets Adjuster. Opacity, width and height can be also changed on the fly by sliding the trackbars. You will realize that interesting effects can be accomplished by changing the insets. Also take a look at the scaling effect by toggling the check box called Scale Properly. You will realize the regular vs. properly scale image differences right away. Also, don't forget to try different sample images provided in the application program.

History

I used similar techniques in my Java applications. Now, I added the same functionality to my C# library. You can always provide feedback and feature request so that we can make it even better.

Have fun :)

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here