Introduction
This article shall describe an approach to building a simple watermarking utility that may be used to add watermarks to any supported image file format. The resulting application shall permit the user to open any supported image file format into a scrollable picture box, to define the text to be applied as a watermark (with a default version supplied), to set the font and color of the watermark, to define the opacity of the watermark, to determine whether or not the watermark appears at the top or bottom of the image, and to preview the watermark prior to saving it to the image.
Figure 1: The Utility Application showing a Watermarked Image.
If you are at all curious about the image, it is of an American Goldfinch, this time of year, I have about 50 or so such birds hanging around my bird feeders. I took the picture with my Fuji S700 digital camera through the kitchen window.
Getting Started
The solution contains a single Windows Forms project called WatermarkingVB
written in Visual Basic 2005; the application contains only a single form (frmWatermark.vb) and all of the code necessary to drive the application is contained in that single Form
class.
Figure 2: Solution Explorer with the Project Visible.
Code: Watermarking Main Form (frmWatermark.vb)
All of the code necessary for this project is contained in this single form; the form shall be described entirely in this section.
The code for this Form
class begins with the following:
Imports System.Drawing
Imports System.Drawing.Drawing2D
Imports System.Drawing.Imaging
Imports System.Text
Public Class frmWatermark
Following the declaration of the Form
class, the next order of business in the application is to declare a collection of member variables requiring form wide scope; these variables are contained in a defined region
entitled, Member Variables
. The declaration of the variables follows; as can been determined, the variables are used to keep track of the current file location and image, codec and encoder information used to translate the image from one format to another, and the color and font used to display the image watermark.
#Region "Member Variables"
Private CurrentFile As String
Private img As Image
Private myImageCodecInfo As ImageCodecInfo
Private myEncoder As System.Drawing.Imaging.Encoder
Private myEncoderParameter As EncoderParameter
Private myEncoderParameters As EncoderParameters
Private myWatermarkColor As System.Drawing.Color
Private myFont As System.Drawing.Font
#End Region
The next block of code in the Form
class is the constructor; in this instance, the constructor is used to establish a default configuration including the definition of the watermark color, the opacity level of the watermark, the positioning option (top or bottom), the text contained in the watermark, and the font used to display the watermark.
#Region "Constructor"
Public Sub New()
InitializeComponent()
myWatermarkColor = Color.SteelBlue
cboOpacity.SelectedIndex = 2
optTop.Checked = True
txtWaterMark.Text = "Your Name " & _
Char.ConvertFromUtf32(169).ToString() & " " & _
DateTime.Now.Year.ToString() + ", All Rights Reserved"
myFont = txtWaterMark.Font
End Sub
#End Region
Following the constructor, there is a region defined to handle file input/output operations. This region contains two event handlers, one for the selection of the Open File menu strip option, and one for the Save buttons’ click event. The Open File menu option is used to allow the user to navigate to and select an image file for load; the selected image file is placed into a scrollable picturebox.
The Save button click event handler is used to save the image file with the watermark; the original file may be renamed or overwritten.
#Region "File IO"
Private Sub openToolStripMenuItem_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles openToolStripMenuItem.Click
openFileDialog1.Title = "Open Image File"
openFileDialog1.Filter = "Bitmap Files|*.bmp" & _
"|Enhanced Windows MetaFile|*.emf" & _
"|Exchangeable Image File|*.exif" & _
"|Gif Files|*.gif|JPEG Files|*.jpg" & _
"|PNG Files|*.png|TIFF Files|*.tif|Windows MetaFile|*.wmf"
openFileDialog1.DefaultExt = "bmp"
openFileDialog1.FilterIndex = 1
openFileDialog1.FileName = ""
openFileDialog1.ShowDialog()
If (openFileDialog1.FileName = "") Then Return
CurrentFile = openFileDialog1.FileName.ToString()
Me.Text = "Watermark Utility: " & CurrentFile.ToString()
Try
img = Image.FromFile(openFileDialog1.FileName, True)
picContainer.Image = img
picContainer.Size = img.Size
Catch ex As Exception
MessageBox.Show(ex.Message, "File Open Error")
End Try
End Sub
Private Sub btnSave_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btnSave.Click
Try
Dim strExt As String
strExt = System.IO.Path.GetExtension(CurrentFile)
strExt = strExt.ToUpper()
strExt = strExt.Remove(0, 1)
SaveFileDialog1.Title = "Save File"
SaveFileDialog1.DefaultExt = strExt
SaveFileDialog1.Filter = strExt & " Image Files|*." + strExt
SaveFileDialog1.FilterIndex = 1
If SaveFileDialog1.ShowDialog() = DialogResult.OK Then
If (SaveFileDialog1.FileName = "") Then
Return
Else
picContainer.Image.Save(SaveFileDialog1.FileName)
End If
CurrentFile = SaveFileDialog1.FileName
Me.Text = "Watermark Utility: " + CurrentFile
MessageBox.Show(CurrentFile.ToString() + " saved.", "File
Save")
Else
MessageBox.Show("The save file request was cancelled by
user.", "Save Cancelled")
End If
Catch ex As Exception
MessageBox.Show(ex.Message.ToString(), "Image Save Error")
End Try
End Sub
#End Region
After handling the file IO operations, the next region of code is the Image Format Conversion section. In this region, the methods provided are used to convert the open image into an alternative format (e.g. bitmap to JPEG, or JPEG to GIF, etc.). Each section of code is annotated and may be reviewed in the following:
#Region "Image Format Conversion"
Private Function GetEncoderInfo(ByVal mimeType As String) As ImageCodecInfo
Dim j As Integer
Dim encoders As ImageCodecInfo()
encoders = ImageCodecInfo.GetImageEncoders()
For j = 0 To encoders.Length
If (encoders(j).MimeType = mimeType) Then
Return encoders(j)
End If
Next
Return Nothing
End Function
Private Sub bitmapToolStripMenuItem_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles bitmapToolStripMenuItem.Click
Dim newName As String = _
System.IO.Path.GetFileNameWithoutExtension(CurrentFile)
newName = newName + ".bmp"
Try
img.Save(newName, ImageFormat.Bmp)
CurrentFile = newName
picContainer.Image = Image.FromFile(CurrentFile)
Me.Text = "Watermark Utility: " + CurrentFile.ToString()
Catch
MessageBox.Show("Failed to save image to bitmap.", "Error", _
MessageBoxButtons.OK, MessageBoxIcon.Error)
Return
End Try
MessageBox.Show("Image file saved to " + newName.ToString(), _
"Image Saved", MessageBoxButtons.OK, MessageBoxIcon.Information)
End Sub
Private Sub emfToolStripMenuItem_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles emfToolStripMenuItem.Click
Dim newName As String = _
System.IO.Path.GetFileNameWithoutExtension(CurrentFile)
newName = newName + ".emf"
Try
img.Save(newName, ImageFormat.Emf)
CurrentFile = newName
picContainer.Image = Image.FromFile(CurrentFile)
Me.Text = "Watermark Utility: " + CurrentFile.ToString()
Catch
MessageBox.Show("Failed to save image to EMF.", "Error", _
MessageBoxButtons.OK, MessageBoxIcon.Error)
Return
End Try
MessageBox.Show("Image file saved to " + newName.ToString(), _
"Image Saved", MessageBoxButtons.OK, MessageBoxIcon.Information)
End Sub
Private Sub exifToolStripMenuItem_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles exifToolStripMenuItem.Click
Dim newName As String = _
System.IO.Path.GetFileNameWithoutExtension(CurrentFile)
newName = newName + ".exif"
Try
img.Save(newName, ImageFormat.Exif)
CurrentFile = newName
picContainer.Image = Image.FromFile(CurrentFile)
Me.Text = "Watermark Utility: " + CurrentFile.ToString()
Catch
MessageBox.Show("Failed to save image to EXIF.", "Error", _
MessageBoxButtons.OK, MessageBoxIcon.Error)
Return
End Try
MessageBox.Show("Image file saved to " + newName.ToString(), _
"Image Saved", MessageBoxButtons.OK, MessageBoxIcon.Information)
End Sub
Private Sub gIFFileToolStripMenuItem_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles gIFFileToolStripMenuItem.Click
Dim newName As String = _
System.IO.Path.GetFileNameWithoutExtension(CurrentFile)
newName = newName + ".gif"
Try
img.Save(newName, ImageFormat.Gif)
CurrentFile = newName
picContainer.Image = Image.FromFile(CurrentFile)
Me.Text = "Watermark Utility: " + CurrentFile.ToString()
Catch
MessageBox.Show("Failed to save image to GIF.", "Error", _
MessageBoxButtons.OK, MessageBoxIcon.Error)
Return
End Try
MessageBox.Show("Image file saved to " + newName.ToString(), _
"Image Saved", MessageBoxButtons.OK, MessageBoxIcon.Information)
End Sub
Private Sub jPEGFileToolStripMenuItem_Click(ByVal sender As _
System.Object, ByVal e As System.EventArgs) Handles _
jPEGFileToolStripMenuItem.Click
Dim newName As String = _
System.IO.Path.GetFileNameWithoutExtension(CurrentFile)
newName = newName + ".jpg"
Try
img.Save(newName, ImageFormat.Jpeg)
CurrentFile = newName
picContainer.Image = Image.FromFile(CurrentFile)
Me.Text = "Watermark Utility: " + CurrentFile.ToString()
Catch
MessageBox.Show("Failed to save image to JPEG.", "Error", _
MessageBoxButtons.OK, MessageBoxIcon.Error)
Return
End Try
MessageBox.Show("Image file saved to " + newName.ToString(), _
"Image Saved", MessageBoxButtons.OK, MessageBoxIcon.Information)
End Sub
Private Sub pNGFileToolStripMenuItem_Click(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles pNGFileToolStripMenuItem.Click
Dim newName As String = _
System.IO.Path.GetFileNameWithoutExtension(CurrentFile)
newName = newName + ".png"
Try
img.Save(newName, ImageFormat.Png)
CurrentFile = newName
picContainer.Image = Image.FromFile(CurrentFile)
Me.Text = "Watermark Utility: " + CurrentFile.ToString()
Catch
MessageBox.Show("Failed to save image to PNG.", "Error", _
MessageBoxButtons.OK, MessageBoxIcon.Error)
Return
End Try
MessageBox.Show("Image file saved to " + newName.ToString(), _
"Image Saved", MessageBoxButtons.OK, MessageBoxIcon.Information)
End Sub
Private Sub tIFFFileToolStripMenuItem_Click(ByVal sender As _
System.Object, ByVal e As System.EventArgs) Handles _
tIFFFileToolStripMenuItem.Click
Dim newName As String = _
System.IO.Path.GetFileNameWithoutExtension(CurrentFile)
newName = newName + ".tif"
Try
img.Save(newName, ImageFormat.Tiff)
CurrentFile = newName
picContainer.Image = Image.FromFile(CurrentFile)
Me.Text = "Watermark Utility: " + CurrentFile.ToString()
Catch
MessageBox.Show("Failed to save image to TIF.", "Error", _
MessageBoxButtons.OK, MessageBoxIcon.Error)
Return
End Try
MessageBox.Show("Image file saved to " + newName.ToString(), _
"Image Saved", MessageBoxButtons.OK, MessageBoxIcon.Information)
End Sub
Private Sub windowsMetafileToolStripMenuItem_Click(ByVal sender As _
System.Object, ByVal e As System.EventArgs) Handles _
windowsMetafileToolStripMenuItem.Click
Dim newName As String = _
System.IO.Path.GetFileNameWithoutExtension(CurrentFile)
newName = newName + ".wmf"
Try
img.Save(newName, ImageFormat.Wmf)
CurrentFile = newName
picContainer.Image = Image.FromFile(CurrentFile)
Me.Text = "Watermark Utility: " + CurrentFile.ToString()
Catch
MessageBox.Show("Failed to save image to WMF.", "Error", _
MessageBoxButtons.OK, MessageBoxIcon.Error)
Return
End Try
MessageBox.Show("Image file saved to " + newName.ToString(), _
"Image Saved", MessageBoxButtons.OK, MessageBoxIcon.Information)
End Sub
#End Region
Following the image conversion routines, the next region of code is used to perform the actual watermarking functions.
#Region "Watermarking"
Private Sub btnPreview_Click(ByVal sender As System.Object, ByVal e As _
System.EventArgs) Handles btnPreview.Click
picContainer.Image = Image.FromFile(CurrentFile)
Dim opac As Integer = 0
Dim sOpacity As String = cboOpacity.Text
Select Case (sOpacity)
Case "100%"
opac = 255
Case "75%"
opac = 191
Case "50%"
opac = 127
Case "25%"
opac = 64
Case "10%"
opac = 25
Case Else
opac = 127
End Select
Dim g As Graphics = Graphics.FromImage(picContainer.Image)
Dim myBrush As Brush
myBrush = New SolidBrush(Color.FromArgb(opac, myWatermarkColor))
Dim sz As SizeF = g.MeasureString(txtWaterMark.Text, myFont)
Dim X As Integer
Dim Y As Integer
If (optTop.Checked = True) Then
X = Convert.ToInt32((picContainer.Image.Width - sz.Width) / 2)
Y = Convert.ToInt32((picContainer.Top + sz.Height) / 2)
Else
X = Convert.ToInt32((picContainer.Image.Width - sz.Width) / 2)
Y = Convert.ToInt32((picContainer.Image.Height - sz.Height))
End If
g.DrawString(txtWaterMark.Text, myFont, myBrush, New Point(X, Y))
End Sub
Private Sub btnFont_Click(ByVal sender As System.Object, ByVal e As _
System.EventArgs) Handles btnFont.Click
fontDialog1.ShowColor = True
fontDialog1.Font = txtWaterMark.Font
fontDialog1.Color = txtWaterMark.ForeColor
If fontDialog1.ShowDialog() <> DialogResult.Cancel Then
myFont = fontDialog1.Font
myWatermarkColor = fontDialog1.Color
txtWaterMark.Font = fontDialog1.Font
txtWaterMark.ForeColor = fontDialog1.Color
End If
End Sub
#End Region
That wraps up the sum of the code needed to drive the Watermarking utility. With the code provided, it is possible to convert from one image format to another and to apply a user defined watermark on an existing image file.
Summary
While this article was written to demonstrate an approach to watermarking an image file in the context of a WinForms utility application; the code used in the project could be modified to batch process image files, or to watermark image files programmatically and without user intervention. Even used as a utility, the application could have some value to anyone wishing to watermark or caption an image file before exposing the image file on the Web.