Patrice Paré

RunAtServer Consulting - Specialized in Microsoft Web Technologies

Resizing GIF Images

I worked this week on a Console application that would allow me to resize all images in a folder to thumbnail size of 128 by 128 pixels. This small project was meant to correct a problem on a web site. My friend can upload any kind of images (bmp, jpg, gif, png) of any size to her web site. The images are then displayed in a catalogue. There are up to 20 images per page. For consistency, every image are set to be displayed in a 128x128 pixels. When the user click on the image, it is displayed in it original size in another browser:

<a href='http://www.website.com/Uploads/Catalogue/myImage001.jpg' 
          target="_blank" id="lnkImage">
 <img id="imgItem" title="My Image" 
          src="../Uploads/Catalogue/myImage001.jpg"
          style="height:128px;width:128px;border-width:0px;" />
</a> 

The problem with this html is if the image is large, it will take time to download. On the other hand, if the image is small, the user does not get anything better when clicking on the image to look at it in another browser because it is of the same size.

To correct this, I suggested her to always upload image files in their original size, the larger the better. And I would take care of displaying images on the right size.

So I develop a class that I would add to the business logic layer of her web site and also to a console application which would run once to resize all of her images already uploaded on her web server.

Here is the class I creates;

   1:   ''' <summary>
   2:   ''' Resize images to 128x128px
   3:   ''' </summary>
   4:   ''' <param name="sourceFilename">
   5:   '''              Complete input file name</param>
   6:   ''' <param name="targetFilename">
   7:   '''                 Complete output file name
   8:   ''' </param>
   9:   ''' <remarks></remarks>
  10:   Public Shared Sub ResizeImageBad( _ 
  11:                ByVal sourceFilename As String, _
  12:                ByVal targetFilename As String)
  13:   
  14:       Dim img As System.Drawing.Image = Nothing
  15:       Dim graph As Graphics = Nothing
  16:       Dim smallImg As System.Drawing.Image
  17:       Dim rectangle As Rectangle
  18:       Dim smlSize As Size = New Size(128, 128)
  19:   
  20:       Try
  21:           img = System.Drawing.Image.FromFile(_ 
  22:                              sourceFilename)
  23:           smallImg = New Bitmap(_ 
  24:                              smlSize.Width, _
  25:                              smlSize.Height, _
  26:                              img.PixelFormat)
  27:           rectangle = New Rectangle(_
  28:                              0, _
  29:                              0, _
  30:                              smlSize.Width, _
  31:                              smlSize.Height)
  32:    
  33:           graph = Graphics.FromImage(smallImg)
  34:           graph.CompositingQuality = CompositingQuality.HighQuality
  35:           graph.SmoothingMode = SmoothingMode.HighQuality
  36:           graph.InterpolationMode = InterpolationMode.Bicubic
  37:           graph.DrawImage(img, rectangle)
  38:   
  39:           smallImg.Save(targetFilename)
  40:   
  41:      Catch ex As Exception
  42:           cLogEventViewer.LogError( _
  43:                  System.Reflection.MethodBase.
GetCurrentMethod.DeclaringType.Name & _
  44:                   " - Exception Resize Image - " & _
  45:                  ex.Message & " " & _
  46:                  ex.StackTrace)
  47:       Finally 'Clean up!
  48:           If Not img Is Nothing Then
  49:               img.Dispose()
  50:               img = Nothing
  51:           End If
  52:   
  53:           If Not graph Is Nothing Then
  54:               graph.Dispose()
  55:               graph = Nothing
  56:           End If
  57:           smlSize = Nothing
  58:           rectangle = Nothing
  59:       End Try
  60:  End Sub
 

When I ran the console application targeting a folder containing only jpg, gif or jpg files, the console application throw exceptions for gif files. The png files were not resized and fortunately the jpg were ok.

Here is the log error from the event viewer:

"A Graphics object cannot be created from an image that has an indexed pixel format. "

Error log from Event Viewer

  After a few readings, I found out that the problem was at the pixel format level. In the code sample I provided earlier, I used the pixel format provided by the System.Drawing.Image object instance loaded from the file name as you can see on line 26.

I changed the pixel format to System.Drawing.Image.PixelFormat.Format24bppRgb which provides 24 bits per pixel, 8 bits for Red, 8 for Green and and 8 for Blue. This change stopped the errors. The GIF files were resized and their weight were lighter. Unfortunately, when I tried to view the image applications I used sent an error on opening.

I search a little further and I added another filter on the file,

graph.PixelOffsetMode = PixelOffsetMode.HighQuality

that I inserted between line 34 and 35. Also, I looked for the ".gif" extension at the end of the file name. If the file name ended with ".gif", I then specified that specific format:

smallImg.Save(targetFilename, Imaging.ImageFormat.Gif)

Also, I changed the InterpolationMode to HighQualityByCubic which provides a higher quality after resizing the GIF file.

Let's have a look at the images. On the next image, on the left, is the original GIF image and on the right is the resized GIF image.

GIF Image Quality Issu

As you can see, the image on the right, after resizing has lost some quality.

Well... I have looked for quite some time now on how I could solve the quality issue and I must admit it, I am now clueless. To complete the application, however, I decided to reformat the GIF to JPEG. doing this solves completely the quality issue but does not answer how I could resize GIF images.

If someone has an answer, I am curious to know how you did it.

But for now, here is the method I use to resize images:

   1:  ''' <summary>
   2:  ''' Resize images to 128x128px
   3:  ''' </summary>
   4:  ''' <param name="sourceFilename">Complete input file name</param>
   5:  ''' <param name="targetFilename">Complete output file name</param>
   6:  ''' <remarks></remarks>
   7:  Public Shared Sub ResizeImage( _
          ByVal sourceFilename As String, _
          ByVal targetFilename As String)
   8:   
   9:     Dim img As System.Drawing.Image = Nothing
  10:     Dim graph As Graphics = Nothing
  11:     Dim smallImg As System.Drawing.Image
  12:     Dim rectangle As Rectangle
  13:     Dim smlSize As Size = New Size(128, 128)
  14:   
  15:      Try
  16:        img = System.Drawing.Image.FromFile(sourceFilename)
  17:        smallImg = New Bitmap(smlSize.Width, smlSize.Height, PixelFormat.Format24bppRgb)
  18:        rectangle = New Rectangle(0, 0, smlSize.Width, smlSize.Height)
  19:   
  20:         graph = Graphics.FromImage(smallImg)
  21:         graph.CompositingQuality = CompositingQuality.HighQuality
  22:         graph.SmoothingMode = SmoothingMode.HighQuality
  23:         graph.PixelOffsetMode = PixelOffsetMode.HighQuality
  24:         graph.InterpolationMode = InterpolationMode.HighQualityBicubic
  25:         graph.DrawImage(img, rectangle)
  26:   
  27:   
  28:         If targetFilename.LastIndexOf(".gif") > 0 AndAlso targetFilename.EndsWith(".gif") Then
  29:             targetFilename = targetFilename.Replace(".gif", ".jpg")
  30:                  smallImg.Save(targetFilename)
  31:         Else
  32:             smallImg.Save(targetFilename)
  33:         End If
  34:   
  35:     Catch ex As Exception
  36:         cLogEventViewer.LogError( _
  37:                System.Reflection.MethodBase.GetCurrentMethod.DeclaringType.Name & _
  38:                " - Exception Resize Image - " & _
  39:                ex.Message & " " & _
  40:                ex.StackTrace)
  41:     Finally 'Clean up!
  42:         If Not img Is Nothing Then
  43:              img.Dispose()
  44:              img = Nothing
  45:         End If
  46:   
  47:         If Not graph Is Nothing Then
  48:              graph.Dispose()
  49:              graph = Nothing
  50:          End If
  51:          smlSize = Nothing
  52:          rectangle = Nothing
  53:      End Try
  54:  End Sub

Have a good one!

Cheers!

Patrice

Mots clés Technorati : ,,,

Comments

ppare said:

je te suggère de sauvegarder en PNG parce que pour moi c'est de loin le format le plus complet. Tu vois, quand tu veux avoir un ombrage sur un objet, tu n'as pas le choix d'utiliser GIF parce que tu dois utiliser la transparence, mais la qualité du GIF est vraiment minable, alors que JPG donne un rendu nettemement supérieur, pas de gros pixels dégueux.

En utilisant le PNG, si ma mémoire est bonne, tu utilises un format ouvert (open source), et puis tu as vraiment le meilleur des deux mondes. Mais comme je te disais, IE 6.0 ne gère pas bien ce format, par contre il existe un contournement. Je ne sais pas pour IE 7.0 et 8.0.

Alors si tu as le contrôle des pages d'un site et que tu peux insérer le JS sur chacune des pages qui affichera les PNG, et bien moi c'est ce que je te suggère.

Bien sûr, FF n'a aucun problème avec les PNG :-D

# mars 23, 2009 3:29
Leave a Comment

(required) 

(required) 

(optional)

(required)