点击式验证码

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

环境 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 "验证码有误";
            }
        }
    }

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();
        }

    }

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>

大体实现思路:

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差别很大,以前的办法都不好使了

时间: 2024-10-04 17:51:47

点击式验证码的相关文章

拖动式验证码

拖动式验证码 问题点: 1.无法直接通过发送url请求来实现鼠标拖动的动作: 2.实际的背景图片是乱的,并不是我们实际肉眼看到的图像! 3.“开创行为判别算法,利用数据挖掘和机器学习,提取超过200多个行为判别特征,建立坚若磐石的多维验证防御体系.”这是官网的描述,听上去就已经很高大上,查了些资料也都说拖动轨迹的识别是geetest的核心内容而无过多的表述,那么这也应该是主要的难点了 提供的是一种思路: 1.获取图片,调整拼接 2.计算图片缺口(这个实例的计算不太理想) 3.生成移动轨迹(模拟)

网易易盾行为式验证码家族添新成员:图标点选验证码上线 尤适出海企业

近日,网易易盾行为式验证码家族迎来一位新的成员--图标点选验证码,在提供高安全性.国际化的同时,又更加通用化,适合出海企业和服务于低龄端的产品应用.左为文字点选式验证码,右为图标点选式验证码 在图标点选式验证码使用上,用户只要根据提示,按照顺序点击图中图标,即可完成验证.相较文字点选式验证码,它更加通用化,非中文用户也可以轻松识别完成验证. 图标点选式验证码开发原理与传统验证码不同,主要是通过收集用户的行为轨迹信息.设备信息等,作为人机判别依据. 不同于文字点选,由于图标元素周期性叠代更新,再加

Jquery插件 防刷新倒计时 “点击获取验证码后60秒内禁止重新获取

Jquery插件实现"点击获取验证码后60秒内禁止重新获取(防刷新)" 效果图: 先到官网(http://plugins.jQuery.com/cookie/)下载cookie插件,放到相应文件夹,代码如下: 1 <style type="text/css"> 2 * {margin: 0; 3 padding: 0; 4 font-family: "Microsoft Yahei"; 5 } 6 .captcha-box { 7 w

Andorid实现点击获取验证码倒计时效果

这篇文章主要介绍了Andorid实现点击获取验证码倒计时效果,这种效果大家经常遇到,想知道如何实现的,请阅读本文 我们在开发中经常用到倒计时的功能,比如发送验证码后,倒计时60s再进行验证码的获取,为了方便以后使用,这里做个记录,讲讲倒计时器的实现. 1.先进行倒计时工具类的封装 1 public class CountDownTimerUtils extends CountDownTimer { 2 private TextView mTextView; 3 4 /** 5 * @param

CSS鼠标点击式变化图片透明度

今天分享前端代码主题:jequery控制css图片透明度 很多时候在网站图片处理上需要实现一些辅助效果,比如鼠标在图片上滑动时或点击时改变图片颜色(变灰或者其他),其实一个简单的办法就是改变图片css透明度属性. 如何改变呢?一种是纯css,一种使用jquery或者javascript代码控制.第一种使用:hover伪类选择器,本示例使用第二种. 先看最后效果: 第一步:放置图片 <ul id="test">        <li>            <

yourphp点击刷新验证码

加入css <script type="text/javascript" src="./Public/Js/my.js"></script>  没有这段js的话,无法刷新验证码 html代码 <div class="f3"><input name="verifyCode" id="verifyCode" size="7" value="

[oldboy-django][2深入django]点击刷新验证码

# 点击更新验证码,只要重新在发送一个请求即可 <img src="/check_code/" onclick="updateCode(this);" width="150px" height="34px" title="点击刷新验证码"> function updateCode(ths) { ths.src = ths.src + '?' } /check_code/ 和/check_code

点击获取验证码效果

1 var Btn = document.getElementById('btn'); 2 var star = 10; 3 4 Btn.onclick = function(){ 5 var timer = setInterval(function(){ 6 star--; 7 Btn.disabled = true; 8 Btn.innerHTML = "重新发送验证码" + "(" + star + ")"; 9 console.log(s

thinkphp3.2 验证码生成和点击刷新验证码

背景:之前说的自己做的项目,偷懒登录模块没加验证码,想了想还是加上,找了下tp的文档,发现是有整合进去的,特记录下. 一.实例化生成验证码的类(该方法放到IndexController里面便于访问) [php] view plaincopy /**   *    * 验证码生成   */   public function verify_c(){       $Verify = new \Think\Verify();       $Verify->fontSize = 18;       $V