Saving Images: EncoderParameter / ImageCODEC Versus Bitmap Save

In this day and age—the selfie age—photos are everything. Apart from self-portraits, images are vital anywhere. As a developer, you normally wouldn’t know which pictures will be used in an application until you receive them. In cases such as mine (I work for a big company, but we have a small IT department), the developers are responsible for creating and obtaining the best pictures for the applications. These pictures include icons, button icons, and backgrounds. We develop mobile applications, Web applications, and Windows applications.

On each platform, images are handled differently. You cannot have a large picture on a mobile device. You cannot have a picture with a big size on either Web or Mobile.

Sometimes, an application will have to output images. Space and speed are huge factors here. How you export, or save, your images from your program influences space on the target device as well as its speed in being created. I will show you a few tricks on how to save JPEG files with the proper encoding to reduce space as well as to reduce creation speed.

Types of Images

There are essentially two types of images:

  • Raster
  • Vector

Raster Images Versus Vector Images

Raster images such as JPEG files consist of pixels. A pixel is a single point, or the smallest single element, in a display device. Vector images, such as fonts, are mathematical calculations from one point to another, thereby forming lines and shapes.

Vector images can be scaled to any size without losing quality, whereas raster images do not scale up optimally. A large vector graphic maintains a small file size whereas large dimensions and detailed images increase a raster image’s size.

Vector images are not best suited for continuous tone images with blends of color or to edit photographs. However, it is more difficult to print raster images using a limited amount of spot colors.

JPEG—Joint Photographic Experts Group

Almost all digital cameras save images in the JPEG format. JPEG supports 24-bit color images (eight bits for red, eight bits for green, and eight bits for blue) as well as eight-bit grayscale images. JPEG applies loss compression to images that result in a reduction of the file size.

TIFF—Tagged Image File Format

Tagged Image File Format (TIFF) saves eight bits or sixteen bits per color (red, green, blue) for 24-bit and 48-bit totals. TIFFs can be lossy or lossless, depending on the technique chosen for storing the pixel data.

GIF—Graphics Interchange Format

The GIF format is limited to an 8-bit palette, or 256 colors. GIF is most often used for storing graphics with few colors, such as shapes, logos, simple diagrams, and cartoon-style images.

BMP—Windows Bitmap

BMP files are uncompressed, large, and lossless, but accepted in a very wide variety of Windows programs.

PNG—Portable Network Graphics

PNG format supports eight-bit palette images and 24-bit TrueColor (16 million colors) or 48-bit TrueColor with and without alpha channel—whereas GIF supports only 256 colors and a single transparent color.

SVG—Scalable Vector Graphics

The SVG format does not have a compression scheme of its own, but can be compressed using a program such as gzip.

Our Project

The purpose of the next example project is to demonstrate two different ways to save a JPEG from your Visual Basic program. One method will be a bit slower and the file output will be larger than the next.

Create a new Visual Basic Windows Forms application and design it as shown in Figure 1.

There are three buttons and a PictureBox. The PictureBox is set to stretch the image. Obviously, you should use your own image. The image I have used is of the beautiful Table Mountain I visited in late 2014. It is truly majestic.

Design
Figure 1: Design

Add the necessary Namespace to do Image processing:

Imports System.Drawing.Imaging

Add the following code to save the PictureBox’s image:

   Private Sub Button3_Click(sender As Object, e As EventArgs) _
      Handles Button3.Click

      If Me.PictureBox1.Image IsNot Nothing Then

         Me.PictureBox1.Image.Save(IO.Path.Combine(My.Computer _
           .FileSystem.SpecialDirectories.MyPictures, _
            "Table Mountain.jpg"))

      End If

   End Sub

This simply determines whether or not there is an image inside the PictureBox. If there is an image, it must be saved. Have a close look at the file size after the save.

Add the following code to save a resized version of the PictureBox image:

   Public Sub Resize_Picture1(strOriginal As String, _
      strDestination As String, intFinalWidth As Integer, _
      intFinalHeight As Integer)

      Dim bmpNew As System.Drawing.Bitmap
      Dim grTemp As System.Drawing.Graphics
      Dim bmpCurrent As New System.Drawing.Bitmap(strOriginal)

      Dim iWidth As Integer
      Dim iHeight As Integer

      If (intFinalHeight = 0) AndAlso (intFinalWidth <> 0) Then

         iWidth = intFinalWidth
         iHeight = (bmpCurrent.Size.Height * iWidth / _
            bmpCurrent.Size.Width)

      ElseIf (intFinalHeight <> 0) AndAlso _
            (intFinalWidth = 0) Then

         iHeight = intFinalHeight
         iWidth = (bmpCurrent.Size.Width * iHeight / _
            bmpCurrent.Size.Height)

      Else

         iWidth = intFinalWidth
         iHeight = intFinalHeight

      End If

      bmpNew = New System.Drawing.Bitmap(iWidth, iHeight)
      grTemp = System.Drawing.Graphics.FromImage(bmpNew)

      grTemp.CompositingMode = _
         System.Drawing.Drawing2D.CompositingMode.SourceOver
      grTemp.CompositingQuality = _
         System.Drawing.Drawing2D.CompositingQuality.HighQuality
      grTemp.SmoothingMode = _
         System.Drawing.Drawing2D.SmoothingMode.HighQuality
      grTemp.InterpolationMode = System.Drawing.Drawing2D _
         .InterpolationMode.HighQualityBicubic
      grTemp.PixelOffsetMode = _
         System.Drawing.Drawing2D.PixelOffsetMode.HighQuality

      grTemp.DrawImage(bmpCurrent, 0, 0, iWidth, iHeight)
      grTemp.Dispose()

      bmpNew.Save(strDestination)

      bmpNew.Dispose()
      bmpCurrent.Dispose()

   End Sub

   Private Sub Button1_Click(sender As Object, e As EventArgs) _
         Handles Button1.Click

      Resize_Picture1(IO.Path.Combine(My.Computer.FileSystem _
         .SpecialDirectories.MyPictures, "Table Mountain.jpg"), _
         IO.Path.Combine(My.Computer.FileSystem _
         .SpecialDirectories.MyPictures, _
         "Table Mountain_1.jpg"), 616, 414)

   End Sub

In the Resize_Picture_1 procedure, I resized the image to the given size. This size is incidentally the same size as what is shown inside the PictureBox. I then made use of the System.Drawing.Drwaing2D.InterpolationMode to set up the picture to be saved.

Add the next code:

   Public Shared Sub Resize_Picture2(strOriginal As String, _
      strDestination As String, intFinalWidth As Integer, _
      intFinalHeight As Integer)

      'Load the image'
      Dim imgSource As Image = Image.FromFile(strOriginal, True)

      'Save'

      Dim bmpNew As Bitmap
      Dim grTemp As Graphics
      Dim iTemp As Image

      Dim bmpCurrent As New Bitmap(strOriginal)

      Dim iWidth As Integer
      Dim iHeight As Integer

      If (intFinalHeight = 0) AndAlso (intFinalWidth <> 0) Then

         iWidth = intFinalWidth
         iHeight = (bmpCurrent.Size.Height * iWidth / _
            bmpCurrent.Size.Width)

      ElseIf (intFinalHeight <> 0) AndAlso _
            (intFinalWidth = 0) Then

         iHeight = intFinalHeight
         iWidth = (bmpCurrent.Size.Width * iHeight / _
            bmpCurrent.Size.Height)

      Else

         iWidth = intFinalWidth
         iHeight = intFinalHeight

      End If

      bmpNew = New Bitmap(iWidth, iHeight)
      grTemp = Graphics.FromImage(bmpNew)
      iTemp = DirectCast(bmpNew.Clone(), Image)

      SaveJpegWithCodecs(strDestination, iTemp, 90)

      imgSource.Dispose()

   End Sub

   Public Shared Sub SaveJpegWithCodecs(strPath As String, _
         imgSource As Image, intQuality As Integer)

      'Encoder'
      Dim epQuality As New EncoderParameter(System.Drawing _
         .Imaging.Encoder.Quality, intQuality)

      Dim cdCodec As ImageCodecInfo = GetEncoderInfo("image/jpeg")

      Dim epEncoder As New EncoderParameters(1)
      epEncoder.Param(0) = epQuality

      imgSource.Save(strPath, cdCodec, epEncoder)

      imgSource.Dispose()

   End Sub

   Private Shared Function GetEncoderInfo(mimeType As String) _
         As ImageCodecInfo

      'Get image codecs'
      Dim cdCodecs As ImageCodecInfo() = _
         ImageCodecInfo.GetImageEncoders()

      'Find correct codec'
      For i As Integer = 0 To cdCodecs.Length—1

         If cdCodecs(i).MimeType = mimeType Then

            Return cdCodecs(i)

         End If

      Next

      Return Nothing

   End Function

   Private Sub Button2_Click(sender As Object, e As EventArgs) _
         Handles Button2.Click

      Resize_Picture2(IO.Path.Combine(My.Computer.FileSystem _
         .SpecialDirectories.MyPictures, "Table Mountain.jpg"), _
         IO.Path.Combine(My.Computer.FileSystem _
         .SpecialDirectories .MyPictures, _
          "Table Mountain_2.jpg") 616, 414)

   End Sub

I also resized the image, but then I made use of EncoderParameter and ImageCodeInfo to save the image. My results are shown in Figure 2.

Output JPEGS
Figure 2: Output JPEGS

Table_Mountain_1 was saved via the first sub procedure whereas Table_Mountain_2 was saved via the second resize procedure. I am including these images as well as the article project. Please see the download section at the bottom of the article to save them for your own use.

Conclusion

This article showed you how to save images in two very different and unique ways, each with its own strengths and weaknesses. Whichever method you choose to save your images is now up to you.

Hannes DuPreez
Hannes DuPreez
Ockert J. du Preez is a passionate coder and always willing to learn. He has written hundreds of developer articles over the years detailing his programming quests and adventures. He has written the following books: Visual Studio 2019 In-Depth (BpB Publications) JavaScript for Gurus (BpB Publications) He was the Technical Editor for Professional C++, 5th Edition (Wiley) He was a Microsoft Most Valuable Professional for .NET (2008–2017).

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read