zoukankan      html  css  js  c++  java
  • Flask实战第40天:图片验证码生成技术

    图片验证码生成

    安装pillow

    pip install pillow

    在utils下新建python package命名为captcha

    把需要需要用到的字体放在captcha下

    编辑captcha.__init__.py, 生成验证码

    import random
    import string
    # Image:一个画布
    # ImageDraw:一个画笔
    # ImageFont:画笔的字体
    
    # pip install pillow
    from PIL import Image, ImageDraw, ImageFont
    
    
    class Captcha(object):
        # 生成几位数的验证码
        number = 4
        # 验证码图片的高度和宽度
        size = (100, 30)
        # 验证码字体大小
        fontsize = 25
        #加入干扰线条数
        line_number = 2
    
        #构建一个验证码源文本
        SOURCE = list(string.ascii_letters)
        for index in range(0, 10):
            SOURCE.append(str(index))
    
        #用来绘制干扰线
        @classmethod
        def __gene_line(cls, draw, width, height):
            begin = (random.randint(0, width), random.randint(0, height))
            end = (random.randint(0, width), random.randint(0, height))
            draw.line([begin, end], fill=cls.__gene_random_color(), width=2)
    
        # 用来绘制干扰点
        @classmethod
        def __gene_points(cls, draw, point_chance, width, height):
            chance = min(100, max(0, int(point_chance))) #大小限制在[0, 100]
            for w in range(width):
                for h in range(height):
                    tmp = random.randint(0, 100)
                    if tmp > 100 - chance:
                        draw.point((w, h), fill=cls.__gene_random_color())
    
        # 生成随机的颜色
        @classmethod
        def __gene_random_color(cls, start=0, end=255):
            random.seed()
            return (random.randint(start, end),random.randint(start, end), random.randint(start, end))
    
        # 随机选择一个字体
        @classmethod
        def __gene_random_font(cls):
            fonts = [
                'Courgette-Regular.ttf',
                'LHANDW.TTF',
                'Lobster-Regular.ttf',
                'verdana.ttf'
            ]
            font = random.choice(fonts)
            return 'utils/captcha/' + font
    
        # 用来随机生成一个字符串
        @classmethod
        def gene_text(cls, number):
            #num是生成验证码的位数
            return ''.join(random.sample(cls.SOURCE, number))
    
        # 生成验证码
        @classmethod
        def gene_graph_captcha(cls):
            #验证码图片的高和宽
            width, height = cls.size
            #创建图片
            image = Image.new('RGBA', (width,height),cls.__gene_random_color(0, 100))
            #验证码的字体
            font = ImageFont.truetype(cls.__gene_random_font(), cls.fontsize)
            #创建画笔
            draw = ImageDraw.Draw(image)
            #生成字符串
            text = cls.gene_text(cls.number)
            #获取字体尺寸
            font_width, font_height = font.getsize(text)
            #填充字符串
            draw.text(((width - font_width) / 2, (height - font_height) / 2), text, font=font,
                      fill=cls.__gene_random_color(150, 255))
            #绘制干扰线
            for x in range(0, cls.line_number):
                cls.__gene_line(draw, width, height)
            #绘制噪点
            cls.__gene_points(draw, 10, width, height)
            return (text, image)
    captcha.__init__.py

    测试的时候我发现有些字体会导致程序崩溃,所以,我只设置了一个字体  fonts = ['verdana.ttf']

    编辑视图。我们把它放到 公共的common里面去,编辑common.views.py

    from flask import Blueprint, make_response
    from utils.captcha import Captcha
    from io import BytesIO
    
    bp = Blueprint('common', __name__, url_prefix='/c')  #common太长,改为c
    
    @bp.route('/')
    def index():
        return 'common index'
    
    
    @bp.route('/graph_captcha/')
    def graph_captcha():
        text, image = Captcha.gene_graph_captcha()
        out = BytesIO()
        image.save(out, 'png')
        out.seek(0)
        resp = make_response(out.read())
        resp.content_type = 'image/png'
        return resp

    访问http://127.0.0.1:5000/c/graph_captcha/

    图片验证放到注册页面。点击一次更换一张

    图片验证码放在注册页面比较简单,只需要把编辑front_signup.html,把里面的“图片验证码”字换成img标签,src设置成图片验证码的url

    <div class="input-group">
        <input type="text" class="form-control" name="graph_captcha" placeholder="图形验证码">
        <span class="input-group-addon captcha-addon"> <!--加了一个类captcha-addon-->
             <img  id="captcha-img" src="{{ url_for('common.graph_captcha') }}"><!--加了id aptcha-img-->
        </span>
    </div>
    
    
    <!--样式-->
    .captcha-addon{
         padding: 0;  //这是内边距为0,因为input-group-addon有设置内边距
         overflow: hidden;   //当里面的元素超出则隐藏
    }
    
    #captcha-img{
          height: 32px;   //设置图片的高度为32px
          cursor: pointer;   //当鼠标移到图片上变成手的图标
    }

    还有个需求就是,我们点击一个图片验证码,则需要更换成另外一个。

    图片验证码更换,只需要替换它的url就可以,但是它的url就是一个http://127.0.0.1:5000/common/captcha/

    所以只需要请求的时候加个参数http://127.0.0.1:5000/front/captcha/?xxx=<随机数>即可

    我还需要对?xxx=<随机数>做处理,不然当用户点击多次,?xxx=<随机数>&xxx=<随机数>...变得很长,而我们只需要一个就可以了,这里封装了一个js, 存放在static/common/js/bbsparams.js中

    /**
     * Created by Administrator on 2017/3/24.
     */
    
    var bbsparam = {
        setParam: function (href,key,value) {
            // 重新加载整个页面
            var isReplaced = false;
            var urlArray = href.split('?');
            if(urlArray.length > 1){
                var queryArray = urlArray[1].split('&');
                for(var i=0; i < queryArray.length; i++){
                    var paramsArray = queryArray[i].split('=');
                    if(paramsArray[0] == key){
                        paramsArray[1] = value;
                        queryArray[i] = paramsArray.join('=');
                        isReplaced = true;
                        break;
                    }
                }
    
                if(!isReplaced){
                    var params = {};
                    params[key] = value;
                    if(urlArray.length > 1){
                        href = href + '&' + $.param(params);
                    }else{
                        href = href + '?' + $.param(params);
                    }
                }else{
                    var params = queryArray.join('&');
                    urlArray[1] = params;
                    href = urlArray.join('?');
                }
            }else{
                var param = {};
                param[key] = value;
                if(urlArray.length > 1){
                    href = href + '&' + $.param(param);
                }else{
                    href = href + '?' + $.param(param);
                }
            }
            return href;
        }
    };
    bbsparams

    然后在static/front/js/下新建front_signup.js,当点击图片时更换src

    $(function(){
        $('#captcha-img').click(function (event) {
            var self = $(this);
            var src = self.attr('src');
            var newsrc = bbsparam.setParam(src,'xx',Math.random());
            self.attr('src',newsrc);
        });
    });

    在signup.html中引入上面两个js

    <script src="{{ url_for('static', filename='common/js/bbsparam.js') }}"></script>
    <script src="{{ url_for('static', filename='front/js/front_signup.js') }}"></script>
  • 相关阅读:
    mycat 1.6.6.1 distinct报错问题
    linux下Tomcat+OpenSSL配置单向&双向认证(自制证书)
    Too many open files错误与解决方法
    Tomcat类加载机制触发的Too many open files问题分析(转)
    spring boot 自签发https证书
    redis集群如何解决重启不了的问题
    centos7 docker 安装 zookeeper 3.4.13 集群
    centos7用docker安装kafka
    心怀感恩
    不使用if switch 各种大于 小于 判断2个数的大小
  • 原文地址:https://www.cnblogs.com/sellsa/p/9496705.html
Copyright © 2011-2022 走看看