zoukankan      html  css  js  c++  java
  • 点击式验证码

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

    环境 W8.1 VS2013 .NET4.5 WPF

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

    /// <summary>
        /// 生成验证码图片
        /// 随机的验证码包含0-9十个数字和A-Z 26个字母(ascii65-90)
        /// </summary>
        internal class CreateValidateImg
        {
            private static string codesource = "QAZXSWEDCVFRTGBNHYUJMKIOLP0123456789";// 随机源
            private static Random rand = new Random();// 随机工具
            private static Dictionary<Point, string> pointdic = null;// 坐标系(键)所在验证码(值)
            private static string codestr = null;// 验证码
            private static int width = 201;//
            private static int height = 121;//
            internal static MemoryStream ms = null;// 保存验证码选择图片的流
            public static MemoryStream mscode = null;// 保存验证码图片的流
            
            /// <summary>
            /// 画出验证码图片,
            /// </summary>
            /// <returns></returns>
            internal static void ValidateImg()
            {
                /*创建验证码选择图片*/
                Bitmap vpic = new Bitmap(width, height);// 创建一个图片 用于验证码选择
    
                Graphics g = Graphics.FromImage(vpic);// 根据这个图片创建绘画工具
                // 开始绘画
                g.FillRectangle(Brushes.Gold, 0, 0, width, height);// 填充一个颜色
                // 1.画一个3行4列的网格,均分160长 60高
                for (int i = 0; i < 4; i++)
                {
                    g.DrawLine(Pens.Blue, new Point(0, i * 40), new Point(width, i * 40));
                }
                for (int i = 0; i < 5; i++)
                {
                    g.DrawLine(Pens.Blue, new Point(i * 50, 0), new Point(i * 50,width));
                }
                // 2.画12个字符
                pointdic = new Dictionary<Point, string>(12);// 初始化坐标系的值
                for (int i = 0; i < 3; i++)
                {
                    for (int j = 0; j < 4; j++)
                    {
                        char a = codesource[rand.Next(0, 36)];//
                        g.DrawString(a.ToString(), new Font("Anonymous Pro", 15,FontStyle.Bold), Brushes.Black,
                            new Point(j * 50 + 16, i * 40 + 10));// 画画
                        pointdic.Add(new Point(j,i), a.ToString());// 坐标 码 键值对
                    }
                }
                // 创建内存流,将图片保存在其中
                ms = new MemoryStream();
                vpic.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
                // 让内存流回到开头的位置
                ms.Seek(0, SeekOrigin.Begin);
    
                /********再创建验证码图片********/
                Bitmap vimg = new Bitmap(200,30);
                g = Graphics.FromImage(vimg);
                g.FillRectangle(Brushes.Orange, 0, 0, 200, 30);
                // 从字典中随机5个验证码字符
                string[] vcodearray = pointdic.Values.ToArray<string>();
                codestr = "";
                for (int i = 0; i < 5; i++)
                {
                    string vc = vcodearray[rand.Next(0, 12)];
                    g.DrawString(vc, new Font("Anonymous Pro", 15, FontStyle.Bold), Brushes.Black,
                            new Point(i*30+30,5));// 画画
                    codestr = codestr + vc;
                }
                mscode = new MemoryStream();
                vimg.Save(mscode, System.Drawing.Imaging.ImageFormat.Jpeg);
                mscode.Seek(0, SeekOrigin.Begin);
            }
    
    
            /// <summary>
            /// 画出验证码图片中被点击的部分
            /// </summary>
            /// <param name="newxy"></param>
            /// <returns></returns>
            internal static MemoryStream ValidateImgPartial(int x,int y)
            {
    
                // 当前的验证码图片 从流中读出来
                Bitmap bmp = new Bitmap(ms);
                // 将点击指定的部分复制出来
                Bitmap pbmp = bmp.Clone(new Rectangle(x * 50, y * 40, 51, 41), System.Drawing.Imaging.PixelFormat.Format24bppRgb);
                // 返回图片数据
                MemoryStream pms = new MemoryStream();
                pbmp.Save(pms, System.Drawing.Imaging.ImageFormat.Jpeg);
                pms.Seek(0, SeekOrigin.Begin);
                return pms;
            }
            /// <summary>
            /// 根据坐标键获取单个验证码
            /// </summary>
            /// <param name="xy"></param>
            internal static string GetCodeByPoint(int x ,int y)
            {
                Point xy = new Point(x, y);
                if(pointdic.ContainsKey(xy))
                {
                    string c=pointdic[xy];
                    return c;
                }
                return "no code are finded";
            }
    
            /// <summary>
            /// 根据坐标数组比较验证码正确性
            /// </summary>
            /// <param name="point"></param>
            /// <returns></returns>
            internal static string ToValidate(Point[] point)
            {
                StringBuilder sb = new StringBuilder();
                foreach (Point item in point)
                {
                    if (pointdic.ContainsKey(item))
                    {
                        sb.Append(pointdic[item]);
                    }
                    else
                    {
                        return "验证码有误";
                    }
                }
                if (string.Compare(codestr, sb.ToString(), true)==0)
                {
                    return "验证码正确";
                }
                else
                {
                    return "验证码有误";
                }
            }
        }
    View Code

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

    /// <summary>
        /// VImage.xaml 的交互逻辑
        /// </summary>
        public partial class VImage : Window
        {
            public VImage()
            {
                InitializeComponent();
            }
            private List<System.Drawing.Point> pointlist = new List<System.Drawing.Point>();// 收集每次点击的坐标,在重置按钮时会被清空
            private void Window_Loaded(object sender, RoutedEventArgs e)
            {
                InItValidateImage();
            }
    
            private void InItValidateImage()
            {
                // 1。验证码图片
                BitmapImage big = new BitmapImage();
                big.BeginInit();// 初始化开始
                CreateValidateImg.ValidateImg();
                big.StreamSource = CreateValidateImg.mscode;// 图片源来自这个流
                big.EndInit();// 初始化完成 
                imgcode.Source = big;// 设为IMAGE控件的源
    
                // 2。验证码选框图片
                big = new BitmapImage();// 用于IMAGE控件的图像源
                big.BeginInit();// 初始化开始
                big.StreamSource = CreateValidateImg.ms;// 图片源来自这个流
                big.EndInit();// 初始化完成 
                imgbox.Source = big;// 设为IMAGE控件的源
            }
    
            private void imgbox_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
            {
                Point xy = e.GetPosition(imgbox);
                //MessageBox.Show((int)xy.X / 50 + "   " + (int)xy.Y / 40);
                Image[] img5 = new Image[] { vimg1, vimg2, vimg3, vimg4, vimg5 };
                for (int i = 0; i < img5.Length; i++)
                {
                    if (img5[i].Source == null)
                    {
                        BitmapImage big = new BitmapImage();
                        big.BeginInit();
                        big.StreamSource=CreateValidateImg.ValidateImgPartial((int)xy.X / 50,(int)xy.Y / 40);
                        big.EndInit();
                        img5[i].Source = big;
                        //MessageBox.Show(CreateImg.GetCodeByPoint((int)xy.X / 50, (int)xy.Y / 40) + "  " + (int)xy.X / 50 + "   " + (int)xy.Y / 40);
                        this.pointlist.Add(new System.Drawing.Point((int)xy.X / 50, (int)xy.Y / 40));// 加入到坐标集合
                        if (i != img5.Length-1)
                            break;
                        // 比对验证码.当点完最后一个时才会验证
                        // 1.收集所有点击过的坐标(目前是放在本窗口定义的一个成员内)
                        isvalidatelbl.Content = CreateValidateImg.ToValidate(this.pointlist.ToArray());
                    }
                }
            }
    
            // 重置
            private void Button_Click(object sender, RoutedEventArgs e)
            {
                // 清空图片
                Image[] img5 = new Image[] { vimg1, vimg2, vimg3, vimg4, vimg5 };
                foreach (Image item in img5)
                {
                    item.Source = null;
                }
                // 清空坐标列表
                this.pointlist = new List<System.Drawing.Point>();
                // 清空验证结果信息
                isvalidatelbl.Content = "请选择验证码";
                // 更换验证码
                this.InItValidateImage();
            }
    
            
    
        }
    View Code

    WPF窗体XAML

    <Window x:Class="WpfApplication1.VImage"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="VImage" Height="400" Width="300" Loaded="Window_Loaded" WindowStartupLocation="CenterOwner">
        <Grid>
            <Image x:Name="imgbox" HorizontalAlignment="Left" Height="121" Margin="52,79,0,0" VerticalAlignment="Top" Width="201" MouseLeftButtonUp="imgbox_MouseLeftButtonUp"/>
            <WrapPanel x:Name="wpl1" Height="45" Margin="0,214,0,0" VerticalAlignment="Top">
                <Image x:Name="vimg1" Height="41" Width="51" RenderTransformOrigin="0.5,0.5" VerticalAlignment="Top" HorizontalAlignment="Left"/>
                <Image x:Name="vimg2" Height="41" Width="51" OpacityMask="#FFDE4A4A" RenderTransformOrigin="0.5,0.5" VerticalAlignment="Top" HorizontalAlignment="Left"/>
                <Image x:Name="vimg3" Height="41" Width="51" OpacityMask="#FFDE4A4A" RenderTransformOrigin="0.5,0.5" VerticalAlignment="Top" HorizontalAlignment="Left"/>
                <Image x:Name="vimg4" Height="41" OpacityMask="#FFDE4A4A" Width="51" RenderTransformOrigin="0.5,0.5" VerticalAlignment="Top" HorizontalAlignment="Left"/>
                <Image x:Name="vimg5" Height="41" Width="51" RenderTransformOrigin="0.5,0.5" OpacityMask="#FFDE4A4A" VerticalAlignment="Top" HorizontalAlignment="Left"/>
            </WrapPanel>
            <Button Content="reset" HorizontalAlignment="Left" Height="22" Margin="106,322,0,0" VerticalAlignment="Top" Width="68" Click="Button_Click" RenderTransformOrigin="2.088,0.727"/>
            <Image x:Name="imgcode" HorizontalAlignment="Left" Height="31" Margin="65,43,0,0" VerticalAlignment="Top" Width="148" RenderTransformOrigin="0.574,0.774"/>
            <Label Content="请在表格中点击输入验证码" HorizontalAlignment="Left" Height="28" Margin="25,10,0,0" VerticalAlignment="Top" Width="187"/>
            <Label x:Name="isvalidatelbl" Content="请点击图片选择验证码" VerticalAlignment="Top" Margin="0,275,0,0" HorizontalContentAlignment="Center" Foreground="#FF8D2121" FontWeight="Bold"/>
    
        </Grid>
    </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差别很大,以前的办法都不好使了

  • 相关阅读:
    Spring MVC(1)Spring MVC的初始化和流程以及SSM的实现
    Spring(四)Spring与数据库编程
    MyBatis(4)-- 动态SQL
    MyBatis(3)-- Mapper映射器
    MyBatis(2)-- MyBatis配置mybatis-config.xml
    MyBatis(1)-- MyBatis介绍
    计算机网络(2)-- URL、HTTP、HTTPS、HTML
    计算机网络(1)- TCP
    Shell脚本编程
    和为定值的多个数
  • 原文地址:https://www.cnblogs.com/mirrortom/p/3991117.html
Copyright © 2011-2022 走看看