给图片添加水印,一般的做法是在上传图片时直接给图片添加上水印,由于我在项目中使用了FCKeditor,在上传时不易控制,同时对方还要求他们自己用时不能有水印,于是我就使用了在图片显示时动态添加水印的办法,另外,为了提高效率,还使用了缓存技术,这样不必每次都添加水印,节省时间和提高性能。
本文中使用到的类是IHttpHandler(准确地说是一个接口),msdn对它的定义是:“定义 ASP.NET 为使用自定义 HTTP 处理程序同步处理 HTTP Web 请求而实现的协定。”HTTP处理程序是实现了System.Web.IHttpHandler接口的.NET组件,任何实现了IHttpHandler接口的类都可以用于处理输入的HTTP请求。也就是每次我们请求asp.net网站上的资源,都会由这个请求处理,这样就好控制了。
我的做法是,实现IHttpHandler接口,由实现这个接口的ImageHandler类专门处理对图片资源的请求,第一次请求某个图片时,由于缓存中没有,就读取这个图片,添加上我们指定的水印(由web.config设置指定),然后把输出到客户端,同时也把它缓存一定时间,在缓存期内就再次请求这个图片就不用添加水印了,直接把缓存中的图片输出就行了。
首先我们要编写自己的类ImageHandler实现IHttpHandler接口,代码如下:
using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using System.Drawing;
using System.Drawing.Imaging;
/// <summary>
///ImageHandler 的摘要说明
/// </summary>
public class ImageHandler:IHttpHandler
{
public ImageHandler()
{
//
//TODO: 在此处添加构造函数逻辑
//
}
#region IHttpHandler 成员
public bool IsReusable
{
get { return true ; }
}
public void ProcessRequest(HttpContext context)
{
string p_w_picpathpath = context.Request.PhysicalPath;
Bitmap p_w_picpath = null;
if (context.Cache[p_w_picpathpath] == null)
{
p_w_picpath = new Bitmap(p_w_picpathpath);
p_w_picpath = AddWaterMark(p_w_picpath);
context.Cache[p_w_picpathpath] = p_w_picpath;
}
else
{
p_w_picpath = context.Cache[p_w_picpathpath] as Bitmap;
}
p_w_picpath.Save(context.Response.OutputStream, ImageFormat.Jpeg);
}
//给图片添加水印
private Bitmap AddWaterMark(Bitmap p_w_picpath)
{
string text = System.Configuration.ConfigurationManager.AppSettings["WaterMark"].ToString();
int fontSize = int.Parse(System.Configuration.ConfigurationManager.AppSettings["Font-Size"].ToString());
Font font = new Font("宋体", fontSize);
//Brush brush = Brushes.DarkGray;
Brush brush = Brushes.Red;
Graphics g = Graphics.FromImage(p_w_picpath);
SizeF size = g.MeasureString(text, font);
g.DrawString(text, font, brush, p_w_picpath.Width - size.Width, p_w_picpath.Height - size.Height);
g.Dispose();
return p_w_picpath;
}
#endregion
}
可以把这个类编译成一个单独的dll文件,不过我现在是演示,直接放在了App_Code文件夹下了。
html页面如下:
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>无标题页</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<img src="Images/1.jpg" /><br />
<img src="Images/2.jpg" /><br />
<img src="3.jpg" /><br />
</div>
</form>
</body>
</html>
最后我们还需要对web.config做一些配置,一是定义我们要添加的水印文字,二是定义文字大小,三是将我们自己的HttpHandler注册到网站,我的web.config文件如下:
<!--
注意: 除了手动编辑此文件以外,您还可以使用
Web 管理工具来配置应用程序的设置。可以使用 Visual Studio 中的
“网站”->“Asp.Net 配置”选项。
设置和注释的完整列表在
machine.config.comments 中,该文件通常位于
WindowsMicrosoft.NetFrameworkv2.xConfig 中
-->
<configuration>
<appSettings>
<!--添加到图片上的水印文字-->
<add key="WaterMark" value="公司网址"/>
<!--水印文字的字体大小-->
<add key="Font-Size" value="14"/>
</appSettings>
<connectionStrings/>
<system.web>
<compilation debug="true"/>
<!--
通过 <authentication> 节可以配置 ASP.NET 使用的
安全身份验证模式,
以标识传入的用户。
-->
<authentication mode="Windows"/>
<httpHandlers>
<!--只处理UploadImages目录下的jpg文件,别的目录下的图片不处理-->
<add path="Images/*.jpg" verb="*" type="ImageHandler"/>
</httpHandlers>
</system.web>
</configuration>
它表明只处理网站根目录下的Images文件夹中的图片,在本实例中Upload文件夹也有图片,可是这个文件夹下的图片是网站logo等常规图片,不需要处理,所以这个元素的path属性值是:path="Images/*.jpg",如果你想给所有jpg图片添加水印,可以写成path="*.jpg",在接下来的页面中我们就会看到结果如我们所愿,在Upload目录下的图片真的没有添加水印,而在Images确实添加了水印!
最后说明:(一)在这儿我将水印文字字体设置为14,同时还是用了醒目的红色,在实际项目中需要根据图片大小计算文字大小,文字颜色不宜过于鲜明;(二)为了演示,缓存使用过于简单,还可以进行一些更负责的设置,更大程度节省内存。(三)添加水印图片原理也很简单,使用GDI+将水印图片画在要添加水印的图片上即可;(四)即使单独在地址栏输入图片的url地址,看到的图片也一样会有水印。