High quality thumbnails in VB.Net

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


Leave a Reply