Image watermarking is a technique for applying text or an image over another image in such a way that the overlay transforms the base image. It is often used for branding or copyright purposes, because removing the watermark is a difficult task, requiring a good deal of graphics editing by hand. Unfortunately, the Microsoft .NET Framework doesn't contain any built-in functionality for performing image watermarking dynamically. To compensate for this shortcoming, we'll construct a class that creates a watermark on a source image using either another image or text. Figure A and Figure B show two examples of watermarked images, one using text and one using an image.
You will note that watermarking isn't very effective in dark sections of the image. With dark images, a text halo is probably better. For information and source code for creating halos, see "Make your text stand out by adding a halo with this VB.NET code."
Our watermark class will have a number of properties that determine where the watermark will be located on the source image, what type of watermark it is (text or image), and the exact watermark information. To begin with, we'll need a utility class with enumerations for the watermark type and location (Listing A).
Once we have this class, we can construct the watermark class. For text watermarks, we need to know what text to use and what font to create the watermark with. For image watermarks, we require a filename to the watermark image. For both kinds of watermarks, we require the original image file's filename and the location for the watermark. The main function to create the watermarked image requires no arguments, since all of the information it needs should have been set in properties. It returns an instance of the System.Drawing.Bitmap type.
The nature of this function makes it ideal for use in multithreaded situations. Depending upon the source image and watermark, watermarking can take a fair amount of CPU time. So it's sometimes better to perform it in the background and allow the main program to continue execution in the foreground. This is especially important if the watermarking process is part of a Web site. For example, if the site allows users to upload photos that should be watermarked, it's preferable to continue processing the rest of the page and check to make sure that the watermark was created than to hold up the whole page display waiting for the watermark to be created.
The watermark process is fairly simple. First, we create an overlay image the same size as the original, with the watermark in the desired location. The watermark is either loaded from an image or dynamically created with the desired font and text. Then, we look over the overlay image, searching for any pixels with color, indicated by the alpha channel value of that pixel. When we find a pixel with color, we use its brightness value to create a multiplier. The multiplier system, while a bit slower, allows the watermark to alter the base image differently based upon the shade of color used in an image watermark. It also allows us to have the potential of providing "watermark intensity" adjustments in the future, either by editing the source code or by providing a mechanism to pass the multiplier amount to the function.
Once we calculate the multiplier, we set the color of the original image at the same pixel location to its original color, but with the red, green, and blue channels multiplied by the multiplier. Because our multiplier is between 0 and 1, it will reduce the color saturation of the pixel, providing the watermark effect. Listing B contains the main processing code for the watermark process.
The line of code here of special notice is the one we use to create the pixel multiplier:
PixelMultiplier = 1 - CSng(((1 - WatermarkPixel.GetBrightness)) * 0.25)
Changing the final number (0.25) in this line adjusts the intensity of the watermark effect. At 0.25, it limits the range of saturation reduction to 0% to 25%. In other words, if the watermark image has pale shades of color, they won't watermark the original image much, if at all, and even the darkest colors will only perform a 25% reduction in color intensity on the original pixel colors. This number should never be below 0.0 (which will never watermark) or above 1.0 (which will make the watermark be white anywhere the watermark should appear). In my tests, I found that keeping this number from 0.2 to 0.3 yields the most pleasing results. Of course, it's possible to make this number a constant in the source code or edit the code to allow this number to be set at run time.
Try out the watermarking app
Programmatic watermarking can be useful for a dynamic Web site or for batch editing of images to meet your marketing needs. With this watermarking class, it's easy to incorporate these techniques into your application. The accompanying download installs a full application that produces watermarked images. The application's installer also copies the full source code for the application and the full class file for the image watermark. Feel free to try the code out yourself, incorporate it into your own project, and modify it to suit your needs.
Justin James is the Lead Architect for Conigent.