CodeProject - 使用GDI+ for .NET创建一个含有水印效果的照片

原创 2006年05月24日 22:16:00

Creating a Watermarked Photograph with GDI+ for .NET
Joel Neubeck

This article describes the process of overlaying a Watermark image on top of a photograph using GDI+ and C# for .NET 






Often when placing photographic images on a website it is necessary to permanently overlay a watermark and/or Copyright statement on top of that image. Such an insertion helps to identify the person that took the photograph and indicate the organization that holds the Copyright. Doing this task by hand can become time consuming and is often inconsistent. Using some simple techniques there is an easy way to accomplish this programmatically using C# and GDI+.



I am going to show you a variety of techniques for manipulating an image. The following is a high level list of some of those techniques:

我将为你展示操作图片的各种各样的技术。以下是这些技术的high level list
  • Inserting text on top of an image positioned relative to the size on an image
  • Dynamically choosing a System.Drawing.Font size to maximize readability
  • Manipulating the opacity of a String of text
  • Replacing a specific color in a bitmap to achieve transparency
  • Changing the opacity of an image through a 5x5 ColorMatrix 
  • 根据图片大小在图片顶部插入文本
  • 动态选择一个System.Drawing.Font大小以达到最大的可读性
  • 操作字符串文本的不透明性
  • 在位图上替换一种特定的颜色以达到透明效果
  • 在一个5x5彩色矩阵上改变图片的透明度
Define Images

(Photo courtesy of AP wire)
(The first step in this process is to load a photographic image for which you would like to apply the watermark. This image can be virtually any size and resolution. For this example we will use an image that has a width of 449 pixels and a height of 346. The resolution is 72 dpi.


When the Main method is instantiated, the two variable of type string are defined. The first will define where to find the photograph, watermark and output the new image. The second will define the Copyright string we will use as part of our watermark.



string WorkingDirectory = @"C:/Projects/WaterMark";
string Copyright = "Copyright © 2002 
                 - AP Photo/David Zalubowski";


The following creates an Image object from the specified file and then defines a variable for both its Width and Height. These dimensions are then used to build a Bitmap object with a 24 bits per pixel format for the color data.  Lastly this Bitmap is then used to create a new Graphics object from the specified Bitmap image.

以下(代码)从一个指定文件创建了一个Image 对象,然后为它的Width Height定义变量。这些长度待会被用来建立一个以24 bits 每像素的格式作为颜色数据的Bitmap对象。


Image imgPhoto = Image.FromFile(WorkingDirectory 
+ "//watermark_photo.jpg");
int phWidth = imgPhoto.Width; int phHeight =

Bitmap bmPhoto 
= new Bitmap(phWidth, phHeight, 

Graphics grPhoto 
= Graphics.FromImage(bmPhoto);

(Image courtesy of

这个代码载入水印图片,水印图片已经被保存为一个BMP文件,以绿色(A=0,R=0,G=255,B=0)作为背景颜色。再一次,会为它的Width Height定义一个变量。



Image imgWatermark = new Bitmap(WorkingDirectory
+ "//watermark.bmp");
int wmWidth = imgWatermark.Width;
int wmHeight = imgWatermark.Height;

Step #1 - Watermark Text

This code draws the
imgPhoto to the Graphics object positioning it (x= 0,y=0) at 100% of its original size. All future drawing will occur on top of the original photograph.


grPhoto.SmoothingMode = SmoothingMode.AntiAlias;
new Rectangle(00, phWidth, phHeight), 


To maximize the size of the Copyright message we will test 7 different Font sizes to determine the largest possible size we can use for the width of our Photograph.  To effectively do this, we will define an array of integers then iterate through those values measuring the Copyright string in the various point sizes.  Once we have determined the largest possible size we will exit the loop and draw the text.



int[] sizes = new int[]{16,14,12,10,8,6,4};
Font crFont 
= null
SizeF crSize 
= new    SizeF(); 
for (int i=0 ;i<7; i++)

= new Font("arial", sizes[i],
= grPhoto.MeasureString(Copyright,

if((ushort)crSize.Width < (ushort)phWidth)


Since all photographs will have varying heights, determine a position 5% from the bottom of the image.  Use the Copyright strings height to determine an appropriate y-coordinate for which to draw the string.  Determine its x-coordinate by calculating the centre of the image then define a StringFormat object and set the StringAlignment to Center. 



int yPixlesFromBottom = (int)(phHeight *.05);
float yPosFromBottom = ((phHeight - 
float xCenterOfImg = (phWidth/2);

StringFormat StrFormat 
= new StringFormat();
= StringAlignment.Center;


Now that we have all of the necessary positioning coordinates create a SolidBrush with a Color of 60% Black (alpha value of 153).  Draw the Copyright string at the appropriate position offset 1 pixel to the right and 1 pixel down. This offset will create a shadow effect.  Repeat this process using a White Brush drawing the same text directly on top of the previously drawn string.



SolidBrush semiTransBrush2 = 
new SolidBrush(Color.FromArgb(15300,0)); 

new PointF(xCenterOfImg+1,yPosFromBottom+1), 

SolidBrush semiTransBrush 
= new SolidBrush(

new PointF(xCenterOfImg,yPosFromBottom),  


Step #2 - Watermark Image

Create a Bitmap based on the previously modified photograph. Load this Bitmap into a new Graphic Object



Bitmap bmWatermark = new Bitmap(bmPhoto); 

Graphics grWatermark 


To achieve a translucent watermark we will apply two color manipulations by defining an ImageAttributes object and setting two of its properties. The first step in manipulating the watermark image is to replace the background color with one that is transparent (Alpha=0, R=0, G=0, B=0). To do this we will use a Colormap and define a RemapTable. As previously shown my watermark was defined with a background of 100% Green this will be the color we search for and replace with transparency.

通过定义一个ImageAttributes对象并设置它的两个属性,我们就是实现了两个颜色的处理,以达到半透明的水印效果。处理水印图象的第一步是把背景图案变为透明的(Alpha=0, R=0, G=0, B=0)。我们使用一个Colormap和定义一个RemapTable来做这个。就像前面展示的,我的水印被定义为100%绿色背景,我们将搜到这个颜色,然后取代为透明。


ImageAttributes imageAttributes =
new ImageAttributes();
ColorMap colorMap 
= new ColorMap();

ColorMap[] remapTable 
= {colorMap};


The second color manipulation is used to change the opacity of the watermark. This is done by applying a 5x5 matrix that contains the coordinates for the RGBA space. By setting the 3rd row and 3rd column to 0.3f we achieve a level of opacity.  The result is a watermark which slightly shows the underlying image.



float[][] colorMatrixElements = 
new float[] {1.0f,  0.0f,  0.0f,  0.0f0.0f},
new float[] {0.0f,  1.0f,  0.0f,  0.0f0.0f},
new float[] {0.0f,  0.0f,  1.0f,  0.0f0.0f},
new float[] {0.0f,  0.0f,  0.0f,  0.3f0.0f},
new float[] {0.0f,  0.0f,  0.0f,  0.0f1.0f}

ColorMatrix wmColorMatrix 
= new



With both color manipulations added to the
imageAttributes object we can now draw the watermark in the upper right hand corner of the photograph. We will offset the image 10 pixels down and 10 pixels to the left.



int xPosOfWm = ((phWidth - wmWidth)-10);
int yPosOfWm = 10;

new Rectangle(xPosOfWm,yPosOfWm,wmWidth,


Or last and final step will be to replace the original Image with the new Bitmap, dispose of both Graphic objects then save this Image to the file system.



imgPhoto = bmWatermark;

imgPhoto.Save(WorkingDirectory + "


That's it! Compile the project, run it, and see what happens! The code is fairly straightforward if it all makes sense then these techniques can be used for 100's of different image manipulations. The possibilities are endless.


Revision History

26 Sep 2002 - Initial Revision


About Joel Neubeck

Joel is a Software Engineer with a Fortune 500 media company. He started programming in 1996 as a consultant and has spent most of his time involved in Web Application Development (IIS, ASP, VB). His latest projects have focused on C# and .NET where he has written various API and Console based applications for use in the media industry.

In his free time, he enjoys Mountain Biking through out Arizona and spending time with his wife and two dogs.

JoelFortune 500媒体公司的软件工程师。他在1996年作为一个顾问开始编程,大多数时间花在了Web Application Development (IIS, ASP, VB).他最新的项目集中在C#.NET,他已经使用C#.NET为多媒体工业写了各种各样的 API和控制台程序。

使用GDI+ for .NET创建一个含有水印效果的照片

IntroductionOften when placing photographic images on a website it is necessary to permanently overl...
  • jhtyt
  • jhtyt
  • 2006年04月22日 01:07
  • 1204

使用GDI+ for .NET创建一个含有水印效果的照片 a Watermarked Photograph with...
  • cutebab0888
  • cutebab0888
  • 2006年09月29日 16:42
  • 1335给图片加上水印效果的类

using System;using System.Collections.Generic;using System.Text;using System.IO;using System.Drawing...
  • web718
  • web718
  • 2007年11月12日 12:01
  • 643


转载请著名出处:王亟亟的大牛之路这两天不知道给Soyi加些什么东西,那就慢慢的往CodeActivity里加东西吧,所以就写了这么个简单的自定义控件LabelImageView。HOW to do?0...
  • ddwhan0123
  • ddwhan0123
  • 2015年12月17日 15:07
  • 2985

ASP.NET Ueditor上传图片添加水印

  • somethingwhat
  • somethingwhat
  • 2015年04月04日 01:41
  • 2180


(2010-08-02 09:46:05) 转载▼ 标签:  杂谈 分类: GDI+ bool GetCodecClsid(LPCTS...
  • pi9nc
  • pi9nc
  • 2014年09月11日 19:25
  • 2002


  • shimachao
  • shimachao
  • 2014年04月06日 16:00
  • 1041

Android Imageview中获取缓存图片添加水印

第一个是 Imageview  从下面的Imageview 获取的缓存图片 再添加文字信息 package com.example.imageview; import
  • u013598111
  • u013598111
  • 2016年01月02日 15:57
  • 984

[GDI+] 创建Images的两种方式

使用Bitmap构造完成一个新的image对象,大小为xsize,ysize[C#]Bitmap myImage = new Bitmap(xsize>,ysize>);[VB]Dim MyImage...
  • hbzxf
  • hbzxf
  • 2004年10月25日 16:54
  • 2835


GDI+中的各种描画方法虽然很好用,但如果想获得一个Graphics中已经画好的内容却不那么容易了。做了一些尝试后,我用以下方法解决了这个问题。 首先,获得源Graphics的HDC,这个通过G...
  • eplanet
  • eplanet
  • 2007年11月28日 12:24
  • 6021
您举报文章:CodeProject - 使用GDI+ for .NET创建一个含有水印效果的照片