Login


Controlling JPEG Compression

By Jonathan Wood on 5/18/2012
Language: C#
Technology: .NET
Platform: Windows
License: CPOL
Views: 19,829
General Programming » Graphics » General » Controlling JPEG Compression

Download Source Code Download Source Code

Introduction

The .NET Framework provides a fairly rich set of libraries for working with a variety of graphics files. You can easily load, modify and save most graphic-file types.

One of the formats .NET supports is the JPG (JPEG) format, which is a very common graphics format. JPG files can be stored with varying levels of quality. However, controlling this quality level from .NET can be a little tricky.

JPG Compression

As with most graphic-file formats, JPG files employ compression to reduce the size of the image data. However, unlike other formats, JPG uses a "lossy" compression, which means some data is lost when the data is uncompressed. The result is that JPG images can have visible artifacts that result from the data being compressed.

The amount of compression, and therefore the image quality, can vary in a JPG file. When using less compression, images are higher quality but result in more data and larger files. So the JPG format lets you choose between smaller files with lower quality or larger files with higher quality.

How noticeable compression is depends also on the type of image. The compression artifacts may be less noticeable on photos with many different colors and textures, while images with large areas of a single color can make those artifacts easier to see.

Most graphics applications lets you specify a value in the range of 0 to 100 for the compression, or quality, when saving JPG files, where higher values represent less compression, higher quality, and larger files. Note that this value is somewhat arbitrary and a quality value of 85 in one graphics application may not match the results of the same value in another application. Figures 1 through 3 show JPG images with varying levels of quality.

Figure 1: Image with Quality Value 75 (3 KB File)

Sample JPG

Figure 2: Image with Quality Value 90 (4 KB File)

Sample JPG

Figure 3: Image with Quality Value 100 (8 KB File)

Sample JPG

As you can probably see, the artifacts are quite visible at 75, and much less so at 90. They are even less visible at 100. What's interesting is the resulting file sizes. From 75 to 90, the difference in quality is substantial with only a small difference in file sizes. But from 90 to 100, the difference in quality is hardly noticeable and yet the files size doubles!

So, as the values gets higher, additional increases cost more in bytes and return less in improved quality. Looking at JPG images created with .NET, the value seems to be somewhere around 75. For better image quality, you may want more like 85 to 95.

Controlling JPG Compression from .NET

When working with .NET graphics classes such as Image, you can save an image to a file using the Save() method. This method is very simple, you can supply a filename and the target image format. The Save() method has a number of overloads, but there are no parameters with names like "JpgQuality" or anything like that.

The main reason there are no such parameters is because the Save() method works with all the supported file types. A JPG-quality parameter would be specific only to JPG files. So controlling JPG quality is not quite as simple as we'd like. But the Save() method still allows us to control such parameters.

Listing 1 shows my SaveJpgSetQuality() method. This method takes an Image object, a file path, and a quality value. The method will save the image to a JPG file with the specified path name with the specified JPG quality.

Listing 1: The SaveJpgSetQuality Method

/// <summary>
/// Saves an image as a JPG file using the specified quality level. The file is stored as JPG
/// format regardless of the extension of the given filename.
/// </summary>
/// <param name="image">Image to save</param>
/// <param name="path">Filename to store the image</param>
/// <param name="quality">A value from 0 to 100. Higher values produce better quality images
/// and larger files</param>
public void SaveJpgSetQuality(Image image, string path, byte quality)
{
    // Get jpeg encoder
    ImageCodecInfo jpgEncoder =
        ImageCodecInfo.GetImageDecoders().First(c => c.FormatID == ImageFormat.Jpeg.Guid);
    // Create an encoder object based on the Quality parameter category
    Encoder encoder = Encoder.Quality;
    // Create an EncoderParameters object with just one EncoderParameter
    EncoderParameters encoderParameters = new EncoderParameters(1);
    encoderParameters.Param[0] = new EncoderParameter(encoder, (long)quality);
    // Write file using encoder and parameters
    image.Save(path, jpgEncoder, encoderParameters);
}

The SaveJpgSetQuality() method starts by locating the ImageCodecInfo object associated with JPG files. This is the same object used when you specify the ImageFormat.Jpeg image format. Next, it creates an Encoder object to control the JPG quality value. It then creates an EncoderParameters object with a single parameter (the quality parameter). Finally, the SaveJpgSetQuality() method passes these objects to the Save() method.

Conclusion

That's all there is to it. Obviously, the Save() method can be used to control many other parameters for the various image file encoders. They aren't quite as accessible as most settings, but they can be accessed.

The downloadable source code contains the SaveJpgSetQuality() method, and some example code I used to generate the images shown in Figures 1 through 3.

End-User License

Use of this article and any related source code or other files is governed by the terms and conditions of The Code Project Open License.

Author Information

Jonathan Wood

I'm a software/website developer working out of the greater Salt Lake City area in Utah. I've developed many websites including Black Belt Coder, Insider Articles, and others.