先看效果:
相对于 Web(B/S)生成模糊验证码的几种方式(转载) :
(1)去掉依赖session的代码,去掉继承自Page类。
(2)修改了贝塞尔曲线的线宽。
(3)优化了超过默认4位验证码报错问题。
asp.net mvc 调用代码:
public ActionResult yanzhengma3() { DrawValidationCode objDrawValidationCode = new DrawValidationCode(); objDrawValidationCode.ValidationCodeCount = 50;//验证码字符个数 objDrawValidationCode.IsTwist = true;//是否扭曲 objDrawValidationCode.IsRandString = true;//随机早点字符 objDrawValidationCode.IsPixel = true;//随机噪点 objDrawValidationCode.RandomStringCount = 8; // //objDrawValidationCode.RandomStringFontSize = 30; objDrawValidationCode.FontMinSize = 35;//验证码字体的大小的最小值 objDrawValidationCode.FontMaxSize = 40; //验证码字体的大小的最小值 //objDrawValidationCode.GaussianDeviation = 3; //默认0,不使用高斯模糊算法处理图像。 //objDrawValidationCode.BrightnessValue = 5; //明暗度,默认0,是使用明暗度算法处理图像 objDrawValidationCode.LineCount = 0; //默认3条。 objDrawValidationCode.BezierCount = 2;//默认3条。 using (MemoryStream ms = new MemoryStream()) { objDrawValidationCode.CreateImage(ms); return File(ms.GetBuffer(), "image/jpeg"); } }
验证码类全部代码(已亲自测试)
1 using System; 2 using System.Collections.Generic; 3 using System.Drawing; 4 using System.Drawing.Drawing2D; 5 using System.Drawing.Imaging; 6 using System.Drawing.Text; 7 using System.IO; 8 using System.Linq; 9 using System.Text; 10 11 namespace JBM.Web.util 12 { 13 #region 验证码生成类 14 /// <summary> 15 /// 验证码生成类 16 /// </summary> 17 public class DrawValidationCode 18 { 19 #region 定义和初始化配置字段 20 //用户存取验证码字符串 21 private string validationCode = String.Empty; 22 /// <summary> 23 /// 获取系统生成的随机验证码 24 /// </summary> 25 public String ValidationCode 26 { 27 get { return validationCode; } 28 } 29 private Int32 validationCodeCount = 4; 30 /// <summary> 31 /// 获取和设置验证码字符串的长度 32 /// </summary> 33 public Int32 ValidationCodeCount 34 { 35 get { return validationCodeCount; } 36 set { validationCodeCount = value; } 37 } 38 Graphics dc = null; 39 private int bgWidth = 130; 40 /// <summary> 41 /// 验证码的宽度,默认为80 42 /// </summary> 43 public Int32 Width 44 { 45 get { return bgWidth; } 46 set { bgWidth = value; } 47 } 48 49 private int bgHeight = 40; 50 /// <summary> 51 /// 验证码的高度,默认为40 52 /// </summary> 53 public Int32 Height 54 { 55 get { return bgHeight; } 56 set { bgHeight = value; } 57 } 58 /* private string[] fontFace = { "Verdana", "Microsoft Sans Serif", "Comic Sans MS", "Arial", "宋体" }; 59 /// <summary> 60 /// 验证码字体列表,默认为{ "Verdana", "Microsoft Sans Serif", "Comic Sans MS", "Arial", "宋体" } 61 /// </summary> 62 public String[] FontFace 63 { 64 get { return fontFace; } 65 set { fontFace = value; } 66 }*/ 67 68 private int fontMinSize = 15; 69 /// <summary> 70 /// 验证码字体的最小值,默认为15,建议不小于15像素 71 /// </summary> 72 public Int32 FontMinSize 73 { 74 get { return fontMinSize; } 75 set { fontMinSize = value; } 76 } 77 private Int32 fontMaxSize = 20; 78 /// <summary> 79 /// 验证码字体的最大值,默认为20 80 /// </summary> 81 public Int32 FontMaxSize 82 { 83 get { return fontMaxSize; } 84 set { fontMaxSize = value; } 85 } 86 private Color[] fontColor = { }; 87 /// <summary> 88 /// 验证码字体的颜色,默认为系统自动生成字体颜色 89 /// </summary> 90 public Color[] FontColor 91 { 92 get { return fontColor; } 93 set { fontColor = value; } 94 } 95 private Color backColor = Color.FromArgb(243, 255, 255); 96 /// <summary> 97 /// 验证码的背景色,默认为Color.FromArgb(243, 251, 254) 98 /// </summary> 99 public Color BackgroundColor 100 { 101 get { return backColor; } 102 set { backColor = value; } 103 } 104 private Int32 bezierCount = 3; 105 /// <summary> 106 /// 贝塞尔曲线的条数,默认为3条 107 /// </summary> 108 public Int32 BezierCount 109 { 110 get { return bezierCount; } 111 set { bezierCount = value; } 112 } 113 private Int32 lineCount = 3; 114 /// <summary> 115 /// 直线条数,默认为3条 116 /// </summary> 117 public Int32 LineCount 118 { 119 get { return lineCount; } 120 set { lineCount = value; } 121 } 122 Random random; 123 124 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; 125 /// <summary> 126 /// 随机字符串列表,请使用英文状态下的逗号分隔。 127 /// </summary> 128 public String CharCollection 129 { 130 get { return charCollection; } 131 set { charCollection = value; } 132 } 133 private Int32 intCount = 4; 134 /// <summary> 135 /// 验证码字符串个数,默认为4个字符 136 /// </summary> 137 public Int32 IntCount 138 { 139 get { return intCount; } 140 set { intCount = value; } 141 } 142 private Boolean isPixel = true; 143 /// <summary> 144 /// 是否添加噪点,默认添加,噪点颜色为系统随机生成。 145 /// </summary> 146 public Boolean IsPixel 147 { 148 get { return isPixel; } 149 set { isPixel = value; } 150 } 151 private Boolean isRandString = true; 152 /// <summary> 153 /// 是否添加随机噪点字符串,默认添加 154 /// </summary> 155 public Boolean IsRandString 156 { 157 get { return isRandString; } 158 set { isRandString = value; } 159 } 160 /// <summary> 161 /// 随机背景字符串的个数 162 /// </summary> 163 public Int32 RandomStringCount 164 { 165 get; 166 set; 167 } 168 private Int32 randomStringFontSize = 9; 169 /// <summary> 170 /// 随机背景字符串的大小 171 /// </summary> 172 public Int32 RandomStringFontSize 173 { 174 get { return randomStringFontSize; } 175 set { randomStringFontSize = value; } 176 } 177 /// <summary> 178 /// 是否对图片进行扭曲 179 /// </summary> 180 public Boolean IsTwist 181 { 182 get; 183 set; 184 } 185 /// <summary> 186 /// 边框样式 187 /// </summary> 188 public enum BorderStyle 189 { 190 /// <summary> 191 /// 无边框 192 /// </summary> 193 None, 194 /// <summary> 195 /// 矩形边框 196 /// </summary> 197 Rectangle, 198 /// <summary> 199 /// 圆角边框 200 /// </summary> 201 RoundRectangle 202 } 203 private Int32 rotationAngle = 40; 204 /// <summary> 205 /// 验证码字符串随机转动的角度的最大值 206 /// </summary> 207 public Int32 RotationAngle 208 { 209 get { return rotationAngle; } 210 set { rotationAngle = value; } 211 } 212 /// <summary> 213 /// 设置或获取边框样式 214 /// </summary> 215 public BorderStyle Border 216 { 217 get; 218 set; 219 } 220 private Point[] strPoint = null; 221 222 private Double gaussianDeviation = 0; 223 /// <summary> 224 /// 对验证码图片进行高斯模糊的阀值,如果设置为0,则不对图片进行高斯模糊,该设置可能会对图片处理的性能有较大影响 225 /// </summary> 226 public Double GaussianDeviation 227 { 228 get { return gaussianDeviation; } 229 set { gaussianDeviation = value; } 230 } 231 private Int32 brightnessValue = 0; 232 /// <summary> 233 /// 对图片进行暗度和亮度的调整,如果该值为0,则不调整。该设置会对图片处理性能有较大影响 234 /// </summary> 235 public Int32 BrightnessValue 236 { 237 get { return brightnessValue; } 238 set { brightnessValue = value; } 239 } 240 #endregion 241 242 #region wq 新增 边框补(默认1像素) 243 int padding = 2; 244 public int Padding 245 { 246 get { return padding; } 247 set { padding = value; } 248 } 249 #endregion 250 251 /// <summary> 252 /// 构造函数,用于初始化常用变量 253 /// </summary> 254 public DrawValidationCode() 255 { 256 random = new Random(Guid.NewGuid().GetHashCode()); 257 strPoint = new Point[validationCodeCount + 1]; 258 if (gaussianDeviation < 0) gaussianDeviation = 0; 259 } 260 261 /// <summary> 262 /// 生成验证码 263 /// </summary> 264 /// <param name="target">用于存储图片的一般字节序列</param> 265 public MemoryStream CreateImage(MemoryStream target) 266 { 267 //新增 wq ,否则后面报错 268 if (strPoint.Length != validationCodeCount) 269 { 270 strPoint = new Point[validationCodeCount + 1];//wq 新增,原因是:构造函数默认初始化5个元素,假如new后,又改了validationCodeCount的数值,则该数字需要重新初始化 271 } 272 273 //新增 wq ,否则图片的画布太小 274 if (fontMaxSize >= (bgHeight / 5) * 4) 275 { 276 //throw new ArgumentException("字体最大值参数FontMaxSize与验证码高度相近,这会导致描绘验证码字符串时出错,请重新设置参数!"); 277 AdjustBitmapSize(); 278 } 279 280 Bitmap bit = new Bitmap(bgWidth + 1, bgHeight + 1); 281 //写字符串 282 dc = Graphics.FromImage(bit); 283 dc.SmoothingMode = SmoothingMode.HighQuality; 284 dc.TextRenderingHint = TextRenderingHint.ClearTypeGridFit; ; 285 dc.InterpolationMode = InterpolationMode.HighQualityBilinear; 286 dc.CompositingQuality = CompositingQuality.HighQuality; 287 288 dc.Clear(Color.White); 289 dc.DrawImageUnscaled(DrawBackground(), 0, 0); 290 291 //绘制随机码 292 Bitmap validatecodeImg = DrawRandomString(); 293 //对随机码图像上的文字进行波形扭曲(扭曲文字方式1) 294 validatecodeImg = TwistImage(validatecodeImg, true, 8, 4); 295 dc.DrawImageUnscaled(validatecodeImg, 0, 0); 296 297 //水波纹效果 文字进行波形扭曲 (扭曲文字方式2) 298 //bit = AdjustRippleEffect(bit, 5); 299 300 301 //对图片进行高斯模糊 302 if (gaussianDeviation > 0) 303 { 304 Gaussian gau = new Gaussian(); 305 bit = gau.FilterProcessImage(gaussianDeviation, bit); 306 } 307 //进行暗度和亮度处理 308 if (brightnessValue != 0) 309 { 310 //对图片进行调暗处理 311 bit = AdjustBrightness(bit, brightnessValue); 312 } 313 bit.Save(target, ImageFormat.Gif); 314 //brush.Dispose(); 315 bit.Dispose(); 316 dc.Dispose(); 317 return target; 318 } 319 320 #region 画验证码背景,例如,增加早点,添加曲线和直线等 321 /// <summary> 322 /// 画验证码背景,例如,增加早点,添加曲线和直线等 323 /// </summary> 324 /// <returns></returns> 325 private Bitmap DrawBackground() 326 { 327 Bitmap bit = new Bitmap(bgWidth + 1, bgHeight + 1); 328 Graphics g = Graphics.FromImage(bit); 329 g.SmoothingMode = SmoothingMode.HighQuality; 330 331 g.Clear(Color.White); 332 Rectangle rectangle = new Rectangle(0, 0, bgWidth, bgHeight); 333 Brush brush = new SolidBrush(backColor); 334 g.FillRectangle(brush, rectangle); 335 336 //画噪点 337 if (isPixel) 338 { 339 g.DrawImageUnscaled(DrawRandomPixel(30), 0, 0); 340 } 341 g.DrawImageUnscaled(DrawRandBgString(), 0, 0); 342 343 344 //画曲线 345 g.DrawImageUnscaled(DrawRandomBezier(bezierCount), 0, 0); 346 //画直线 347 g.DrawImageUnscaled(DrawRandomLine(lineCount), 0, 0); 348 349 //dc.DrawImageUnscaled(DrawStringline(), 0, 0); 350 if (Border == BorderStyle.Rectangle) 351 { 352 //绘制边框 353 g.DrawRectangle(new Pen(Color.FromArgb(90, 87, 46)), 0, 0, bgWidth, bgHeight); 354 } 355 else if (Border == BorderStyle.RoundRectangle) 356 { 357 //画圆角 358 DrawRoundRectangle(g, rectangle, Color.FromArgb(90, 87, 46), 1, 3); 359 } 360 361 return bit; 362 363 } 364 #endregion 365 366 #region 画正弦曲线 367 private Bitmap DrawTwist(Bitmap bmp, Int32 tWidth, Int32 tHeight, float angle, Color color) 368 { 369 //为了方便查看效果,在这里我定义了一个常量。 370 //它在定义数组的长度和for循环中都要用到。 371 int size = bgWidth; 372 373 double[] x = new double[size]; 374 Bitmap b = new Bitmap(bmp.Width, bmp.Height); 375 b.MakeTransparent(); 376 Graphics graphics = Graphics.FromImage(b); 377 Pen pen = new Pen(color); 378 379 //画正弦曲线的横轴间距参数。建议所用的值应该是 正数且是2的倍数。 380 //在这里采用2。 381 int val = 2; 382 383 float temp = 0.0f; 384 385 //把画布下移100。为什么要这样做,只要你把这一句给注释掉,运行一下代码, 386 //你就会明白是为什么? 387 graphics.TranslateTransform(0, 100); 388 graphics.SmoothingMode = SmoothingMode.HighQuality; 389 graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; 390 for (int i = 0; i < size; i++) 391 { 392 //改变tWidth,实现正弦曲线宽度的变化。 393 //改tHeight,实现正弦曲线高度的变化。 394 x[i] = Math.Sin(2 * Math.PI * i / tWidth) * tHeight; 395 396 graphics.DrawLine(pen, i * val, temp, i * val + val / 2, (float)x[i]); 397 temp = (float)x[i]; 398 } 399 graphics.RotateTransform(60, MatrixOrder.Prepend); 400 401 //旋转图片 402 // b = KiRotate(b, angle, Color.Transparent); 403 return b; 404 } 405 #endregion 406 407 #region 正弦曲线Wave扭曲图片 408 /// <summary> 409 /// 正弦曲线Wave扭曲图片 410 /// </summary> 411 /// <param name="srcBmp">图片路径</param> 412 /// <param name="bXDir">如果扭曲则选择为True</param> 413 /// <param name="dMultValue">波形的幅度倍数,越大扭曲的程度越高,一般为3</param> 414 /// <param name="dPhase">波形的起始相位,取值区间[0-2*PI)</param> 415 /// <returns></returns> 416 public Bitmap TwistImage(Bitmap srcBmp, bool bXDir, double dMultValue, double dPhase) 417 { 418 System.Drawing.Bitmap destBmp = new Bitmap(srcBmp.Width, srcBmp.Height); 419 double PI2 = 6.283185307179586476925286766559; 420 // 将位图背景填充为白色 421 System.Drawing.Graphics graph = System.Drawing.Graphics.FromImage(destBmp); 422 graph.FillRectangle(new SolidBrush(System.Drawing.Color.White), 0, 0, destBmp.Width, destBmp.Height); 423 graph.Dispose(); 424 425 double dBaseAxisLen = bXDir ? (double)destBmp.Height : (double)destBmp.Width; 426 427 for (int i = 0; i < destBmp.Width; i++) 428 { 429 for (int j = 0; j < destBmp.Height; j++) 430 { 431 double dx = 0; 432 dx = bXDir ? (PI2 * (double)j) / dBaseAxisLen : (PI2 * (double)i) / dBaseAxisLen; 433 dx += dPhase; 434 double dy = Math.Sin(dx); 435 436 // 取得当前点的颜色 437 int nOldX = 0, nOldY = 0; 438 nOldX = bXDir ? i + (int)(dy * dMultValue) : i; 439 nOldY = bXDir ? j : j + (int)(dy * dMultValue); 440 441 System.Drawing.Color color = srcBmp.GetPixel(i, j); 442 if (nOldX >= 0 && nOldX < destBmp.Width 443 && nOldY >= 0 && nOldY < destBmp.Height) 444 { 445 destBmp.SetPixel(nOldX, nOldY, color); 446 } 447 } 448 } 449 return destBmp; 450 } 451 #endregion 452 453 #region 图片任意角度旋转 454 /// <summary> 455 /// 图片任意角度旋转 456 /// </summary> 457 /// <param name="bmp">原始图Bitmap</param> 458 /// <param name="angle">旋转角度</param> 459 /// <param name="bkColor">背景色</param> 460 /// <returns>输出Bitmap</returns> 461 public static Bitmap KiRotate(Bitmap bmp, float angle, Color bkColor) 462 { 463 int w = bmp.Width; 464 int h = bmp.Height; 465 466 PixelFormat pf; 467 468 if (bkColor == Color.Transparent) 469 { 470 pf = PixelFormat.Format32bppArgb; 471 } 472 else 473 { 474 pf = bmp.PixelFormat; 475 } 476 477 Bitmap tmp = new Bitmap(w, h, pf); 478 Graphics g = Graphics.FromImage(tmp); 479 g.Clear(bkColor); 480 g.DrawImageUnscaled(bmp, 1, 1); 481 g.Dispose(); 482 483 GraphicsPath path = new GraphicsPath(); 484 path.AddRectangle(new RectangleF(0f, 0f, w, h)); 485 Matrix mtrx = new Matrix(); 486 mtrx.Rotate(angle); 487 RectangleF rct = path.GetBounds(mtrx); 488 489 Bitmap dst = new Bitmap((int)rct.Width, (int)rct.Height, pf); 490 g = Graphics.FromImage(dst); 491 g.Clear(bkColor); 492 g.TranslateTransform(-rct.X, -rct.Y); 493 g.RotateTransform(angle); 494 g.InterpolationMode = InterpolationMode.HighQualityBilinear; 495 g.DrawImageUnscaled(tmp, 0, 0); 496 g.Dispose(); 497 tmp.Dispose(); 498 499 return dst; 500 } 501 #endregion 502 503 #region 随机生成贝塞尔曲线 504 /// <summary> 505 /// 随机生成贝塞尔曲线 506 /// </summary> 507 /// <param name="bmp">一个图片的实例</param> 508 /// <param name="lineNum">线条数量</param> 509 /// <returns></returns> 510 public Bitmap DrawRandomBezier(Int32 lineNum) 511 { 512 Bitmap b = new Bitmap(bgWidth, bgHeight); 513 b.MakeTransparent(); 514 Graphics g = Graphics.FromImage(b); 515 g.Clear(Color.Transparent); 516 g.SmoothingMode = SmoothingMode.HighQuality; 517 g.PixelOffsetMode = PixelOffsetMode.HighQuality; 518 519 GraphicsPath gPath1 = new GraphicsPath(); 520 Int32 lineRandNum = random.Next(lineNum); 521 522 for (int i = 0; i < (lineNum - lineRandNum); i++) 523 { 524 Pen p = new Pen(GetRandomDeepColor(),3f); //wq,增加贝塞尔曲线的线宽参数 525 Point[] point = { 526 new Point(random.Next(1, (b.Width / 10)), random.Next(1, (b.Height))), 527 new Point(random.Next((b.Width / 10) * 2, (b.Width / 10) * 4), random.Next(1, (b.Height))), 528 new Point(random.Next((b.Width / 10) * 4, (b.Width / 10) * 6), random.Next(1, (b.Height))), 529 new Point(random.Next((b.Width / 10) * 8, b.Width), random.Next(1, (b.Height))) 530 }; 531 532 gPath1.AddBeziers(point); 533 g.DrawPath(p, gPath1); 534 p.Dispose(); 535 } 536 537 for (int i = 0; i < lineRandNum; i++) 538 { 539 Pen p = new Pen(GetRandomDeepColor()); 540 Point[] point = { 541 new Point(random.Next(1, b.Width), random.Next(1, b.Height)), 542 new Point(random.Next((b.Width / 10) * 2, b.Width), random.Next(1, b.Height)), 543 new Point(random.Next((b.Width / 10) * 4, b.Width), random.Next(1, b.Height)), 544 new Point(random.Next(1, b.Width), random.Next(1, b.Height)) 545 }; 546 gPath1.AddBeziers(point); 547 g.DrawPath(p, gPath1); 548 p.Dispose(); 549 } 550 return b; 551 } 552 #endregion 553 554 #region 画直线 555 /// <summary> 556 /// 画直线 557 /// </summary> 558 /// <param name="bmp">一个bmp实例</param> 559 /// <param name="lineNum">线条个数</param> 560 /// <returns></returns> 561 public Bitmap DrawRandomLine(Int32 lineNum) 562 { 563 if (lineNum < 0) throw new ArgumentNullException("参数bmp为空!"); 564 Bitmap b = new Bitmap(bgWidth, bgHeight); 565 b.MakeTransparent(); 566 Graphics g = Graphics.FromImage(b); 567 g.Clear(Color.Transparent); 568 g.PixelOffsetMode = PixelOffsetMode.HighQuality; 569 g.SmoothingMode = SmoothingMode.HighQuality; 570 for (int i = 0; i < lineNum; i++) 571 { 572 Pen p = new Pen(GetRandomDeepColor()); 573 Point pt1 = new Point(random.Next(1, (b.Width / 5) * 2), random.Next(b.Height)); 574 Point pt2 = new Point(random.Next((b.Width / 5) * 3, b.Width), random.Next(b.Height)); 575 g.DrawLine(p, pt1, pt2); 576 p.Dispose(); 577 } 578 579 return b; 580 } 581 #endregion 582 583 #region 画随机噪点 584 /// <summary> 585 /// 画随机噪点 586 /// </summary> 587 /// <param name="pixNum">噪点的百分比</param> 588 /// <returns></returns> 589 public Bitmap DrawRandomPixel(Int32 pixNum) 590 { 591 Bitmap b = new Bitmap(bgWidth, bgHeight); 592 b.MakeTransparent(); 593 Graphics graph = Graphics.FromImage(b); 594 graph.SmoothingMode = SmoothingMode.HighQuality; 595 graph.InterpolationMode = InterpolationMode.HighQualityBilinear; 596 597 //画噪点 598 for (int i = 0; i < (bgHeight * bgWidth) / pixNum; i++) 599 { 600 int x = random.Next(b.Width); 601 int y = random.Next(b.Height); 602 b.SetPixel(x, y, GetRandomDeepColor()); 603 //下移坐标重新画点 604 if ((x + 1) < b.Width && (y + 1) < b.Height) 605 { 606 //画图片的前景噪音点 607 graph.DrawRectangle(new Pen(Color.Silver), random.Next(b.Width), random.Next(b.Height), 1, 1); 608 } 609 610 } 611 612 return b; 613 } 614 #endregion 615 616 #region 画随机字符串中间连线 617 /// <summary> 618 /// 画随机字符串中间连线 619 /// </summary> 620 /// <returns></returns> 621 private Bitmap DrawStringline() 622 { 623 Bitmap b = new Bitmap(bgWidth, bgHeight); 624 b.MakeTransparent(); 625 Graphics g = Graphics.FromImage(b); 626 g.SmoothingMode = SmoothingMode.AntiAlias; 627 628 Point[] p = new Point[validationCodeCount]; 629 for (int i = 0; i < validationCodeCount; i++) 630 { 631 p[i] = strPoint[i]; 632 //throw new Exception(strPoint.Length.ToString()); 633 } 634 // g.DrawBezier(new Pen(GetRandomDeepColor()), strPoint); 635 //g.DrawClosedCurve(new Pen(GetRandomDeepColor()), strPoint); 636 g.DrawCurve(new Pen(GetRandomDeepColor(), 1), strPoint); 637 638 return b; 639 } 640 #endregion 641 642 #region 写入验证码的字符串 643 /// <summary> 644 /// 写入验证码的字符串 645 /// </summary> 646 private Bitmap DrawRandomString() 647 { 648 if (fontMaxSize >= (bgHeight / 5) * 4) 649 { 650 //throw new ArgumentException("字体最大值参数FontMaxSize与验证码高度相近,这会导致描绘验证码字符串时出错,请重新设置参数!"); 651 AdjustBitmapSize(); 652 } 653 654 655 Bitmap b = new Bitmap(bgWidth, bgHeight); 656 b.MakeTransparent(); 657 Graphics g = Graphics.FromImage(b); 658 659 g.Clear(Color.Transparent); 660 g.PixelOffsetMode = PixelOffsetMode.Half; 661 g.SmoothingMode = SmoothingMode.HighQuality; 662 g.TextRenderingHint = TextRenderingHint.SingleBitPerPixelGridFit; 663 g.InterpolationMode = InterpolationMode.HighQualityBilinear; 664 665 char[] chars = GetRandomString(validationCodeCount).ToCharArray();//拆散字符串成单字符数组 666 validationCode = chars.ToString(); //这个类的外部,也可以通过这个参数,获取到本次的验证码字符串值。 667 668 //设置字体显示格式 669 StringFormat format = new StringFormat(StringFormatFlags.NoClip); 670 format.Alignment = StringAlignment.Center; 671 format.LineAlignment = StringAlignment.Center; 672 FontFamily f = new FontFamily(GenericFontFamilies.Monospace); 673 674 675 Int32 charNum = chars.Length; 676 677 Point sPoint = new Point(); 678 Int32 fontSize = 9; 679 for (int i = 0; i < validationCodeCount; i++) 680 { 681 int findex = random.Next(validationCodeCount+1);// random.Next(5); 682 //定义字体 683 Font textFont = new Font(f, random.Next(fontMinSize, fontMaxSize), FontStyle.Bold); 684 //定义画刷,用于写字符串 685 //Brush brush = new SolidBrush(GetRandomDeepColor()); 686 Int32 textFontSize = Convert.ToInt32(textFont.Size); 687 fontSize = textFontSize; 688 Point point = new Point(random.Next((bgWidth / charNum) * i + 5, (bgWidth / charNum) * (i + 1)), random.Next(bgHeight / 5 + textFontSize / 2, bgHeight - textFontSize / 2)); 689 690 691 692 //如果当前字符X坐标小于字体的二分之一大小 693 if (point.X < textFontSize / 2) 694 { 695 point.X = point.X + textFontSize / 2; 696 } 697 //防止文字叠加 698 if (i > 0 && (point.X - sPoint.X < (textFontSize / 2 + textFontSize / 2))) 699 { 700 point.X = point.X + textFontSize; 701 } 702 //如果当前字符X坐标大于图片宽度,就减去字体的宽度 703 if (point.X > (bgWidth - textFontSize / 2)) 704 { 705 point.X = bgWidth - textFontSize / 2; 706 } 707 708 sPoint = point; 709 710 float angle = random.Next(-rotationAngle, rotationAngle);//转动的度数 711 g.TranslateTransform(point.X, point.Y);//移动光标到指定位置 712 g.RotateTransform(angle); 713 714 //设置渐变画刷 715 Rectangle myretang = new Rectangle(0, 1, Convert.ToInt32(textFont.Size), Convert.ToInt32(textFont.Size)); 716 Color c = GetRandomDeepColor(); 717 LinearGradientBrush mybrush2 = new LinearGradientBrush(myretang, c, GetLightColor(c, 120), random.Next(180)); 718 719 g.DrawString(chars[i].ToString(), textFont, mybrush2, 1, 1, format); 720 721 g.RotateTransform(-angle);//转回去 722 g.TranslateTransform(-point.X, -point.Y);//移动光标到指定位置,每个字符紧凑显示,避免被软件识别 723 724 strPoint[i] = point; 725 726 textFont.Dispose(); 727 mybrush2.Dispose(); 728 } 729 return b; 730 } 731 #endregion 732 733 #region wq 新增的矫正验证码的宽高 734 private void AdjustBitmapSize() 735 { 736 int fSize = fontMaxSize; 737 int fWidth = fSize + Padding; 738 739 int imageWidth = (int)(validationCodeCount * fWidth) + 4 + Padding * 2; 740 int imageHeight = fSize * 2 + Padding; 741 bgWidth = imageWidth; 742 bgHeight = imageHeight; 743 } 744 #endregion 745 746 #region 画干扰背景文字 747 /// <summary> 748 /// 画背景干扰文字 749 /// </summary> 750 /// <returns></returns> 751 private Bitmap DrawRandBgString() 752 { 753 Bitmap b = new Bitmap(bgWidth, bgHeight); 754 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" }; 755 b.MakeTransparent(); 756 Graphics g = Graphics.FromImage(b); 757 758 g.Clear(Color.Transparent); 759 g.PixelOffsetMode = PixelOffsetMode.HighQuality; 760 g.SmoothingMode = SmoothingMode.HighQuality; 761 g.TextRenderingHint = TextRenderingHint.AntiAlias; 762 g.InterpolationMode = InterpolationMode.HighQualityBilinear; 763 764 //设置字体显示格式 765 StringFormat format = new StringFormat(StringFormatFlags.NoClip); 766 format.Alignment = StringAlignment.Center; 767 format.LineAlignment = StringAlignment.Center; 768 769 FontFamily f = new FontFamily(GenericFontFamilies.Serif); 770 Font textFont = new Font(f, randomStringFontSize, FontStyle.Underline); 771 772 int randAngle = 60; //随机转动角度 773 774 for (int i = 0; i < RandomStringCount; i++) 775 { 776 777 Brush brush = new System.Drawing.SolidBrush(GetRandomLightColor()); 778 Point pot = new Point(random.Next(5, bgWidth - 5), random.Next(5, bgHeight - 5)); 779 //随机转动的度数 780 float angle = random.Next(-randAngle, randAngle); 781 782 //转动画布 783 g.RotateTransform(angle); 784 g.DrawString(randStr[random.Next(randStr.Length)], textFont, brush, pot, format); 785 //转回去,为下一个字符做准备 786 g.RotateTransform(-angle); 787 //释放资源 788 brush.Dispose(); 789 } 790 textFont.Dispose(); 791 format.Dispose(); 792 f.Dispose(); 793 794 return b; 795 } 796 #endregion 797 798 #region 生成随机字符串 799 /// <summary> 800 /// 生成随机字符串 801 /// </summary> 802 /// <returns></returns> 803 private string GetRandomString(Int32 textLength) 804 { 805 string[] randomArray = charCollection.Split(','); //将字符串生成数组 806 int arrayLength = randomArray.Length; 807 string randomString = ""; 808 for (int i = 0; i < textLength; i++) 809 { 810 randomString += randomArray[random.Next(0, arrayLength)]; 811 } 812 //Session["CheckCode"] = randomString; 813 return randomString; //长度是textLength +1 814 } 815 #endregion 816 817 #region 内部方法:绘制验证码背景 818 private void DrawBackground(HatchStyle hatchStyle) 819 { 820 //设置填充背景时用的笔刷 821 HatchBrush hBrush = new HatchBrush(hatchStyle, backColor); 822 823 //填充背景图片 824 dc.FillRectangle(hBrush, 0, 0, this.bgWidth, this.bgHeight); 825 } 826 #endregion 827 828 #region 根据指定长度,返回随机验证码 829 /// <summary> 830 /// 根据指定长度,返回随机验证码 831 /// </summary> 832 /// <param >制定长度</param> 833 /// <returns>随即验证码</returns> 834 public string Next(int length) 835 { 836 this.validationCode = GetRandomCode(length); 837 return this.validationCode; 838 } 839 #endregion 840 841 #region 内部方法:返回指定长度的随机验证码字符串 842 /// <summary> 843 /// 根据指定大小返回随机验证码 844 /// </summary> 845 /// <param >字符串长度</param> 846 /// <returns>随机字符串</returns> 847 private string GetRandomCode(int length) 848 { 849 StringBuilder sb = new StringBuilder(6); 850 851 for (int i = 0; i < length; i++) 852 { 853 sb.Append(Char.ConvertFromUtf32(RandomAZ09())); 854 } 855 856 return sb.ToString(); 857 } 858 #endregion 859 860 #region 内部方法:产生随机数和随机点 861 862 /// <summary> 863 /// 产生0-9A-Z的随机字符代码 864 /// </summary> 865 /// <returns>字符代码</returns> 866 private int RandomAZ09() 867 { 868 int result = 48; 869 Random ram = new Random(); 870 int i = ram.Next(2); 871 872 switch (i) 873 { 874 case 0: 875 result = ram.Next(48, 58); 876 break; 877 case 1: 878 result = ram.Next(65, 91); 879 break; 880 } 881 882 return result; 883 } 884 885 /// <summary> 886 /// 返回一个随机点,该随机点范围在验证码背景大小范围内 887 /// </summary> 888 /// <returns>Point对象</returns> 889 private Point RandomPoint() 890 { 891 Random ram = new Random(); 892 Point point = new Point(ram.Next(this.bgWidth), ram.Next(this.bgHeight)); 893 return point; 894 } 895 #endregion 896 897 #region 随机生成颜色值 898 /// <summary> 899 /// 生成随机深颜色 900 /// </summary> 901 /// <returns></returns> 902 public Color GetRandomDeepColor() 903 { 904 int nRed, nGreen, nBlue; // nBlue,nRed nGreen 相差大一点 nGreen 小一些 905 //int high = 255; 906 int redLow = 160; 907 int greenLow = 100; 908 int blueLow = 160; 909 nRed = random.Next(redLow); 910 nGreen = random.Next(greenLow); 911 nBlue = random.Next(blueLow); 912 Color color = Color.FromArgb(nRed, nGreen, nBlue); 913 return color; 914 } 915 916 /// <summary> 917 /// 生成随机浅颜色 918 /// </summary> 919 /// <returns>randomColor</returns> 920 public Color GetRandomLightColor() 921 { 922 int nRed, nGreen, nBlue; //越大颜色越浅 923 int low = 180; //色彩的下限 924 int high = 255; //色彩的上限 925 nRed = random.Next(high) % (high - low) + low; 926 nGreen = random.Next(high) % (high - low) + low; 927 nBlue = random.Next(high) % (high - low) + low; 928 Color color = Color.FromArgb(nRed, nGreen, nBlue); 929 return color; 930 } 931 /// <summary> 932 /// 生成随机颜色值 933 /// </summary> 934 /// <returns></returns> 935 public Color GetRandomColor() 936 { 937 int nRed, nGreen, nBlue; //越大颜色越浅 938 int low = 10; //色彩的下限 939 int high = 255; //色彩的上限 940 nRed = random.Next(high) % (high - low) + low; 941 nGreen = random.Next(high) % (high - low) + low; 942 nBlue = random.Next(high) % (high - low) + low; 943 Color color = Color.FromArgb(nRed, nGreen, nBlue); 944 return color; 945 } 946 /// <summary> 947 /// 获取与当前颜色值相加后的颜色 948 /// </summary> 949 /// <param name="c"></param> 950 /// <returns></returns> 951 public Color GetLightColor(Color c, Int32 value) 952 { 953 int nRed = c.R, nGreen = c.G, nBlue = c.B; //越大颜色越浅 954 if (nRed + value < 255 && nRed + value > 0) 955 { 956 nRed = c.R + 40; 957 } 958 if (nGreen + value < 255 && nGreen + value > 0) 959 { 960 nGreen = c.G + 40; 961 } 962 if (nBlue + value < 255 && nBlue + value > 0) 963 { 964 nBlue = c.B + 40; 965 } 966 Color color = Color.FromArgb(nRed, nGreen, nBlue); 967 return color; 968 } 969 #endregion 970 971 #region 合并图片 972 /// <summary> 973 /// 合并图片 974 /// </summary> 975 /// <param name="maps"></param> 976 /// <returns></returns> 977 private Bitmap MergerImg(params Bitmap[] maps) 978 { 979 int i = maps.Length; 980 if (i == 0) 981 throw new Exception("图片数不能够为0"); 982 //创建要显示的图片对象,根据参数的个数设置宽度 983 Bitmap backgroudImg = new Bitmap(i * 12, 16); 984 Graphics g = Graphics.FromImage(backgroudImg); 985 //清除画布,背景设置为白色 986 g.Clear(System.Drawing.Color.White); 987 for (int j = 0; j < i; j++) 988 { 989 //g.DrawImage(maps[j], j * 11, 0, maps[j].Width, maps[j].Height); 990 g.DrawImageUnscaled(maps[j], 0, 0); 991 } 992 g.Dispose(); 993 return backgroudImg; 994 } 995 #endregion 996 997 #region 生成不重复的随机数,该函数会消耗大量系统资源 998 /// <summary> 999 /// 生成不重复的随机数,该函数会消耗大量系统资源 1000 /// </summary> 1001 /// <returns></returns> 1002 private static int GetRandomSeed() 1003 { 1004 byte[] bytes = new byte[4]; 1005 System.Security.Cryptography.RNGCryptoServiceProvider rng = new System.Security.Cryptography.RNGCryptoServiceProvider(); 1006 rng.GetBytes(bytes); 1007 return BitConverter.ToInt32(bytes, 0); 1008 } 1009 #endregion 1010 1011 #region 缩放图片 1012 /// <summary> 1013 /// 缩放图片 1014 /// </summary> 1015 /// <param name="bmp">原始Bitmap</param> 1016 /// <param name="newW">新的宽度</param> 1017 /// <param name="newH">新的高度</param> 1018 /// <param name="Mode">缩放质量</param> 1019 /// <returns>处理以后的图片</returns> 1020 public static Bitmap KiResizeImage(Bitmap bmp, int newW, int newH, InterpolationMode Mode) 1021 { 1022 try 1023 { 1024 Bitmap b = new Bitmap(newW, newH); 1025 Graphics g = Graphics.FromImage(b); 1026 // 插值算法的质量 1027 g.InterpolationMode = Mode; 1028 g.DrawImage(bmp, new Rectangle(0, 0, newW, newH), new Rectangle(0, 0, bmp.Width, bmp.Height), GraphicsUnit.Pixel); 1029 g.Dispose(); 1030 return b; 1031 } 1032 catch 1033 { 1034 return null; 1035 } 1036 } 1037 #endregion 1038 1039 #region 绘制圆角矩形 1040 /// <summary> 1041 /// C# GDI+ 绘制圆角矩形 1042 /// </summary> 1043 /// <param name="g">Graphics 对象</param> 1044 /// <param name="rectangle">Rectangle 对象,圆角矩形区域</param> 1045 /// <param name="borderColor">边框颜色</param> 1046 /// <param name="borderWidth">边框宽度</param> 1047 /// <param name="r">圆角半径</param> 1048 private static void DrawRoundRectangle(Graphics g, Rectangle rectangle, Color borderColor, float borderWidth, int r) 1049 { 1050 // 如要使边缘平滑,请取消下行的注释 1051 g.SmoothingMode = SmoothingMode.HighQuality; 1052 1053 // 由于边框也需要一定宽度,需要对矩形进行修正 1054 //rectangle = new Rectangle(rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height); 1055 Pen p = new Pen(borderColor, borderWidth); 1056 // 调用 getRoundRectangle 得到圆角矩形的路径,然后再进行绘制 1057 g.DrawPath(p, getRoundRectangle(rectangle, r)); 1058 } 1059 #endregion 1060 1061 #region 根据普通矩形得到圆角矩形的路径 1062 /// <summary> 1063 /// 根据普通矩形得到圆角矩形的路径 1064 /// </summary> 1065 /// <param name="rectangle">原始矩形</param> 1066 /// <param name="r">半径</param> 1067 /// <returns>图形路径</returns> 1068 private static GraphicsPath getRoundRectangle(Rectangle rectangle, int r) 1069 { 1070 int l = 2 * r; 1071 // 把圆角矩形分成八段直线、弧的组合,依次加到路径中 1072 GraphicsPath gp = new GraphicsPath(); 1073 gp.AddLine(new Point(rectangle.X + r, rectangle.Y), new Point(rectangle.Right - r, rectangle.Y)); 1074 gp.AddArc(new Rectangle(rectangle.Right - l, rectangle.Y, l, l), 270F, 90F); 1075 1076 gp.AddLine(new Point(rectangle.Right, rectangle.Y + r), new Point(rectangle.Right, rectangle.Bottom - r)); 1077 gp.AddArc(new Rectangle(rectangle.Right - l, rectangle.Bottom - l, l, l), 0F, 90F); 1078 1079 gp.AddLine(new Point(rectangle.Right - r, rectangle.Bottom), new Point(rectangle.X + r, rectangle.Bottom)); 1080 gp.AddArc(new Rectangle(rectangle.X, rectangle.Bottom - l, l, l), 90F, 90F); 1081 1082 gp.AddLine(new Point(rectangle.X, rectangle.Bottom - r), new Point(rectangle.X, rectangle.Y + r)); 1083 gp.AddArc(new Rectangle(rectangle.X, rectangle.Y, l, l), 180F, 90F); 1084 return gp; 1085 } 1086 #endregion 1087 1088 #region 柔化 1089 ///<summary> 1090 /// 柔化 1091 /// </summary> 1092 /// <param name="b">原始图</param> 1093 /// <returns>输出图</returns> 1094 public static Bitmap KiBlur(Bitmap b) 1095 { 1096 1097 if (b == null) 1098 { 1099 return null; 1100 } 1101 1102 int w = b.Width; 1103 int h = b.Height; 1104 1105 try 1106 { 1107 1108 Bitmap bmpRtn = new Bitmap(w, h, PixelFormat.Format24bppRgb); 1109 1110 BitmapData srcData = b.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb); 1111 BitmapData dstData = bmpRtn.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb); 1112 1113 unsafe 1114 { 1115 byte* pIn = (byte*)srcData.Scan0.ToPointer(); 1116 byte* pOut = (byte*)dstData.Scan0.ToPointer(); 1117 int stride = srcData.Stride; 1118 byte* p; 1119 1120 for (int y = 0; y < h; y++) 1121 { 1122 for (int x = 0; x < w; x++) 1123 { 1124 //取周围9点的值 1125 if (x == 0 || x == w - 1 || y == 0 || y == h - 1) 1126 { 1127 //不做 1128 pOut[0] = pIn[0]; 1129 pOut[1] = pIn[1]; 1130 pOut[2] = pIn[2]; 1131 } 1132 else 1133 { 1134 int r1, r2, r3, r4, r5, r6, r7, r8, r9; 1135 int g1, g2, g3, g4, g5, g6, g7, g8, g9; 1136 int b1, b2, b3, b4, b5, b6, b7, b8, b9; 1137 1138 float vR, vG, vB; 1139 1140 //左上 1141 p = pIn - stride - 3; 1142 r1 = p[2]; 1143 g1 = p[1]; 1144 b1 = p[0]; 1145 1146 //正上 1147 p = pIn - stride; 1148 r2 = p[2]; 1149 g2 = p[1]; 1150 b2 = p[0]; 1151 1152 //右上 1153 p = pIn - stride + 3; 1154 r3 = p[2]; 1155 g3 = p[1]; 1156 b3 = p[0]; 1157 1158 //左侧 1159 p = pIn - 3; 1160 r4 = p[2]; 1161 g4 = p[1]; 1162 b4 = p[0]; 1163 1164 //右侧 1165 p = pIn + 3; 1166 r5 = p[2]; 1167 g5 = p[1]; 1168 b5 = p[0]; 1169 1170 //右下 1171 p = pIn + stride - 3; 1172 r6 = p[2]; 1173 g6 = p[1]; 1174 b6 = p[0]; 1175 1176 //正下 1177 p = pIn + stride; 1178 r7 = p[2]; 1179 g7 = p[1]; 1180 b7 = p[0]; 1181 1182 //右下 1183 p = pIn + stride + 3; 1184 r8 = p[2]; 1185 g8 = p[1]; 1186 b8 = p[0]; 1187 1188 //自己 1189 p = pIn; 1190 r9 = p[2]; 1191 g9 = p[1]; 1192 b9 = p[0]; 1193 1194 vR = (float)(r1 + r2 + r3 + r4 + r5 + r6 + r7 + r8 + r9); 1195 vG = (float)(g1 + g2 + g3 + g4 + g5 + g6 + g7 + g8 + g9); 1196 vB = (float)(b1 + b2 + b3 + b4 + b5 + b6 + b7 + b8 + b9); 1197 1198 vR /= 9; 1199 vG /= 9; 1200 vB /= 9; 1201 1202 pOut[0] = (byte)vB; 1203 pOut[1] = (byte)vG; 1204 pOut[2] = (byte)vR; 1205 1206 } 1207 1208 pIn += 3; 1209 pOut += 3; 1210 }// end of x 1211 1212 pIn += srcData.Stride - w * 3; 1213 pOut += srcData.Stride - w * 3; 1214 } // end of y 1215 } 1216 1217 b.UnlockBits(srcData); 1218 bmpRtn.UnlockBits(dstData); 1219 1220 return bmpRtn; 1221 } 1222 catch 1223 { 1224 return null; 1225 } 1226 1227 } // end of KiBlur 1228 #endregion 1229 1230 #region 滤镜 1231 /// <summary> 1232 /// 红色滤镜 1233 /// </summary> 1234 /// <param name="bitmap">Bitmap</param> 1235 /// <param name="threshold">阀值 -255~255</param> 1236 /// <returns></returns> 1237 public System.Drawing.Bitmap AdjustToRed(System.Drawing.Bitmap bitmap, int threshold) 1238 { 1239 for (int y = 0; y < bitmap.Height; y++) 1240 { 1241 for (int x = 0; x < bitmap.Width; x++) 1242 { 1243 // 取得每一個 pixel 1244 var pixel = bitmap.GetPixel(x, y); 1245 var pR = pixel.R + threshold; 1246 pR = Math.Max(pR, 0); 1247 pR = Math.Min(255, pR); 1248 // 將改過的 RGB 寫回 1249 // 只寫入紅色的值 , G B 都放零 1250 System.Drawing.Color newColor = System.Drawing.Color.FromArgb(pixel.A, pR, 0, 0); 1251 bitmap.SetPixel(x, y, newColor); 1252 } 1253 } 1254 // 回傳結果 1255 return bitmap; 1256 } 1257 1258 /// <summary> 1259 /// 绿色滤镜 1260 /// </summary> 1261 /// <param name="bitmap">一个图片实例</param> 1262 /// <param name="threshold">阀值 -255~+255</param> 1263 /// <returns></returns> 1264 public System.Drawing.Bitmap AdjustToGreen(System.Drawing.Bitmap bitmap, int threshold) 1265 { 1266 for (int y = 0; y < bitmap.Height; y++) 1267 { 1268 for (int x = 0; x < bitmap.Width; x++) 1269 { 1270 // 取得每一個 pixel 1271 var pixel = bitmap.GetPixel(x, y); 1272 //判斷是否超過255 如果超過就是255 1273 var pG = pixel.G + threshold; 1274 //如果小於0就為0 1275 if (pG > 255) pG = 255; 1276 if (pG < 0) pG = 0; 1277 // 將改過的 RGB 寫回 1278 // 只寫入綠色的值 , R B 都放零 1279 System.Drawing.Color newColor = System.Drawing.Color.FromArgb(pixel.A, 0, pG, 0); 1280 bitmap.SetPixel(x, y, newColor); 1281 } 1282 } 1283 // 回傳結果 1284 return bitmap; 1285 } 1286 /// <summary> 1287 /// 蓝色滤镜 1288 /// </summary> 1289 /// <param name="bitmap">一个图片实例</param> 1290 /// <param name="threshold">阀值 -255~255</param> 1291 /// <returns></returns> 1292 public System.Drawing.Bitmap AdjustToBlue(System.Drawing.Bitmap bitmap, int threshold) 1293 { 1294 for (int y = 0; y < bitmap.Height; y++) 1295 { 1296 for (int x = 0; x < bitmap.Width; x++) 1297 { 1298 // 取得每一個 pixel 1299 var pixel = bitmap.GetPixel(x, y); 1300 //判斷是否超過255 如果超過就是255 1301 var pB = pixel.B + threshold; 1302 //如果小於0就為0 1303 if (pB > 255) pB = 255; 1304 if (pB < 0) pB = 0; 1305 // 將改過的 RGB 寫回 1306 // 只寫入藍色的值 , R G 都放零 1307 System.Drawing.Color newColor = System.Drawing.Color.FromArgb(pixel.A, 0, 0, pB); 1308 bitmap.SetPixel(x, y, newColor); 1309 } 1310 } 1311 // 回傳結果 1312 return bitmap; 1313 } 1314 /// <summary> 1315 /// 调整 RGB 色调 1316 /// </summary> 1317 /// <param name="bitmap"></param> 1318 /// <param name="thresholdRed">红色阀值</param> 1319 /// <param name="thresholdBlue">蓝色阀值</param> 1320 /// <param name="thresholdGreen">绿色阀值</param> 1321 /// <returns></returns> 1322 public System.Drawing.Bitmap AdjustToCustomColor(System.Drawing.Bitmap bitmap, int thresholdRed, int thresholdGreen, int thresholdBlue) 1323 { 1324 for (int y = 0; y < bitmap.Height; y++) 1325 { 1326 for (int x = 0; x < bitmap.Width; x++) 1327 { 1328 // 取得每一個 pixel 1329 var pixel = bitmap.GetPixel(x, y); 1330 //判斷是否超過255 如果超過就是255 1331 var pG = pixel.G + thresholdGreen; 1332 //如果小於0就為0 1333 if (pG > 255) pG = 255; 1334 if (pG < 0) pG = 0; 1335 //判斷是否超過255 如果超過就是255 1336 var pR = pixel.R + thresholdRed; 1337 //如果小於0就為0 1338 if (pR > 255) pR = 255; 1339 if (pR < 0) pR = 0; 1340 //判斷是否超過255 如果超過就是255 1341 var pB = pixel.B + thresholdBlue; 1342 //如果小於0就為0 1343 if (pB > 255) pB = 255; 1344 if (pB < 0) pB = 0; 1345 // 將改過的 RGB 寫回 1346 // 只寫入綠色的值 , R B 都放零 1347 System.Drawing.Color newColor = System.Drawing.Color.FromArgb(pixel.A, pR, pG, pB); 1348 bitmap.SetPixel(x, y, newColor); 1349 } 1350 } 1351 return bitmap; 1352 } 1353 #endregion 1354 1355 #region 图片去色(图片黑白化) 1356 /// <summary> 1357 /// 图片去色(图片黑白化) 1358 /// </summary> 1359 /// <param name="original">一个需要处理的图片</param> 1360 /// <returns></returns> 1361 public static Bitmap MakeGrayscale(Bitmap original) 1362 { 1363 //create a blank bitmap the same size as original 1364 Bitmap newBitmap = new Bitmap(original.Width, original.Height); 1365 1366 //get a graphics object from the new image 1367 Graphics g = Graphics.FromImage(newBitmap); 1368 g.SmoothingMode = SmoothingMode.HighQuality; 1369 //create the grayscale ColorMatrix 1370 ColorMatrix colorMatrix = new ColorMatrix(new float[][] 1371 { 1372 new float[] {.3f, .3f, .3f, 0, 0}, 1373 new float[] {.59f, .59f, .59f, 0, 0}, 1374 new float[] {.11f, .11f, .11f, 0, 0}, 1375 new float[] {0, 0, 0, 1, 0}, 1376 new float[] {0, 0, 0, 0, 1} 1377 }); 1378 1379 //create some image attributes 1380 ImageAttributes attributes = new ImageAttributes(); 1381 1382 //set the color matrix attribute 1383 attributes.SetColorMatrix(colorMatrix); 1384 1385 //draw the original image on the new image 1386 //using the grayscale color matrix 1387 g.DrawImage(original, new Rectangle(0, 0, original.Width, original.Height), 1388 0, 0, original.Width, original.Height, GraphicsUnit.Pixel, attributes); 1389 1390 //dispose the Graphics object 1391 g.Dispose(); 1392 return newBitmap; 1393 } 1394 #endregion 1395 1396 #region 增加或減少亮度 1397 /// <summary> 1398 /// 增加或減少亮度 1399 /// </summary> 1400 /// <param name="img">System.Drawing.Image Source </param> 1401 /// <param name="valBrightness">0~255</param> 1402 /// <returns></returns> 1403 public System.Drawing.Bitmap AdjustBrightness(System.Drawing.Image img, int valBrightness) 1404 { 1405 // 讀入欲轉換的圖片並轉成為 Bitmap 1406 System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(img); 1407 1408 for (int y = 0; y < bitmap.Height; y++) 1409 { 1410 for (int x = 0; x < bitmap.Width; x++) 1411 { 1412 // 取得每一個 pixel 1413 var pixel = bitmap.GetPixel(x, y); 1414 1415 // 判斷 如果處理過後 255 就設定為 255 如果小於則設定為 0 1416 var pR = ((pixel.R + valBrightness > 255) ? 255 : pixel.R + valBrightness) < 0 ? 0 : ((pixel.R + valBrightness > 255) ? 255 : pixel.R + valBrightness); 1417 var pG = ((pixel.G + valBrightness > 255) ? 255 : pixel.G + valBrightness) < 0 ? 0 : ((pixel.G + valBrightness > 255) ? 255 : pixel.G + valBrightness); 1418 var pB = ((pixel.B + valBrightness > 255) ? 255 : pixel.B + valBrightness) < 0 ? 0 : ((pixel.B + valBrightness > 255) ? 255 : pixel.B + valBrightness); 1419 1420 // 將改過的 RGB 寫回 1421 System.Drawing.Color newColor = System.Drawing.Color.FromArgb(pixel.A, pR, pG, pB); 1422 1423 bitmap.SetPixel(x, y, newColor); 1424 1425 } 1426 } 1427 // 回傳結果 1428 return bitmap; 1429 } 1430 #endregion 1431 1432 #region 浮雕效果 1433 /// <summary> 1434 /// 浮雕效果 1435 /// </summary> 1436 /// <param name="src">一个图片实例</param> 1437 /// <returns></returns> 1438 public Bitmap AdjustToStone(Bitmap src) 1439 { 1440 // 依照 Format24bppRgb 每三个表示一 Pixel 0: 蓝 1: 绿 2: 红 1441 BitmapData bitmapData = src.LockBits(new Rectangle(0, 0, src.Width, src.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); 1442 1443 unsafe 1444 { 1445 // 抓住第一个 Pixel 第一个数值 1446 byte* p = (byte*)(void*)bitmapData.Scan0; 1447 1448 // 跨步值 - 宽度 *3 可以算出畸零地 之后跳到下一行 1449 int nOffset = bitmapData.Stride - src.Width * 3; 1450 1451 for (int y = 0; y < src.Height; ++y) 1452 { 1453 for (int x = 0; x < src.Width; ++x) 1454 { 1455 // 为了理解方便 所以特地在命名 1456 int r, g, b; 1457 // 先取得下一个 Pixel 1458 var q = p + 3; 1459 r = Math.Abs(p[2] - q[2] + 128); 1460 r = r < 0 ? 0 : r; 1461 r = r > 255 ? 255 : r; 1462 p[2] = (byte)r; 1463 1464 g = Math.Abs(p[1] - q[1] + 128); 1465 g = g < 0 ? 0 : g; 1466 g = g > 255 ? 255 : g; 1467 p[1] = (byte)g; 1468 1469 b = Math.Abs(p[0] - q[0] + 128); 1470 b = b < 0 ? 0 : b; 1471 b = b > 255 ? 255 : b; 1472 p[0] = (byte)b; 1473 1474 // 跳去下一个 Pixel 1475 p += 3; 1476 1477 } 1478 // 跨越畸零地 1479 p += nOffset; 1480 } 1481 } 1482 src.UnlockBits(bitmapData); 1483 return src; 1484 } 1485 #endregion 1486 1487 #region 水波纹效果 1488 /// <summary> 1489 /// 水波纹效果 1490 /// </summary> 1491 /// <param name="src"></param> 1492 /// <param name="nWave">坡度</param> 1493 /// www.it165.net 1494 /// <returns></returns> 1495 public Bitmap AdjustRippleEffect(Bitmap src, short nWave) 1496 { 1497 1498 int nWidth = src.Width; 1499 int nHeight = src.Height; 1500 1501 // 透过公式进行水波纹的採样 1502 1503 PointF[,] fp = new PointF[nWidth, nHeight]; 1504 1505 Point[,] pt = new Point[nWidth, nHeight]; 1506 1507 Point mid = new Point(); 1508 mid.X = nWidth / 2; 1509 mid.Y = nHeight / 2; 1510 1511 double newX, newY; 1512 double xo, yo; 1513 1514 //先取样将水波纹座标跟RGB取出 1515 for (int x = 0; x < nWidth; ++x) 1516 for (int y = 0; y < nHeight; ++y) 1517 { 1518 xo = ((double)nWave * Math.Sin(2.0 * 3.1415 * (float)y / 128.0)); 1519 yo = ((double)nWave * Math.Cos(2.0 * 3.1415 * (float)x / 128.0)); 1520 1521 newX = (x + xo); 1522 newY = (y + yo); 1523 1524 if (newX > 0 && newX < nWidth) 1525 { 1526 fp[x, y].X = (float)newX; 1527 pt[x, y].X = (int)newX; 1528 } 1529 else 1530 { 1531 fp[x, y].X = (float)0.0; 1532 pt[x, y].X = 0; 1533 } 1534 1535 1536 if (newY > 0 && newY < nHeight) 1537 { 1538 fp[x, y].Y = (float)newY; 1539 pt[x, y].Y = (int)newY; 1540 } 1541 else 1542 { 1543 fp[x, y].Y = (float)0.0; 1544 pt[x, y].Y = 0; 1545 } 1546 } 1547 1548 1549 //进行合成 1550 Bitmap bSrc = (Bitmap)src.Clone(); 1551 1552 // 依照 Format24bppRgb 每三个表示一 Pixel 0: 蓝 1: 绿 2: 红 1553 BitmapData bitmapData = src.LockBits(new Rectangle(0, 0, src.Width, src.Height), ImageLockMode.ReadWrite, 1554 PixelFormat.Format24bppRgb); 1555 BitmapData bmSrc = bSrc.LockBits(new Rectangle(0, 0, bSrc.Width, bSrc.Height), ImageLockMode.ReadWrite, 1556 PixelFormat.Format24bppRgb); 1557 1558 int scanline = bitmapData.Stride; 1559 1560 IntPtr Scan0 = bitmapData.Scan0; 1561 IntPtr SrcScan0 = bmSrc.Scan0; 1562 1563 unsafe 1564 { 1565 byte* p = (byte*)(void*)Scan0; 1566 byte* pSrc = (byte*)(void*)SrcScan0; 1567 1568 int nOffset = bitmapData.Stride - src.Width * 3; 1569 1570 int xOffset, yOffset; 1571 1572 for (int y = 0; y < nHeight; ++y) 1573 { 1574 for (int x = 0; x < nWidth; ++x) 1575 { 1576 xOffset = pt[x, y].X; 1577 yOffset = pt[x, y].Y; 1578 1579 if (yOffset >= 0 && yOffset < nHeight && xOffset >= 0 && xOffset < nWidth) 1580 { 1581 p[0] = pSrc[(yOffset * scanline) + (xOffset * 3)]; 1582 p[1] = pSrc[(yOffset * scanline) + (xOffset * 3) + 1]; 1583 p[2] = pSrc[(yOffset * scanline) + (xOffset * 3) + 2]; 1584 } 1585 1586 p += 3; 1587 } 1588 p += nOffset; 1589 } 1590 } 1591 1592 src.UnlockBits(bitmapData); 1593 bSrc.UnlockBits(bmSrc); 1594 1595 return src; 1596 } 1597 #endregion 1598 1599 #region 调整曝光度值 1600 /// <summary> 1601 /// 调整曝光度值 1602 /// </summary> 1603 /// <param name="src">原图</param> 1604 /// <param name="r"></param> 1605 /// <param name="g"></param> 1606 /// <param name="b"></param> 1607 /// <returns></returns> 1608 public Bitmap AdjustGamma(Bitmap src, double r, double g, double b) 1609 { 1610 // 判断是不是在0.2~5 之间 1611 r = Math.Min(Math.Max(0.2, r), 5); 1612 g = Math.Min(Math.Max(0.2, g), 5); 1613 b = Math.Min(Math.Max(0.2, b), 5); 1614 1615 // 依照 Format24bppRgb 每三个表示一 Pixel 0: 蓝 1: 绿 2: 红 1616 BitmapData bitmapData = src.LockBits(new Rectangle(0, 0, src.Width, src.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); 1617 1618 unsafe 1619 { 1620 // 抓住第一个 Pixel 第一个数值 1621 byte* p = (byte*)(void*)bitmapData.Scan0; 1622 1623 // 跨步值 - 宽度 *3 可以算出畸零地 之后跳到下一行 1624 int nOffset = bitmapData.Stride - src.Width * 3; 1625 1626 for (int y = 0; y < src.Height; y++) 1627 { 1628 for (int x = 0; x < src.Width; x++) 1629 { 1630 p[2] = (byte)Math.Min(255, (int)((255.0 * Math.Pow(p[2] / 255.0, 1.0 / r)) + 0.5)); 1631 p[1] = (byte)Math.Min(255, (int)((255.0 * Math.Pow(p[1] / 255.0, 1.0 / g)) + 0.5)); 1632 p[0] = (byte)Math.Min(255, (int)((255.0 * Math.Pow(p[0] / 255.0, 1.0 / b)) + 0.5)); 1633 1634 1635 // 跳去下一个 Pixel 1636 p += 3; 1637 1638 } 1639 // 跨越畸零地 1640 p += nOffset; 1641 } 1642 } 1643 src.UnlockBits(bitmapData); 1644 return src; 1645 1646 } 1647 #endregion 1648 1649 #region 高对比,对过深的颜色调浅,过浅的颜色调深。 1650 /// <summary> 1651 /// 高对比,对过深的颜色调浅,过浅的颜色调深。 1652 /// </summary> 1653 /// <param name="src"></param> 1654 /// <param name="effectThreshold"> 高对比程度 -100~100</param> 1655 /// <returns></returns> 1656 public Bitmap Contrast(Bitmap src, float effectThreshold) 1657 { 1658 1659 // 依照 Format24bppRgb 每三个表示一 Pixel 0: 蓝 1: 绿 2: 红 1660 BitmapData bitmapData = src.LockBits(new Rectangle(0, 0, src.Width, src.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); 1661 1662 // 判断是否在 -100~100 1663 effectThreshold = effectThreshold < -100 ? -100 : effectThreshold; 1664 effectThreshold = effectThreshold > 100 ? 100 : effectThreshold; 1665 1666 effectThreshold = (float)((100.0 + effectThreshold) / 100.0); 1667 effectThreshold *= effectThreshold; 1668 1669 unsafe 1670 { 1671 // 抓住第一个 Pixel 第一个数值 www.it165.net 1672 byte* p = (byte*)(void*)bitmapData.Scan0; 1673 1674 // 跨步值 - 宽度 *3 可以算出畸零地 之后跳到下一行 1675 int nOffset = bitmapData.Stride - src.Width * 3; 1676 1677 1678 1679 for (int y = 0; y < src.Height; y++) 1680 { 1681 for (int x = 0; x < src.Width; x++) 1682 { 1683 double buffer = 0; 1684 1685 1686 // 公式 (Red/255)-0.5= 偏离中间值程度 1687 // ((偏离中间值程度 * 影响范围)+0.4 ) * 255 1688 buffer = ((((p[2] / 255.0) - 0.5) * effectThreshold) + 0.5) * 255.0; 1689 buffer = buffer > 255 ? 255 : buffer; 1690 buffer = buffer < 0 ? 0 : buffer; 1691 p[2] = (byte)buffer; 1692 1693 buffer = ((((p[1] / 255.0) - 0.5) * effectThreshold) + 0.5) * 255.0; 1694 buffer = buffer > 255 ? 255 : buffer; 1695 buffer = buffer < 0 ? 0 : buffer; 1696 p[1] = (byte)buffer; 1697 1698 1699 buffer = ((((p[0] / 255.0) - 0.5) * effectThreshold) + 0.5) * 255.0; 1700 buffer = buffer > 255 ? 255 : buffer; 1701 buffer = buffer < 0 ? 0 : buffer; 1702 p[0] = (byte)buffer; 1703 1704 1705 1706 1707 // 跳去下一个 Pixel 1708 p += 3; 1709 1710 } 1711 // 跨越畸零地 1712 p += nOffset; 1713 } 1714 } 1715 src.UnlockBits(bitmapData); 1716 return src; 1717 1718 1719 } 1720 #endregion 1721 1722 #region 对图片进行雾化效果 1723 /// <summary> 1724 /// 对图片进行雾化效果 1725 /// </summary> 1726 /// <param name="bmp"></param> 1727 /// <returns></returns> 1728 public Bitmap Atomization(Bitmap bmp) 1729 { 1730 1731 int Height = bmp.Height; 1732 int Width = bmp.Width; 1733 Bitmap newBitmap = new Bitmap(Width, Height); 1734 Bitmap oldBitmap = bmp; 1735 Color pixel; 1736 for (int x = 1; x < Width - 1; x++) 1737 { 1738 for (int y = 1; y < Height - 1; y++) 1739 { 1740 Random MyRandom = new Random(Guid.NewGuid().GetHashCode()); 1741 int k = MyRandom.Next(123456); 1742 //像素块大小 1743 int dx = x + k % 19; 1744 int dy = y + k % 19; 1745 if (dx >= Width) 1746 dx = Width - 1; 1747 if (dy >= Height) 1748 dy = Height - 1; 1749 pixel = oldBitmap.GetPixel(dx, dy); 1750 newBitmap.SetPixel(x, y, pixel); 1751 } 1752 } 1753 return newBitmap; 1754 } 1755 #endregion 1756 1757 1758 } //END Class DrawValidationCode 1759 #endregion 1760 1761 #region 高斯模糊算法 1762 /// <summary> 1763 /// 高斯模糊算法 1764 /// </summary> 1765 public class Gaussian 1766 { 1767 public static double[,] Calculate1DSampleKernel(double deviation, int size) 1768 { 1769 double[,] ret = new double[size, 1]; 1770 double sum = 0; 1771 int half = size / 2; 1772 for (int i = 0; i < size; i++) 1773 { 1774 ret[i, 0] = 1 / (Math.Sqrt(2 * Math.PI) * deviation) * Math.Exp(-(i - half) * (i - half) / (2 * deviation * deviation)); 1775 sum += ret[i, 0]; 1776 } 1777 return ret; 1778 } 1779 public static double[,] Calculate1DSampleKernel(double deviation) 1780 { 1781 int size = (int)Math.Ceiling(deviation * 3) * 2 + 1; 1782 return Calculate1DSampleKernel(deviation, size); 1783 } 1784 public static double[,] CalculateNormalized1DSampleKernel(double deviation) 1785 { 1786 return NormalizeMatrix(Calculate1DSampleKernel(deviation)); 1787 } 1788 public static double[,] NormalizeMatrix(double[,] matrix) 1789 { 1790 double[,] ret = new double[matrix.GetLength(0), matrix.GetLength(1)]; 1791 double sum = 0; 1792 for (int i = 0; i < ret.GetLength(0); i++) 1793 { 1794 for (int j = 0; j < ret.GetLength(1); j++) 1795 sum += matrix[i, j]; 1796 } 1797 if (sum != 0) 1798 { 1799 for (int i = 0; i < ret.GetLength(0); i++) 1800 { 1801 for (int j = 0; j < ret.GetLength(1); j++) 1802 ret[i, j] = matrix[i, j] / sum; 1803 } 1804 } 1805 return ret; 1806 } 1807 public static double[,] GaussianConvolution(double[,] matrix, double deviation) 1808 { 1809 double[,] kernel = CalculateNormalized1DSampleKernel(deviation); 1810 double[,] res1 = new double[matrix.GetLength(0), matrix.GetLength(1)]; 1811 double[,] res2 = new double[matrix.GetLength(0), matrix.GetLength(1)]; 1812 //x-direction 1813 for (int i = 0; i < matrix.GetLength(0); i++) 1814 { 1815 for (int j = 0; j < matrix.GetLength(1); j++) 1816 res1[i, j] = processPoint(matrix, i, j, kernel, 0); 1817 } 1818 //y-direction 1819 for (int i = 0; i < matrix.GetLength(0); i++) 1820 { 1821 for (int j = 0; j < matrix.GetLength(1); j++) 1822 res2[i, j] = processPoint(res1, i, j, kernel, 1); 1823 } 1824 return res2; 1825 } 1826 private static double processPoint(double[,] matrix, int x, int y, double[,] kernel, int direction) 1827 { 1828 double res = 0; 1829 int half = kernel.GetLength(0) / 2; 1830 for (int i = 0; i < kernel.GetLength(0); i++) 1831 { 1832 int cox = direction == 0 ? x + i - half : x; 1833 int coy = direction == 1 ? y + i - half : y; 1834 if (cox >= 0 && cox < matrix.GetLength(0) && coy >= 0 && coy < matrix.GetLength(1)) 1835 { 1836 res += matrix[cox, coy] * kernel[i, 0]; 1837 } 1838 } 1839 return res; 1840 } 1841 /// <summary> 1842 /// 对颜色值进行灰色处理 1843 /// </summary> 1844 /// <param name="cr"></param> 1845 /// <returns></returns> 1846 private Color grayscale(Color cr) 1847 { 1848 return Color.FromArgb(cr.A, (int)(cr.R * .3 + cr.G * .59 + cr.B * 0.11), 1849 (int)(cr.R * .3 + cr.G * .59 + cr.B * 0.11), 1850 (int)(cr.R * .3 + cr.G * .59 + cr.B * 0.11)); 1851 } 1852 /// <summary> 1853 /// 对图片进行高斯模糊 1854 /// </summary> 1855 /// <param name="d">模糊数值,数值越大模糊越很</param> 1856 /// <param name="image">一个需要处理的图片</param> 1857 /// <returns></returns> 1858 public Bitmap FilterProcessImage(double d, Bitmap image) 1859 { 1860 Bitmap ret = new Bitmap(image.Width, image.Height); 1861 Double[,] matrixR = new Double[image.Width, image.Height]; 1862 Double[,] matrixG = new Double[image.Width, image.Height]; 1863 Double[,] matrixB = new Double[image.Width, image.Height]; 1864 for (int i = 0; i < image.Width; i++) 1865 { 1866 for (int j = 0; j < image.Height; j++) 1867 { 1868 //matrix[i, j] = grayscale(image.GetPixel(i, j)).R; 1869 matrixR[i, j] = image.GetPixel(i, j).R; 1870 matrixG[i, j] = image.GetPixel(i, j).G; 1871 matrixB[i, j] = image.GetPixel(i, j).B; 1872 } 1873 } 1874 matrixR = Gaussian.GaussianConvolution(matrixR, d); 1875 matrixG = Gaussian.GaussianConvolution(matrixG, d); 1876 matrixB = Gaussian.GaussianConvolution(matrixB, d); 1877 for (int i = 0; i < image.Width; i++) 1878 { 1879 for (int j = 0; j < image.Height; j++) 1880 { 1881 Int32 R = (int)Math.Min(255, matrixR[i, j]); 1882 Int32 G = (int)Math.Min(255, matrixG[i, j]); 1883 Int32 B = (int)Math.Min(255, matrixB[i, j]); 1884 ret.SetPixel(i, j, Color.FromArgb(R, G, B)); 1885 } 1886 } 1887 return ret; 1888 } 1889 1890 } 1891 #endregion 1892 1893 }
该代码转载自: Web(B/S)生成模糊验证码的几种方式(转载)