用C#的GDI+技术生成复杂型彩色验证码

http://my.oschina.net/idufei/blog/95502

该类是生成一个验证码的类。本人集合了网上大部分的C#关于GDI+的文章进行多次改进,现在已经形成了可在生产环节中使用的验证码。

该验证码加入了背景噪点,背景噪点曲线和直线,背景噪点文字以及扭曲,调暗,模糊等。完全可以实现防识别。

对安全性要求比较高的网站尤其适用。

同时该类还还收集了GDI+的图像处理方面的函数,包括雾化,扭曲,水波,锐化,高斯模糊,画直线,画曲线生成随机颜色,缩放图片,柔化图片,图片黑白化,增加曝光度,RGB滤镜,绘制圆角等功能。

代码注释已经很详细了,就不再啰嗦了,有需要的就拿走吧。

 

 

   1 using System;

   2 using System.Collections.Generic;

   3 using System.Text;

   4 using System.IO;

   5 using System.Drawing;

   6 using System.Drawing.Drawing2D;

   7 using System.Drawing.Text;

   8 using System.Drawing.Imaging;

   9 

  10 /**********************

  11  * 验证码生成类

  12  * 作者:李飞麟

  13  * URL:http://www.xuehuwang.com 

  14  * Email:[email protected] 

  15  * 

  16  * *********************/

  17 namespace NS.DrawValidationCode

  18 {

  19     #region 验证码生成类

  20     /// <summary>

  21     /// 验证码生成类

  22     /// </summary>

  23     public class DrawValidationCode

  24     {

  25         #region 定义和初始化配置字段

  26         //用户存取验证码字符串

  27         private string validationCode = String.Empty;

  28         /// <summary>

  29         /// 获取系统生成的随机验证码

  30         /// </summary>

  31         public String ValidationCode

  32         {

  33             get { return validationCode; }

  34         }

  35         private Int32 validationCodeCount = 4;

  36         /// <summary>

  37         /// 获取和设置验证码字符串的长度

  38         /// </summary>

  39         public Int32 ValidationCodeCount

  40         {

  41             get { return validationCodeCount; }

  42             set { validationCodeCount = value; }

  43         }

  44         Graphics dc = null;

  45         private int bgWidth = 130;

  46         /// <summary>

  47         /// 验证码的宽度,默认为80

  48         /// </summary>

  49         public Int32 Width

  50         {

  51             get { return bgWidth; }

  52             set { bgWidth = value; }

  53         }

  54 

  55         private int bgHeight = 40;

  56         /// <summary>

  57         /// 验证码的高度,默认为40

  58         /// </summary>

  59         public Int32 Height

  60         {

  61             get { return bgHeight; }

  62             set { bgHeight = value; }

  63         }

  64         /* private string[] fontFace = { "Verdana", "Microsoft Sans Serif", "Comic Sans MS", "Arial", "宋体" };

  65          /// <summary>

  66          /// 验证码字体列表,默认为{ "Verdana", "Microsoft Sans Serif", "Comic Sans MS", "Arial", "宋体" }

  67          /// </summary>

  68          public String[] FontFace

  69          {

  70              get { return fontFace; }

  71              set { fontFace = value; }

  72          }*/

  73 

  74         private int fontMinSize = 15;

  75         /// <summary>

  76         /// 验证码字体的最小值,默认为15,建议不小于15像素

  77         /// </summary>

  78         public Int32 FontMinSize

  79         {

  80             get { return fontMinSize; }

  81             set { fontMinSize = value; }

  82         }

  83         private Int32 fontMaxSize = 20;

  84         /// <summary>

  85         /// 验证码字体的最大值,默认为20

  86         /// </summary>

  87         public Int32 FontMaxSize

  88         {

  89             get { return fontMaxSize; }

  90             set { fontMaxSize = value; }

  91         }

  92         private Color[] fontColor = { };

  93         /// <summary>

  94         /// 验证码字体的颜色,默认为系统自动生成字体颜色

  95         /// </summary>

  96         public Color[] FontColor

  97         {

  98             get { return fontColor; }

  99             set { fontColor = value; }

 100         }

 101         private Color backColor = Color.FromArgb(243, 255, 255);

 102         /// <summary>

 103         /// 验证码的背景色,默认为Color.FromArgb(243, 251, 254)

 104         /// </summary>

 105         public Color BackgroundColor

 106         {

 107             get { return backColor; }

 108             set { backColor = value; }

 109         }

 110         private Int32 bezierCount = 3;

 111         /// <summary>

 112         /// 贝塞尔曲线的条数,默认为3条

 113         /// </summary>

 114         public Int32 BezierCount

 115         {

 116             get { return bezierCount; }

 117             set { bezierCount = value; }

 118         }

 119         private Int32 lineCount = 3;

 120         /// <summary>

 121         /// 直线条数,默认为3条

 122         /// </summary>

 123         public Int32 LineCount

 124         {

 125             get { return lineCount; }

 126             set { lineCount = value; }

 127         }

 128         Random random;

 129 

 130         private String charCollection = "2,3,4,5,6,7,8,9,a,s,d,f,g,h,z,c,v,b,n,m,k,q,w,e,r,t,y,u,p,A,S,D,F,G,H,Z,C,V,B,N,M,K,Q,W,E,R,T,Y,U,P"; //定义验证码字符及出现频次 ,避免出现0 o j i l 1 x;  

 131         /// <summary>

 132         /// 随机字符串列表,请使用英文状态下的逗号分隔。

 133         /// </summary>

 134         public String CharCollection

 135         {

 136             get { return charCollection; }

 137             set { charCollection = value; }

 138         }

 139         private Int32 intCount = 4;

 140         /// <summary>

 141         /// 验证码字符串个数,默认为4个字符

 142         /// </summary>

 143         public Int32 IntCount

 144         {

 145             get { return intCount; }

 146             set { intCount = value; }

 147         }

 148         private Boolean isPixel = true;

 149         /// <summary>

 150         /// 是否添加噪点,默认添加,噪点颜色为系统随机生成。

 151         /// </summary>

 152         public Boolean IsPixel

 153         {

 154             get { return isPixel; }

 155             set { isPixel = value; }

 156         }

 157         private Boolean isRandString = true;

 158         /// <summary>

 159         /// 是否添加随机噪点字符串,默认添加

 160         /// </summary>

 161         public Boolean IsRandString

 162         {

 163             get { return isRandString; }

 164             set { isRandString = value; }

 165         }

 166         /// <summary>

 167         /// 随机背景字符串的个数

 168         /// </summary>

 169         public Int32 RandomStringCount

 170         {

 171             get;

 172             set;

 173         }

 174         private Int32 randomStringFontSize = 9;

 175         /// <summary>

 176         /// 随机背景字符串的大小

 177         /// </summary>

 178         public Int32 RandomStringFontSize

 179         {

 180             get { return randomStringFontSize; }

 181             set { randomStringFontSize = value; }

 182         }

 183         /// <summary>

 184         /// 是否对图片进行扭曲

 185         /// </summary>

 186         public Boolean IsTwist

 187         {

 188             get;

 189             set;

 190         }

 191         /// <summary>

 192         /// 边框样式

 193         /// </summary>

 194         public enum BorderStyle

 195         {

 196             /// <summary>

 197             /// 无边框

 198             /// </summary>

 199             None,

 200             /// <summary>

 201             /// 矩形边框

 202             /// </summary>

 203             Rectangle,

 204             /// <summary>

 205             /// 圆角边框

 206             /// </summary>

 207             RoundRectangle

 208         }

 209         private Int32 rotationAngle = 40;

 210         /// <summary>

 211         /// 验证码字符串随机转动的角度的最大值

 212         /// </summary>

 213         public Int32 RotationAngle

 214         {

 215             get { return rotationAngle; }

 216             set { rotationAngle = value; }

 217         }

 218         /// <summary>

 219         /// 设置或获取边框样式

 220         /// </summary>

 221         public BorderStyle Border

 222         {

 223             get;

 224             set;

 225         }

 226         private Point[] strPoint = null;

 227 

 228         private Double gaussianDeviation = 0;

 229         /// <summary>

 230         /// 对验证码图片进行高斯模糊的阀值,如果设置为0,则不对图片进行高斯模糊,该设置可能会对图片处理的性能有较大影响

 231         /// </summary>

 232         public Double GaussianDeviation

 233         {

 234             get { return gaussianDeviation; }

 235             set { gaussianDeviation = value; }

 236         }

 237         private Int32 brightnessValue = 0;

 238         /// <summary>

 239         /// 对图片进行暗度和亮度的调整,如果该值为0,则不调整。该设置会对图片处理性能有较大影响

 240         /// </summary>

 241         public Int32 BrightnessValue

 242         {

 243             get { return brightnessValue; }

 244             set { brightnessValue = value; }

 245         }

 246         #endregion

 247         /// <summary>

 248         /// 构造函数,用于初始化常用变量

 249         /// </summary>

 250         public DrawValidationCode()

 251         {

 252             random = new Random(Guid.NewGuid().GetHashCode());

 253             strPoint = new Point[validationCodeCount + 1];

 254             if (gaussianDeviation < 0) gaussianDeviation = 0;

 255         }

 256 

 257         /// <summary>

 258         /// 生成验证码

 259         /// </summary>

 260         /// <param name="target">用于存储图片的一般字节序列</param>

 261         public void CreateImage(Stream target)

 262         {

 263             Bitmap bit = new Bitmap(bgWidth + 1, bgHeight + 1);

 264             //写字符串

 265             dc = Graphics.FromImage(bit);

 266             dc.SmoothingMode = SmoothingMode.HighQuality;

 267             dc.TextRenderingHint = TextRenderingHint.ClearTypeGridFit; ;

 268             dc.InterpolationMode = InterpolationMode.HighQualityBilinear;

 269             dc.CompositingQuality = CompositingQuality.HighQuality;

 270 

 271             dc.Clear(Color.White);

 272             dc.DrawImageUnscaled(DrawBackground(), 0, 0);

 273             dc.DrawImageUnscaled(DrawRandomString(), 0, 0);

 274             //对图片文字进行扭曲

 275             bit = AdjustRippleEffect(bit, 5);

 276             //对图片进行高斯模糊

 277             if (gaussianDeviation > 0)

 278             {

 279                 Gaussian gau = new Gaussian();

 280                 bit = gau.FilterProcessImage(gaussianDeviation, bit);

 281             }

 282             //进行暗度和亮度处理

 283             if (brightnessValue != 0)

 284             {

 285                 //对图片进行调暗处理

 286                 bit = AdjustBrightness(bit, brightnessValue);

 287             }

 288             bit.Save(target, ImageFormat.Gif);

 289             //brush.Dispose();

 290             bit.Dispose();

 291             dc.Dispose();

 292         }

 293 

 294         #region 画验证码背景,例如,增加早点,添加曲线和直线等

 295         /// <summary>

 296         /// 画验证码背景,例如,增加早点,添加曲线和直线等

 297         /// </summary>

 298         /// <returns></returns>

 299         private Bitmap DrawBackground()

 300         {

 301             Bitmap bit = new Bitmap(bgWidth + 1, bgHeight + 1);

 302             Graphics g = Graphics.FromImage(bit);

 303             g.SmoothingMode = SmoothingMode.HighQuality;

 304 

 305             g.Clear(Color.White);

 306             Rectangle rectangle = new Rectangle(0, 0, bgWidth, bgHeight);

 307             Brush brush = new SolidBrush(backColor);

 308             g.FillRectangle(brush, rectangle);

 309 

 310             //画噪点

 311             if (isPixel)

 312             {

 313                 g.DrawImageUnscaled(DrawRandomPixel(30), 0, 0);

 314             }

 315             g.DrawImageUnscaled(DrawRandBgString(), 0, 0);

 316 

 317 

 318             //画曲线

 319             g.DrawImageUnscaled(DrawRandomBezier(bezierCount), 0, 0);

 320             //画直线

 321             g.DrawImageUnscaled(DrawRandomLine(lineCount), 0, 0);

 322 

 323             //dc.DrawImageUnscaled(DrawStringline(), 0, 0);

 324             if (Border == BorderStyle.Rectangle)

 325             {

 326                 //绘制边框

 327                 g.DrawRectangle(new Pen(Color.FromArgb(90, 87, 46)), 0, 0, bgWidth, bgHeight);

 328             }

 329             else if (Border == BorderStyle.RoundRectangle)

 330             {

 331                 //画圆角

 332                 DrawRoundRectangle(g, rectangle, Color.FromArgb(90, 87, 46), 1, 3);

 333             }

 334 

 335             return bit;

 336 

 337         }

 338         #endregion

 339 

 340         #region 画正弦曲线

 341         private Bitmap DrawTwist(Bitmap bmp, Int32 tWidth, Int32 tHeight, float angle, Color color)

 342         {

 343             //为了方便查看效果,在这里我定义了一个常量。

 344             //它在定义数组的长度和for循环中都要用到。

 345             int size = bgWidth;

 346 

 347             double[] x = new double[size];

 348             Bitmap b = new Bitmap(bmp.Width, bmp.Height);

 349             b.MakeTransparent();

 350             Graphics graphics = Graphics.FromImage(b);

 351             Pen pen = new Pen(color);

 352 

 353             //画正弦曲线的横轴间距参数。建议所用的值应该是 正数且是2的倍数。

 354             //在这里采用2。

 355             int val = 2;

 356 

 357             float temp = 0.0f;

 358 

 359             //把画布下移100。为什么要这样做,只要你把这一句给注释掉,运行一下代码,

 360             //你就会明白是为什么?

 361             graphics.TranslateTransform(0, 100);

 362             graphics.SmoothingMode = SmoothingMode.HighQuality;

 363             graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;

 364             for (int i = 0; i < size; i++)

 365             {

 366                 //改变tWidth,实现正弦曲线宽度的变化。

 367                 //改tHeight,实现正弦曲线高度的变化。

 368                 x[i] = Math.Sin(2 * Math.PI * i / tWidth) * tHeight;

 369 

 370                 graphics.DrawLine(pen, i * val, temp, i * val + val / 2, (float)x[i]);

 371                 temp = (float)x[i];

 372             }

 373             graphics.RotateTransform(60, MatrixOrder.Prepend);

 374 

 375             //旋转图片

 376             // b = KiRotate(b, angle, Color.Transparent);

 377             return b;

 378         }

 379         #endregion

 380 

 381         #region 正弦曲线Wave扭曲图片

 382         /// <summary>

 383         /// 正弦曲线Wave扭曲图片

 384         /// </summary>

 385         /// <param name="srcBmp">图片路径</param>

 386         /// <param name="bXDir">如果扭曲则选择为True</param>

 387         /// <param name="dMultValue">波形的幅度倍数,越大扭曲的程度越高,一般为3</param>

 388         /// <param name="dPhase">波形的起始相位,取值区间[0-2*PI)</param>

 389         /// <returns></returns>

 390         public Bitmap TwistImage(Bitmap srcBmp, bool bXDir, double dMultValue, double dPhase)

 391         {

 392             System.Drawing.Bitmap destBmp = new Bitmap(srcBmp.Width, srcBmp.Height);

 393             double PI2 = 6.283185307179586476925286766559;

 394             // 将位图背景填充为白色

 395             System.Drawing.Graphics graph = System.Drawing.Graphics.FromImage(destBmp);

 396             graph.FillRectangle(new SolidBrush(System.Drawing.Color.White), 0, 0, destBmp.Width, destBmp.Height);

 397             graph.Dispose();

 398 

 399             double dBaseAxisLen = bXDir ? (double)destBmp.Height : (double)destBmp.Width;

 400 

 401             for (int i = 0; i < destBmp.Width; i++)

 402             {

 403                 for (int j = 0; j < destBmp.Height; j++)

 404                 {

 405                     double dx = 0;

 406                     dx = bXDir ? (PI2 * (double)j) / dBaseAxisLen : (PI2 * (double)i) / dBaseAxisLen;

 407                     dx += dPhase;

 408                     double dy = Math.Sin(dx);

 409 

 410                     // 取得当前点的颜色

 411                     int nOldX = 0, nOldY = 0;

 412                     nOldX = bXDir ? i + (int)(dy * dMultValue) : i;

 413                     nOldY = bXDir ? j : j + (int)(dy * dMultValue);

 414 

 415                     System.Drawing.Color color = srcBmp.GetPixel(i, j);

 416                     if (nOldX >= 0 && nOldX < destBmp.Width

 417                      && nOldY >= 0 && nOldY < destBmp.Height)

 418                     {

 419                         destBmp.SetPixel(nOldX, nOldY, color);

 420                     }

 421                 }

 422             }

 423             return destBmp;

 424         }

 425         #endregion

 426 

 427         #region 图片任意角度旋转

 428         /// <summary>

 429         /// 图片任意角度旋转

 430         /// </summary>

 431         /// <param name="bmp">原始图Bitmap</param>

 432         /// <param name="angle">旋转角度</param>

 433         /// <param name="bkColor">背景色</param>

 434         /// <returns>输出Bitmap</returns>

 435         public static Bitmap KiRotate(Bitmap bmp, float angle, Color bkColor)

 436         {

 437             int w = bmp.Width;

 438             int h = bmp.Height;

 439 

 440             PixelFormat pf;

 441 

 442             if (bkColor == Color.Transparent)

 443             {

 444                 pf = PixelFormat.Format32bppArgb;

 445             }

 446             else

 447             {

 448                 pf = bmp.PixelFormat;

 449             }

 450 

 451             Bitmap tmp = new Bitmap(w, h, pf);

 452             Graphics g = Graphics.FromImage(tmp);

 453             g.Clear(bkColor);

 454             g.DrawImageUnscaled(bmp, 1, 1);

 455             g.Dispose();

 456 

 457             GraphicsPath path = new GraphicsPath();

 458             path.AddRectangle(new RectangleF(0f, 0f, w, h));

 459             Matrix mtrx = new Matrix();

 460             mtrx.Rotate(angle);

 461             RectangleF rct = path.GetBounds(mtrx);

 462 

 463             Bitmap dst = new Bitmap((int)rct.Width, (int)rct.Height, pf);

 464             g = Graphics.FromImage(dst);

 465             g.Clear(bkColor);

 466             g.TranslateTransform(-rct.X, -rct.Y);

 467             g.RotateTransform(angle);

 468             g.InterpolationMode = InterpolationMode.HighQualityBilinear;

 469             g.DrawImageUnscaled(tmp, 0, 0);

 470             g.Dispose();

 471             tmp.Dispose();

 472 

 473             return dst;

 474         }

 475         #endregion

 476 

 477         #region 随机生成贝塞尔曲线

 478         /// <summary>

 479         /// 随机生成贝塞尔曲线

 480         /// </summary>

 481         /// <param name="bmp">一个图片的实例</param>

 482         /// <param name="lineNum">线条数量</param>

 483         /// <returns></returns>

 484         public Bitmap DrawRandomBezier(Int32 lineNum)

 485         {

 486             Bitmap b = new Bitmap(bgWidth, bgHeight);

 487             b.MakeTransparent();

 488             Graphics g = Graphics.FromImage(b);

 489             g.Clear(Color.Transparent);

 490             g.SmoothingMode = SmoothingMode.HighQuality;

 491             g.PixelOffsetMode = PixelOffsetMode.HighQuality;

 492 

 493             GraphicsPath gPath1 = new GraphicsPath();

 494             Int32 lineRandNum = random.Next(lineNum);

 495 

 496             for (int i = 0; i < (lineNum - lineRandNum); i++)

 497             {

 498                 Pen p = new Pen(GetRandomDeepColor());

 499                 Point[] point = {

 500                                     new Point(random.Next(1, (b.Width / 10)), random.Next(1, (b.Height))),

 501                                     new Point(random.Next((b.Width / 10) * 2, (b.Width / 10) * 4), random.Next(1, (b.Height))),

 502                                     new Point(random.Next((b.Width / 10) * 4, (b.Width / 10) * 6), random.Next(1, (b.Height))),

 503                                     new Point(random.Next((b.Width / 10) * 8, b.Width), random.Next(1, (b.Height)))

 504                                 };

 505 

 506                 gPath1.AddBeziers(point);

 507                 g.DrawPath(p, gPath1);

 508                 p.Dispose();

 509             }

 510             for (int i = 0; i < lineRandNum; i++)

 511             {

 512                 Pen p = new Pen(GetRandomDeepColor());

 513                 Point[] point = {

 514                             new Point(random.Next(1, b.Width), random.Next(1, b.Height)),

 515                             new Point(random.Next((b.Width / 10) * 2, b.Width), random.Next(1, b.Height)),

 516                             new Point(random.Next((b.Width / 10) * 4, b.Width), random.Next(1, b.Height)),

 517                             new Point(random.Next(1, b.Width), random.Next(1, b.Height))

 518                                 };

 519                 gPath1.AddBeziers(point);

 520                 g.DrawPath(p, gPath1);

 521                 p.Dispose();

 522             }

 523             return b;

 524         }

 525         #endregion

 526 

 527         #region 画直线

 528         /// <summary>

 529         /// 画直线

 530         /// </summary>

 531         /// <param name="bmp">一个bmp实例</param>

 532         /// <param name="lineNum">线条个数</param>

 533         /// <returns></returns>

 534         public Bitmap DrawRandomLine(Int32 lineNum)

 535         {

 536             if (lineNum < 0) throw new ArgumentNullException("参数bmp为空!");

 537             Bitmap b = new Bitmap(bgWidth, bgHeight);

 538             b.MakeTransparent();

 539             Graphics g = Graphics.FromImage(b);

 540             g.Clear(Color.Transparent);

 541             g.PixelOffsetMode = PixelOffsetMode.HighQuality;

 542             g.SmoothingMode = SmoothingMode.HighQuality;

 543             for (int i = 0; i < lineNum; i++)

 544             {

 545                 Pen p = new Pen(GetRandomDeepColor());

 546                 Point pt1 = new Point(random.Next(1, (b.Width / 5) * 2), random.Next(b.Height));

 547                 Point pt2 = new Point(random.Next((b.Width / 5) * 3, b.Width), random.Next(b.Height));

 548                 g.DrawLine(p, pt1, pt2);

 549                 p.Dispose();

 550             }

 551 

 552             return b;

 553         }

 554         #endregion

 555 

 556         #region 画随机噪点

 557         /// <summary>

 558         /// 画随机噪点

 559         /// </summary>

 560         /// <param name="pixNum">噪点的百分比</param>

 561         /// <returns></returns>

 562         public Bitmap DrawRandomPixel(Int32 pixNum)

 563         {

 564             Bitmap b = new Bitmap(bgWidth, bgHeight);

 565             b.MakeTransparent();

 566             Graphics graph = Graphics.FromImage(b);

 567             graph.SmoothingMode = SmoothingMode.HighQuality;

 568             graph.InterpolationMode = InterpolationMode.HighQualityBilinear;

 569 

 570             //画噪点 

 571             for (int i = 0; i < (bgHeight * bgWidth) / pixNum; i++)

 572             {

 573                 int x = random.Next(b.Width);

 574                 int y = random.Next(b.Height);

 575                 b.SetPixel(x, y, GetRandomDeepColor());

 576                 //下移坐标重新画点

 577                 if ((x + 1) < b.Width && (y + 1) < b.Height)

 578                 {

 579                     //画图片的前景噪音点

 580                     graph.DrawRectangle(new Pen(Color.Silver), random.Next(b.Width), random.Next(b.Height), 1, 1);

 581                 }

 582 

 583             }

 584 

 585             return b;

 586         }

 587         #endregion

 588 

 589         #region 画随机字符串中间连线

 590         /// <summary>

 591         /// 画随机字符串中间连线

 592         /// </summary>

 593         /// <returns></returns>

 594         private Bitmap DrawStringline()

 595         {

 596             Bitmap b = new Bitmap(bgWidth, bgHeight);

 597             b.MakeTransparent();

 598             Graphics g = Graphics.FromImage(b);

 599             g.SmoothingMode = SmoothingMode.AntiAlias;

 600 

 601             Point[] p = new Point[validationCodeCount];

 602             for (int i = 0; i < validationCodeCount; i++)

 603             {

 604                 p[i] = strPoint[i];

 605                 //throw new Exception(strPoint.Length.ToString());

 606             }

 607             // g.DrawBezier(new Pen(GetRandomDeepColor()), strPoint);

 608             //g.DrawClosedCurve(new Pen(GetRandomDeepColor()), strPoint);

 609             g.DrawCurve(new Pen(GetRandomDeepColor(), 1), strPoint);

 610 

 611             return b;

 612         }

 613         #endregion

 614 

 615         #region 写入验证码的字符串

 616         /// <summary>

 617         /// 写入验证码的字符串

 618         /// </summary>

 619         private Bitmap DrawRandomString()

 620         {

 621             if (fontMaxSize >= (bgHeight / 5) * 4) throw new ArgumentException("字体最大值参数FontMaxSize与验证码高度相近,这会导致描绘验证码字符串时出错,请重新设置参数!");

 622             Bitmap b = new Bitmap(bgWidth, bgHeight);

 623             b.MakeTransparent();

 624             Graphics g = Graphics.FromImage(b);

 625 

 626             g.Clear(Color.Transparent);

 627             g.PixelOffsetMode = PixelOffsetMode.Half;

 628             g.SmoothingMode = SmoothingMode.HighQuality;

 629             g.TextRenderingHint = TextRenderingHint.SingleBitPerPixelGridFit;

 630             g.InterpolationMode = InterpolationMode.HighQualityBilinear;

 631 

 632             char[] chars = GetRandomString(validationCodeCount).ToCharArray();//拆散字符串成单字符数组

 633             validationCode = chars.ToString();

 634 

 635             //设置字体显示格式

 636             StringFormat format = new StringFormat(StringFormatFlags.NoClip);

 637             format.Alignment = StringAlignment.Center;

 638             format.LineAlignment = StringAlignment.Center;

 639             FontFamily f = new FontFamily(GenericFontFamilies.Monospace);

 640 

 641 

 642             Int32 charNum = chars.Length;

 643 

 644             Point sPoint = new Point();

 645             Int32 fontSize = 9;

 646             for (int i = 0; i < validationCodeCount; i++)

 647             {

 648                 int findex = random.Next(5);

 649                 //定义字体

 650                 Font textFont = new Font(f, random.Next(fontMinSize, fontMaxSize), FontStyle.Bold);

 651                 //定义画刷,用于写字符串

 652                 //Brush brush = new SolidBrush(GetRandomDeepColor());

 653                 Int32 textFontSize = Convert.ToInt32(textFont.Size);

 654                 fontSize = textFontSize;

 655                 Point point = new Point(random.Next((bgWidth / charNum) * i + 5, (bgWidth / charNum) * (i + 1)), random.Next(bgHeight / 5 + textFontSize / 2, bgHeight - textFontSize / 2));

 656 

 657 

 658 

 659                 //如果当前字符X坐标小于字体的二分之一大小

 660                 if (point.X < textFontSize / 2)

 661                 {

 662                     point.X = point.X + textFontSize / 2;

 663                 }

 664                 //防止文字叠加

 665                 if (i > 0 && (point.X - sPoint.X < (textFontSize / 2 + textFontSize / 2)))

 666                 {

 667                     point.X = point.X + textFontSize;

 668                 }

 669                 //如果当前字符X坐标大于图片宽度,就减去字体的宽度

 670                 if (point.X > (bgWidth - textFontSize / 2))

 671                 {

 672                     point.X = bgWidth - textFontSize / 2;

 673                 }

 674 

 675                 sPoint = point;

 676 

 677                 float angle = random.Next(-rotationAngle, rotationAngle);//转动的度数

 678                 g.TranslateTransform(point.X, point.Y);//移动光标到指定位置

 679                 g.RotateTransform(angle);

 680 

 681                 //设置渐变画刷  

 682                 Rectangle myretang = new Rectangle(0, 1, Convert.ToInt32(textFont.Size), Convert.ToInt32(textFont.Size));

 683                 Color c = GetRandomDeepColor();

 684                 LinearGradientBrush mybrush2 = new LinearGradientBrush(myretang, c, GetLightColor(c, 120), random.Next(180));

 685 

 686                 g.DrawString(chars[i].ToString(), textFont, mybrush2, 1, 1, format);

 687 

 688                 g.RotateTransform(-angle);//转回去

 689                 g.TranslateTransform(-point.X, -point.Y);//移动光标到指定位置,每个字符紧凑显示,避免被软件识别

 690 

 691                 strPoint[i] = point;

 692 

 693                 textFont.Dispose();

 694                 mybrush2.Dispose();

 695             }

 696             return b;

 697         }

 698         #endregion

 699 

 700         #region 画干扰背景文字

 701         /// <summary>

 702         /// 画背景干扰文字

 703         /// </summary>

 704         /// <returns></returns>

 705         private Bitmap DrawRandBgString()

 706         {

 707             Bitmap b = new Bitmap(bgWidth, bgHeight);

 708             String[] randStr = { "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z" };

 709             b.MakeTransparent();

 710             Graphics g = Graphics.FromImage(b);

 711 

 712             g.Clear(Color.Transparent);

 713             g.PixelOffsetMode = PixelOffsetMode.HighQuality;

 714             g.SmoothingMode = SmoothingMode.HighQuality;

 715             g.TextRenderingHint = TextRenderingHint.AntiAlias;

 716             g.InterpolationMode = InterpolationMode.HighQualityBilinear;

 717 

 718             //设置字体显示格式

 719             StringFormat format = new StringFormat(StringFormatFlags.NoClip);

 720             format.Alignment = StringAlignment.Center;

 721             format.LineAlignment = StringAlignment.Center;

 722 

 723             FontFamily f = new FontFamily(GenericFontFamilies.Serif);

 724             Font textFont = new Font(f, randomStringFontSize, FontStyle.Underline);

 725 

 726             int randAngle = 60; //随机转动角度

 727 

 728             for (int i = 0; i < RandomStringCount; i++)

 729             {

 730 

 731                 Brush brush = new System.Drawing.SolidBrush(GetRandomLightColor());

 732                 Point pot = new Point(random.Next(5, bgWidth - 5), random.Next(5, bgHeight - 5));

 733                 //随机转动的度数

 734                 float angle = random.Next(-randAngle, randAngle);

 735 

 736                 //转动画布

 737                 g.RotateTransform(angle);

 738                 g.DrawString(randStr[random.Next(randStr.Length)], textFont, brush, pot, format);

 739                 //转回去,为下一个字符做准备

 740                 g.RotateTransform(-angle);

 741                 //释放资源

 742                 brush.Dispose();

 743             }

 744             textFont.Dispose();

 745             format.Dispose();

 746             f.Dispose();

 747 

 748             return b;

 749         }

 750         #endregion

 751 

 752         #region 生成随机字符串

 753         /// <summary>

 754         /// 生成随机字符串    

 755         /// </summary>

 756         /// <returns></returns>

 757         private string GetRandomString(Int32 textLength)

 758         {

 759             string[] randomArray = charCollection.Split(','); //将字符串生成数组     

 760             int arrayLength = randomArray.Length;

 761             string randomString = "";

 762             for (int i = 0; i < textLength; i++)

 763             {

 764                 randomString += randomArray[random.Next(0, arrayLength)];

 765             }

 766             return randomString; //长度是textLength +1

 767         }

 768         #endregion

 769 

 770         #region 内部方法:绘制验证码背景

 771         private void DrawBackground(HatchStyle hatchStyle)

 772         {

 773             //设置填充背景时用的笔刷

 774             HatchBrush hBrush = new HatchBrush(hatchStyle, backColor);

 775 

 776             //填充背景图片

 777             dc.FillRectangle(hBrush, 0, 0, this.bgWidth, this.bgHeight);

 778         }

 779         #endregion

 780 

 781         #region 根据指定长度,返回随机验证码

 782         /// <summary>

 783         /// 根据指定长度,返回随机验证码

 784         /// </summary>

 785         /// <param >制定长度</param>

 786         /// <returns>随即验证码</returns>

 787         public string Next(int length)

 788         {

 789             this.validationCode = GetRandomCode(length);

 790             return this.validationCode;

 791         }

 792         #endregion

 793 

 794         #region 内部方法:返回指定长度的随机验证码字符串

 795         /// <summary>

 796         /// 根据指定大小返回随机验证码

 797         /// </summary>

 798         /// <param >字符串长度</param>

 799         /// <returns>随机字符串</returns>

 800         private string GetRandomCode(int length)

 801         {

 802             StringBuilder sb = new StringBuilder(6);

 803 

 804             for (int i = 0; i < length; i++)

 805             {

 806                 sb.Append(Char.ConvertFromUtf32(RandomAZ09()));

 807             }

 808 

 809             return sb.ToString();

 810         }

 811         #endregion

 812 

 813         #region 内部方法:产生随机数和随机点

 814 

 815         /// <summary>

 816         /// 产生0-9A-Z的随机字符代码

 817         /// </summary>

 818         /// <returns>字符代码</returns>

 819         private int RandomAZ09()

 820         {

 821             int result = 48;

 822             Random ram = new Random();

 823             int i = ram.Next(2);

 824 

 825             switch (i)

 826             {

 827                 case 0:

 828                     result = ram.Next(48, 58);

 829                     break;

 830                 case 1:

 831                     result = ram.Next(65, 91);

 832                     break;

 833             }

 834 

 835             return result;

 836         }

 837 

 838         /// <summary>

 839         /// 返回一个随机点,该随机点范围在验证码背景大小范围内

 840         /// </summary>

 841         /// <returns>Point对象</returns>

 842         private Point RandomPoint()

 843         {

 844             Random ram = new Random();

 845             Point point = new Point(ram.Next(this.bgWidth), ram.Next(this.bgHeight));

 846             return point;

 847         }

 848         #endregion

 849 

 850         #region 随机生成颜色值

 851         /// <summary>

 852         /// 生成随机深颜色

 853         /// </summary>

 854         /// <returns></returns>

 855         public Color GetRandomDeepColor()

 856         {

 857             int nRed, nGreen, nBlue;    // nBlue,nRed  nGreen 相差大一点 nGreen 小一些

 858             //int high = 255;       

 859             int redLow = 160;

 860             int greenLow = 100;

 861             int blueLow = 160;

 862             nRed = random.Next(redLow);

 863             nGreen = random.Next(greenLow);

 864             nBlue = random.Next(blueLow);

 865             Color color = Color.FromArgb(nRed, nGreen, nBlue);

 866             return color;

 867         }

 868 

 869         /// <summary>

 870         /// 生成随机浅颜色

 871         /// </summary>

 872         /// <returns>randomColor</returns>

 873         public Color GetRandomLightColor()

 874         {

 875             int nRed, nGreen, nBlue;    //越大颜色越浅

 876             int low = 180;           //色彩的下限

 877             int high = 255;          //色彩的上限      

 878             nRed = random.Next(high) % (high - low) + low;

 879             nGreen = random.Next(high) % (high - low) + low;

 880             nBlue = random.Next(high) % (high - low) + low;

 881             Color color = Color.FromArgb(nRed, nGreen, nBlue);

 882             return color;

 883         }

 884         /// <summary>

 885         /// 生成随机颜色值

 886         /// </summary>

 887         /// <returns></returns>

 888         public Color GetRandomColor()

 889         {

 890             int nRed, nGreen, nBlue;    //越大颜色越浅

 891             int low = 10;           //色彩的下限

 892             int high = 255;          //色彩的上限    

 893             nRed = random.Next(high) % (high - low) + low;

 894             nGreen = random.Next(high) % (high - low) + low;

 895             nBlue = random.Next(high) % (high - low) + low;

 896             Color color = Color.FromArgb(nRed, nGreen, nBlue);

 897             return color;

 898         }

 899         /// <summary>

 900         /// 获取与当前颜色值相加后的颜色

 901         /// </summary>

 902         /// <param name="c"></param>

 903         /// <returns></returns>

 904         public Color GetLightColor(Color c, Int32 value)

 905         {

 906             int nRed = c.R, nGreen = c.G, nBlue = c.B;    //越大颜色越浅

 907             if (nRed + value < 255 && nRed + value > 0)

 908             {

 909                 nRed = c.R + 40;

 910             }

 911             if (nGreen + value < 255 && nGreen + value > 0)

 912             {

 913                 nGreen = c.G + 40;

 914             }

 915             if (nBlue + value < 255 && nBlue + value > 0)

 916             {

 917                 nBlue = c.B + 40;

 918             }

 919             Color color = Color.FromArgb(nRed, nGreen, nBlue);

 920             return color;

 921         }

 922         #endregion

 923 

 924         #region 合并图片

 925         /// <summary>       

 926         /// 合并图片        

 927         /// </summary>        

 928         /// <param name="maps"></param>        

 929         /// <returns></returns>        

 930         private Bitmap MergerImg(params Bitmap[] maps)

 931         {

 932             int i = maps.Length;

 933             if (i == 0)

 934                 throw new Exception("图片数不能够为0");

 935             //创建要显示的图片对象,根据参数的个数设置宽度            

 936             Bitmap backgroudImg = new Bitmap(i * 12, 16);

 937             Graphics g = Graphics.FromImage(backgroudImg);

 938             //清除画布,背景设置为白色            

 939             g.Clear(System.Drawing.Color.White);

 940             for (int j = 0; j < i; j++)

 941             {

 942                 //g.DrawImage(maps[j], j * 11, 0, maps[j].Width, maps[j].Height);

 943                 g.DrawImageUnscaled(maps[j], 0, 0);

 944             }

 945             g.Dispose();

 946             return backgroudImg;

 947         }

 948         #endregion

 949 

 950         #region 生成不重复的随机数,该函数会消耗大量系统资源

 951         /// <summary>

 952         /// 生成不重复的随机数,该函数会消耗大量系统资源

 953         /// </summary>

 954         /// <returns></returns>

 955         private static int GetRandomSeed()

 956         {

 957             byte[] bytes = new byte[4];

 958             System.Security.Cryptography.RNGCryptoServiceProvider rng = new System.Security.Cryptography.RNGCryptoServiceProvider();

 959             rng.GetBytes(bytes);

 960             return BitConverter.ToInt32(bytes, 0);

 961         }

 962         #endregion

 963 

 964         #region 缩放图片

 965         /// <summary>

 966         /// 缩放图片

 967         /// </summary>

 968         /// <param name="bmp">原始Bitmap</param>

 969         /// <param name="newW">新的宽度</param>

 970         /// <param name="newH">新的高度</param>

 971         /// <param name="Mode">缩放质量</param>

 972         /// <returns>处理以后的图片</returns>

 973         public static Bitmap KiResizeImage(Bitmap bmp, int newW, int newH, InterpolationMode Mode)

 974         {

 975             try

 976             {

 977                 Bitmap b = new Bitmap(newW, newH);

 978                 Graphics g = Graphics.FromImage(b);

 979                 // 插值算法的质量

 980                 g.InterpolationMode = Mode;

 981                 g.DrawImage(bmp, new Rectangle(0, 0, newW, newH), new Rectangle(0, 0, bmp.Width, bmp.Height), GraphicsUnit.Pixel);

 982                 g.Dispose();

 983                 return b;

 984             }

 985             catch

 986             {

 987                 return null;

 988             }

 989         }

 990         #endregion

 991 

 992         #region 绘制圆角矩形

 993         /// <summary>

 994         /// C# GDI+ 绘制圆角矩形

 995         /// </summary>

 996         /// <param name="g">Graphics 对象</param>

 997         /// <param name="rectangle">Rectangle 对象,圆角矩形区域</param>

 998         /// <param name="borderColor">边框颜色</param>

 999         /// <param name="borderWidth">边框宽度</param>

1000         /// <param name="r">圆角半径</param>

1001         private static void DrawRoundRectangle(Graphics g, Rectangle rectangle, Color borderColor, float borderWidth, int r)

1002         {

1003             // 如要使边缘平滑,请取消下行的注释

1004             g.SmoothingMode = SmoothingMode.HighQuality;

1005 

1006             // 由于边框也需要一定宽度,需要对矩形进行修正

1007             //rectangle = new Rectangle(rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height);

1008             Pen p = new Pen(borderColor, borderWidth);

1009             // 调用 getRoundRectangle 得到圆角矩形的路径,然后再进行绘制

1010             g.DrawPath(p, getRoundRectangle(rectangle, r));

1011         }

1012         #endregion

1013 

1014         #region 根据普通矩形得到圆角矩形的路径

1015         /// <summary>

1016         /// 根据普通矩形得到圆角矩形的路径

1017         /// </summary>

1018         /// <param name="rectangle">原始矩形</param>

1019         /// <param name="r">半径</param>

1020         /// <returns>图形路径</returns>

1021         private static GraphicsPath getRoundRectangle(Rectangle rectangle, int r)

1022         {

1023             int l = 2 * r;

1024             // 把圆角矩形分成八段直线、弧的组合,依次加到路径中

1025             GraphicsPath gp = new GraphicsPath();

1026             gp.AddLine(new Point(rectangle.X + r, rectangle.Y), new Point(rectangle.Right - r, rectangle.Y));

1027             gp.AddArc(new Rectangle(rectangle.Right - l, rectangle.Y, l, l), 270F, 90F);

1028 

1029             gp.AddLine(new Point(rectangle.Right, rectangle.Y + r), new Point(rectangle.Right, rectangle.Bottom - r));

1030             gp.AddArc(new Rectangle(rectangle.Right - l, rectangle.Bottom - l, l, l), 0F, 90F);

1031 

1032             gp.AddLine(new Point(rectangle.Right - r, rectangle.Bottom), new Point(rectangle.X + r, rectangle.Bottom));

1033             gp.AddArc(new Rectangle(rectangle.X, rectangle.Bottom - l, l, l), 90F, 90F);

1034 

1035             gp.AddLine(new Point(rectangle.X, rectangle.Bottom - r), new Point(rectangle.X, rectangle.Y + r));

1036             gp.AddArc(new Rectangle(rectangle.X, rectangle.Y, l, l), 180F, 90F);

1037             return gp;

1038         }

1039         #endregion

1040 

1041         #region 柔化

1042         ///<summary>

1043         /// 柔化

1044         /// </summary>

1045         /// <param name="b">原始图</param>

1046         /// <returns>输出图</returns>

1047         public static Bitmap KiBlur(Bitmap b)

1048         {

1049 

1050             if (b == null)

1051             {

1052                 return null;

1053             }

1054 

1055             int w = b.Width;

1056             int h = b.Height;

1057 

1058             try

1059             {

1060 

1061                 Bitmap bmpRtn = new Bitmap(w, h, PixelFormat.Format24bppRgb);

1062 

1063                 BitmapData srcData = b.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);

1064                 BitmapData dstData = bmpRtn.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb);

1065 

1066                 unsafe

1067                 {

1068                     byte* pIn = (byte*)srcData.Scan0.ToPointer();

1069                     byte* pOut = (byte*)dstData.Scan0.ToPointer();

1070                     int stride = srcData.Stride;

1071                     byte* p;

1072 

1073                     for (int y = 0; y < h; y++)

1074                     {

1075                         for (int x = 0; x < w; x++)

1076                         {

1077                             //取周围9点的值

1078                             if (x == 0 || x == w - 1 || y == 0 || y == h - 1)

1079                             {

1080                                 //不做

1081                                 pOut[0] = pIn[0];

1082                                 pOut[1] = pIn[1];

1083                                 pOut[2] = pIn[2];

1084                             }

1085                             else

1086                             {

1087                                 int r1, r2, r3, r4, r5, r6, r7, r8, r9;

1088                                 int g1, g2, g3, g4, g5, g6, g7, g8, g9;

1089                                 int b1, b2, b3, b4, b5, b6, b7, b8, b9;

1090 

1091                                 float vR, vG, vB;

1092 

1093                                 //左上

1094                                 p = pIn - stride - 3;

1095                                 r1 = p[2];

1096                                 g1 = p[1];

1097                                 b1 = p[0];

1098 

1099                                 //正上

1100                                 p = pIn - stride;

1101                                 r2 = p[2];

1102                                 g2 = p[1];

1103                                 b2 = p[0];

1104 

1105                                 //右上

1106                                 p = pIn - stride + 3;

1107                                 r3 = p[2];

1108                                 g3 = p[1];

1109                                 b3 = p[0];

1110 

1111                                 //左侧

1112                                 p = pIn - 3;

1113                                 r4 = p[2];

1114                                 g4 = p[1];

1115                                 b4 = p[0];

1116 

1117                                 //右侧

1118                                 p = pIn + 3;

1119                                 r5 = p[2];

1120                                 g5 = p[1];

1121                                 b5 = p[0];

1122 

1123                                 //右下

1124                                 p = pIn + stride - 3;

1125                                 r6 = p[2];

1126                                 g6 = p[1];

1127                                 b6 = p[0];

1128 

1129                                 //正下

1130                                 p = pIn + stride;

1131                                 r7 = p[2];

1132                                 g7 = p[1];

1133                                 b7 = p[0];

1134 

1135                                 //右下

1136                                 p = pIn + stride + 3;

1137                                 r8 = p[2];

1138                                 g8 = p[1];

1139                                 b8 = p[0];

1140 

1141                                 //自己

1142                                 p = pIn;

1143                                 r9 = p[2];

1144                                 g9 = p[1];

1145                                 b9 = p[0];

1146 

1147                                 vR = (float)(r1 + r2 + r3 + r4 + r5 + r6 + r7 + r8 + r9);

1148                                 vG = (float)(g1 + g2 + g3 + g4 + g5 + g6 + g7 + g8 + g9);

1149                                 vB = (float)(b1 + b2 + b3 + b4 + b5 + b6 + b7 + b8 + b9);

1150 

1151                                 vR /= 9;

1152                                 vG /= 9;

1153                                 vB /= 9;

1154 

1155                                 pOut[0] = (byte)vB;

1156                                 pOut[1] = (byte)vG;

1157                                 pOut[2] = (byte)vR;

1158 

1159                             }

1160 

1161                             pIn += 3;

1162                             pOut += 3;

1163                         }// end of x

1164 

1165                         pIn += srcData.Stride - w * 3;

1166                         pOut += srcData.Stride - w * 3;

1167                     } // end of y

1168                 }

1169 

1170                 b.UnlockBits(srcData);

1171                 bmpRtn.UnlockBits(dstData);

1172 

1173                 return bmpRtn;

1174             }

1175             catch

1176             {

1177                 return null;

1178             }

1179 

1180         } // end of KiBlur

1181         #endregion

1182 

1183         #region 滤镜

1184         /// <summary>

1185         /// 红色滤镜

1186         /// </summary>

1187         /// <param name="bitmap">Bitmap</param>

1188         /// <param name="threshold">阀值 -255~255</param>

1189         /// <returns></returns>

1190         public System.Drawing.Bitmap AdjustToRed(System.Drawing.Bitmap bitmap, int threshold)

1191         {

1192             for (int y = 0; y < bitmap.Height; y++)

1193             {

1194                 for (int x = 0; x < bitmap.Width; x++)

1195                 {

1196                     // 取得每一個 pixel

1197                     var pixel = bitmap.GetPixel(x, y);

1198                     var pR = pixel.R + threshold;

1199                     pR = Math.Max(pR, 0);

1200                     pR = Math.Min(255, pR);

1201                     // 將改過的 RGB 寫回

1202                     // 只寫入紅色的值 , G B 都放零

1203                     System.Drawing.Color newColor = System.Drawing.Color.FromArgb(pixel.A, pR, 0, 0);

1204                     bitmap.SetPixel(x, y, newColor);

1205                 }

1206             }

1207             // 回傳結果

1208             return bitmap;

1209         }

1210 

1211         /// <summary>

1212         /// 绿色滤镜

1213         /// </summary>

1214         /// <param name="bitmap">一个图片实例</param>

1215         /// <param name="threshold">阀值 -255~+255</param>

1216         /// <returns></returns>

1217         public System.Drawing.Bitmap AdjustToGreen(System.Drawing.Bitmap bitmap, int threshold)

1218         {

1219             for (int y = 0; y < bitmap.Height; y++)

1220             {

1221                 for (int x = 0; x < bitmap.Width; x++)

1222                 {

1223                     // 取得每一個 pixel

1224                     var pixel = bitmap.GetPixel(x, y);

1225                     //判斷是否超過255 如果超過就是255 

1226                     var pG = pixel.G + threshold;

1227                     //如果小於0就為0

1228                     if (pG > 255) pG = 255;

1229                     if (pG < 0) pG = 0;

1230                     // 將改過的 RGB 寫回

1231                     // 只寫入綠色的值 , R B 都放零

1232                     System.Drawing.Color newColor = System.Drawing.Color.FromArgb(pixel.A, 0, pG, 0);

1233                     bitmap.SetPixel(x, y, newColor);

1234                 }

1235             }

1236             // 回傳結果

1237             return bitmap;

1238         }

1239         /// <summary>

1240         /// 蓝色滤镜

1241         /// </summary>

1242         /// <param name="bitmap">一个图片实例</param>

1243         /// <param name="threshold">阀值 -255~255</param>

1244         /// <returns></returns>

1245         public System.Drawing.Bitmap AdjustToBlue(System.Drawing.Bitmap bitmap, int threshold)

1246         {

1247             for (int y = 0; y < bitmap.Height; y++)

1248             {

1249                 for (int x = 0; x < bitmap.Width; x++)

1250                 {

1251                     // 取得每一個 pixel

1252                     var pixel = bitmap.GetPixel(x, y);

1253                     //判斷是否超過255 如果超過就是255 

1254                     var pB = pixel.B + threshold;

1255                     //如果小於0就為0

1256                     if (pB > 255) pB = 255;

1257                     if (pB < 0) pB = 0;

1258                     // 將改過的 RGB 寫回

1259                     // 只寫入藍色的值 , R G 都放零

1260                     System.Drawing.Color newColor = System.Drawing.Color.FromArgb(pixel.A, 0, 0, pB);

1261                     bitmap.SetPixel(x, y, newColor);

1262                 }

1263             }

1264             // 回傳結果

1265             return bitmap;

1266         }

1267         /// <summary>

1268         /// 调整 RGB 色调

1269         /// </summary>

1270         /// <param name="bitmap"></param>

1271         /// <param name="thresholdRed">红色阀值</param>

1272         /// <param name="thresholdBlue">蓝色阀值</param>

1273         /// <param name="thresholdGreen">绿色阀值</param>

1274         /// <returns></returns>

1275         public System.Drawing.Bitmap AdjustToCustomColor(System.Drawing.Bitmap bitmap, int thresholdRed, int thresholdGreen, int thresholdBlue)

1276         {

1277             for (int y = 0; y < bitmap.Height; y++)

1278             {

1279                 for (int x = 0; x < bitmap.Width; x++)

1280                 {

1281                     // 取得每一個 pixel

1282                     var pixel = bitmap.GetPixel(x, y);

1283                     //判斷是否超過255 如果超過就是255 

1284                     var pG = pixel.G + thresholdGreen;

1285                     //如果小於0就為0

1286                     if (pG > 255) pG = 255;

1287                     if (pG < 0) pG = 0;

1288                     //判斷是否超過255 如果超過就是255 

1289                     var pR = pixel.R + thresholdRed;

1290                     //如果小於0就為0

1291                     if (pR > 255) pR = 255;

1292                     if (pR < 0) pR = 0;

1293                     //判斷是否超過255 如果超過就是255 

1294                     var pB = pixel.B + thresholdBlue;

1295                     //如果小於0就為0

1296                     if (pB > 255) pB = 255;

1297                     if (pB < 0) pB = 0;

1298                     // 將改過的 RGB 寫回

1299                     // 只寫入綠色的值 , R B 都放零

1300                     System.Drawing.Color newColor = System.Drawing.Color.FromArgb(pixel.A, pR, pG, pB);

1301                     bitmap.SetPixel(x, y, newColor);

1302                 }

1303             }

1304             return bitmap;

1305         }

1306         #endregion

1307 

1308         #region 图片去色(图片黑白化)

1309         /// <summary>

1310         /// 图片去色(图片黑白化)

1311         /// </summary>

1312         /// <param name="original">一个需要处理的图片</param>

1313         /// <returns></returns>

1314         public static Bitmap MakeGrayscale(Bitmap original)

1315         {

1316             //create a blank bitmap the same size as original

1317             Bitmap newBitmap = new Bitmap(original.Width, original.Height);

1318 

1319             //get a graphics object from the new image

1320             Graphics g = Graphics.FromImage(newBitmap);

1321             g.SmoothingMode = SmoothingMode.HighQuality;

1322             //create the grayscale ColorMatrix

1323             ColorMatrix colorMatrix = new ColorMatrix(new float[][] 

1324                           {

1325                              new float[] {.3f, .3f, .3f, 0, 0},

1326                              new float[] {.59f, .59f, .59f, 0, 0},

1327                              new float[] {.11f, .11f, .11f, 0, 0},

1328                              new float[] {0, 0, 0, 1, 0},

1329                              new float[] {0, 0, 0, 0, 1}

1330                           });

1331 

1332             //create some image attributes

1333             ImageAttributes attributes = new ImageAttributes();

1334 

1335             //set the color matrix attribute

1336             attributes.SetColorMatrix(colorMatrix);

1337 

1338             //draw the original image on the new image

1339             //using the grayscale color matrix

1340             g.DrawImage(original, new Rectangle(0, 0, original.Width, original.Height),

1341                0, 0, original.Width, original.Height, GraphicsUnit.Pixel, attributes);

1342 

1343             //dispose the Graphics object

1344             g.Dispose();

1345             return newBitmap;

1346         }

1347         #endregion

1348 

1349         #region 增加或減少亮度

1350         /// <summary>

1351         /// 增加或減少亮度

1352         /// </summary>

1353         /// <param name="img">System.Drawing.Image Source </param>

1354         /// <param name="valBrightness">0~255</param>

1355         /// <returns></returns>

1356         public System.Drawing.Bitmap AdjustBrightness(System.Drawing.Image img, int valBrightness)

1357         {

1358             // 讀入欲轉換的圖片並轉成為 Bitmap

1359             System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(img);

1360 

1361             for (int y = 0; y < bitmap.Height; y++)

1362             {

1363                 for (int x = 0; x < bitmap.Width; x++)

1364                 {

1365                     // 取得每一個 pixel

1366                     var pixel = bitmap.GetPixel(x, y);

1367 

1368                     // 判斷 如果處理過後 255 就設定為 255 如果小於則設定為 0

1369                     var pR = ((pixel.R + valBrightness > 255) ? 255 : pixel.R + valBrightness) < 0 ? 0 : ((pixel.R + valBrightness > 255) ? 255 : pixel.R + valBrightness);

1370                     var pG = ((pixel.G + valBrightness > 255) ? 255 : pixel.G + valBrightness) < 0 ? 0 : ((pixel.G + valBrightness > 255) ? 255 : pixel.G + valBrightness);

1371                     var pB = ((pixel.B + valBrightness > 255) ? 255 : pixel.B + valBrightness) < 0 ? 0 : ((pixel.B + valBrightness > 255) ? 255 : pixel.B + valBrightness);

1372 

1373                     // 將改過的 RGB 寫回

1374                     System.Drawing.Color newColor = System.Drawing.Color.FromArgb(pixel.A, pR, pG, pB);

1375 

1376                     bitmap.SetPixel(x, y, newColor);

1377 

1378                 }

1379             }

1380             // 回傳結果

1381             return bitmap;

1382         }

1383         #endregion

1384 

1385         #region 浮雕效果

1386         /// <summary>

1387         /// 浮雕效果

1388         /// </summary>

1389         /// <param name="src">一个图片实例</param>

1390         /// <returns></returns>

1391         public Bitmap AdjustToStone(Bitmap src)

1392         {

1393             // 依照 Format24bppRgb 每三个表示一 Pixel 0: 蓝 1: 绿 2: 红

1394             BitmapData bitmapData = src.LockBits(new Rectangle(0, 0, src.Width, src.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

1395 

1396             unsafe

1397             {

1398                 // 抓住第一个 Pixel 第一个数值

1399                 byte* p = (byte*)(void*)bitmapData.Scan0;

1400 

1401                 // 跨步值 - 宽度 *3 可以算出畸零地 之后跳到下一行

1402                 int nOffset = bitmapData.Stride - src.Width * 3;

1403 

1404                 for (int y = 0; y < src.Height; ++y)

1405                 {

1406                     for (int x = 0; x < src.Width; ++x)

1407                     {

1408                         // 为了理解方便 所以特地在命名

1409                         int r, g, b;

1410                         // 先取得下一个 Pixel

1411                         var q = p + 3;

1412                         r = Math.Abs(p[2] - q[2] + 128);

1413                         r = r < 0 ? 0 : r;

1414                         r = r > 255 ? 255 : r;

1415                         p[2] = (byte)r;

1416 

1417                         g = Math.Abs(p[1] - q[1] + 128);

1418                         g = g < 0 ? 0 : g;

1419                         g = g > 255 ? 255 : g;

1420                         p[1] = (byte)g;

1421 

1422                         b = Math.Abs(p[0] - q[0] + 128);

1423                         b = b < 0 ? 0 : b;

1424                         b = b > 255 ? 255 : b;

1425                         p[0] = (byte)b;

1426 

1427                         // 跳去下一个 Pixel

1428                         p += 3;

1429 

1430                     }

1431                     // 跨越畸零地

1432                     p += nOffset;

1433                 }

1434             }

1435             src.UnlockBits(bitmapData);

1436             return src;

1437         }

1438         #endregion

1439 

1440         #region 水波纹效果

1441         /// <summary>

1442         /// 水波纹效果

1443         /// </summary>

1444         /// <param name="src"></param>

1445         /// <param name="nWave">坡度</param>

1446         /// www.it165.net

1447         /// <returns></returns>

1448         public Bitmap AdjustRippleEffect(Bitmap src, short nWave)

1449         {

1450 

1451             int nWidth = src.Width;

1452             int nHeight = src.Height;

1453 

1454             // 透过公式进行水波纹的採样

1455 

1456             PointF[,] fp = new PointF[nWidth, nHeight];

1457             

1458             Point[,] pt = new Point[nWidth, nHeight];

1459 

1460             Point mid = new Point();

1461             mid.X = nWidth / 2;

1462             mid.Y = nHeight / 2;

1463 

1464             double newX, newY;

1465             double xo, yo;

1466 

1467             //先取样将水波纹座标跟RGB取出

1468             for (int x = 0; x < nWidth; ++x)

1469                 for (int y = 0; y < nHeight; ++y)

1470                 {

1471                     xo = ((double)nWave * Math.Sin(2.0 * 3.1415 * (float)y / 128.0));

1472                     yo = ((double)nWave * Math.Cos(2.0 * 3.1415 * (float)x / 128.0));

1473 

1474                     newX = (x + xo);

1475                     newY = (y + yo);

1476 

1477                     if (newX > 0 && newX < nWidth)

1478                     {

1479                         fp[x, y].X = (float)newX;

1480                         pt[x, y].X = (int)newX;

1481                     }

1482                     else

1483                     {

1484                         fp[x, y].X = (float)0.0;

1485                         pt[x, y].X = 0;

1486                     }

1487 

1488 

1489                     if (newY > 0 && newY < nHeight)

1490                     {

1491                         fp[x, y].Y = (float)newY;

1492                         pt[x, y].Y = (int)newY;

1493                     }

1494                     else

1495                     {

1496                         fp[x, y].Y = (float)0.0;

1497                         pt[x, y].Y = 0;

1498                     }

1499                 }

1500 

1501 

1502             //进行合成

1503             Bitmap bSrc = (Bitmap)src.Clone();

1504 

1505             // 依照 Format24bppRgb 每三个表示一 Pixel 0: 蓝 1: 绿 2: 红

1506             BitmapData bitmapData = src.LockBits(new Rectangle(0, 0, src.Width, src.Height), ImageLockMode.ReadWrite,

1507                                            PixelFormat.Format24bppRgb);

1508             BitmapData bmSrc = bSrc.LockBits(new Rectangle(0, 0, bSrc.Width, bSrc.Height), ImageLockMode.ReadWrite,

1509                                              PixelFormat.Format24bppRgb);

1510 

1511             int scanline = bitmapData.Stride;

1512 

1513             IntPtr Scan0 = bitmapData.Scan0;

1514             IntPtr SrcScan0 = bmSrc.Scan0;

1515 

1516             unsafe

1517             {

1518                 byte* p = (byte*)(void*)Scan0;

1519                 byte* pSrc = (byte*)(void*)SrcScan0;

1520 

1521                 int nOffset = bitmapData.Stride - src.Width * 3;

1522 

1523                 int xOffset, yOffset;

1524 

1525                 for (int y = 0; y < nHeight; ++y)

1526                 {

1527                     for (int x = 0; x < nWidth; ++x)

1528                     {

1529                         xOffset = pt[x, y].X;

1530                         yOffset = pt[x, y].Y;

1531 

1532                         if (yOffset >= 0 && yOffset < nHeight && xOffset >= 0 && xOffset < nWidth)

1533                         {

1534                             p[0] = pSrc[(yOffset * scanline) + (xOffset * 3)];

1535                             p[1] = pSrc[(yOffset * scanline) + (xOffset * 3) + 1];

1536                             p[2] = pSrc[(yOffset * scanline) + (xOffset * 3) + 2];

1537                         }

1538 

1539                         p += 3;

1540                     }

1541                     p += nOffset;

1542                 }

1543             }

1544 

1545             src.UnlockBits(bitmapData);

1546             bSrc.UnlockBits(bmSrc);

1547 

1548             return src;

1549         }

1550         #endregion

1551 

1552         #region 调整曝光度值

1553         /// <summary>

1554         /// 调整曝光度值

1555         /// </summary>

1556         /// <param name="src">原图</param>

1557         /// <param name="r"></param>

1558         /// <param name="g"></param>

1559         /// <param name="b"></param>

1560         /// <returns></returns>

1561         public Bitmap AdjustGamma(Bitmap src, double r, double g, double b)

1562         {

1563             // 判断是不是在0.2~5 之间

1564             r = Math.Min(Math.Max(0.2, r), 5);

1565             g = Math.Min(Math.Max(0.2, g), 5);

1566             b = Math.Min(Math.Max(0.2, b), 5);

1567 

1568             // 依照 Format24bppRgb 每三个表示一 Pixel 0: 蓝 1: 绿 2: 红

1569             BitmapData bitmapData = src.LockBits(new Rectangle(0, 0, src.Width, src.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

1570 

1571             unsafe

1572             {

1573                 // 抓住第一个 Pixel 第一个数值

1574                 byte* p = (byte*)(void*)bitmapData.Scan0;

1575 

1576                 // 跨步值 - 宽度 *3 可以算出畸零地 之后跳到下一行

1577                 int nOffset = bitmapData.Stride - src.Width * 3;

1578 

1579                 for (int y = 0; y < src.Height; y++)

1580                 {

1581                     for (int x = 0; x < src.Width; x++)

1582                     {

1583                         p[2] = (byte)Math.Min(255, (int)((255.0 * Math.Pow(p[2] / 255.0, 1.0 / r)) + 0.5));

1584                         p[1] = (byte)Math.Min(255, (int)((255.0 * Math.Pow(p[1] / 255.0, 1.0 / g)) + 0.5));

1585                         p[0] = (byte)Math.Min(255, (int)((255.0 * Math.Pow(p[0] / 255.0, 1.0 / b)) + 0.5));

1586 

1587 

1588                         // 跳去下一个 Pixel

1589                         p += 3;

1590 

1591                     }

1592                     // 跨越畸零地

1593                     p += nOffset;

1594                 }

1595             }

1596             src.UnlockBits(bitmapData);

1597             return src;

1598 

1599         }

1600         #endregion

1601 

1602         #region 高对比,对过深的颜色调浅,过浅的颜色调深。

1603         /// <summary>

1604         /// 高对比,对过深的颜色调浅,过浅的颜色调深。

1605         /// </summary>

1606         /// <param name="src"></param>

1607         /// <param name="effectThreshold"> 高对比程度 -100~100</param>

1608         /// <returns></returns>

1609         public Bitmap Contrast(Bitmap src, float effectThreshold)

1610         {

1611 

1612             // 依照 Format24bppRgb 每三个表示一 Pixel 0: 蓝 1: 绿 2: 红

1613             BitmapData bitmapData = src.LockBits(new Rectangle(0, 0, src.Width, src.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

1614 

1615             // 判断是否在 -100~100

1616             effectThreshold = effectThreshold < -100 ? -100 : effectThreshold;

1617             effectThreshold = effectThreshold > 100 ? 100 : effectThreshold;

1618 

1619             effectThreshold = (float)((100.0 + effectThreshold) / 100.0);

1620             effectThreshold *= effectThreshold;

1621 

1622             unsafe

1623             {

1624                 // 抓住第一个 Pixel 第一个数值 www.it165.net

1625                 byte* p = (byte*)(void*)bitmapData.Scan0;

1626 

1627                 // 跨步值 - 宽度 *3 可以算出畸零地 之后跳到下一行

1628                 int nOffset = bitmapData.Stride - src.Width * 3;

1629 

1630 

1631 

1632                 for (int y = 0; y < src.Height; y++)

1633                 {

1634                     for (int x = 0; x < src.Width; x++)

1635                     {

1636                         double buffer = 0;

1637 

1638 

1639                         // 公式  (Red/255)-0.5= 偏离中间值程度

1640                         // ((偏离中间值程度 * 影响范围)+0.4 ) * 255

1641                         buffer = ((((p[2] / 255.0) - 0.5) * effectThreshold) + 0.5) * 255.0;

1642                         buffer = buffer > 255 ? 255 : buffer;

1643                         buffer = buffer < 0 ? 0 : buffer;

1644                         p[2] = (byte)buffer;

1645 

1646                         buffer = ((((p[1] / 255.0) - 0.5) * effectThreshold) + 0.5) * 255.0;

1647                         buffer = buffer > 255 ? 255 : buffer;

1648                         buffer = buffer < 0 ? 0 : buffer;

1649                         p[1] = (byte)buffer;

1650 

1651 

1652                         buffer = ((((p[0] / 255.0) - 0.5) * effectThreshold) + 0.5) * 255.0;

1653                         buffer = buffer > 255 ? 255 : buffer;

1654                         buffer = buffer < 0 ? 0 : buffer;

1655                         p[0] = (byte)buffer;

1656 

1657 

1658 

1659 

1660                         // 跳去下一个 Pixel

1661                         p += 3;

1662 

1663                     }

1664                     // 跨越畸零地

1665                     p += nOffset;

1666                 }

1667             }

1668             src.UnlockBits(bitmapData);

1669             return src;

1670 

1671 

1672         }

1673         #endregion

1674 

1675         #region 对图片进行雾化效果

1676         /// <summary>

1677         /// 对图片进行雾化效果

1678         /// </summary>

1679         /// <param name="bmp"></param>

1680         /// <returns></returns>

1681         public Bitmap Atomization(Bitmap bmp)

1682         {

1683 

1684             int Height = bmp.Height;

1685             int Width = bmp.Width;

1686             Bitmap newBitmap = new Bitmap(Width, Height);

1687             Bitmap oldBitmap = bmp;

1688             Color pixel;

1689             for (int x = 1; x < Width - 1; x++)

1690             {

1691                 for (int y = 1; y < Height - 1; y++)

1692                 {

1693                     Random MyRandom = new Random( Guid.NewGuid().GetHashCode());

1694                     int k = MyRandom.Next(123456);

1695                     //像素块大小

1696                     int dx = x + k % 19;

1697                     int dy = y + k % 19;

1698                     if (dx >= Width)

1699                         dx = Width - 1;

1700                     if (dy >= Height)

1701                         dy = Height - 1;

1702                     pixel = oldBitmap.GetPixel(dx, dy);

1703                     newBitmap.SetPixel(x, y, pixel);

1704                 }

1705             }

1706             return newBitmap;

1707         }

1708         #endregion

1709 

1710     } //END Class DrawValidationCode

1711     #endregion

1712 

1713     #region 高斯模糊算法

1714     /// <summary>

1715     /// 高斯模糊算法

1716     /// </summary>

1717     public class Gaussian

1718     {

1719         public static double[,] Calculate1DSampleKernel(double deviation, int size)

1720         {

1721             double[,] ret = new double[size, 1];

1722             double sum = 0;

1723             int half = size / 2;

1724             for (int i = 0; i < size; i++)

1725             {

1726                 ret[i, 0] = 1 / (Math.Sqrt(2 * Math.PI) * deviation) * Math.Exp(-(i - half) * (i - half) / (2 * deviation * deviation));

1727                 sum += ret[i, 0];

1728             }

1729             return ret;

1730         }

1731         public static double[,] Calculate1DSampleKernel(double deviation)

1732         {

1733             int size = (int)Math.Ceiling(deviation * 3) * 2 + 1;

1734             return Calculate1DSampleKernel(deviation, size);

1735         }

1736         public static double[,] CalculateNormalized1DSampleKernel(double deviation)

1737         {

1738             return NormalizeMatrix(Calculate1DSampleKernel(deviation));

1739         }

1740         public static double[,] NormalizeMatrix(double[,] matrix)

1741         {

1742             double[,] ret = new double[matrix.GetLength(0), matrix.GetLength(1)];

1743             double sum = 0;

1744             for (int i = 0; i < ret.GetLength(0); i++)

1745             {

1746                 for (int j = 0; j < ret.GetLength(1); j++)

1747                     sum += matrix[i, j];

1748             }

1749             if (sum != 0)

1750             {

1751                 for (int i = 0; i < ret.GetLength(0); i++)

1752                 {

1753                     for (int j = 0; j < ret.GetLength(1); j++)

1754                         ret[i, j] = matrix[i, j] / sum;

1755                 }

1756             }

1757             return ret;

1758         }

1759         public static double[,] GaussianConvolution(double[,] matrix, double deviation)

1760         {

1761             double[,] kernel = CalculateNormalized1DSampleKernel(deviation);

1762             double[,] res1 = new double[matrix.GetLength(0), matrix.GetLength(1)];

1763             double[,] res2 = new double[matrix.GetLength(0), matrix.GetLength(1)];

1764             //x-direction

1765             for (int i = 0; i < matrix.GetLength(0); i++)

1766             {

1767                 for (int j = 0; j < matrix.GetLength(1); j++)

1768                     res1[i, j] = processPoint(matrix, i, j, kernel, 0);

1769             }

1770             //y-direction

1771             for (int i = 0; i < matrix.GetLength(0); i++)

1772             {

1773                 for (int j = 0; j < matrix.GetLength(1); j++)

1774                     res2[i, j] = processPoint(res1, i, j, kernel, 1);

1775             }

1776             return res2;

1777         }

1778         private static double processPoint(double[,] matrix, int x, int y, double[,] kernel, int direction)

1779         {

1780             double res = 0;

1781             int half = kernel.GetLength(0) / 2;

1782             for (int i = 0; i < kernel.GetLength(0); i++)

1783             {

1784                 int cox = direction == 0 ? x + i - half : x;

1785                 int coy = direction == 1 ? y + i - half : y;

1786                 if (cox >= 0 && cox < matrix.GetLength(0) && coy >= 0 && coy < matrix.GetLength(1))

1787                 {

1788                     res += matrix[cox, coy] * kernel[i, 0];

1789                 }

1790             }

1791             return res;

1792         }

1793         /// <summary>

1794         /// 对颜色值进行灰色处理

1795         /// </summary>

1796         /// <param name="cr"></param>

1797         /// <returns></returns>

1798         private Color grayscale(Color cr)

1799         {

1800             return Color.FromArgb(cr.A, (int)(cr.R * .3 + cr.G * .59 + cr.B * 0.11),

1801                (int)(cr.R * .3 + cr.G * .59 + cr.B * 0.11),

1802               (int)(cr.R * .3 + cr.G * .59 + cr.B * 0.11));

1803         }

1804         /// <summary>

1805         /// 对图片进行高斯模糊

1806         /// </summary>

1807         /// <param name="d">模糊数值,数值越大模糊越很</param>

1808         /// <param name="image">一个需要处理的图片</param>

1809         /// <returns></returns>

1810         public Bitmap FilterProcessImage(double d, Bitmap image)

1811         {

1812             Bitmap ret = new Bitmap(image.Width, image.Height);

1813             Double[,] matrixR = new Double[image.Width, image.Height];

1814             Double[,] matrixG = new Double[image.Width, image.Height];

1815             Double[,] matrixB = new Double[image.Width, image.Height];

1816             for (int i = 0; i < image.Width; i++)

1817             {

1818                 for (int j = 0; j < image.Height; j++)

1819                 {

1820                     //matrix[i, j] = grayscale(image.GetPixel(i, j)).R;

1821                     matrixR[i, j] = image.GetPixel(i, j).R;

1822                     matrixG[i, j] = image.GetPixel(i, j).G;

1823                     matrixB[i, j] = image.GetPixel(i, j).B;

1824                 }

1825             }

1826             matrixR = Gaussian.GaussianConvolution(matrixR, d);

1827             matrixG = Gaussian.GaussianConvolution(matrixG, d);

1828             matrixB = Gaussian.GaussianConvolution(matrixB, d);

1829             for (int i = 0; i < image.Width; i++)

1830             {

1831                 for (int j = 0; j < image.Height; j++)

1832                 {

1833                     Int32 R = (int)Math.Min(255, matrixR[i, j]);

1834                     Int32 G = (int)Math.Min(255, matrixG[i, j]);

1835                     Int32 B = (int)Math.Min(255, matrixB[i, j]);

1836                     ret.SetPixel(i, j, Color.FromArgb(R, G, B));

1837                 }

1838             }

1839             return ret;

1840         }

1841 

1842     }

1843     #endregion

1844 }
验证码生成类

 

你可能感兴趣的:(验证码)