Create a Scaled Thumbnail with GDI+ (i.e. Constrain Proportions)

by Justin 6. February 2008 11:35

GDI+ comes with a function to create a thumbnail, but you must specify the size of the image. I wanted a function that I could pass an image, and the maximum height and width of the thumbnail. The function would then scale the image down to fit within that size; however, it would also retain the same height and width ratio so the thumbnail would not be distorted. Myself and a co-worker of mine (i.e. David Johnston) came up with a simple algorithm, and I coded it out. Note that this function will work not only with BMPs, but also GIF, JPG, PNG, etc—which are all basically compressed forms of a bitmap, and can be read into .NET's System.Drawing.Bitmap class.

Note: Please make sure you import the System.Drawing namespace if you plan on using this function. 

Update: This function uses the GetThumbnailImage method if the image is small (150px dimensions or less), because it produces more visually pleasing results when creating thumbnails. On the other hand, if you try to create a larger image using the GetThumbnailImage method the results will be blocky and overly compressed. This function takes this into consideration so it will always give good results.

C#

/// <summary>
/// Returns a new bitmap resized to fix a maximum size 
/// while still maintaining the correct aspect ratio.
/// </summary>
/// <param name="oldImage">The image to create a thumbnail from.</param>
/// <param name="maxWidth">The maximum allowed thumbnail width in pixels.</param>
/// <param name="maxHeight">The maximum allowed thumbnail height in pixels.</param>
/// <returns>A properly scaled thumbnail image.</returns>
private static Bitmap GetResizedImage(ref Bitmap oldImage, int maxWidth, int maxHeight)
{
    Bitmap newImage = null;
 
    // if the image is too large (i.e. needs to be resized).
    if (oldImage.Width > maxWidth || oldImage.Height > maxHeight)
    {
        // we use ratios to properly constrain proportions of the image.
        decimal imgRatio = (decimal)oldImage.Width / (decimal)oldImage.Height;
        decimal maxRatio = (decimal)maxWidth / (decimal)maxHeight;
 
        // if the image can be scaled down to perfectly fit the max height and max width.
        if (imgRatio == maxRatio)
        {
            newImage = new Bitmap(oldImage, maxWidth, maxHeight);
        }
        else if (imgRatio < maxRatio)
        {
            // Adjust the width to match the maximum height.
            decimal newRatio = (decimal)maxHeight / (decimal)oldImage.Height;
            int newWidth = (int)decimal.Round(newRatio * oldImage.Width);
 
            // if new image is a thumbnail then use the method that produces better thumbnail results.
            if (maxWidth <= 150 && maxHeight <= 150)
                newImage = (Bitmap)oldImage.GetThumbnailImage(newWidth, maxHeight, null, new IntPtr());
            else
                newImage = new Bitmap(oldImage, newWidth, maxHeight);
        }
        else
        {
            // Adjust the height to match the maximum width.
            decimal newRatio = (decimal)maxWidth / (decimal)oldImage.Width;
            int newHeight = (int)decimal.Round(newRatio * oldImage.Height);
 
            // if new image is a thumbnail then use the method that produces better thumbnail results.
            if (maxWidth <= 150 && maxHeight <= 150)
                newImage = (Bitmap)oldImage.GetThumbnailImage(maxWidth, newHeight, null, new IntPtr());
            else
                newImage = new Bitmap(oldImage, maxWidth, newHeight);
        }
    }
    else
    {
        // return a copy because it's smaller than our max size.
        newImage = new Bitmap(oldImage);
    }
 
    return newImage;
}

VB.NET

''' <summary>
''' Returns a new bitmap resized to fix a maximum size 
''' while still maintaining the correct aspect ratio.
''' </summary>
''' <param name="oldImage">The image to create a thumbnail from.</param>
''' <param name="maxWidth">The maximum allowed thumbnail width in pixels.</param>
''' <param name="maxHeight">The maximum allowed thumbnail height in pixels.</param>
''' <returns>A properly scaled thumbnail image.</returns>
Private Shared Function GetResizedImage(ByRef oldImage As Bitmap, ByVal maxWidth As Integer, ByVal maxHeight As Integer) As Bitmap
    Dim newImage As Bitmap = Nothing
 
    ' if the image is too large (i.e. needs to be resized).
    If oldImage.Width > maxWidth Or oldImage.Height > maxHeight Then
 
        ' we use ratios to maintain the proper aspect ratio of the image.
        Dim imgRatio As Decimal = CDec(oldImage.Width) / CDec(oldImage.Height)
        Dim maxRatio As Decimal = CDec(maxWidth) / CDec(maxHeight)
 
        ' if the image can be scaled down to perfectly fit the max height and max width.
        If imgRatio = maxRatio Then
            newImage = CType(oldImage.GetThumbnailImage(maxWidth, maxHeight, Nothing, New IntPtr()), Bitmap)
        ElseIf imgRatio < maxRatio Then
            ' Adjust the width to match the maximum height.
            Dim newRatio As Decimal = CDec(maxHeight) / CDec(oldImage.Height)
            Dim newWidth As Integer = CType(Decimal.Round(newRatio * oldImage.Width), Integer)
 
            ' if new image is a thumbnail then use the method that produces better thumbnail results.
            If maxWidth <= 150 AndAlso maxHeight <= 150 Then
                newImage = CType(oldImage.GetThumbnailImage(NewWidth, maxHeight, Nothing, New IntPtr()), Bitmap)
            Else
                newImage = New Bitmap(oldImage, newWidth, maxHeight)
            End If
        Else
            ' Adjust the height to match the maximum width.
            Dim newRatio As Decimal = CDec(maxWidth) / CDec(oldImage.Width)
            Dim newHeight As Integer = CInt(Decimal.Round(newRatio * oldImage.Height))
 
            ' if new image is a thumbnail then use the method that produces better thumbnail results.
            If maxWidth <= 150 AndAlso maxHeight <= 150 Then
                newImage = CType(oldImage.GetThumbnailImage(maxWidth, newHeight, Nothing, New IntPtr()), Bitmap)
            Else
                newImage = New Bitmap(oldImage, maxWidth, newHeight)
            End If
        End If
    Else
        ' return a copy because it's smaller than our max size.
        newImage = New Bitmap(oldImage)
    End If
    Return newImage
End Function

Currently rated 4.3 by 3 people

  • Currently 4.333333/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: , ,

Comments

Add comment


(Will show your Gravatar icon)  

  Country flag

biuquote
  • Comment
  • Preview
Loading



Powered by BlogEngine.NET 1.4.5.0
Theme by Mads Kristensen

About the author

Justin HoltonHi, my  name is Justin. I cut my teeth learning HTML back when Netscape Navigator was still the most popular web browser. Later that inspired me to major in Computer Science at college. Today I'm a professional web developer with experience in everything from social networking application design to Search Engine Optimization (SEO). I believe the Internet is the most important achievement of man since the printing press, and I'm grateful that I was born in time to see it go from obscurity to a ubiquity.

Page List