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

Simple Image Resizing Library

By , 18 Jan 2008
 

Introduction

I seem to be doing a lot of applications where I have to deal with images a lot, and specifically the issue of dynamically resizing images - so I decided to write a library to make the process as simple as possible.

Background

My goals for this library were to make it easy to use, and flexible enough to be used no matter how you store your images (FileSystem, Database, Amazon Web Services, etc.). As for the discussion on which way is the "best" way to store images, I'll leave that to someone else. However, anyway you go, there's still some common things you have to think about: resizing images and maintaining aspect ratio, uniqueness of file names, etc.

Using the code

I usually try not to add extra objects when creating simple libraries like this one - but in this case, I thought it might actually help. To resize images, sometimes a lot of information is needed: the image stream, content type, desired width or height, etc. So, rather than create methods with a ton of parameters, this library will use the ImageInfo object which holds most of this information for us. I've also split some methods up into two "manager" classes: WebManager and FileManager. If you're using this library on a code-behind page, then the "WebManager" object is probably the best way to go - otherwise you'd use the "FileManager" class.

Best of all, you can override or inherit from just about anything, so you can modify it to fit your specific situation.

The attached demo project includes all the samples described here, as well as a separate project containing the library.

Sample: Save an uploaded image and resized versions

In this first example, we'll assume that we've just posted an ASPX page, and used a FileUpload control to select an image to upload. This code is placed in the ButtonSubmit_Click method:

//use WebManager to get the file, and save it
IImageInfo img = WebManager.GetImageInfo(fileUploader);
img.Path = "uploadedImages";
img.Save();
    
//now create resized versions, and save them
IImageInfo imgLarge = img.ResizeMe(null, 300);    //constrain to 300 pixels wide
imgLarge.Save("uploadedImages/large");        //save file in a folder named "large"
    
IImageInfo imgMedium = img.ResizeMe(185, null);    //constrain to 185 pixels high
imgMedium.Save("uploadedImages/medium");

IImageInfo imgSmall = img.ResizeMe(null, 100);    //constrain to 100 pixels wide
imgSmall.Save("uploadedImages/small");

IImageInfo imgTiny = img.ResizeMe(50, null);    //constrain to 50 pixels high
imgTiny.Save("uploadedImages/tiny");

Let's go over the example above, line by line. The first line calls the static GetImageInfo method on the WebManager class. This method takes the FileUpload, populates an object that uses the IImageInfo interface with the information of the uploaded image, and returns it.

IImageInfo img = WebManager.GetImageInfo(fileUploader);

The next line sets the Path to the directory "uploadedImages". This is the directory that we want to save the original uploaded file into. **Please note that you must adjust the permissions on this directory to allow the .NET process to write to it. In my case, I have given "modify" privileges to three users: IIS_WPG, ASPNET, and IIS_IUSRS.

img.Path = "uploadedImages";

The next line simply calls the Save method that is available on the ImageInfo object. Because we didn't pass in any parameters, this method will save the uploaded image using its existing file name.

img.Save();

The next line uses the ResizeMe method available on the ImageInfo class to resize the image it holds, and then returns a new ImageInfo object with the resized image. The ImageInfo object contains all of the same information as the original image (path, filename, etc), but the PhotoStream, Width, and Height are set to the resized image dimensions. The ResizeMe method takes two nullable integers: maxHeight and maxWidth. In this case, we only care about the width being 300 pixels - so we can set maxHeight to null (or 0). Setting both the maxHeight and maxWidth parameters would resize the image so that neither the maxHeight nor maxWidth was exceeded. It would not resize the image to the exact maxHeight and maxWidth specified - it would still maintain the correct aspect ratio. In the example below, we pass in null for the maxHeight, and 300 for the width, resulting in an image resized with a width of 300 pixels.

IImageInfo imgLarge = img.ResizeMe(null, 300);

The next line calls the Save method again, but this time, we pass in the path that we want to save the image to. In this case, we want the resized image to reside in the "uploadedImages/large" directory.

imgLarge.Save("uploadedImages/large");

(**Note: We could also prepend "/large" to the existing Path property of the imgLarge variable as shown below, and then call Save()):

imgLarge.Path += "/large";

The next section does the same resize action shown above, but this time resizes the image by setting a maxHeight, and no maxWidth.

IImageInfo imgMedium = img.ResizeMe(185, null);
imgMedium.Save("uploadedImages/medium");

So, that's the bare bones example. However, you're not always going to save images in this way; many times, they need to be tied to specific records in a database, or be named in a specific way. Let's take a look at what we might do in some other situations.

Other examples

In the following code sample, we'll save a pointer to an image in the database first, then use the new ID in the image filename.

//get uploaded image
IImageInfo img = WebManager.GetImageInfo(fileUploader);
string[] fileNameParts = img.FileName.split('.');
string fileExtension = fileNameParts.GetValue((fileNameParts.Length - 1));

Photo p = new Photo();
p.ProductID = 1;    //tie it to a product
p.Path = "uploadedImages/photos";
p.Description = "Left side view";
p.FileExtension = fileExtension;
ProductRepository.Save(p);

int newID = p.PhotoID;

img.Path = p.Path;
img.FileName = string.Format("{0}.{1}", newID.ToString(), p.FileExtension);
img.Save();

//save thumbnail versions
img.ResizeMe(null, 185).Save(p.Path += "/large");
img.ResizeMe(null, 100).Save(p.Path += "/medium");
img.ResizeMe(null, 50).Save(p.Path += "/small");

The above sample shows how this library makes things a bit easier when saving product photos. In it, we save the record to the database first, then save the images to the file system using the unique ID generated when the record was created. Now, when we need to display this product photo, we can simply point to the "uploadedImages/photos/[PhotoID].[FileExtension]" file. If the smaller image is needed, simply point to the image under the "large", "medium", or "small" subfolder.

So, given the sample above, what happens if we need to delete a pPhoto? It'd be nice to delete the original image from the file system as well as all the thumbnail images that were generated. Luckily, we can do that a couple different ways. To delete the images that were created in the example above, you would do something like this:

Photo p = PhotoRepository.GetPhotoByID(id);

//first, delete the images
string[] pathsToDeleteFrom = new string[] { p.Path, p.Path += 
  "/large", p.Path += "/medium", p.Path += "/small" };
WebManager.DeleteImageSetFromFileSystem(string.Format("{0}.{1}", 
  p.PhotoID.ToString(), p.FileExtension), pathsToDeleteFrom);

//now delete the database record
PhotoRepository.Delete(p);

The DeleteImageSetFromFileSystem method takes in the filename and the string array of paths (directories) to delete that file from. So, in this example, the filename with this photo's PhotoID will be deleted from each of the paths in the string array.

Conclusion

So, that's a quick look at the library. I hope you find it useful. I hope to update with more features in the future, and will post those here when I do.

Any feedback/suggestions are definitely welcome!

License

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

About the Author

Leftend
Software Developer (Senior) Leftend
United States United States
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

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 5memberJenni Osborn19 Jan '12 - 0:19 
Fantastic, simple and elegent, Many Thanks.
QuestionSee imageresizing.net insteadmemberNathanael Jones6 Jan '12 - 6:43 
For an open-source implementation without these bugs, see the imageresizing.net project.
GeneralObject reference not set to an instance of an objectmemberavigalim200014 May '11 - 5:22 
Hi,
 
I try to use the library in my project to resize an image.
I get "Object reference not set to an instance of an object" when calling this line:
"IImageInfo imgThumb = img.ResizeMe(null, thumbMaxSize);".
 
VS 2010, .net framework 4.0.
 
Any ideas?
Thanks,
Aviram
GeneralThanks!memberRkHrd30 Jan '10 - 8:18 
Yeah, this is very useful. Thanks Smile | :)
GeneralImage or Blob ResizingmemberSP Vilakazi1 Oct '09 - 7:36 
Hi
 
1. I am currently working on Automatic Number Plate Recognition using mainly AForge.NET filters. I have managed to binarise the image, filter out all unwanted blobs and I can display each blob by entering its position.
 
2. However, I am now trying to resize a blob to 16X16 so that I can try to get its intensity matrix to use for correlation. The aim of correlation is to recognise the alphanumeric symbol represented by the the blob. Even though only one blob is displayed at a time, the image area is still the whole number plate and I am failing to automate it because in applying the for loop or while loop, the result is only the last blob that is displayed. I tried to google for a code that does this, with no success. I also couldnt get the code to get the intensity matrix from a binary image. Refer to the code below:
foreach (Rectangle symbol in numberPlate)
                {
 
                    //Get the position and size of each object
                    System.Diagnostics.Debug.WriteLine(string.Format("Position: ({0}, {1}), Size: {2}x{3}", symbol.Left, symbol.Top, symbol.Width, symbol.Height));
 
                   for (int i = 0; i <= numberPlate.Length - 3; )// displays one symbol at a time
                    {
 
                        // create filter
                        CanvasCrop filter11 = new CanvasCrop(new Rectangle(
                                                numberPlate[i].Left -2, 0, symbol.Width + 4, maxY - minY + 5), 1); //1 means that the rest of the space must be filled with black
                        //making the rest of the space black ensures that no new blobs will be created by symbol segmentation
                        // Above: new CanvasCrop(new Rectangle(xposition, yposition, width, Height), colour);

                        // apply the filter
                         newImage_ = filter11.Apply(image6_);
                         pictureBox1.Image = newImage_;
                         for (int intPauseCounter = 1; intPauseCounter <= 600000; intPauseCounter++)
                       {
                       }
                        ++i;
 
//                        // create filter
//                        // create filter
//                        Edges filter12 = new Edges();
//                        // apply the filter
//                        Bitmap image12_ = filter12.Apply(newImage_);

//                        Difference filter13 = new Difference(image12_);
//                        Bitmap image13_ = filter13.Apply(newImage_);
                        
//                        pictureBox1.Image = image13_;

                        int x = 0;
 
                        // An array of integers
                        //int[] array1 = {0, 1, 2, 3, 4, 5};

                        while (x < 4)
                        {
                            Console.WriteLine(numberPlate[x].ToString());// get the intensity matrix
                            x++;
                        };
 

 
 
 
                    }
                }
        }
                    
                    public byte[] imageToByteArray(Bitmap image6_)
		{
			MemoryStream ms = new MemoryStream();
			image6_.Save(ms,System.Drawing.Imaging.ImageFormat.Bmp);
			
            //System.Diagnostics.Debug.WriteLine("Object Array: "); // Get the number of objects
            return ms.ToArray();
 
                    }
 
3. The code that I used to get the intensity of the image only gives the position and size of the blob.
 
Please help with your guidance as I am still learning C# and I am using .NET.
 
Thank you in advance
Regards
GeneralVC6 & Simple Image Resizing Librarymemberandwan07 Jun '09 - 7:10 
Since this is a library, is it a standalone library (eg. DLL) where we can use in VC6 projects?
GeneralRe: VC6 & Simple Image Resizing LibrarymemberLeftend8 Jun '09 - 7:08 
It is a standalone library, however, it's built on the .NET Framework - so that's a prerequisite as well.
Generalabout dynamics,,memberykorotia18 Jan '09 - 3:04 
Ask you as senior developer, 'cause junior probably doesn't know..
 
Situation: we need to upload large image, then resize into small and save it to database.
Question: is it possible to do it using only memory stream, no stores files, etc. Just web request, processing, web response. No files, just memory?
 
regards
GeneralRe: about dynamics,,memberLeftend18 Jan '09 - 10:38 
Absolutely, it's definitely possible. In fact, the library provided in this article will get you half way there. It will resize the image in memory. You can then save the resized image to the database. One caveat... ASP.NET does have a default setting for how big of a file you can upload... and this library won't help you there. If you find that the images you need to upload are bigger than the default size limit, then you can either increase the size limit in the web.config file - or use another third party tool that uses other technologies (like Flash) to allow for bigger file uploads.
 
Hope that helps.
JokeRe: about dynamics,,memberykorotia18 Jan '09 - 11:29 
Yes. Some parts of your code will be used as it's useful (with proper link for your name, of course).
Currently there's one codesnippet from http://snippets.dzone.com/posts/show/1485 by Edgardo. Works fine, except transparency.. painful thing, probably. Those pixels left, pixels right.. ooh. Maybe someday you will implement that feature into your library? Sleepy | :zzz:
 
regards

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

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130523.1 | Last Updated 18 Jan 2008
Article Copyright 2008 by Leftend
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid