Click here to Skip to main content
15,880,972 members
Articles / Desktop Programming / Windows Forms

EnhancedImage Project

Rate me:
Please Sign up or sign in to vote.
4.94/5 (22 votes)
1 Sep 20054 min read 68.9K   2.9K   63   9
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.

Image 2

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:

C#
//----------------- 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 in 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. :)

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

Image 3

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.


Written By
Software Developer
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionHelp: those frames.... for Project Dogwaffle? Pin
staigerman6-Sep-05 8:12
staigerman6-Sep-05 8:12 
GeneralThanks man but 1 question Pin
Trance Junkie5-Sep-05 1:47
Trance Junkie5-Sep-05 1:47 
GeneralInteresting Pin
The_Mega_ZZTer2-Sep-05 5:33
The_Mega_ZZTer2-Sep-05 5:33 
XP Visual Styles actually uses this very same techniquie to scale buttons, groupboxes, and so forth. I made a few classes that emulated this same behavior, which do pretty much the same thing yours do, except maybe a little less elegantly.

One thing XPVS implement that you didn't is the ability to tile the image (horizontally, vertically, or both) instead of stretching... so I could stretch horizontally and tile vertically, or tile both ways. I think for the most part Visual Styles images stretch, but if an image is made with tiling in mind, it could look better than a stretched image (since it won't get pixelated or blurry, although it will repeat). Just something to consider implementing.

-- modified at 11:33 Friday 2nd September, 2005
GeneralRe: Interesting Pin
otigli2-Sep-05 9:16
otigli2-Sep-05 9:16 
GeneralFlicker and your Inserts Adjuster Pin
fwsouthern1-Sep-05 16:00
fwsouthern1-Sep-05 16:00 
GeneralRe: Flicker and your Inserts Adjuster Pin
otigli1-Sep-05 16:20
otigli1-Sep-05 16:20 
GeneralRe: Flicker and your Inserts Adjuster Pin
sheraziii12-Sep-05 0:14
sheraziii12-Sep-05 0:14 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.