Skip to main content

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


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 information.
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 re-size (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 re-sized 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 re-sized image on using a Graphics (System.Drawing.Graphics) object. I also set the interpolation mode, which is the algorithm used to re-size 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;
}

Comments

  1. What a very good article. I appreciate your post.We are an PHOTO CROPPING Company. Recently we have post an article about add brushes to photoshop and Vehicles Background Replacement. Please check out. Thanks

    ReplyDelete

Post a Comment

Popular posts from this blog

C# Snippet - Shuffling a Dictionary [Beginner]

Randomizing something can be a daunting task, especially with all the algorithms out there. However, sometimes you just need to shuffle things up, in a simple, yet effective manner. Today we are going to take a quick look at an easy and simple way to randomize a dictionary, which is most likely something that you may be using in a complex application. The tricky thing about ordering dictionaries is that...well they are not ordered to begin with. Typically they are a chaotic collection of key/value pairs. There is no first element or last element, just elements. This is why it is a little tricky to randomize them. Before we get started, we need to build a quick dictionary. For this tutorial, we will be doing an extremely simple string/int dictionary, but rest assured the steps we take can be used for any kind of dictionary you can come up with, no matter what object types you use. Dictionary < String , int > origin = new Dictionary < string , int >();

C# Snippet - The Many Uses Of The Using Keyword [Beginner]

What is the first thing that pops into your mind when you think of the using keyword for C#? Probably those lines that always appear at the top of C# code files - the lines that import types from other namespaces into your code. But while that is the most common use of the using keyword, it is not the only one. Today we are going to take a look at the different uses of the using keyword and what they are useful for. The Using Directive There are two main categories of use for the using keyword - as a "Using Directive" and as a "Using Statement". The lines at the top of a C# file are directives, but that is not the only place they can go. They can also go inside of a namespace block, but they have to be before any other elements declared in the namespace (i.e., you can't add a using statement after a class declaration). Namespace Importing This is by far the most common use of the keyword - it is rare that you see a C# file that does not h

C# WPF Printing Part 2 - Pagination [Intermediate]

About two weeks ago, we had a tutorial here at SOTC on the basics of printing in WPF . It covered the standard stuff, like popping the print dialog, and what you needed to do to print visuals (both created in XAML and on the fly). But really, that's barely scratching the surface - any decent printing system in pretty much any application needs to be able to do a lot more than that. So today, we are going to take one more baby step forward into the world of printing - we are going to take a look at pagination. The main class that we will need to do pagination is the DocumentPaginator . I mentioned this class very briefly in the previous tutorial, but only in the context of the printing methods on PrintDialog , PrintVisual (which we focused on last time) and PrintDocument (which we will be focusing on today). This PrintDocument function takes a DocumentPaginator to print - and this is why we need to create one. Unfortunately, making a DocumentPaginator is not as easy as