Click here to Skip to main content
Click here to Skip to main content

Build a Simple Watermarking Utility in C#

, 19 Jan 2008 CPOL
Rate this:
Please Sign up or sign in to vote.
An article on building a simple Watermarking utility in C#

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 Watermarking written in C#; the application contains only a single form (frmWatermark.cs) 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.cs)

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: (Note the highlighted text showing additional libraries added to the project; these additions to the default configuration were added to support the manipulation of the image files and the rendering of the watermark onto an image).

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Text;
using System.Windows.Forms;

namespace Watermarking
{
    /// <span class="code-SummaryComment"><summary></span>
    /// An Image Watermarking Utility
    /// <span class="code-SummaryComment"></summary></span>
    public partial class frmWatermark : Form
    {

Following the declaration of the namespace and 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 be 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

        string CurrentFile;
        Image img;
        ImageCodecInfo myImageCodecInfo;
        System.Drawing.Imaging.Encoder myEncoder;
        EncoderParameter myEncoderParameter;
        EncoderParameters myEncoderParameters;
        System.Drawing.Color myWatermarkColor;
        System.Drawing.Font myFont;

#endregion

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

        /// <span class="code-SummaryComment"><summary></span>
        /// constructor with default configuration settings
        /// <span class="code-SummaryComment"></summary></span>
        public frmWatermark()
        {
            InitializeComponent();

            // setup default settings
            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;
        }

#endregion

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

        /// <span class="code-SummaryComment"><summary></span>
        /// Open an image file into the picture box control
        /// <span class="code-SummaryComment"></summary></span>
        /// <span class="code-SummaryComment"><param name="sender"></param></span>
        /// <span class="code-SummaryComment"><param name="e"></param></span>
        private void openToolStripMenuItem_Click(object sender, EventArgs e)
        {
            // configure the open file dialog to point to some
            // common (usable) image file formats
            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 the user did not select a file, return
            if (openFileDialog1.FileName == "")
                return;

            // update the current file and form caption text
            CurrentFile = openFileDialog1.FileName.ToString();
            this.Text = "Watermark Utility: " + CurrentFile.ToString();

            try
            {
                // open the image into the picture box
                img = Image.FromFile(openFileDialog1.FileName, true);
                picContainer.Image = img;

                // resize the picture box to support scrolling
                // large images
                picContainer.Size = img.Size;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "File Open Error");
            }
        }

        /// <span class="code-SummaryComment"><summary></span>
        /// Save the Current Image with the Watermark
        /// <span class="code-SummaryComment"></summary></span>
        /// <span class="code-SummaryComment"><param name="sender"></param></span>
        /// <span class="code-SummaryComment"><param name="e"></param></span>
        private void btnSave_Click(object sender, EventArgs e)
        {
            try
            {
                // get the extension to figure out how to limit the save
                // option to the current image file type
                string strExt;
                strExt = System.IO.Path.GetExtension(CurrentFile);
                strExt = strExt.ToUpper();
                strExt = strExt.Remove(0, 1);

                // if the current image is, for example, a gif, only
                // allow the user to save the file with the watermark
                // as a gif
                SaveFileDialog1.Title = "Save File";
                SaveFileDialog1.DefaultExt = strExt;
                SaveFileDialog1.Filter = strExt + " Image Files|*." + strExt;
                SaveFileDialog1.FilterIndex = 1;

                if (SaveFileDialog1.ShowDialog() == DialogResult.OK)
                {
                    if (SaveFileDialog1.FileName == "")
                    {
                        return;
                    }
                    else
                    {
                        // save the file with the name supplied by the user
                        picContainer.Image.Save(SaveFileDialog1.FileName);
                    }

                    // update the current image file to point to the newly
                    // saved image
                    CurrentFile = SaveFileDialog1.FileName;
                    this.Text = "Watermark Utility: " + CurrentFile;
                    MessageBox.Show(CurrentFile.ToString() + " saved.", "File
                    Save");
                }
                else
                {
                    MessageBox.Show("The save file request was cancelled by
                    user.", "Save Cancelled");
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message.ToString(), "Image Save Error");
            }
        }

#endregion

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

        /// <span class="code-SummaryComment"><summary></span>
        /// Return the available image encoders
        /// <span class="code-SummaryComment"></summary></span>
        /// <span class="code-SummaryComment"><param name="mimeType"></param></span>
        /// <span class="code-SummaryComment"><returns></returns></span>
        private static ImageCodecInfo GetEncoderInfo(String mimeType)
        {
            int j;
            ImageCodecInfo[] encoders;
            encoders = ImageCodecInfo.GetImageEncoders();
            for (j = 0; j < encoders.Length; ++j)
            {
                if (encoders[j].MimeType == mimeType)
                    return encoders[j];
            }
            return null;
        }

        /// <span class="code-SummaryComment"><summary></span>
        /// Convert the current file to a bitmap
        /// <span class="code-SummaryComment"></summary></span>
        /// <span class="code-SummaryComment"><param name="sender"></param></span>
        /// <span class="code-SummaryComment"><param name="e"></param></span>
        private void bitmapToolStripMenuItem_Click(object sender, EventArgs e)
        {
            // create a new name with the bitmap extension
            string newName =
            System.IO.Path.GetFileNameWithoutExtension(CurrentFile);
            newName = newName + ".bmp";

            try
            {
                // save the file as a bitmap
                img.Save(newName, ImageFormat.Bmp);
                CurrentFile = newName;
                picContainer.Image = Image.FromFile(CurrentFile);
                this.Text = "Watermark Utility: " + CurrentFile.ToString();
            }
            catch
            {
                MessageBox.Show("Failed to save image to bitmap.", "Error",
                MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            MessageBox.Show("Image file saved to " + newName.ToString(),
            "Image Saved", MessageBoxButtons.OK,
            MessageBoxIcon.Information);
        }

        /// <span class="code-SummaryComment"><summary></span>
        /// Convert the current image file to an EMF file
        /// <span class="code-SummaryComment"></summary></span>
        /// <span class="code-SummaryComment"><param name="sender"></param></span>
        /// <span class="code-SummaryComment"><param name="e"></param></span>
        private void emfToolStripMenuItem_Click(object sender, EventArgs e)
        {
            string newName =
            System.IO.Path.GetFileNameWithoutExtension(CurrentFile);
            newName = newName + ".emf";

            try
            {
                img.Save(newName, ImageFormat.Emf);
                CurrentFile = newName;
                picContainer.Image = Image.FromFile(CurrentFile);
                this.Text = "Watermark Utility: " + CurrentFile.ToString();
            }
            catch
            {
                MessageBox.Show("Failed to save image to EMF format.",
                "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            MessageBox.Show("Image file saved to " + newName.ToString(),
            "Image Saved", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        /// <span class="code-SummaryComment"><summary></span>
        /// Convert the current image file to an EXIF file
        /// <span class="code-SummaryComment"></summary></span>
        /// <span class="code-SummaryComment"><param name="sender"></param></span>
        /// <span class="code-SummaryComment"><param name="e"></param></span>
        private void exifToolStripMenuItem_Click(object sender, EventArgs e)
        {
            string newName =
            System.IO.Path.GetFileNameWithoutExtension(CurrentFile);
            newName = newName + ".exif";

            try
            {
                img.Save(newName, ImageFormat.Exif);
                CurrentFile = newName;
                picContainer.Image = Image.FromFile(CurrentFile);
                this.Text = "Watermark Utility: " + CurrentFile.ToString();
            }
            catch
            {
                MessageBox.Show("Failed to save image to EXIF format.",
                "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            MessageBox.Show("Image file saved to " + newName.ToString(),
            "Image Saved", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        /// <span class="code-SummaryComment"><summary></span>
        /// Convert the current image file to GIF format
        /// <span class="code-SummaryComment"></summary></span>
        /// <span class="code-SummaryComment"><param name="sender"></param></span>
        /// <span class="code-SummaryComment"><param name="e"></param></span>
        private void gIFFileToolStripMenuItem_Click(object sender, EventArgs e)
        {
            string newName =
            System.IO.Path.GetFileNameWithoutExtension(CurrentFile);
            newName = newName + ".gif";

            try
            {
                img.Save(newName, ImageFormat.Gif);
                CurrentFile = newName;
                picContainer.Image = Image.FromFile(CurrentFile);
                this.Text = "Watermark Utility: " + CurrentFile.ToString();
            }
            catch
            {
                MessageBox.Show("Failed to save image to GIF format.",
                "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            MessageBox.Show("Image file saved to " + newName.ToString(),
            "Image Saved", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        /// <span class="code-SummaryComment"><summary></span>
        /// Convert the current image file to JPEG format
        /// <span class="code-SummaryComment"></summary></span>
        /// <span class="code-SummaryComment"><param name="sender"></param></span>
        /// <span class="code-SummaryComment"><param name="e"></param></span>
        private void jPEGFileToolStripMenuItem_Click(object sender, EventArgs e)
        {
            string newName =
            System.IO.Path.GetFileNameWithoutExtension(CurrentFile);
            newName = newName + ".jpg";

            // Get an ImageCodecInfo object that represents the JPEG codec.
            myImageCodecInfo = GetEncoderInfo("image/jpeg");

            // for the Quality parameter category.
            myEncoder = System.Drawing.Imaging.Encoder.Quality;

            // EncoderParameter object in the array.
            myEncoderParameters = new EncoderParameters(1);

            try
            {
                // Save the bitmap as a JPEG file with quality level 75.
                myEncoderParameter = new EncoderParameter(myEncoder, 75L);
                myEncoderParameters.Param[0] = myEncoderParameter;
                img.Save(newName, myImageCodecInfo, myEncoderParameters);
                CurrentFile = newName;
                picContainer.Image = Image.FromFile(CurrentFile);
                this.Text = "Watermark Utility: " + CurrentFile.ToString();
            }
            catch
            {
                MessageBox.Show("Failed to save image to JPEG format.",
                "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            MessageBox.Show("Image file saved to " + newName.ToString(),
            "Image Saved", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        /// <span class="code-SummaryComment"><summary></span>
        /// Convert the current image file to PNG format
        /// <span class="code-SummaryComment"></summary></span>
        /// <span class="code-SummaryComment"><param name="sender"></param></span>
        /// <span class="code-SummaryComment"><param name="e"></param></span>
        private void pNGFileToolStripMenuItem_Click(object sender, EventArgs e)
        {
            string newName =
            System.IO.Path.GetFileNameWithoutExtension(CurrentFile);
            newName = newName + ".png";

            try
            {
                img.Save(newName, ImageFormat.Png);
                CurrentFile = newName;
                picContainer.Image = Image.FromFile(CurrentFile);
                this.Text = "Watermark Utility: " + CurrentFile.ToString();
            }
            catch
            {
                MessageBox.Show("Failed to save image to PNG format.",
                "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            MessageBox.Show("Image file saved to " + newName.ToString(),
            "Image Saved", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        /// <span class="code-SummaryComment"><summary></span>
        /// Convert the current image file to TIFF format
        /// <span class="code-SummaryComment"></summary></span>
        /// <span class="code-SummaryComment"><param name="sender"></param></span>
        /// <span class="code-SummaryComment"><param name="e"></param></span>
        private void tIFFFileToolStripMenuItem_Click(object sender, EventArgs e)
        {
            string newName =
            System.IO.Path.GetFileNameWithoutExtension(CurrentFile);
            newName = newName + ".tif";

            try
            {
                img.Save(newName, ImageFormat.Tiff);
                CurrentFile = newName;
                picContainer.Image = Image.FromFile(CurrentFile);
                this.Text = "Watermark Utility: " + CurrentFile.ToString();
            }
            catch
            {
                MessageBox.Show("Failed to save image to TIFF format.",
                "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            MessageBox.Show("Image file saved to " + newName.ToString(),
            "Image Saved", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        /// <span class="code-SummaryComment"><summary></span>
        /// Convert the current image to WMF format
        /// <span class="code-SummaryComment"></summary></span>
        /// <span class="code-SummaryComment"><param name="sender"></param></span>
        /// <span class="code-SummaryComment"><param name="e"></param></span>
        private void windowsMetafileToolStripMenuItem_Click(object sender, EventArgs e)
        {
            string newName =
            System.IO.Path.GetFileNameWithoutExtension(CurrentFile);
            newName = newName + ".wmf";

            try
            {
                img.Save(newName, ImageFormat.Wmf);
                CurrentFile = newName;
                picContainer.Image = Image.FromFile(CurrentFile);
                this.Text = "Watermark Utility: " + CurrentFile.ToString();
            }
            catch
            {
                MessageBox.Show("Failed to save image to WMF format.",
                "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            MessageBox.Show("Image file saved to " + newName.ToString(),
            "Image Saved", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

#endregion 

Following the image conversion routines, the next region of code is used to perform the actual watermarking functions.

#region Watermarking

        /// <span class="code-SummaryComment"><summary></span>
        /// Display the watermark as it would appear after the
        /// watermark were saved to the file
        /// <span class="code-SummaryComment"></summary></span>
        /// <span class="code-SummaryComment"><param name="sender"></param></span>
        /// <span class="code-SummaryComment"><param name="e"></param></span>
        private void btnPreview_Click(object sender, EventArgs e)
        {
            // Update the application by reloading the image
            picContainer.Image = Image.FromFile(CurrentFile);

            int opac = 0;
            string sOpacity = cboOpacity.Text;

            // Determine the opacity of the watermark
            switch (sOpacity)
            {
                case "100%":
                    opac = 255; // 1 * 255
                    break;
                case "75%":
                    opac = 191; // .75 * 255
                    break;
                case "50%":
                    opac = 127; // .5 * 255
                    break;
                case "25%":
                    opac = 64;  // .25 * 255
                    break;
                case "10%":
                    opac = 25;  // .10 * 255
                    break;
                default:
                    opac = 127; // default at 50%; .5 * 255
                    break;
            }

            // Get a graphics context
            Graphics g = Graphics.FromImage(picContainer.Image);

            // Create a solid brush to write the watermark text on the image
            Brush myBrush = new SolidBrush(Color.FromArgb(opac,
            myWatermarkColor));

            // Calculate the size of the text
            SizeF sz = g.MeasureString(txtWaterMark.Text, myFont);

            // Create a copy of variables to keep track of the
            // drawing position (X,Y)
            int X;
            int Y;

            // Set the drawing position based on the users
            // selection of placing the text at the bottom or
            // top of the image
            if (optTop.Checked == true)
            {
                X = (int)(picContainer.Image.Width - sz.Width) / 2;
                Y = (int)(picContainer.Top + sz.Height) / 2;
            }
            else
            {
                X = (int)(picContainer.Image.Width - sz.Width) / 2;
                Y = (int)(picContainer.Image.Height - sz.Height);
            }

            // draw the water mark text
            g.DrawString(txtWaterMark.Text, myFont, myBrush,
            new Point(X, Y));
        }

        /// <span class="code-SummaryComment"><summary></span>
        /// Set the font and color of the font for the watermark
        /// <span class="code-SummaryComment"></summary></span>
        /// <span class="code-SummaryComment"><param name="sender"></param></span>
        /// <span class="code-SummaryComment"><param name="e"></param></span>
        private void btnFont_Click(object sender, EventArgs e)
        {
            // default the current font and color to that
            // used in the watermark textbox
            fontDialog1.ShowColor = true;
            fontDialog1.Font = txtWaterMark.Font;
            fontDialog1.Color = txtWaterMark.ForeColor;

            if (fontDialog1.ShowDialog() != DialogResult.Cancel)
            {
                myFont = fontDialog1.Font;
                myWatermarkColor = fontDialog1.Color;
                txtWaterMark.Font = fontDialog1.Font;
                txtWaterMark.ForeColor = fontDialog1.Color;
            }
        }

#endregion

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 WinFoms 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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

salysle
Software Developer (Senior)
United States United States
No Biography provided

Comments and Discussions

 
GeneralOne word : Awesome - Very easy to use modify PinmemberPokemonCraft24-Sep-11 3:37 
GeneralPost Pinmemberchris2001jm2-Aug-11 6:33 
GeneralHelp required PinmemberAryan.atul5-Oct-10 8:40 
Generalfor large file not useable Pinmemberbencanim12-Aug-10 2:45 
AnswerRe: for large file not useable PinmemberPokemonCraft24-Sep-11 3:39 
GeneralThere is error PinmemberErvin Ter15-Sep-09 17:48 
QuestionGreat Work! How to watermark digonally? something like attachment? PinmemberDesignerInCore9-Sep-09 16:46 
GeneralMultiPage Tiff file Pinmembergistshu012013-Jul-09 17:51 
GeneralThank you... PinmemberRoy Williams30-Apr-09 18:20 
GeneralHi PinmemberD.Jothi26-Jan-09 0:01 
GeneralWorks great! Thanks! PinmemberBit-Smacker2-Oct-08 7:48 
GeneralUseful utility Pinmemberjhaga19-Jan-08 7:39 
GeneralRe: Useful utility Pinmembersalysle19-Jan-08 8:47 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.141030.1 | Last Updated 19 Jan 2008
Article Copyright 2008 by salysle
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid