Click here to Skip to main content
15,867,686 members
Articles / Programming Languages / C#
Tip/Trick

Resize Images to Size Limit

Rate me:
Please Sign up or sign in to vote.
4.83/5 (16 votes)
3 Jun 2013CPOL3 min read 75.6K   2.6K   22   25
This tip describes how to resize an existing image (e.g. uploaded by a user) so it does not exceed a defined size limit.

Introduction

To enable customers to upload images which exceed the maximum upload size given by the system, it became necessary to scale down large images until the given size limit was no longer exceeded. Since I did not find any articles about this problem, I decided to write one myself to maybe help others struggling with a similar problem.

Initialization

Before we can start the resizing process, we need to obtain the source path of the uploaded image, the destination path (which is very likely the same path) and the maximum allowed size given by your system. All these values are initialized in the constructor:

C#
private int allowedFileSizeInByte;
private string sourcePath;
private string destinationPath;

public ImageResizer(int allowedSize, string sourcePath, string destinationPath)
{
	allowedFileSizeInByte = allowedSize;
	this.sourcePath = sourcePath;
	this.destinationPath = destinationPath;
}

Scaling Images

Let's start with the function which does the scaling. I use a Bitmap as the source image and a scale factor which is applied to change the width and height of the image. Later, we will see how to calculate this scale factor. Since the following code is pretty straight forward, I won't go into further details:

C#
public Bitmap ScaleImage(Bitmap image, double scale)
{
	int newWidth = (int)(image.Width * scale);
	int newHeight = (int)(image.Height * scale);

	Bitmap result = new Bitmap(newWidth, newHeight, PixelFormat.Format24bppRgb);
	result.SetResolution(image.HorizontalResolution, image.VerticalResolution);

	using (Graphics g = Graphics.FromImage(result))
	{
		g.InterpolationMode = InterpolationMode.HighQualityBicubic;
		g.CompositingQuality = CompositingQuality.HighQuality;
		g.SmoothingMode = SmoothingMode.HighQuality;
		g.PixelOffsetMode = PixelOffsetMode.HighQuality;

		g.DrawImage(image, 0, 0, result.Width, result.Height);
	}
	return result;
}   

Calculating the Scale Factor

The scale factor for the file size can be approximated by dividing the allowed file size by the file size of the image. This simply describes by which amount the file size has to decrease to reach the size limit. Since we generally don't know anything about the compression of the uploaded image, we cannot exactly predict by which factor we have to scale the width and height of our image. However, we know that the file size of an image will increment quadratically if we increase its width and height, since the file size is approximately calculated by multiplying width and height. Since we want to decrease the file size of the picture, we simply have to calculate the square root of the scale factor calculated above and use this value as a parameter for our ScaleImage function. To clarify this process, take a look at the following function which will be called by the client to perform the resizing:

C#
public void ScaleImage()
{
	using (MemoryStream ms = new MemoryStream())
	{
		using (FileStream fs = new FileStream(sourcePath, FileMode.Open))
		{
			Bitmap bmp = (Bitmap)Image.FromStream(fs);
			SaveTemporary(bmp, ms, 100);

			while (ms.Length > allowedFileSizeInByte)
			{
				double scale = Math.Sqrt
				((double)allowedFileSizeInByte / (double)ms.Length);
				ms.SetLength(0);
				bmp = ScaleImage(bmp, scale);
				SaveTemporary(bmp, ms, 100);
			}

			if (bmp != null)
				bmp.Dispose();
			SaveImageToFile(ms);
		}
	}
}	

As you can see, we use a while MemoryStream to save the uploaded image in memory instead of the hard disk during the resizing process. The Bitmap variable bmp contains the image to be resized which is obtained through a FileStream. Inside the while loop, the image is resized using the scale factor and the new image is saved back into the MemoryStream using the SaveTemporary function we will see in a minute. This while loop is applied until the size limit is not exceeded anymore. We need to iterate here, because our scale factor is really only an approximation and depending on the image it might not provide enough scaling when calling ScaleImage for the first time.

Other Helper Functions

Finally, let's take a look at the helper functions used by the scaling process:

C#
private void SaveTemporary(Bitmap bmp, MemoryStream ms, int quality)
{
	EncoderParameter qualityParam = new EncoderParameter
		(System.Drawing.Imaging.Encoder.Quality, quality);
	var codec = GetImageCodecInfo();
	var encoderParams = new EncoderParameters(1);
	encoderParams.Param[0] = qualityParam;
	bmp.Save(ms, codec, encoderParams);
}

private void SaveImageToFile(MemoryStream ms)
{
	byte[] data = ms.ToArray();

	using (FileStream fs = new FileStream(destinationPath, FileMode.Create))
	{
		fs.Write(data, 0, data.Length);
	}
}

private ImageCodecInfo GetImageCodecInfo()
{
	FileInfo fi = new FileInfo(sourcePath);

	switch (fi.Extension)
	{
		case ".bmp": return ImageCodecInfo.GetImageEncoders()[0];
		case ".jpg":
		case ".jpeg": return ImageCodecInfo.GetImageEncoders()[1];
		case ".gif": return ImageCodecInfo.GetImageEncoders()[2];
		case ".tiff": return ImageCodecInfo.GetImageEncoders()[3];
		case ".png": return ImageCodecInfo.GetImageEncoders()[4];
		default: return null;
	}
}

The SaveTemporary function is used to temporarily save the image into the provided MemoryStream during each iteration. It uses .NET EncoderParameters and ImageCodecInfo to get high quality compression rates which are nearly as good as the compression rates provided by Image editing software. Using the EncoderParameters and ImageCodecInfo in the call to bmp.Save provides better result than using the save function which takes a stream and an ImageFormat instance as its only parameters, so I advise you to use this version to get the best results. The SaveImageToFile function is finally used to write the MemoryStream, which contains the resized image, to its final location on the hard disk.

Summary

Hopefully you find this code useful and can apply it to solve similar problems. I appreciate any feedback tips and suggestions.

License

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


Written By
Software Developer (Senior)
Germany Germany
Hi there 🙂
My name is Philipp Engelmann, I work as a web developer at FIO SYSTEMS AG in Leipzig. I am interested in C#, Python, (REST-)API-Design, software architecture, algorithms and AI. Check out my blog at https://cheesyprogrammer.com/

Comments and Discussions

 
Questionminimum height and width Pin
Ajula14-Nov-17 11:32
Ajula14-Nov-17 11:32 
AnswerRe: minimum height and width Pin
Philipp_Engelmann22-Dec-17 1:44
Philipp_Engelmann22-Dec-17 1:44 
Questioncode to read a raw image(image.raw file) Pin
Member 1342274821-Sep-17 15:30
Member 1342274821-Sep-17 15:30 
AnswerRe: code to read a raw image(image.raw file) Pin
Philipp_Engelmann22-Dec-17 1:48
Philipp_Engelmann22-Dec-17 1:48 
QuestionIO exception Pin
Member 126240477-Jul-16 11:59
Member 126240477-Jul-16 11:59 
AnswerRe: IO exception Pin
Member 38286545-Sep-17 0:05
Member 38286545-Sep-17 0:05 
GeneralThanks Helped Pin
Sadique KT7-Oct-15 0:07
Sadique KT7-Oct-15 0:07 
QuestionProblem rotate Image Pin
Ali_308524-Mar-15 5:54
Ali_308524-Mar-15 5:54 
AnswerRe: Problem rotate Image Pin
Philipp_Engelmann25-Mar-15 4:14
Philipp_Engelmann25-Mar-15 4:14 
GeneralRe: Problem rotate Image Pin
Ali_308525-Mar-15 4:52
Ali_308525-Mar-15 4:52 
SuggestionProblem solved Pin
Ali_308526-Mar-15 4:45
Ali_308526-Mar-15 4:45 
GeneralRe: Problem solved Pin
Philipp_Engelmann27-Mar-15 5:20
Philipp_Engelmann27-Mar-15 5:20 
NewsThanks for Simple and fast code Pin
Rockford Sol1-Dec-14 9:04
Rockford Sol1-Dec-14 9:04 
GeneralRe: Thanks for Simple and fast code Pin
Philipp_Engelmann13-Jan-15 3:41
Philipp_Engelmann13-Jan-15 3:41 
GeneralRe: Thanks for Simple and fast code Pin
Rockford Sol18-Jan-15 8:20
Rockford Sol18-Jan-15 8:20 
GeneralRe: Thanks for Simple and fast code Pin
Philipp_Engelmann18-Jan-15 22:10
Philipp_Engelmann18-Jan-15 22:10 
GeneralVery Good Solution. Exactly what I wanted. Pin
DhanushkaG10-Nov-14 7:11
DhanushkaG10-Nov-14 7:11 
QuestionReduce image size without affecting the image dimension Pin
Member 992590810-Mar-14 1:46
Member 992590810-Mar-14 1:46 
AnswerRe: Reduce image size without affecting the image dimension Pin
Philipp_Engelmann10-Mar-14 2:03
Philipp_Engelmann10-Mar-14 2:03 
QuestionThanks - exactly what I was looking for! Pin
kmf15-Feb-14 0:14
kmf15-Feb-14 0:14 
GeneralMy vote of 5 Pin
YuukanOO23-Jul-13 3:57
YuukanOO23-Jul-13 3:57 
GeneralRe: My vote of 5 Pin
Philipp Engelmann23-Jul-13 4:18
Philipp Engelmann23-Jul-13 4:18 
GeneralMy vote of 5 Pin
Volynsky Alex6-Jun-13 9:32
professionalVolynsky Alex6-Jun-13 9:32 
QuestionVery Useful Pin
ryanoc3334-Jun-13 4:45
ryanoc3334-Jun-13 4:45 
AnswerRe: Very Useful Pin
Philipp Engelmann4-Jun-13 5:05
Philipp Engelmann4-Jun-13 5:05 

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.