Introduction
Recently, I have been involved in a new project which was dealing a lot with image manipulations. The basic process was in regards to be able to upload an image to a Web server and resize it after. Then, we found out the resizing, as is, was giving a new image but not properly in ratio as to what it should have been. So, we have to find a way to resize but to respect the ratio. So, the image cropping then was introduced. Then, later on, we had the need to save that into a JPG high resolution format.
Simple image resizing
As many good developers would do, whenever comes time to build a new method, we always think about making a class for that as well as building other related methods and exposing some properties which would then be related and useful to have.
As our first method would deal with image resizing, let's define our class like this:
Imports System.IO Imports System.Drawing.Imaging Imports System.Drawing Namespace Framework Public Class Image Public Function ImageResize() As Boolean Return True End Function End Class End Namespace
Basically, when I started to work with this class, I figured out the main property would be to have a property for our image object. So, whoever is the client calling this class, we would then assume they would initialize the image object into this property and simply call the related method after. So, for that need, I have created a property oImage. As our first method deals with image resizing, we would then need to add a property nWidth for the width as well as a property nHeight for the height of the resized image.
So, basically, the three properties created would then look like this:
Public nHeight As Integer = 0 Public nWidth As Integer = 0 Public oImage As System.Drawing.Image
When having worked with this a lot, I also found it was necessary to have a property to indicate if the image has been resized or not. This is needed in the case when we would not have to resize assuming the width and height of the source image is already properly resized.
This property is then defined as this:
Public lImageHasBeenPreserved As Boolean = False
When having worked a lot with this, I realized not in some cases, we need to maintain the ratio of the image in our resized version. Because, if we simply resize as is, our image will be a victim of distortion. Basically, a distortion is the alteration of the original shape of an object, image, sound, waveform or other form of information or representation.
Public lMaintainRatio As Boolean = False
When this property will be set to True, our ImageResize() method will calculate the ratio of the source image and use that ratio to be able to crop the image before resizing it. The cropping will be done from the upper left. Thus, this will assure our image ratio will be preserved.
Our ImageResize() method can then be defined as this:
Public Function ImageResize() As Boolean Dim lnRatio As Double = 0 Dim lnRatioImage As Double = 0 Dim loGraphics As System.Drawing.Graphics Dim loImage As System.Drawing.Bitmap lImageHasBeenPreserved = False ' If the image is already with the proper dimensions If nWidth = oImage.Width And nHeight = oImage.Height Then lImageHasBeenPreserved = True Return True End If loImage = New System.Drawing.Bitmap(nWidth, nHeight, oImage.PixelFormat) ' Make sure we can resize If loImage.PixelFormat = Drawing.Imaging.PixelFormat.Format1bppIndexed Or _ loImage.PixelFormat = Drawing.Imaging.PixelFormat.Format4bppIndexed Or _ loImage.PixelFormat = Drawing.Imaging.PixelFormat.Format8bppIndexed Or _ loImage.PixelFormat = Drawing.Imaging.PixelFormat.Undefined Or _ loImage.PixelFormat = Drawing.Imaging.PixelFormat.DontCare Or _ loImage.PixelFormat = Drawing.Imaging.PixelFormat.Format16bppArgb1555 Or _ loImage.PixelFormat = Drawing.Imaging.PixelFormat.Format16bppGrayScale Then cError = cPixelFormatNotSupported nError = 1 Return False End If ' If we have to maintain the ratio If lMaintainRatio Then lnRatio = nWidth / nHeight lnRatioImage = oImage.Width / oImage.Height If lnRatioImage < lnRatio Then nCropWidth = oImage.Width nCropHeight = oImage.Width / lnRatio Else nCropWidth = oImage.Height * lnRatio nCropHeight = oImage.Height End If ' Crop first If Not Crop() Then Return False End If End If loGraphics = System.Drawing.Graphics.FromImage(loImage) loGraphics.SmoothingMode = Drawing.Drawing2D.SmoothingMode.HighQuality loGraphics.InterpolationMode = Drawing.Drawing2D.InterpolationMode.HighQualityBicubic loGraphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality loGraphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality loGraphics.DrawImage(oImage, 0, 0, loImage.Width, loImage.Height) loGraphics.Dispose() oImage = loImage Return True End Function
As this method makes use of a Crop() method, I then have defined it as follow:
Public Function Crop() As Boolean Dim loGraphics As System.Drawing.Graphics Dim loImage As System.Drawing.Bitmap loImage = New System.Drawing.Bitmap(nCropWidth, nCropHeight) loGraphics = System.Drawing.Graphics.FromImage(loImage) loGraphics.DrawImage(oImage, New System.Drawing.Rectangle(0, 0, nCropWidth, nCropHeight), _ nStartXPoint, nStartYPoint, nCropWidth, nCropHeight, System.Drawing.GraphicsUnit.Pixel) loGraphics.Dispose() oImage = loImage Return True End Function
Calling it from our client application
From our client application, we can then make use of this method like this:
Dim loImage As System.Drawing.Bitmap Dim loImage2 As Framework.Image = New Framework.Image() ' Image source loImage = New System.Drawing.Bitmap("d:\Temp.jpg") ' Initialize the loImage2 properties loImage2.oImage = loImage loImage2.nWidth = 90 loImage2.nHeight = 100 ' Resize the image If Not loImage2.ImageResize() Then ' Do something, the error message is from loImage2.cError and from loImage2.nError Return False End If
Saving the image on disk
To allow our client to save the image as a JPG file, we will add another property:
Public cFilePath As String = ""
Public Function SaveAsHighQualityJpegFile() As Boolean Dim loEncoderParameters As System.Drawing.Imaging.EncoderParameters = _ New System.Drawing.Imaging.EncoderParameters(1) Dim loImageCodecInfo As System.Drawing.Imaging.ImageCodecInfo = Nothing Dim loCodec As System.Drawing.Imaging.ImageCodecInfo loEncoderParameters.Param(0) = _ New System.Drawing.Imaging.EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100) For Each loCodec In System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders() If loCodec.MimeType = "image/jpeg" Then loImageCodecInfo = loCodec Exit For End If Next oImage.Save(cFilePath, loImageCodecInfo, loEncoderParameters) Return True End Function
' If the image has not been altered by the Image class If loImage2.lImageHasBeenPreserved Then Else loImage2.cFilePath = "D:\TempResizedVersion.jpg" loImage2.SaveAsHighQualityJpegFile() End If
Conclusion
This article covers only some basic manipulations with images. However, for a social site I have been involved with recently, this was enough to allow new members to upload a profile picture, resize it by keeping the proper ratio, to allow them to upload additional images in their profile with different dimensions and so on.
Soure code
Imports System.IO Imports System.Drawing.Imaging Imports System.Drawing Namespace Framework Public Class Image Public nCropHeight As Integer = 0 Public nCropWidth As Integer = 0 Public cError As String = "" Public cFilePath As String = "" Public lImageHasBeenPreserved As Boolean = False Public lMaintainRatio As Boolean = False Public nError As String = 0 Public nHeight As Integer = 0 Public nStartXPoint As Integer = 0 Public nStartYPoint As Integer = 0 Public nWidth As Integer = 0 Public oImage As System.Drawing.Image Public oPoint As New System.Drawing.Point Private cPixelFormatNotSupported As String = "" Private nLanguage As Integer = 0 Sub New() Init() End Sub Private Function Init() As Boolean Select Case nLanguage ' English Case 1 cPixelFormatNotSupported = "Pixel format of the image is not supported." ' French Case 2 cPixelFormatNotSupported = "Le format pixel de cette image n'est pas supporté." ' Spanish Case 3 cPixelFormatNotSupported = "Pixel format of the image is not supported." ' Portuguese Case 4 cPixelFormatNotSupported = "Pixel format of the image is not supported." End Select Return True End Function Public Function ImageResize() As Boolean Dim lnRatio As Double = 0 Dim lnRatioImage As Double = 0 Dim loGraphics As System.Drawing.Graphics Dim loImage As System.Drawing.Bitmap lImageHasBeenPreserved = False ' If the image is already with the proper dimensions If nWidth = oImage.Width And nHeight = oImage.Height Then lImageHasBeenPreserved = True Return True End If loImage = New System.Drawing.Bitmap(nWidth, nHeight, oImage.PixelFormat) ' Make sure we can resize If loImage.PixelFormat = Drawing.Imaging.PixelFormat.Format1bppIndexed Or _ loImage.PixelFormat = Drawing.Imaging.PixelFormat.Format4bppIndexed Or _ loImage.PixelFormat = Drawing.Imaging.PixelFormat.Format8bppIndexed Or _ loImage.PixelFormat = Drawing.Imaging.PixelFormat.Undefined Or _ loImage.PixelFormat = Drawing.Imaging.PixelFormat.DontCare Or _ loImage.PixelFormat = Drawing.Imaging.PixelFormat.Format16bppArgb1555 Or _ loImage.PixelFormat = Drawing.Imaging.PixelFormat.Format16bppGrayScale Then cError = cPixelFormatNotSupported nError = 1 Return False End If ' If we have to maintain the ratio If lMaintainRatio Then lnRatio = nWidth / nHeight lnRatioImage = oImage.Width / oImage.Height If lnRatioImage < lnRatio Then nCropWidth = oImage.Width nCropHeight = oImage.Width / lnRatio Else nCropWidth = oImage.Height * lnRatio nCropHeight = oImage.Height End If ' Crop first If Not Crop() Then Return False End If End If loGraphics = System.Drawing.Graphics.FromImage(loImage) loGraphics.SmoothingMode = Drawing.Drawing2D.SmoothingMode.HighQuality loGraphics.InterpolationMode = Drawing.Drawing2D.InterpolationMode.HighQualityBicubic loGraphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality loGraphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality loGraphics.DrawImage(oImage, 0, 0, loImage.Width, loImage.Height) loGraphics.Dispose() oImage = loImage Return True End Function Public Function Crop() As Boolean Dim loGraphics As System.Drawing.Graphics Dim loImage As System.Drawing.Bitmap loImage = New System.Drawing.Bitmap(nCropWidth, nCropHeight) loGraphics = System.Drawing.Graphics.FromImage(loImage) loGraphics.DrawImage(oImage, New System.Drawing.Rectangle(0, 0, nCropWidth, nCropHeight), _ nStartXPoint, nStartYPoint, nCropWidth, nCropHeight, System.Drawing.GraphicsUnit.Pixel) loGraphics.Dispose() oImage = loImage Return True End Function Public Function SaveAsHighQualityJpegFile() As Boolean Dim loEncoderParameters As System.Drawing.Imaging.EncoderParameters = _ New System.Drawing.Imaging.EncoderParameters(1) Dim loImageCodecInfo As System.Drawing.Imaging.ImageCodecInfo = Nothing Dim loCodec As System.Drawing.Imaging.ImageCodecInfo loEncoderParameters.Param(0) = _ New System.Drawing.Imaging.EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100) For Each loCodec In System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders() If loCodec.MimeType = "image/jpeg" Then loImageCodecInfo = loCodec Exit For End If Next oImage.Save(cFilePath, loImageCodecInfo, loEncoderParameters) Return True End Function End Class End Namespace