Virtual Developer Workshop: Containerized Development with Docker
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 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 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.
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.
Figure 1: Design
Add the necessary Namespace to do Image processing:
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.
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.
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.