C# Tutorial - Image Editing: Saving, Cropping, and Resizing

Skill

C# Tutorial - Image Editing: Saving, Cropping, and Resizing

Posted in:

In C# it can be tiresome to do certain image editing functions using GDI+. This post has some fun editing methods which can come in handy at times. I have also included a nice little C# program to show all the functionality of the methods below.

Saving a Jpeg

The first thing to do here is set up the method signature with the input parameters. These are the save file path (string), the Image to save (System.Drawing.Bitmap), and a quality setting (long).

private void saveJpeg(string path, Bitamp img, long quality)

The next few things to do are setting up encoder information for saving the file. This includes setting an EncoderParameter for the quality of the Jpeg. The next thing is to get the codec information from your computer for jpegs. I do this by having a function to loop through the available ones on the computer and making sure jpeg is there. The line under that makes sure that the jpeg codec was found on the computer. If not it just returns out of the method.

The last thing to do is save the bitmap using the codec and the encoder infomation.

private void saveJpeg(string path, Bitmap img, long quality)
{
   // Encoder parameter for image quality
   EncoderParameter qualityParam = new EncoderParameter(Encoder.Quality, quality);

   // Jpeg image codec
   ImageCodecInfo jpegCodec = this.getEncoderInfo("image/jpeg");

   if(jpegCodec == null)
      return;

   EncoderParameters encoderParams = new EncoderParameters(1);
   encoderParams.Param[0] = qualityParam;

   img.Save(path, jpegCodec, encoderParams);
}

private ImageCodecInfo getEncoderInfo(string mimeType)
{
   // Get image codecs for all image formats
   ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();

   // Find the correct image codec
   for (int i = 0; i < codecs.Length; i++)
      if (codecs[i].MimeType == mimeType)
         return codecs[i];
   return null;
}

Cropping

The method takes two objects - the image to crop (System.Drawing.Image) and the rectangle to crop out (System.Drawing.Rectangle). The next thing done is to create a Bitmap (System.Drawing.Bitmap) of the image. The only thing left is to crop the image. This is done by cloning the original image but only taking a rectangle of the original.

private static Image cropImage(Image img, Rectangle cropArea)
{
   Bitmap bmpImage = new Bitmap(img);
   Bitmap bmpCrop = bmpImage.Clone(cropArea,
   bmpImage.PixelFormat);
   return (Image)(bmpCrop);
}

Resizing

This next set of code is a slightly longer and more complex. The main reason this code is longer is because this resize function will keep the height and width proportional.

To start with we see that the input parameters are the image to resize (System.Drawing.Image) and the size (System.Drawing.Size). Also in this set of code are a few variables we use. The first two are the source height and width which is used later. And there are 3 other variables to calculate the proportion information.

private static Image resizeImage(Image imgToResize, Size size)
{
   int sourceWidth = imgToResize.Width;
   int sourceHeight = imgToResize.Height;

   float nPercent = 0;
   float nPercentW = 0;
   float nPercentH = 0;
}

The next step is to actually figure out what the size of the resized image should be. The first step is to calculate the percentages of the new size compared to the original. Next we need to decide which percentage is smaller because this is the percent of the original image we will use for both height and width. And now we calculate the number of height and width pixels for the destination image.

nPercentW = ((float)size.Width / (float)sourceWidth);
nPercentH = ((float)size.Height / (float)sourceHeight);

if (nPercentH < nPercentW)
   nPercent = nPercentH;
else
   nPercent = nPercentW;

int destWidth = (int)(sourceWidth * nPercent);
int destHeight = (int)(sourceHeight * nPercent);

The final thing to do is create the bitmap (System.Drawing.Bitmap) which we will draw the resized image on using a Graphics (System.Drawing.Graphics) object. I also set the interpolation mode, which is the algorithm used to resize the image. I prefer HighQualityBicubic, which from my testing seems to return the highest quality results. And just to clean up a little I dispose the Graphics object.

Bitmap b = new Bitmap(destWidth, destHeight);
Graphics g = Graphics.FromImage((Image)b);
g.InterpolationMode = InterpolationMode.HighQualityBicubic;

g.DrawImage(imgToResize, 0, 0, destWidth, destHeight);
g.Dispose();

And this gives us the final code.

private static Image resizeImage(Image imgToResize, Size size)
{
   int sourceWidth = imgToResize.Width;
   int sourceHeight = imgToResize.Height;

   float nPercent = 0;
   float nPercentW = 0;
   float nPercentH = 0;

   nPercentW = ((float)size.Width / (float)sourceWidth);
   nPercentH = ((float)size.Height / (float)sourceHeight);

   if (nPercentH < nPercentW)
      nPercent = nPercentH;
   else
      nPercent = nPercentW;

   int destWidth = (int)(sourceWidth * nPercent);
   int destHeight = (int)(sourceHeight * nPercent);

   Bitmap b = new Bitmap(destWidth, destHeight);
   Graphics g = Graphics.FromImage((Image)b);
   g.InterpolationMode = InterpolationMode.HighQualityBicubic;

   g.DrawImage(imgToResize, 0, 0, destWidth, destHeight);
   g.Dispose();

   return (Image)b;
}

Here is the source code and a C# VS2005 Express Edition solution with the needed methods and some test code. Click Me for Code

Jim
05/04/2007 - 13:52

Like the tutorial! Thanks :)

reply

mathy
06/05/2009 - 01:37

I want to process the *.img & *.tif format images by using the C# codings. Any body could you assit me?

reply

Cardin
05/23/2007 - 08:07

Nice tutorial! But it would be nice to put up how to resize images without preserving the aspect ratio as well. I've been very bugged up over that. D=

reply

The Reddest
05/23/2007 - 12:10

I can answer that right here. To resize the image without preserving the aspect ratio just skip the ratio calculations. Just set destWidth to size.Width and destHeight to size.Height and you're all set.

reply

Praveen
06/11/2007 - 01:34

its really nice to see this example. i'm very thankfull to this code.

reply

Albert
06/20/2007 - 05:47

Thanks, thanks, thanks

reply

Thilina Vithanage
06/26/2007 - 04:59

Thankx.

finally i found what i looked...

reply

Amir
07/01/2007 - 09:59

Thanks

reply

Chris Wiegand
07/02/2007 - 15:51

For resizing you can also use Image.GetThumbnailImage.

reply

The Reddest
07/02/2007 - 19:51

Image.GetThumbnailImage does not use interpolation when resizing, so loss of quality can be a concern. For quick resizing where quality is not important, GetThumbnailImage is definitely a good alternative.

reply

BasiK
07/25/2007 - 17:49

Thx for tutorial! I was looking for resizing info other than GetThumbnailImage.
Though when I compared my resized pics with those generated from 'gthumb', the quality of mine isn't good enough (and they take less space), even with a quality level of 100. Gthumb uses essentially the same jpeg encoders I would think, but doesn't use C#/.NET. Any suggestions to get yet higher quality thumbs ?

reply

The Reddest
07/25/2007 - 18:15

I would be interested in seeing your results. When I run the above code at quality 100, I get very nice looking thumbnails. Here's an example I just ran. It was originally a 512x512 that I ran through the resizeImage function, then ran the output through the saveJpeg funtion.

As far as I can tell, there is very little (if any) loss of quality. Here were my steps:

Bitmap b = new Bitmap("C:\\original_image.jpg");
Image i = resizeImage(b, new Size(100, 100));
saveJpeg("C:\\test_resize.jpg", (Bitmap)i, 100);

If you want to post links to your images (you won't be able to put an image tag in the comment) and the code you're using, we can take a look to try to see where the error might be.

reply

BasiK
07/26/2007 - 03:54

A comparison of the ouput can be found at http://basik.studentenweb.org/pics/

I now use the exact methods (resize and save) presented here and:

Bitmap b = new Bitmap(fileName);
Image i = resizeImage(b, new Size(120, 100));
saveJpeg(String.Concat(fileName.Replace(sourceDirectory,
  destinationDirectory), ".thumb.jpg"),(Bitmap)i, 100);

I should also mention I am using mono instead of .NET since I'm working on a Linux environment. But i don't think that should matter ?

reply

The Reddest
07/26/2007 - 11:03

I installed Mono (on my Windows machine), compiled, and ran the code and I got the exact same thumbnail that I got using .NET. Mono isn't a 100% implementation of .NET (although they're very close) and I'm guessing you ran across a bug in their Linux version. I did some research and couldn't find any instances of other people experiencing the same issue. If you have a Windows machine available, try running the code on that and if the results are better, post a bug report to Mono. If there is a bug, they may have some known work-arounds.

reply

Tharindha
08/13/2007 - 03:21

Very helpful tutorial. Good luck.

reply

Ram
08/20/2007 - 12:48

Thankx.

Finally i found what i'm looking for....

reply

Ram
08/20/2007 - 12:51

here the image format is of jpg..
can i use it fot gif..
by replacing

ImageCodecInfo jpegCodec = this.getEncoderInfo("image/gif");

i didnt run the code..

reply

The Reddest
08/20/2007 - 17:43

Ram, yes you can. That's the only thing you have to change in order to make it a gif file. Remember that it will use a default color pallet of 256 colors so quality might be an issue depending on your application.

reply

Ram
08/21/2007 - 00:05

Reddest, thanks for ur reply.

reply

Kim
08/26/2007 - 16:38

Hello, thank you for this tutorial. I tried to try the cropping funtion but it seems like I missed something and it's not working.

Here is the code:

public void CaptureWindowToFile(IntPtr handle,
    string filename, ImageFormat format)
{
  Image img = CaptureWindow(handle);
           
  img = cropImage(img,new Rectangle(0, 42, 847, 450));
  //img = resizeImage(img, new Size(760, 526));
                       
  img.Save(filename, format);
}

the cropImage in my code is same from the cropImage method here.

Thank you!

reply

The Reddest
08/26/2007 - 17:03

Kim, you code looks fine. The problem is I don't know what output you're expecting. Can you be more specific on what exactly isn't working? Is it cropping incorrectly, or not cropping at all? I just ran the crop code on the flower image above and everything seemed to work fine.

reply

Cheeseroll
08/29/2007 - 07:09

Great work, thanks!

reply

Me
11/02/2007 - 21:35

Hey, Hows it going, I have a very newby type of question. When I try to run this in Visual studio, I get "Error while trying to run project,unable to start debugging, Binding handle is invalid"
thanks

reply

The Reddest
11/02/2007 - 21:48

It sounds like there is a problem with your Visual Studio settings. I don't have any experience with that error myself, but here's an MSDN forum that seems to address a similar problem.

Unable to debug: The binding handle is invalid.

Hopefully that helps a little.

reply

Me
11/03/2007 - 00:05

That did it, I was able to find the link below from your link. It was due to the Terminal Services being disabled. They say it has been fixed in vs sp1 -more info at the link below if anyone needs it. THANKS AGAIN

http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=105751

reply

Me
11/06/2007 - 12:50

Another newbie question; When I upload the files to a server, and attempt to open the page, the application file is displayed as xml source code in the browser. I am using apache/fed core 3, Do I need to install some sort of xml parsing module?
thanks

reply

Feeki
01/03/2008 - 13:39

Thanks for the Post, it really helped. I'm working on a project using WIA, I scanned a documents and need to CROP out 4 different areas.

How can I determine the Rectangle of each area by simply Loading the Scanned Image in a picture box and dragging my mouse over each area like in Microsoft Paint?.

This will really save me from the over head of using WIA to scan and crop for each area.

reply

Silverox
02/18/2008 - 23:49

Thanks a lot...Great tutorial !

reply

Anonymous
02/23/2008 - 02:06

protected void Button1_Click(object sender, EventArgs e)
{
  if (FileUpload1.HasFile == true)
  {
    if (FileUpload1.PostedFile.ContentType == "image/pjpeg")
    {
      FileUpload1.PostedFile.SaveAs(Server.MapPath(
          "./upload/" + FileUpload1.FileName));
     
      Label1.Text = "file saved";
    }
  }
  else
  {
    Label1.Text = "cant save";
  }
}

this code is upload the image
and i want to resize the image after uploading so pla give me code ans

reply

The Reddest
02/23/2008 - 11:53

After the image has been uploaded, it's in the hands of your server code. If your server is written in ASP.NET, you can use the same code that's in this post. If your server is written in another language, you'll have to do some searching on how to resize images with your specific language.

reply

Martin Randerson
03/03/2008 - 08:56

Saved me a few hours and from having to use a Graphics object to do cropping. Cheers muchly

reply

BillC
03/06/2008 - 14:40

Thank you!

Finally!
A way to crop and flip my background image!

Great tutorial!

reply

Mike
03/06/2008 - 22:59

Awesome! I was trying to figure out how to use the Developer's Image Library (DevIL). All I wanted was to be able to open, resize, crop, and save a picture, so It seemed way overkill to use their library. Your tutorial is exactly what I wanted! Thanks!

reply

OldBob
03/21/2008 - 08:47

Excellent snippet of code. Explained everything clearly and saved me a couple of hours of work. Much appreciated

reply

Karl Sieburg
03/26/2008 - 08:29

Thanks for this very useful resizeImage method.

reply

Chilly
03/30/2008 - 19:16

Thanks a lot!! I was looking for something like this for my project.

reply

Jon
04/15/2008 - 19:02

How come the gif loses its animation if cropped?

reply

Youtube
04/16/2008 - 01:12

how can i save a rectangle as xml data.

Graphics g=picturebox.creategraphics();
g.drawrectangle(...);

i want to save this rectangle

reply

Cliff
05/14/2008 - 23:50

Thanks very much for the code. I integrated it into something I was doing for some staff at work who wanted to be able to re-size images simply. I threw a little c# application together and it works pretty well.

One issue i do have it that the GDI+ component seems to fail if the image is non-colour managed. In other words, I can use it for RGB/8 (8 bit RGB images) but other colour spaces (like RGB/8# - unmanaged) causes a GDI+ error.

Does anyone have any experience in that area?

The downside for me is that my application only works with some jpgs - not all jpgs.

Thanks again for the code. Very cool and useful for people new to it all (like I am)

Cliff

reply

Matt
05/16/2008 - 08:16

Thank you so much! Well done!

reply

Laik
06/12/2008 - 00:54

So cool!

reply

Shaymaa
06/21/2008 - 11:01

great article
but i want to know how can i use the code to resize certain image to fixed width (100 for example) and keeping the height proportional?

reply

Anonymous
06/23/2008 - 02:56

thx2u

reply

John Ward
06/25/2008 - 02:21

Thank you for this great code. I'm having one odd problem though, and if anyone has any ideas I'd be grateful.

My problem is that after calling resizeImage, my original source file is locked. So when the user modifies the image and tries to save it, I can't overwrite the original image (my goal).

Here's my client usage snippet:

System.Drawing.Image img = new Bitmap(srcfile);
img = imageResize(img, new Size(100,100));
img.Save(destfile));
img.Dispose();

When I bypass the resize method and simply do a File.Copy(src,dst), the source file is not locked. I've spent two days trying to work around this--it's killing me.

I think the issue is related to the "redefinition" of "img". It is allocated in the client code (new Bitmap(source)), then more space is allocated in resizeImage as "b" (thumbnail Image), then "b" is returned and assigned to "img". Is there an orphaned IO stream for the first "img" allocation that holds an open handle to the source file?

This problem is a bit over my head, so any help would be awesome! Thanks.

I'm on ASP.NET, Framework 3.5, IIS6, Win 2k3 server

reply

John Ward
06/25/2008 - 09:24

Update regarding my previous comment: My problems don't appear to have anything to do with imageResize(). I'll keep chugging along in search of a solution.

Regarding quality of the created thumbnail, I have to say it's stunning.

reply

Javier Callico
01/27/2010 - 17:03

John

I had the same problem with the handle to the source image remaining open and what solved for me was forcing the Graphics instance to be released.

using (Graphics g = Graphics.FromImage(image))
{
}

Hope this helps.

Javier

reply

Rich
07/13/2008 - 00:43

Thanks! This is just what I've been looking for.

Oh, the time this could have saved me in the past!

reply

Mark
07/23/2008 - 21:06

Love the tutorial. One question, though. You supply a cropping routine, which is wonderful, but one thing that would be of great interest to me is a tutorial about selecting the image to be cropped. There seems to be few good examples of selecting a rectangle on the screen a la Windows Paintbrush or Photoshop. Any ideas where I might find such an example?

reply

Aytekin
07/30/2008 - 10:34

This is cool!!!
Thanks mannnnn, that is what I am talkin about!

reply

Heitor
08/27/2008 - 13:37

Thanks man!

reply

Santhosh
09/01/2008 - 04:23

Simple and beautiful....

reply

Anonymous
09/09/2008 - 06:40

smple the best

reply

Mox
09/10/2008 - 09:41

Thanks a lot. Keep up the good work. This resize method was exactly what I needed.
God Bless

reply

Anonymous
09/11/2008 - 21:19

many thanks

reply

quesera
09/15/2008 - 19:31

how am i suppose to do multiple upload of files?? can you guys help me?

reply

Muhammad
09/23/2008 - 22:21

terific tutorial i ve gained lot of knoweledge by thius

reply

Muhammad Hussain
09/26/2008 - 18:24

Terrific site. I was in the deep woe.but now i found my requiremetns
Lot of Thanks for code

reply

Coder
10/03/2008 - 03:11

Hi,

I have a TIFF image whose background color is Black and the text i.e the foreground color is in white. I want it to be changed to White background and Black foreground. can you please help me on how to achieve this?

reply

Mathew
11/11/2008 - 22:52

Thanks a lot for that code....

reply

SixPack
11/20/2008 - 14:19

Thanks for the code, I tried a lot of examples but this one does exactly what I wanted.

reply

Nicolò
12/11/2008 - 09:10

I save PNG image from RTF file.
All possible resizing-cropping-saving with this excellent code leave image in a strange aspect.
It is like elements (characters from “symbol font”) are too near between them…
Someone can help me?

reply

Kuldeep Shige
12/14/2008 - 23:22

thanks sir u hve done good job.

reply

phil
03/09/2009 - 13:19

Thanks! Hundreds of images resized at the click of a button; it's a beautiful thing. This is awesome.

reply

toby
04/22/2009 - 01:41

Good code, just one thing: Avoid calling dispose yourself, use a using-block:

using (Graphics g = Graphics.FromImage((Image)b))
{
    g.InterpolationMode = InterpolationMode.HighQualityBicubic;
    g.DrawImage(imgToResize, 0, 0, destWidth, destHeight);
}

it's not 100% necessary, but it's good pratice, and if you felt you should call dispose, you might as well use using.

reply

Anonymous
07/05/2009 - 12:24

There is a useful ActiveX control called AccessImage.
It does all the work about images for you.

FOR DEVELOPER: binds to database field (if needed), auto resizes big images, can manage pics in external storage, generates previews.

FOR END USER: load from file, paste from clipboard, scan or drag n drop image in 1 click. Crop it right on the form. Undo if something goes wrong.

Watch action video here: http://access.bukrek.net/tutorial/action-video/

reply

Dre
08/25/2009 - 22:29

you all are the best, I have been trying to write an implementation of an image resizing and cropping algorithm, using VS2005. Email me any code at bpgueze@hotmail.com

reply

dviljoen
11/17/2009 - 13:23

BTW, change this:
if (nPercentH < nPercentW)

to this:
if (nPercentH > nPercentW)

if you want to superscribe the image to the cliprect. This code inscribes the image to the cliprect.

reply

youtubeline
12/28/2009 - 13:02

thanks

reply

sireesha
01/04/2010 - 17:12

Hi everyone. The issue we’re having is we have a wpf richtextbox, and we’re pasting images into it, but we want to be able to limit the physical data size, not the display size of the images being pasted in. In other words, if a user paste in an image that’s 2MB, we want to automatically shrink it down to a more manageable size. We have to have many users who share richtextbox data. So their text and images gets saved up to a cloud database so other users may download it. Please note that when an image gets pasted in, it’s a System.Windows.Controls.Image object.Any help will be greately appreciated

reply

Isu the Mule
01/07/2010 - 14:30

I'm using the cropping code, and I'm getting an outOfMemoryException error.

Bitmap frame = new Bitmap(picFinal.Image);
picMotion.Image = (Image)frame.Clone(new Rectangle(xStart, yStart, frame.Width, frame.Height), frame.PixelFormat);

I don't even know where start with this.

reply

Anonymous
01/29/2010 - 04:09

Are the X and Y values legit? i.e. is the new Rectangle within the frame image dimensions?

reply

Add Comment

Put code snippets inside language tags:
[language] [/language]

Examples:
[javascript] [/javascript]
[actionscript] [/actionscript]
[csharp] [/csharp]

See here for supported languages.

Javascript must be enabled to submit anonymous comments - or you can login.

Sponsors