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 }