Click here to Skip to main content
Click here to Skip to main content

Resize Images using 9 Slices

By , 4 May 2012
 

Introduction

Resizing images using 9 slices is a common practice to expand or shrink images without loss of quality in border areas. You can use for example a small image (for example, a resource in your app) to fill a large area or react on resize of an area without loss of quality.  

Background

The presented solution cuts your image into 9 parts. 1 part for each corner which will never be resized. 2 parts for left and right border which will be resized vertically. 2 parts for top and bottom border which will be resized horizontally and a part for the center area which will be resized in both directions.

Let's take a look at the differences:

Resized without 9 slices Resized with 9 slices

Using the Code

For easy use, I've implemented the resizing method as an extension method of the Image-Class. This allows you to resize an image easily like this:  

myImage = myImage.ResizeUsingSlices(new Size(250,250), 
new SliceBorders{ Top=8, Left=8, Right=8, Bottom=8});

The Code Itself

public static class ImageEx
{
	/// <summary>
	/// Resize an image using 9 slices
	/// </summary>
	/// <param name="image">image to be resized</param>
	/// <param name="newsize">new size</param>
	/// <param name="borders">
	/// borders which define the slicing areas</param>
	/// <returns>resized image</returns>
	public static Image ResizeUsingSlices
	(this Image image, Size newsize, SliceBorders borders)
	{
		if (image == null)
		{
			return image;
		}

		Bitmap bitmap = new Bitmap
		(newsize.Width, newsize.Height, image.PixelFormat);
		bitmap.SetResolution(96, 96);

		using (Graphics graphics = Graphics.FromImage(bitmap))
		{
			graphics.SmoothingMode = 
			System.Drawing.Drawing2D.SmoothingMode.None;
			graphics.InterpolationMode = 
			System.Drawing.Drawing2D.InterpolationMode.Default;
			graphics.Clear(Color.Transparent);
			Bitmap original = new Bitmap(image);

			try
			{
				// top left corner
				using (Bitmap slice = _GetSlice
				(original, new Rectangle(0, 0, borders.Left, borders.Top)))
				{
					graphics.DrawImageUnscaled((Image)slice, 0, 0);
				}
				
				// top right corner
				using (Bitmap slice = _GetSlice(original, 
				new Rectangle(image.Width - borders.Right, 
				0, borders.Right, borders.Top)))
				{
					graphics.DrawImageUnscaled((Image)slice, 
					newsize.Width - borders.Right, 0);
				}
				
				// bottom left corner
				using (Bitmap slice = _GetSlice(original, 
				new Rectangle(0, image.Height - 
				borders.Bottom, borders.Left, borders.Bottom)))
				{
					graphics.DrawImageUnscaled((Image)slice, 
					0, newsize.Height - borders.Bottom);
				}
				
				// bottom right corner
				using (Bitmap slice = _GetSlice(original, 
				new Rectangle(image.Width - borders.Right, 
				image.Height - borders.Bottom, 
				borders.Right, borders.Bottom)))
				{
					graphics.DrawImageUnscaled((Image)slice, 
					newsize.Width - borders.Right, 
					newsize.Height - borders.Bottom);
				}
				
				// top border
				using (Bitmap slice = _GetSlice(original, 
				new Rectangle(borders.Left, 0, 
				image.Width - borders.Left - 
				borders.Right, borders.Top)))
				{
					graphics.DrawImageUnscaled(slice.Resize
					(new Size(newsize.Width - 
					borders.Left - borders.Right, borders.Top)), 
					borders.Left, 0);
				}
				
				// bottom border
				using (Bitmap slice = _GetSlice(original, 
				new Rectangle(borders.Left, image.Height - borders.Bottom, 
				image.Width - borders.Left - borders.Right, borders.Bottom)))
				{
					graphics.DrawImageUnscaled(slice.Resize(new Size
					(newsize.Width - borders.Left - 
					borders.Right, borders.Bottom)), 
					borders.Left, newsize.Height - borders.Bottom);
				}
				
				// left border
				using (Bitmap slice = _GetSlice(original, new Rectangle
				(0, borders.Top, borders.Left, 
				image.Height - borders.Top - borders.Bottom)))
				{
					graphics.DrawImageUnscaled(slice.Resize(new Size
					(borders.Left, newsize.Height - 
					borders.Bottom - borders.Top)), 0, borders.Top);
				}
				
				// right border
				using (Bitmap slice = _GetSlice(original, new Rectangle
				(image.Width - borders.Right, 
				borders.Top, borders.Right, 
				image.Height - borders.Top - borders.Bottom)))
				{
					graphics.DrawImageUnscaled(slice.Resize(new Size
					(borders.Right, newsize.Height - 
					borders.Bottom - borders.Top)), 
					newsize.Width - borders.Right, borders.Top);
				}
				
				// center area
				using (Bitmap slice = _GetSlice(original, new Rectangle
				(borders.Left, borders.Top, 
				image.Width - borders.Left - borders.Right, 
				image.Height - borders.Top - borders.Bottom)))
				{
					graphics.DrawImageUnscaled
					(slice.Resize(new Size(newsize.Width - 
					borders.Left - borders.Right, 
					newsize.Height - borders.Top - 
					borders.Bottom)), borders.Left, borders.Top);
				}
			}
			catch (Exception ex)
			{
				throw ex;
			}
			finally
			{
				original.Dispose();
			}
		}

		return bitmap;
	}

	private static Bitmap _GetSlice(Bitmap img, Rectangle rect)
	{
		return img.Clone(rect, img.PixelFormat);
	}

	/// <summary>
	/// Resize an Image
	/// </summary>
	/// <param name="img">image to be resized</param>
	/// <param name="newsize">new size</param>
	/// <returns>resized image</returns>
	public static Image Resize(this Image img, Size newsize)
	{
		return img.GetThumbnailImage(newsize.Width, newsize.Height, delegate() 
		{ return false; }, IntPtr.Zero);
	}
}

/// <summary>
/// Helper-Class for define borders to use in Image.ResizeUsingSlices
/// </summary>
public class SliceBorders
{
	/// <summary>
	/// left border
	/// </summary>
	public int Left { get; set; }
	/// <summary>
	/// top border
	/// </summary>
	public int Top { get; set; }
	/// <summary>
	/// right border
	/// </summary>
	public int Right { get; set; }
	/// <summary>
	/// bottom border
	/// </summary>
	public int Bottom { get; set; }

	/// <summary>
	/// Constructor
	/// </summary>
	public SliceBorders()
	{
	}
}  

As you can see, I use a little Helper-Class for an easier definition of the border areas. Of course, you could also define the 4 border sizes directly if you wish.

Points of Interest

There is nothing very special. All you need is an image that has border areas and a center area with a single color or an gradient.

Here are a few images with recommended border sizes. To use it in your application, simply right click the image and 'save as...', put it in your application and use it like described before. ;-)

Border sizes:  Top 13, Left  9, Right 9, Bottom 3 

Border sizes:  Top 13, Left  9, Right 9, Bottom 3 

Border sizes:  Top 4, Left  4, Right 4, Bottom 6  

Border sizes:  Top 4, Left  4, Right 4, Bottom 6  

 

Border sizes:  Top 4, Left  4, Right 4, Bottom 6

History

  • 2012-05-03 First version
  • 2012-05-04 Second version - better bitmap handling to avoid undisposed bitmaps

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

H. Mueller
Software Developer (Senior)
Germany Germany
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
Hint: For improved responsiveness ensure Javascript is enabled and choose 'Normal' from the Layout dropdown and hit 'Update'.
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 5memberSeishin#3 May '12 - 21:36 
GeneralRe: My vote of 5memberH. Mueller4 May '12 - 1:29 
SuggestionInteresting, what is the application for this? (also, it "leaks" Bitmaps)memberMatt T Heffron3 May '12 - 10:28 
GeneralRe: Interesting, what is the application for this? (also, it "leaks" Bitmaps)memberH. Mueller3 May '12 - 20:34 
GeneralRe: Interesting, what is the application for this? (also, it "leaks" Bitmaps)memberMatt T Heffron4 May '12 - 12:14 

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

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130523.1 | Last Updated 4 May 2012
Article Copyright 2012 by H. Mueller
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid