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
{
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
{
using (Bitmap slice = _GetSlice
(original, new Rectangle(0, 0, borders.Left, borders.Top)))
{
graphics.DrawImageUnscaled((Image)slice, 0, 0);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
public static Image Resize(this Image img, Size newsize)
{
return img.GetThumbnailImage(newsize.Width, newsize.Height, delegate()
{ return false; }, IntPtr.Zero);
}
}
public class SliceBorders
{
public int Left { get; set; }
public int Top { get; set; }
public int Right { get; set; }
public int Bottom { get; set; }
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