ASP.NET为图片添加水印功能示例详解


    这两天主要在学习如何给图片添加水印,查找了一下相关的解决方案,其中有一个别人写好的水印dll,虽然能实现很多的功能,但很遗憾不能用于其他商业用途,没办法只能再找找别的办法,后面找到的这种方法比较简单,就是通过Graphics重新绘制bitmap的方法来绘制水印,当然,文字水印可能稍微要麻烦一点儿,需要设置字体相关的东东,比如字号、阴影、颜色啥的,但整体来看,思路基本是一样的。

 

    至于具体的步骤说明,请查看源码上的注释即可,应该能够保证大家不至于太迷糊:

 

    第一部分:水印相关参数结构体和枚举

 

    View Code

 
  1         /// <summary>
  2         /// 水印位置枚举
  3         /// </summary>
  4         public enum ImagePosition
  5         {
  6             LeftTop, //左上 
  7             LeftBottom, //左下 
  8             RightTop, //右上 
  9             RigthBottom, //右下 
 10             TopMiddle, //顶部居中 
 11             BottomMiddle, //底部居中 
 12             Center //中心 
 13         }
 14 
 15         /// <summary>
 16         /// 图片水印参数结构体
 17         /// </summary>
 18         public struct ImageWatermarkParameters
 19         {
 20             /// <summary>
 21             /// 源图片路径
 22             /// </summary>
 23             public string SourceImagePath;
 24             /// <summary>
 25             /// 水印图片路径
 26             /// </summary>
 27             public string WatermarkImagePath;
 28             /// <summary>
 29             /// 源图片数据流(即如果设置数据流,则忽略SourceImagePath属性值)
 30             /// </summary>
 31             public MemoryStream SourceImageStream;
 32             /// <summary>
 33             /// 水印图片数据流(即如果设置数据流,则忽略WatermarkImagePath属性值)
 34             /// </summary>
 35             public MemoryStream WatermarkImageStream;
 36             /// <summary>
 37             /// 透明度,数值介于0.1 - 1.0之间,不包括0.0
 38             /// </summary>
 39             public float Alpha;
 40             /// <summary>
 41             /// 水印位置
 42             /// </summary>
 43             public ImagePosition WmPosition;
 44             private string _sourceImageFileExtensionName;
 45             /// <summary>
 46             /// 源图片文件扩展名
 47             /// </summary>
 48             public string SourceImageFileExtensionName
 49             {
 50                 set { _sourceImageFileExtensionName = value; }
 51                 get
 52                 {
 53                     if (string.IsNullOrEmpty(this.SourceImagePath))
 54                     {
 55                         // 如果设置的图片扩展名为ContentType类型,则进行转化
 56                         if (_sourceImageFileExtensionName.IndexOf("/") > 0)
 57                             _sourceImageFileExtensionName = TransferContentTypeToUnifyExName(_sourceImageFileExtensionName);
 58 
 59                         return _sourceImageFileExtensionName;
 60                     }
 61                     else
 62                         return Path.GetExtension(SourceImagePath).ToLower();
 63                 }
 64             }
 65 
 66 
 67             public ImageWatermarkParameters(string sourceImagePath, string watermarkImagePath, float alpha, ImagePosition wmPosition)
 68             {
 69                 this.SourceImageStream = null;
 70                 this.WatermarkImageStream = null;
 71                 this._sourceImageFileExtensionName = string.Empty;
 72 
 73                 this.SourceImagePath = sourceImagePath;
 74                 this.WatermarkImagePath = watermarkImagePath;
 75                 this.Alpha = alpha;
 76                 this.WmPosition = wmPosition;
 77             }
 78 
 79             public ImageWatermarkParameters(MemoryStream sourceImageStream, MemoryStream watermarkImageStream, 
 80                 string sourceImageFileExtensionName, float alpha, ImagePosition wmPosition)
 81             {
 82                 this.SourceImagePath = string.Empty;
 83                 this.WatermarkImagePath = string.Empty; ;
 84 
 85                 this.SourceImageStream = sourceImageStream;
 86                 this.WatermarkImageStream = watermarkImageStream;
 87                 this.Alpha = alpha;
 88                 this.WmPosition = wmPosition;
 89                 this._sourceImageFileExtensionName = sourceImageFileExtensionName;
 90             }
 91 
 92             /// <summary>
 93             /// 参数检查并设定默认值
 94             /// </summary>
 95             /// <param name="errorMsg"></param>
 96             /// <returns></returns>
 97             public bool CheckAndSetDefault(out string errorMsg)
 98             {
 99                 errorMsg = string.Empty;
100 
101                 // 前置检查
102                 if ((string.IsNullOrEmpty(this.SourceImagePath) && SourceImageStream == null)
103                     || (string.IsNullOrEmpty(this.WatermarkImagePath) && WatermarkImageStream == null)
104                     || (SourceImageStream != null && string.IsNullOrEmpty(_sourceImageFileExtensionName))
105                     || this.Alpha <= 0.0 || this.Alpha > 1.0
106                     || this.WmPosition == null)
107                 {
108                     errorMsg = "文字水印参数实体中含有非法的参数项。";
109                     return false;
110                 }
111 
112                 // 检查图片路径是否合法
113                 if ((SourceImageStream == null && !string.IsNullOrEmpty(this.SourceImagePath) && !File.Exists(this.SourceImagePath)) // 仅赋值源图片路径,且路径不存在的情况
114                     || (WatermarkImageStream == null && !string.IsNullOrEmpty(this.WatermarkImagePath) && !File.Exists(this.WatermarkImagePath))) // 仅赋值水印图片路径,但文件不存在的情况
115                 {
116                     errorMsg = "输入的源图片或水印图片路径不存在。";
117                     return false;
118                 }
119 
120 
121                 // 检查图片扩展名
122                 bool validExName = true;
123                 if (!string.IsNullOrEmpty(this.SourceImagePath) && !string.IsNullOrEmpty(this.WatermarkImagePath))
124                 {
125                     if (!CheckImageExtensionType(this.SourceImagePath) || !CheckImageExtensionType(this.WatermarkImagePath))
126                         validExName = false;
127                 }
128                 else if (this.SourceImageStream != null && this.WatermarkImageStream != null)
129                 {
130                     if ((_sourceImageFileExtensionName != ".gif" && _sourceImageFileExtensionName != ".jpg" && _sourceImageFileExtensionName != ".png"))
131                         validExName = false;
132                 }
133                 else
134                     validExName = false;
135 
136                 if (!validExName)
137                 {
138                     errorMsg = "暂不支持源图片或水印图片的格式类型。";
139                     return false;
140                 }
141 
142                 return true;
143             }
144         }
145 
146         /// <summary>
147         /// 文字水印参数结构体
148         /// </summary>
149         public struct TextWatermarkParameters
150         {
151             /// <summary>
152             /// 源图片路径
153             /// </summary>
154             public string SourceImagePath;
155             /// <summary>
156             /// 水印文字
157             /// </summary>
158             public string WatermarkText;
159             /// <summary>
160             /// 源图片数据流
161             /// </summary>
162             public MemoryStream SourceImageStream;
163             /// <summary>
164             /// 透明度,数值介于0.1 - 1.0之间,不包括0.0
165             /// </summary>
166             public float Alpha;
167             /// <summary>
168             /// 水印位置
169             /// </summary>
170             public ImagePosition WmPosition;
171             /// <summary>
172             /// 水印文字字体样式
173             /// </summary>
174             public Font WmTextFont;
175             /// <summary>
176             /// 水印文字阴影宽度
177             /// </summary>
178             public int TextShadowWidth;
179             private string _sourceImageFileExtensionName;
180             /// <summary>
181             /// 源图片文件扩展名
182             /// </summary>
183             public string SourceImageFileExtensionName
184             {
185                 set { _sourceImageFileExtensionName = value; }
186                 get
187                 {
188                     if (string.IsNullOrEmpty(this.SourceImagePath))
189                     {
190                         // 如果设置的图片扩展名为ContentType类型,则进行转化
191                         if (_sourceImageFileExtensionName.IndexOf("/") > 0)
192                             _sourceImageFileExtensionName = TransferContentTypeToUnifyExName(_sourceImageFileExtensionName);
193 
194                         return _sourceImageFileExtensionName;
195                     }
196                     else
197                         return Path.GetExtension(SourceImagePath).ToLower();
198                 }
199             }
200 
201 
202             public TextWatermarkParameters(MemoryStream sourceImageStream, string sourceImageFileExtensionName, string watermarkText, float alpha, 
203                 ImagePosition wmPosition, Font wmTextFont, int textShadowWidth = 5)
204             {
205                 this.SourceImagePath = string.Empty ;
206 
207                 this.SourceImageStream = sourceImageStream;
208                 this.WatermarkText = watermarkText;
209                 this.Alpha = alpha;
210                 this.WmPosition = wmPosition;
211                 this.WmTextFont = wmTextFont;
212                 this.TextShadowWidth = textShadowWidth;
213                 this._sourceImageFileExtensionName = sourceImageFileExtensionName;
214             }
215 
216             public TextWatermarkParameters(string sourceImagePath, string watermarkText, float alpha,
217                 ImagePosition wmPosition, Font wmTextFont, int textShadowWidth = 5)
218             {
219                 this.SourceImageStream = null;
220                 this._sourceImageFileExtensionName = string.Empty;
221 
222                 this.SourceImagePath = sourceImagePath;
223                 this.WatermarkText = watermarkText;
224                 this.Alpha = alpha;
225                 this.WmPosition = wmPosition;
226                 this.WmTextFont = wmTextFont;
227                 this.TextShadowWidth = textShadowWidth;
228             }
229 
230             /// <summary>
231             /// 参数检查并设定默认值
232             /// </summary>
233             /// <param name="errorMsg"></param>
234             /// <returns></returns>
235             public bool CheckAndSetDefault(out string errorMsg)
236             {
237                 errorMsg = string.Empty;
238 
239                 // 前置检查
240                 if ((string.IsNullOrEmpty(this.SourceImagePath) && this.SourceImageStream == null) || (!string.IsNullOrEmpty(this.SourceImagePath) && !File.Exists(this.SourceImagePath)) 
241                     || string.IsNullOrEmpty(this.WatermarkText)
242                     || (SourceImageStream != null && string.IsNullOrEmpty(_sourceImageFileExtensionName))
243                     || this.Alpha <= 0.0 || this.Alpha > 1.0
244                     || this.WmPosition == null
245                     || this.WmTextFont == null)
246                 {
247                     errorMsg = "文字水印参数实体中含有非法的参数项。";
248                     return false;
249                 }
250 
251                 // 检查图片路径是否合法
252                 if ((SourceImageStream == null && !string.IsNullOrEmpty(this.SourceImagePath) && !File.Exists(this.SourceImagePath))) // 仅赋值源图片路径,且路径不存在的情况
253                 {
254                     errorMsg = "输入的源图片路径不存在。";
255                     return false;
256                 }
257 
258                 // 检查图片扩展名
259                 bool validExName = true;
260                 if (!string.IsNullOrEmpty(this.SourceImagePath))
261                 {
262                     if (!CheckImageExtensionType(this.SourceImagePath))
263                         validExName = false;
264                 }
265                 else if (this.SourceImageStream != null)
266                 {
267                     if ((_sourceImageFileExtensionName != ".gif" && _sourceImageFileExtensionName != ".jpg" && _sourceImageFileExtensionName != ".png"))
268                         validExName = false;
269                 }
270                 else
271                     validExName = false;
272 
273                 if (!validExName)
274                 {
275                     errorMsg = "暂不支持源图片的格式类型。";
276                     return false;
277                 }
278 
279                 return true;
280             }
281

 

    第二部分:水印功能处理类 -> 内部辅助函数部分

 

    View Code

 
        /// <summary>
        
/// 获取编码参数数组
        
/// </summary>
        
/// <returns></returns>
        private static EncoderParameters GetEncoderParameters()
        {
            EncoderParameters eps = new EncoderParameters(1);
            EncoderParameter ep = new EncoderParameter(Encoder.Quality, _imageSaveQualityValue);
            eps.Param[0] = ep;

            return eps;
        }

        /// <summary>
        
/// 根据图片格式获取编码信息
        
/// </summary>
        
/// <param name="mimeType">图片格式</param>
        
/// <returns>编码信息</returns>
        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;
        }

        /// <summary>
        
/// 获取最终图片保存的图像格式
        
/// </summary>
        
/// <param name="imageExtensionName">图片扩展名称</param>
        
/// <returns>图片格式</returns>
        private static ImageCodecInfo GetFinalImageCodecInfo(string imageExtensionName)
        {
            switch (imageExtensionName)
            { 
                case ".gif":
                    return GetEncoderInfo("image/gif");
                case ".png":
                    return GetEncoderInfo("image/png");
                case ".jpg":
                default:
                    return GetEncoderInfo("image/jpeg");
            }
        }

        /// <summary>
        
/// 获取文字画刷
        
/// </summary>
        
/// <param name="alpha">透明度</param>
        
/// <returns></returns>
        private static SolidBrush GetTextBrush(float alpha)
        {
            // 从四个 ARGB 分量(alpha、红色、绿色和蓝色)值创建 Color 结构,这里设置透明度为153 
            
// 这个画笔为描绘正式文字的笔刷,呈白色 
            SolidBrush semiTransBrush = new SolidBrush(Color.FromArgb(Convert.ToInt32(255 * alpha), Color.White));
            return semiTransBrush;
        }

        /// <summary>
        
/// 获取阴影画刷
        
/// </summary>
        
/// <returns></returns>
        private static SolidBrush GetShadowBrush()
        {
            // SolidBrush:定义单色画笔。画笔用于填充图形形状,如矩形、椭圆、扇形、多边形和封闭路径。 
            
// 这个画笔为描绘阴影的画笔,呈灰色
            return new SolidBrush(Color.FromArgb(153, Color.Blue));
        }

        /// <summary>
        
/// 获取文本布局信息
        
/// </summary>
        
/// <returns></returns>
        private static StringFormat GetStringFormat()
        {
            // 封装文本布局信息(如对齐、文字方向和 Tab 停靠位),显示操作(如省略号插入和国家标准 (National) 数字替换)和 OpenType 功能
            StringFormat StrFormat = new StringFormat();
            StrFormat.Alignment = StringAlignment.Center;

            return StrFormat;
        }

        /// <summary>
        
/// Get image attribute instance.
        
/// </summary>
        
/// <param name="alpha">transparency value</param>
        
/// <returns></returns>
        private static ImageAttributes GetImageAttributesInstance(float alpha)
        {
            // imageattributes instance which will control the related infomations for image.
            ImageAttributes imageAttributes = new ImageAttributes();

            // 图片映射:水印图被定义成拥有绿色背景色的图片被替换成透明 
            ColorMap colorMap = new ColorMap();
            colorMap.OldColor = Color.FromArgb(25502550);
            colorMap.NewColor = Color.FromArgb(0000);
            imageAttributes.SetRemapTable(new ColorMap[] { colorMap }, ColorAdjustType.Bitmap);

            float[][] colorMatrixElements = new float[][] 
            { 
                new float[] {1.0f0.0f0.0f0.0f0.0f}, // red红色 
                new float[] {0.0f1.0f0.0f0.0f0.0f}, // green绿色 
                new float[] {0.0f0.0f1.0f0.0f0.0f}, // blue蓝色 
                new float[] {0.0f0.0f0.0f, alpha, 0.0f}, // 透明度 
                new float[] {0.0f0.0f0.0f0.0f1.0f}
            };

            // ColorMatrix:定义包含 RGBA 空间坐标的 5 x 5 矩阵。 
            
// ImageAttributes:类的若干方法通过使用颜色矩阵调整图像颜色。 
            imageAttributes.SetColorMatrix(new ColorMatrix(colorMatrixElements), ColorMatrixFlag.Default, ColorAdjustType.Bitmap);

            return imageAttributes;
        }

        /// <summary>
        
/// Calculate the watermark image position.
        
/// </summary>
        
/// <param name="position">position</param>
        
/// <param name="srcWidth">source image width</param>
        
/// <param name="srcHeight">source image height</param>
        
/// <param name="wmWidth">watermark image width</param>
        
/// <param name="wmHeight">watermark image height</param>
        
/// <param name="xPosOfWm">final x position</param>
        
/// <param name="yPosOfWm">final y position</param>
        private static void GetWatermarkImagePosition(ImagePosition position, int srcWidth, int srcHeight, int wmWidth, int wmHeight, out int xPosOfWm, out int yPosOfWm)
        {
            switch (position)
            {
                case ImagePosition.BottomMiddle:
                    xPosOfWm = (srcWidth - wmWidth) / 2;
                    yPosOfWm = srcHeight - wmHeight - 10;
                    break;
                case ImagePosition.Center:
                    xPosOfWm = (srcWidth - wmWidth) / 2;
                    yPosOfWm = (srcHeight - wmHeight) / 2;
                    break;
                case ImagePosition.LeftBottom:
                    xPosOfWm = 10;
                    yPosOfWm = srcHeight - wmHeight - 10;
                    break;
                case ImagePosition.LeftTop:
                    xPosOfWm = 10;
                    yPosOfWm = 10;
                    break;
                case ImagePosition.RightTop:
                    xPosOfWm = srcWidth - wmWidth - 10;
                    yPosOfWm = 10;
                    break;
                case ImagePosition.RigthBottom:
                    xPosOfWm = srcWidth - wmWidth - 10;
                    yPosOfWm = srcHeight - wmHeight - 10;
                    break;
                case ImagePosition.TopMiddle:
                    xPosOfWm = (srcWidth - wmWidth) / 2;
                    yPosOfWm = 10;
                    break;
                default:
                    xPosOfWm = 10;
                    yPosOfWm = srcHeight - wmHeight - 10;
                    break;
            }
        }

        /// <summary>
        
/// Calculate the watermark image position.
        
/// </summary>
        
/// <param name="position">position</param>
        
/// <param name="srcWidth">source image width</param>
        
/// <param name="srcHeight">source image height</param>
        
/// <param name="wmWidth">watermark image width</param>
        
/// <param name="wmHeight">watermark image height</param>
        
/// <param name="xPosOfWm">final x position</param>
        
/// <param name="yPosOfWm">final y position</param>
        private static void GetWatermarkTextPosition(ImagePosition position, int srcWidth, int srcHeight, float wmWidth, float wmHeight, out float xPosOfWm, out float yPosOfWm)
        {
            switch (position)
            {
                case ImagePosition.BottomMiddle:
                    xPosOfWm = srcWidth / 2;
                    yPosOfWm = srcHeight - wmHeight - 10;
                    break;
                case ImagePosition.Center:
                    xPosOfWm = srcWidth / 2;
                    yPosOfWm = srcHeight / 2;
                    break;
                case ImagePosition.LeftBottom:
                    xPosOfWm = wmWidth;
                    yPosOfWm = srcHeight - wmHeight - 10;
                    break;
                case ImagePosition.LeftTop:
                    xPosOfWm = wmWidth / 2;
                    yPosOfWm = wmHeight / 2;
                    break;
                case ImagePosition.RightTop:
                    xPosOfWm = srcWidth - wmWidth - 10;
                    yPosOfWm = wmHeight;
                    break;
                case ImagePosition.RigthBottom:
                    xPosOfWm = srcWidth - wmWidth - 10;
                    yPosOfWm = srcHeight - wmHeight - 10;
                    break;
                case ImagePosition.TopMiddle:
                    xPosOfWm = srcWidth / 2;
                    yPosOfWm = wmWidth;
                    break;
                default:
                    xPosOfWm = wmWidth;
                    yPosOfWm = srcHeight - wmHeight - 10;
                    break;
            }
        }

        /// <summary>
        
/// Check image extension type.
        
/// </summary>
        
/// <param name="sourceImagePath">image path</param>
        
/// <returns>examine result</returns>
        private static bool CheckImageExtensionType(string imagePath)
        {
            string fileExtensionType = System.IO.Path.GetExtension(imagePath).ToLower();
            return (System.IO.File.Exists(imagePath) && (fileExtensionType == ".gif" || fileExtensionType == ".jpg" || fileExtensionType == ".png"));
        }

        /// <summary>
        
/// 获取Bitmap的MemoryStream
        
/// </summary>
        
/// <param name="finalImage"></param>
        
/// <returns></returns>
        private static MemoryStream GetMemoryStreamFromBitmap(Bitmap finalImage, string sourceImageFileExName)
        {
            MemoryStream ms = new MemoryStream();
            // 将位图保存到数据流中
            finalImage.Save(ms, GetFinalImageCodecInfo(sourceImageFileExName), GetEncoderParameters());
            return ms;
        }

        /// <summary>
        
/// 获取源图片和水印图片的数据流
        
/// </summary>
        
/// <param name="parameters">参数实例</param>
        
/// <param name="sourceImageStream">源图片数据流</param>
        
/// <param name="waterImageStream">水印图片数据流</param>
        
/// <param name="errorMsg">错误信息</param>
        
/// <returns>是否获取成功</returns>
        private static bool GetSourceAndWatermarkImageStream(ImageWatermarkParameters parameters,
            out MemoryStream sourceImageStream, out MemoryStream waterImageStream, out string errorMsg)
        {
            errorMsg = string.Empty;

            // 根据是否设置图片路径来判断如何获取图片数据流,分别获取源图片和水印图片的数据流。
            string scErrMsg = string.Empty, wmErrMsg = string.Empty;
            sourceImageStream = parameters.SourceImageStream == null ?
                GetImageMemoryStream(parameters.SourceImagePath, out scErrMsg) : parameters.SourceImageStream;

            waterImageStream = parameters.WatermarkImageStream == null ?
                GetImageMemoryStream(parameters.WatermarkImagePath, out wmErrMsg) : parameters.WatermarkImageStream;

            if (!string.IsNullOrEmpty(scErrMsg) || !string.IsNullOrEmpty(wmErrMsg))
            {
                errorMsg = "通过图片路径获取数据流失败:" + scErrMsg + "" + wmErrMsg;
                return false;
            }

            return true;
        }

        /// <summary>
        
/// 判断图片的PixelFormat 是否在 引发异常的 PixelFormat 之中
        
/// </summary>
        
/// <param name="imgPixelFormat">原图片的PixelFormat</param>
        
/// <returns></returns>
        private static bool IsPixelFormatIndexed(PixelFormat imgPixelFormat)
        {
            PixelFormat[] indexedPixelFormats = { 
                PixelFormat.Undefined, 
                PixelFormat.DontCare,
                PixelFormat.Format16bppArgb1555, 
                PixelFormat.Format1bppIndexed, 
                PixelFormat.Format4bppIndexed,
                PixelFormat.Format8bppIndexed
            };

            // 遍历匹配
            foreach (PixelFormat pf in indexedPixelFormats)
                if (pf.Equals(imgPixelFormat))
                    return true;

            return false;
        }

        /// <summary>
        
/// 将原图未索引像素格式之类的Image转化为Bitmap
        
/// </summary>
        
/// <param name="image">图像实体</param>
        
/// <returns>位图实体</returns>
        private static Bitmap RedrawBitmapByImage(Image image) 
        {
            Bitmap bmp = new Bitmap(image.Width, image.Height, PixelFormat.Format32bppArgb);
            using (Graphics g = Graphics.FromImage(bmp))
            {
                g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
                g.DrawImage(image, 00);
            }

            return bmp;
        }

        /// <summary>
        
/// 保证得到内部统一使用的文件扩展格式
        
/// </summary>
        
/// <param name="extensionName"></param>
        
/// <returns></returns>
        private static string TransferContentTypeToUnifyExName(string contentType)
        {
            string exName = string.Empty;
            switch (contentType.ToLower())
            {
                case "image/jpeg":
                case "image/pjpeg":
                    exName = ".jpg";
                    break;
                case "image/gif":
                    exName = ".gif";
                    break;
                case "image/x-png":
                case "image/png":
                    exName = ".png";
                    break;
                default:
                    exName = contentType;
                    break;
            }

            return exName;

 

    第三部分:水印功能处理类 -> 主体处理函数部分

 

    View Code

 
        #region 添加水印功能主体函数

        /// <summary>
        
/// 为图片添加文字水印
        
/// </summary>
        
/// <param name="parameters">文字水印相关参数体</param>
        
/// <param name="errMsg">错误信息</param>
        
/// <returns>添加完水印的位图对象</returns>
        private static Bitmap AddWatermarkTextForSourceImage(TextWatermarkParameters parameters, out string errMsg)
        {
            Image srcImage = null;
            Graphics srcGraphics = null;
            errMsg = string.Empty;

            try
            {
                //
                
// 获取源图片数据流
                MemoryStream scMs = parameters.SourceImageStream == null ?
                    GetImageMemoryStream(parameters.SourceImagePath, out errMsg) : parameters.SourceImageStream;
                if (scMs == null && !string.IsNullOrEmpty(errMsg))
                    throw new InvalidDataException("获取图片数据流失败!");

                //
                
//
                srcImage = Image.FromStream(scMs as Stream);
                // 新建位图并设定分辨率,需要根据图像的像素格式来判断是否需要重新绘制该图像
                Bitmap srcBitmap = (IsPixelFormatIndexed(srcImage.PixelFormat)) ? 
                    RedrawBitmapByImage(srcImage) : 
                    new Bitmap(srcImage.Width, srcImage.Height, srcImage.PixelFormat);
                srcBitmap.SetResolution(srcImage.HorizontalResolution, srcImage.VerticalResolution);
                // 封装一个GDI+绘图图面,并设置图形品质
                srcGraphics = Graphics.FromImage(srcBitmap);
                srcGraphics.SmoothingMode = SmoothingMode.AntiAlias;
                // 向源图片绘制到位图中
                srcGraphics.DrawImage(srcImage, new Rectangle(00, srcImage.Width, srcImage.Height), 00, srcImage.Width, srcImage.Height, GraphicsUnit.Pixel);


                //
                
// 矩形的宽度和高度,SizeF有三个属性,分别为Height高,width宽,IsEmpty是否为空 
                SizeF crSize = srcGraphics.MeasureString(parameters.WatermarkText, parameters.WmTextFont);
                // 获取水印文字的起始位置
                float xPosOfWm, yPosOfWm = 0;
                GetWatermarkTextPosition(parameters.WmPosition, srcImage.Width, srcImage.Height, crSize.Width, crSize.Height, out xPosOfWm, out yPosOfWm);

                //
                
// 文本样式
                StringFormat vmTextFormat = GetStringFormat();
                // 阴影画刷
                SolidBrush shadowBrush = GetShadowBrush();
                // 文字画刷
                SolidBrush semiTransBrush = GetTextBrush(parameters.Alpha);
                // 第一步,绘制阴影
                srcGraphics.DrawString(parameters.WatermarkText, parameters.WmTextFont, shadowBrush,
                    new PointF(xPosOfWm + parameters.TextShadowWidth, yPosOfWm + parameters.TextShadowWidth), vmTextFormat);
                // 第二步,绘制文字
                srcGraphics.DrawString(parameters.WatermarkText, parameters.WmTextFont, semiTransBrush, new PointF(xPosOfWm, yPosOfWm), vmTextFormat);

                return srcBitmap;
            }
            catch (Exception e)
            {
                errMsg = e.Message.ToString();
                return null;
            }
            finally
            { // 释放资源
                if (srcImage != null)
                    srcImage.Dispose();
                if (srcGraphics != null)
                    srcGraphics.Dispose();
            }
        }

        /// <summary>
        
/// 为源图片添加图片水印
        
/// </summary>
        
/// <param name="parameters">参数集合</param>
        
/// <param name="errMsg">错误消息</param>
        
/// <returns>添加完水印的位图对象</returns>
        private static Bitmap AddWatermarkImageForSourceImage(ImageWatermarkParameters parameters, out string errMsg)
        {
            Image sourceImage = null;
            Bitmap sourceBitmap = null;
            Graphics sourceGraphics = null;
            Image watermarkImage = null;
            Graphics watermarkGraphics = null;
            errMsg = string.Empty;

            try
            {
                // 获取源图片和水印图片的数据流
                MemoryStream sourceImageStream, waterImageStream = null;
                if (GetSourceAndWatermarkImageStream(parameters, out sourceImageStream, out waterImageStream, out errMsg) == false)
                    throw new InvalidDataException(errMsg);


                sourceImage = Image.FromStream(sourceImageStream as Stream);
                // 实例化一个与源图大小一样、分辨率一致的位图对象,并将其载入Graphics对象中,以便后续编辑;
                
// 需要根据图像的像素格式来判断是否需要重新绘制该图像
                sourceBitmap = (IsPixelFormatIndexed(sourceImage.PixelFormat)) ?
                    RedrawBitmapByImage(sourceImage) :
                    new Bitmap(sourceImage.Width, sourceImage.Height, sourceImage.PixelFormat);
                sourceBitmap.SetResolution(sourceImage.HorizontalResolution, sourceImage.VerticalResolution);
                sourceGraphics = Graphics.FromImage(sourceBitmap);

                // SmoothingMode:指定是否将平滑处理(消除锯齿)应用于直线、曲线和已填充区域的边缘。 
                
// 成员名称 说明 
                
// AntiAlias 指定消除锯齿的呈现。 
                
// Default 指定不消除锯齿。 
                
// HighQuality 指定高质量、低速度呈现。 
                
// HighSpeed 指定高速度、低质量呈现。 
                
// Invalid 指定一个无效模式。 
                
// None 指定不消除锯齿。 
                sourceGraphics.SmoothingMode = SmoothingMode.AntiAlias;
                // 将源图像Image对象添加到绘图板中
                sourceGraphics.DrawImage(sourceImage, new Rectangle(00, sourceImage.Width, sourceImage.Height),
                                            00, sourceImage.Width, sourceImage.Height, GraphicsUnit.Pixel);


                //
                
// 按照源图片的操作方式,需要创建水印图片的Image对象、位图对象,
                
// 只是需要根据输入参数来调整水印图片在源图片中的位置、显示效果等。
                watermarkImage = new Bitmap(waterImageStream);
                // 这里尤其注意,生成新位图的时候,载入的是已经添加了源图片作为背景的位图哦!
                
// 并将设定好分辨率的位图载入到新的Graphics实例中,以进一步绘制水印。
                Bitmap watermarkBitmap = new Bitmap(sourceBitmap);
                watermarkBitmap.SetResolution(sourceImage.HorizontalResolution, sourceImage.VerticalResolution);
                watermarkGraphics = Graphics.FromImage(watermarkBitmap);

                // 通过imageAttributes实例来设定水印图片的绘制效果,包括位置和现实效果等
                ImageAttributes imageAttributes = GetImageAttributesInstance(parameters.Alpha);
                // 获取水印图片的起始位置
                int xPosOfWm, yPosOfWm = 0;
                GetWatermarkImagePosition(parameters.WmPosition, sourceImage.Width, sourceImage.Height, watermarkImage.Width, watermarkImage.Height, out xPosOfWm, out yPosOfWm);
                // 绘制水印图片
                watermarkGraphics.DrawImage(watermarkImage, new Rectangle(xPosOfWm, yPosOfWm, watermarkImage.Width, watermarkImage.Height),
                                                00, watermarkImage.Width, watermarkImage.Height, GraphicsUnit.Pixel, imageAttributes);

                return watermarkBitmap;
            }
            catch (Exception e)
            {
                errMsg = e.Message.ToString();
                return null;
            }
            finally
            {
                // 释放
                if (sourceImage != null)
                    sourceImage.Dispose();
                if (sourceBitmap != null)
                    sourceBitmap.Dispose();
                if (sourceGraphics != null)
                    sourceGraphics.Dispose();
                if (watermarkImage != null)
                    watermarkImage.Dispose();
                if (watermarkGraphics != null)
                    watermarkGraphics.Dispose();
            }
        }

        

 

    第四部分:水印功能处理类 -> 对外公开方法(即调用方法)

 

    View Code

 
        #region 主要公开方法

        /// <summary>
        
/// 图片保存质量值
        
/// </summary>
        private static int _imageSaveQualityValue = 100;


        /// <summary>
        
/// 为图片添加图片水印
        
/// </summary>
        
/// <param name="parameters">添加图片水印相关参数体</param>
        
/// <param name="errorMsg">错误信息</param>
        
/// <returns>已加水印的图片数据流</returns>
        public static MemoryStream DrawImage(ImageWatermarkParameters parameters, out string errorMsg)
        {
            errorMsg = string.Empty;

            try
            {
                // 参数检查
                if (!parameters.CheckAndSetDefault(out errorMsg))
                    throw new InvalidDataException(errorMsg);

                // 为源图片添加图片水印
                Bitmap finalImage = AddWatermarkImageForSourceImage(parameters, out errorMsg);
                if (finalImage == null && !string.IsNullOrEmpty(errorMsg))
                    throw new InvalidDataException("生成水印图片失败:" + errorMsg);

                // 获取Bitmap的MemoryStream
                return GetMemoryStreamFromBitmap(finalImage, parameters.SourceImageFileExtensionName);
            }
            catch (Exception ex)
            {
                errorMsg = ex.Message.ToString();
                return null;
            }
        }

        /// <summary>
        
/// 为图片添加文字水印
        
/// </summary>
        
/// <param name="parameters">文字水印过程需要的参数体</param>
        
/// <param name="errorMsg">异常信息</param>
        
/// <returns>已加水印的图片数据流</returns>
        public static MemoryStream DrawText(TextWatermarkParameters parameters, out string errorMsg)
        {
            errorMsg = string.Empty;

            try
            {
                // 参数检查
                if (!parameters.CheckAndSetDefault(out errorMsg))
                    throw new InvalidDataException(errorMsg);

                // 为源图片添加文字水印
                Bitmap finalImage = AddWatermarkTextForSourceImage(parameters, out errorMsg);
                if (finalImage == null && !string.IsNullOrEmpty(errorMsg))
                    throw new InvalidDataException("生成水印图片失败:" + errorMsg);

                return GetMemoryStreamFromBitmap(finalImage, parameters.SourceImageFileExtensionName);
            }
            catch (Exception ex)
            {
                errorMsg = ex.Message.ToString();
                return null;
            }
        }

        /// <summary>
        
/// 根据文件路径获取图片数据流
        
/// </summary>
        
/// <param name="filePath"></param>
        
/// <returns></returns>
        private static MemoryStream GetImageMemoryStream(string filePath, out string errorMsg)
        {
            MemoryStream ms = null;
            errorMsg = string.Empty;

            try
            {
                using (FileStream fs = File.OpenRead(filePath))
                { // 读取图片数据流
                    byte[] buffer = new byte[fs.Length];
                    fs.Read(buffer, 0, buffer.Length);
                    ms.Write(buffer, 0, buffer.Length);
                }

                return ms;
            }
            catch (Exception e)
            {
                errorMsg = e.Message.ToString();
                return null;
            }
        }

        

  

    第五部分:添加水印功能调用示例

 

    View Code

 
            string errorMsg = string.Empty;
            string origenalImagePath = "D:\\sourcePicture.jpg";
            float alpha = 0.5F;

            // 图片水印

            string waterPicturePath = "D:\\watermarkPicture.jpg";
            WatermarkImageManager.ImageWatermarkParameters image_parameters =
                new WatermarkImageManager.ImageWatermarkParameters(FileToStream(origenalImagePath), FileToStream(waterPicturePath), ".jpg", alpha, WatermarkImageManager.ImagePosition.LeftBottom);
            MemoryStream wmImageMS = WatermarkImageManager.DrawImage(image_parameters, out errorMsg);

            // 文字水印
            string wmText = "水印文字";
            Font font = new Font("arial"30, FontStyle.Bold);

            WatermarkImageManager.TextWatermarkParameters text_parameters =
                new WatermarkImageManager.TextWatermarkParameters(FileToStream(origenalImagePath), ".jpg", wmText, alpha, WatermarkImageManager.ImagePosition.Center, font);
            MemoryStream wmTextMS = WatermarkImageManager.DrawText(text_parameters, out

 

    最后把该水印处理类的代码文件附上,方便大家调整,同时支持,传入MemoryStream或输入文件路径两种形式的数据,详情请看参数结构类部分。

 

    点击下载WatermarkImageManager.cs类文件

 

    希望有所帮助~ 

posted on 2012-06-14 15:13  酸甜西瓜  阅读(3730)  评论(5编辑  收藏  举报