C#, WPF – Fast image resize

Today I read a blog on http://weblogs.asp.net/bleroy/archive/2009/12/10/resizing-images-from-the-server-using-wpf-wic-instead-of-gdi.aspx which introduces a new way to resize image with WPF. This new method does not use GDI+ (Microsoft Windows GDI+ is the portion of the Windows XP operating system or Windows Server 2003 operating system that provides two-dimensional vector graphics, imaging, and typography.) but it uses WPF library for resizing images very fast. You can read more details about this method in that blog. In the code below, I would like to summarize and explain a little how it works.
The main concept, that we will read all bytes of image, read the first frame of image and use class TransformedBitmap to create a new bitmap frame with the specific scale transform. In the code snippet below shows how the process runs. So that code below works we need to add reference to following assemblies: PresentationCore and WindowsBase.

static void Main(string[] args)
{
	string strFileName = "Marshimaro.jpg";
	string strThumbnail = "MarshimaroThumb.png";
	byte[] baSource = File.ReadAllBytes(strFileName);
	using (Stream streamPhoto = new MemoryStream(baSource))
	{
		BitmapFrame bfPhoto = ReadBitmapFrame(streamPhoto);

		int nThumbnailSize = 200, nWidth, nHeight;
		if (bfPhoto.Width > bfPhoto.Height)
		{
			nWidth = nThumbnailSize;
			nHeight = (int)(bfPhoto.Height * nThumbnailSize / bfPhoto.Width);
		}
		else
		{
			nHeight = nThumbnailSize;
			nWidth = (int)(bfPhoto.Width * nThumbnailSize / bfPhoto.Height);
		}
		BitmapFrame bfResize = FastResize(bfPhoto, nWidth, nHeight);
		byte[] baResize = ToByteArray(bfResize);

		File.WriteAllBytes(@"Thumbnails\" + Path.GetFileNameWithoutExtension(strThumbnail) + ".png", baResize);
		Console.WriteLine("Resize done!!!");
		Console.ReadLine();
	}
}

BitmapFrame represents image data returned by a decoder and accepted by encoders. You can see in the function ReadBitmapFrame how we can use BitmapDecoder to decode stream data of image and get the first bitmap frame.
The core of complete code is the class TransformedBitmap which supports only orthogonal transforms such as rotation transforms of 90° increments and scale transforms. In FastResize function, we apply ScaleTransform to resize image as following.

private static BitmapFrame FastResize(BitmapFrame bfPhoto, int nWidth, int nHeight)
{
	TransformedBitmap tbBitmap = new TransformedBitmap(bfPhoto, new ScaleTransform(nWidth / bfPhoto.Width, nHeight / bfPhoto.Height, 0, 0));
	return BitmapFrame.Create(tbBitmap);
}

private static byte[] ToByteArray(BitmapFrame bfResize)
{
	using (MemoryStream msStream = new MemoryStream())
	{
		PngBitmapEncoder pbdDecoder = new PngBitmapEncoder();
		pbdDecoder.Frames.Add(bfResize);
		pbdDecoder.Save(msStream);
		return msStream.ToArray();
	}
}

private static BitmapFrame ReadBitmapFrame(Stream streamPhoto)
{
	BitmapDecoder bdDecoder = BitmapDecoder.Create(streamPhoto, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.None);
	return bdDecoder.Frames[0];
}

You can parse the code into class and use it everywhere. The complete code can be downloaded here “WPF Fast image resize

UPDATE 11.03.2010 : Insert (using Stream) to prevent memory leak.

6 thoughts on “C#, WPF – Fast image resize”

  1. Hi,

    I’ve just tried to implement this and yes, it is very fast, but I’m getting some really bad memory leaks. It resizes the image correctly, but keeps the original sized image in memory somewhere and doesn’t dispose of it.

    I didn’t follow your method exactly because I’m using BitmapSources and putting them straight into WPF Image controls rather than saving them as files.

  2. @harry: I updated source code with using to prevent memory leak. Please try if it works for your case.

  3. It didn’t fix it, but I think there’s something else going wrong with my code. Cheers anyway for trying!

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>