Your digital camera's pictures are great, but they're way too big to send attached to your family emails. You want to shrink them to a manageable size, but you also want to control the compression so there's no compromise in the resulting quality of the images.
Sample code folder: Chapter 10\CompressImages
The CompressJPEG class presented in this recipe wraps all the code required to compress JPEG pictures to any desired absolute or relative size. It lets you set the compression factor so you get a good balance between file size and quality in the resulting JPEG images.
Before presenting the CompressJPEG class itself, let's see how it's called. The following code shows how a large picture named Family.jpg is compressed to 25 percent of its starting size using a compression-factor setting of 70 percent. A CompressJPEG object is created, and its SizePercent and QualityPercent properties are set to 25 and 70, respectively. The Load() method loads the original JPEG image, and the Save() method then saves the compressed and resized image to a new JPEG file:
Dim imageConverter As New CompressJPEG imageConverter.SizePercent = 25 imageConverter.QualityPercent = 70 imageConverter.Load("Family.jpg") imageConverter.Save("SmallerFamily.jpg")
Both the SizePercent and QualityPercent properties affect the final number of bytes in the output file, and it's important to understand the difference between these two settings. SizePercent refers to the physical dimensions of the image; that is, how many pixels wide and high it will be after compression. JPEG compression is not a lossless compression technique, and the QualityPercent setting controls how much of the original information content of the picture is retained. A low setting results in graininess and blockiness in the image, whereas a high value for this setting retains the detail and quality of the original image. Typically, a setting of around 75 to 85 provides good compression with little or no noticeable loss of image quality. If you don't set the QualityPercent property, it defaults to a very reasonable value of 85. If you don't set the SizePercent property, the output image retains the same dimensions as the original.
The following code is for the CompressJPEG class itself. In addition to the properties and methods described so far, there are two more properties you might find handy: instead of setting SizePercent, which resizes the picture to a percentage of its original size, you can set the Width or Height properties to define the compressed file's dimensions. If you set one of these properties, the other is calculated to retain the proportions of the original image. Here's the code for the CompressJPEG class:
Imports System.Drawing.Imaging Public Class CompressJPEG Private SourceImage As Image Private UseQualityPercent As Double Private UseSizePercent As Double Private UseWidth As Integer Private UseHeight As Integer Public Sub Load(ByVal filePath As String) ' ----- Assign the user-specified file. SourceImage = Image.FromFile(filePath) End Sub Public Sub Save(ByVal outputFile As String) ' ----- Save the file, making adjustments as requested. Dim wide As Integer Dim tall As Integer Dim newImage As Bitmap Dim canvas As Graphics Dim codecs( ) As ImageCodecInfo Dim jpegCodec As ImageCodecInfo Dim scanCodec As ImageCodecInfo Dim qualityParam As EncoderParameters ' ----- Don't bother if there is no image. If IsNothing(SourceImage) = True Then Return ' ----- Use default values if needed. If UseQualityPercent = 0 Then UseQualityPercent = 85 ' ----- Calculate the new dimensions. If (UseWidth <> 0) And (UseHeight = 0) Then ' ----- Proportional to the width. wide = UseWidth tall = CInt(UseWidth * _ SourceImage.Height / SourceImage.Width) ElseIf (UseWidth = 0) And (UseHeight <> 0) Then ' ----- Proportional to the height. wide = CInt(UseHeight * _ SourceImage.Width / SourceImage.Height) tall = UseHeight ElseIf (UseWidth <> 0) And (UseHeight <> 0) Then ' ----- User-specified size. wide = UseWidth tall = UseHeight ElseIf (UseSizePercent <> 0) Then ' ----- Percent scale. wide = CInt(SourceImage.Width * _ UseSizePercent / 100) tall = CInt(SourceImage.Height * _ UseSizePercent / 100) Else ' ----- Retain the size. wide = SourceImage.Width tall = SourceImage.Height End If ' ----- Redraw the image to the new size. newImage = New Bitmap(wide, tall) canvas = Graphics.FromImage(newImage) canvas.DrawImage(SourceImage, 0, 0, wide, tall) canvas.Dispose( ) ' ----- Locate the processor for JPEG images. codecs = ImageCodecInfo.GetImageEncoders jpegCodec = codecs(0) qualityParam = New EncoderParameters For Each scanCodec In codecs If (scanCodec.MimeType = "image/jpeg") Then ' ----- Found the one we're looking for. jpegCodec = scanCodec Exit For End If Next scanCodec ' ----- Prepare the quality reduction. qualityParam.Param(0) = New EncoderParameter( _ Encoder.Quality, CInt(UseQualityPercent)) ' ----- Adjust and save the new image in one command. newImage.Save( outputFile, jpegCodec, qualityParam) SourceImage = Nothing End Sub Public Property QualityPercent( ) As Double Get Return UseQualityPercent End Get Set(ByVal Value As Double) Select Case Value Case Is < 1 UseQualityPercent = 1 Case Is > 100 UseQualityPercent = 100 Case Else UseQualityPercent = Value End Select End Set End Property Public Property SizePercent( ) As Double Get Return UseSizePercent End Get Set(ByVal Value As Double) Select Case Value Case Is < 1 UseSizePercent = 1 Case Is > 400 UseSizePercent = 400 Case Else UseSizePercent = Value End Select End Set End Property Public Property Width( ) As Integer Get If (UseWidth > 0) Then Return UseWidth Else If (SourceImage.Width > 0) Then Return CInt(SourceImage.Width * _ UseSizePercent / 100) End If End If End Get Set(ByVal Value As Integer) UseWidth = Value End Set End Property Public Property Height( ) As Integer Get Return UseHeight End Get Set(ByVal Value As Integer) UseHeight = Value End Set End Property End Class
Figure 10-11 shows an image after compression from the original, much larger file. This compressed file is less than 19 KB in size, reduced from an original of over 1.25 MB!
Figure 10-11. Compressed and reduced images can be made much smaller, without noticeable loss of quality