When i started .Net programming i appreciated all the new functionalities of the framework, everything was easier and faster to do. I tought the same thing about thumbnails generation when i found the GetThumbnailImage method of the System.Drawing.Bitmap class but giving a deeper look at it’s behaviour i understood it was not so easy.
WHY IT WASN’T SO EASY
The GetThumbnailImage method isn’t so useful because image formats like JPG can store the thumbnail image inside the same file. A lot of graphics softwares store the thumbnail version of the image into the .JPG file and you can’t choose it’s width, height and quality. The GetThumbnailImage method checks if there’s a thumbnail image stored into the file and, if the thumb is found, it returns that thumbnail version scaled to the width and height you requested. If the thumbnail version of the image is smaller then the size you asked for you can imagine what will be the result, a very low quality and pixelated image. If you want to have the full control over the thumbnail quality you have to use something different by the GetThumbnailImage method.
THE APPROACH
What we have to do is to load the JPG file into a System.Drawing.Image object, scale it to the desired width and height preserving a good quality and save it to a new file.
To preserve the image quality we have to follow these few steps:
- Load the original file into a System.Drawing.Image object
- Create the target image with the desired size as System.Drawing.Bitmap
- Create a System.Drawing.Graphics object from the target Bitmap to draw the scaled image
- Set the System.Drawing.Graphics object property SmoothingMode to HighQuality
- Set the System.Drawing.Graphics object property CompositingQuality to HighQuality
- Set the System.Drawing.Graphics object property InterpolationMode to High
- Draw the original image into the target Graphics object scaling to the desired width and height
- Get the System.Drawing.Imaging.ImageCodecInfo object of the JPEG file format
- Set the Codec param System.Drawing.Imaging.Encoder.Quality to the desired quality (for jpg is 0-100)
- Save the new image using the Codec and the filled quality parameter
THE CODE
I wrote a simple class CImageHelper where i put all the imaging routines, here there’s a simple version with the SaveImage function to save ThumbNails (or scaled versions of any image) with a very high quality.
Click here to download the code
Or start reading it
Imports Microsoft.VisualBasic
Imports System.Drawing
Imports System.Drawing.Drawing2D
Public Class CImgHelper
Public Function SavePhoto(ByVal src As String, ByVal dest As String, ByVal w As Integer) As Boolean
Dim imgTmp As System.Drawing.Image
Dim sf As Double
Dim imgFoto As System.Drawing.Bitmap
imgTmp = System.Drawing.Image.FromFile(src)
If (imgTmp.Width > w) Then
sf = imgTmp.Width / w
imgFoto = New System.Drawing.Bitmap(w, CInt(imgTmp.Height / sf))
Dim recDest As New Rectangle(0, 0, w, imgFoto.Height)
Dim gphCrop As Graphics = Graphics.FromImage(imgFoto)
gphCrop.SmoothingMode = SmoothingMode.HighQuality
gphCrop.CompositingQuality = CompositingQuality.HighQuality
gphCrop.InterpolationMode = InterpolationMode.High
gphCrop.DrawImage(imgTmp, recDest, 0, 0, imgTmp.Width, imgTmp.Height, GraphicsUnit.Pixel)
Else
imgFoto = imgTmp
End If
'Dim myImageCodecInfo As System.Drawing.Imaging.ImageCodecInfo
Dim myEncoder As System.Drawing.Imaging.Encoder
Dim myEncoderParameter As System.Drawing.Imaging.EncoderParameter
Dim myEncoderParameters As System.Drawing.Imaging.EncoderParameters
Dim arrayICI() As System.Drawing.Imaging.ImageCodecInfo = System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders()
Dim jpegICI As System.Drawing.Imaging.ImageCodecInfo = Nothing
Dim x As Integer = 0
For x = 0 To arrayICI.Length - 1
If (arrayICI(x).FormatDescription.Equals("JPEG")) Then
jpegICI = arrayICI(x)
Exit For
End If
Next
myEncoder = System.Drawing.Imaging.Encoder.Quality
myEncoderParameters = New System.Drawing.Imaging.EncoderParameters(1)
myEncoderParameter = New System.Drawing.Imaging.EncoderParameter(myEncoder, 60L)
myEncoderParameters.Param(0) = myEncoderParameter
imgFoto.Save(dest, jpegICI, myEncoderParameters)
imgFoto.Dispose()
imgTmp.Dispose()
Return True
End Function
End Class
