看到网上的点击式验证码,觉得很方便.

环境 W8.1 VS2013 .NET4.5 WPF

验证码类 CreateValidateImg 主要包含生成验证图片的方法,和比较验证码的方法

  1. /// <summary>
  2. /// 生成验证码图片
  3. /// 随机的验证码包含0-9十个数字和A-Z 26个字母(ascii65-90)
  4. /// </summary>
  5. internal class CreateValidateImg
  6. {
  7. private static string codesource = "QAZXSWEDCVFRTGBNHYUJMKIOLP0123456789";// 随机源
  8. private static Random rand = new Random();// 随机工具
  9. private static Dictionary<Point, string> pointdic = null;// 坐标系(键)所在验证码(值)
  10. private static string codestr = null;// 验证码
  11. private static int width = 201;//
  12. private static int height = 121;//
  13. internal static MemoryStream ms = null;// 保存验证码选择图片的流
  14. public static MemoryStream mscode = null;// 保存验证码图片的流
  15. /// <summary>
  16. /// 画出验证码图片,
  17. /// </summary>
  18. /// <returns></returns>
  19. internal static void ValidateImg()
  20. {
  21. /*创建验证码选择图片*/
  22. Bitmap vpic = new Bitmap(width, height);// 创建一个图片 用于验证码选择
  23. Graphics g = Graphics.FromImage(vpic);// 根据这个图片创建绘画工具
  24. // 开始绘画
  25. g.FillRectangle(Brushes.Gold, 0, 0, width, height);// 填充一个颜色
  26. // 1.画一个3行4列的网格,均分160长 60高
  27. for (int i = 0; i < 4; i++)
  28. {
  29. g.DrawLine(Pens.Blue, new Point(0, i * 40), new Point(width, i * 40));
  30. }
  31. for (int i = 0; i < 5; i++)
  32. {
  33. g.DrawLine(Pens.Blue, new Point(i * 50, 0), new Point(i * 50,width));
  34. }
  35. // 2.画12个字符
  36. pointdic = new Dictionary<Point, string>(12);// 初始化坐标系的值
  37. for (int i = 0; i < 3; i++)
  38. {
  39. for (int j = 0; j < 4; j++)
  40. {
  41. char a = codesource[rand.Next(0, 36)];//
  42. g.DrawString(a.ToString(), new Font("Anonymous Pro", 15,FontStyle.Bold), Brushes.Black,
  43. new Point(j * 50 + 16, i * 40 + 10));// 画画
  44. pointdic.Add(new Point(j,i), a.ToString());// 坐标 码 键值对
  45. }
  46. }
  47. // 创建内存流,将图片保存在其中
  48. ms = new MemoryStream();
  49. vpic.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
  50. // 让内存流回到开头的位置
  51. ms.Seek(0, SeekOrigin.Begin);
  52. /********再创建验证码图片********/
  53. Bitmap vimg = new Bitmap(200,30);
  54. g = Graphics.FromImage(vimg);
  55. g.FillRectangle(Brushes.Orange, 0, 0, 200, 30);
  56. // 从字典中随机5个验证码字符
  57. string[] vcodearray = pointdic.Values.ToArray<string>();
  58. codestr = "";
  59. for (int i = 0; i < 5; i++)
  60. {
  61. string vc = vcodearray[rand.Next(0, 12)];
  62. g.DrawString(vc, new Font("Anonymous Pro", 15, FontStyle.Bold), Brushes.Black,
  63. new Point(i*30+30,5));// 画画
  64. codestr = codestr + vc;
  65. }
  66. mscode = new MemoryStream();
  67. vimg.Save(mscode, System.Drawing.Imaging.ImageFormat.Jpeg);
  68. mscode.Seek(0, SeekOrigin.Begin);
  69. }
  70. /// <summary>
  71. /// 画出验证码图片中被点击的部分
  72. /// </summary>
  73. /// <param name="newxy"></param>
  74. /// <returns></returns>
  75. internal static MemoryStream ValidateImgPartial(int x,int y)
  76. {
  77. // 当前的验证码图片 从流中读出来
  78. Bitmap bmp = new Bitmap(ms);
  79. // 将点击指定的部分复制出来
  80. Bitmap pbmp = bmp.Clone(new Rectangle(x * 50, y * 40, 51, 41), System.Drawing.Imaging.PixelFormat.Format24bppRgb);
  81. // 返回图片数据
  82. MemoryStream pms = new MemoryStream();
  83. pbmp.Save(pms, System.Drawing.Imaging.ImageFormat.Jpeg);
  84. pms.Seek(0, SeekOrigin.Begin);
  85. return pms;
  86. }
  87. /// <summary>
  88. /// 根据坐标键获取单个验证码
  89. /// </summary>
  90. /// <param name="xy"></param>
  91. internal static string GetCodeByPoint(int x ,int y)
  92. {
  93. Point xy = new Point(x, y);
  94. if(pointdic.ContainsKey(xy))
  95. {
  96. string c=pointdic[xy];
  97. return c;
  98. }
  99. return "no code are finded";
  100. }
  101. /// <summary>
  102. /// 根据坐标数组比较验证码正确性
  103. /// </summary>
  104. /// <param name="point"></param>
  105. /// <returns></returns>
  106. internal static string ToValidate(Point[] point)
  107. {
  108. StringBuilder sb = new StringBuilder();
  109. foreach (Point item in point)
  110. {
  111. if (pointdic.ContainsKey(item))
  112. {
  113. sb.Append(pointdic[item]);
  114. }
  115. else
  116. {
  117. return "验证码有误";
  118. }
  119. }
  120. if (string.Compare(codestr, sb.ToString(), true)==0)
  121. {
  122. return "验证码正确";
  123. }
  124. else
  125. {
  126. return "验证码有误";
  127. }
  128. }
  129. }

View Code

 

WPF窗体 包含一个验证码图片框 ,一个验证码选择图片框,点击时存放所点击的验证码图片的框(共有5个)

  1. /// <summary>
  2. /// VImage.xaml 的交互逻辑
  3. /// </summary>
  4. public partial class VImage : Window
  5. {
  6. public VImage()
  7. {
  8. InitializeComponent();
  9. }
  10. private List<System.Drawing.Point> pointlist = new List<System.Drawing.Point>();// 收集每次点击的坐标,在重置按钮时会被清空
  11. private void Window_Loaded(object sender, RoutedEventArgs e)
  12. {
  13. InItValidateImage();
  14. }
  15. private void InItValidateImage()
  16. {
  17. // 1。验证码图片
  18. BitmapImage big = new BitmapImage();
  19. big.BeginInit();// 初始化开始
  20. CreateValidateImg.ValidateImg();
  21. big.StreamSource = CreateValidateImg.mscode;// 图片源来自这个流
  22. big.EndInit();// 初始化完成
  23. imgcode.Source = big;// 设为IMAGE控件的源
  24. // 2。验证码选框图片
  25. big = new BitmapImage();// 用于IMAGE控件的图像源
  26. big.BeginInit();// 初始化开始
  27. big.StreamSource = CreateValidateImg.ms;// 图片源来自这个流
  28. big.EndInit();// 初始化完成
  29. imgbox.Source = big;// 设为IMAGE控件的源
  30. }
  31. private void imgbox_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
  32. {
  33. Point xy = e.GetPosition(imgbox);
  34. //MessageBox.Show((int)xy.X / 50 + " " + (int)xy.Y / 40);
  35. Image[] img5 = new Image[] { vimg1, vimg2, vimg3, vimg4, vimg5 };
  36. for (int i = 0; i < img5.Length; i++)
  37. {
  38. if (img5[i].Source == null)
  39. {
  40. BitmapImage big = new BitmapImage();
  41. big.BeginInit();
  42. big.StreamSource=CreateValidateImg.ValidateImgPartial((int)xy.X / 50,(int)xy.Y / 40);
  43. big.EndInit();
  44. img5[i].Source = big;
  45. //MessageBox.Show(CreateImg.GetCodeByPoint((int)xy.X / 50, (int)xy.Y / 40) + " " + (int)xy.X / 50 + " " + (int)xy.Y / 40);
  46. this.pointlist.Add(new System.Drawing.Point((int)xy.X / 50, (int)xy.Y / 40));// 加入到坐标集合
  47. if (i != img5.Length-1)
  48. break;
  49. // 比对验证码.当点完最后一个时才会验证
  50. // 1.收集所有点击过的坐标(目前是放在本窗口定义的一个成员内)
  51. isvalidatelbl.Content = CreateValidateImg.ToValidate(this.pointlist.ToArray());
  52. }
  53. }
  54. }
  55. // 重置
  56. private void Button_Click(object sender, RoutedEventArgs e)
  57. {
  58. // 清空图片
  59. Image[] img5 = new Image[] { vimg1, vimg2, vimg3, vimg4, vimg5 };
  60. foreach (Image item in img5)
  61. {
  62. item.Source = null;
  63. }
  64. // 清空坐标列表
  65. this.pointlist = new List<System.Drawing.Point>();
  66. // 清空验证结果信息
  67. isvalidatelbl.Content = "请选择验证码";
  68. // 更换验证码
  69. this.InItValidateImage();
  70. }
  71. }

View Code

WPF窗体XAML

  1. <Window x:Class="WpfApplication1.VImage"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. Title="VImage" Height="400" Width="300" Loaded="Window_Loaded" WindowStartupLocation="CenterOwner">
  5. <Grid>
  6. <Image x:Name="imgbox" HorizontalAlignment="Left" Height="121" Margin="52,79,0,0" VerticalAlignment="Top" Width="201" MouseLeftButtonUp="imgbox_MouseLeftButtonUp"/>
  7. <WrapPanel x:Name="wpl1" Height="45" Margin="0,214,0,0" VerticalAlignment="Top">
  8. <Image x:Name="vimg1" Height="41" Width="51" RenderTransformOrigin="0.5,0.5" VerticalAlignment="Top" HorizontalAlignment="Left"/>
  9. <Image x:Name="vimg2" Height="41" Width="51" OpacityMask="#FFDE4A4A" RenderTransformOrigin="0.5,0.5" VerticalAlignment="Top" HorizontalAlignment="Left"/>
  10. <Image x:Name="vimg3" Height="41" Width="51" OpacityMask="#FFDE4A4A" RenderTransformOrigin="0.5,0.5" VerticalAlignment="Top" HorizontalAlignment="Left"/>
  11. <Image x:Name="vimg4" Height="41" OpacityMask="#FFDE4A4A" Width="51" RenderTransformOrigin="0.5,0.5" VerticalAlignment="Top" HorizontalAlignment="Left"/>
  12. <Image x:Name="vimg5" Height="41" Width="51" RenderTransformOrigin="0.5,0.5" OpacityMask="#FFDE4A4A" VerticalAlignment="Top" HorizontalAlignment="Left"/>
  13. </WrapPanel>
  14. <Button Content="reset" HorizontalAlignment="Left" Height="22" Margin="106,322,0,0" VerticalAlignment="Top" Width="68" Click="Button_Click" RenderTransformOrigin="2.088,0.727"/>
  15. <Image x:Name="imgcode" HorizontalAlignment="Left" Height="31" Margin="65,43,0,0" VerticalAlignment="Top" Width="148" RenderTransformOrigin="0.574,0.774"/>
  16. <Label Content="请在表格中点击输入验证码" HorizontalAlignment="Left" Height="28" Margin="25,10,0,0" VerticalAlignment="Top" Width="187"/>
  17. <Label x:Name="isvalidatelbl" Content="请点击图片选择验证码" VerticalAlignment="Top" Margin="0,275,0,0" HorizontalContentAlignment="Center" Foreground="#FF8D2121" FontWeight="Bold"/>
  18.  
  19. </Grid>
  20. </Window>

View Code

大体实现思路:

1.画出两个图片,一张是包含验证码的图片(小图),一张是包含验证码和其它字符的图片(大图),在这图上点击选择验证码,这两个图的生成是同时的,成对的.

2.将两张图片保存为流,并且设为Image控件的Source值.这个方法见http://www.cnblogs.com/pilang/archive/2010/05/30/1747485.html

3.点选时,得到坐标.就是那个3行4列表格里的数字的左上角坐标,如上图中的X坐标是(2,1).当点击选择时,通过获取点击的坐标计算所点字符的相对坐标,如点击X所在的方格时,会得到此时鼠标的坐标值(须以当前图片做为参照元素),将X/50,Y/40就得到X(2,1)的相对坐标.50,40指X所在方格的长宽.

4.将上面得到的坐标还原成实际方格所在坐标,就是再乘以相应的长和宽.到原图中复制出以此坐标为起点,长和宽的值为大小构造的矩形区域.实际就是那个被点的字符块.复制后设为下面的小格中的Image的source值

5.对比验证码,收集每次点击的坐标,在后台字典中(坐标和验证码字符的键值对)找出这些值,然后比较字符即可

其它 :坐标计算 图片部分复制 WPF控件的用法和winform差别很大,以前的办法都不好使了

版权声明:本文为mirrortom原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/mirrortom/p/3991117.html