tornado 图形验证码

 

 

from handlers import VerifyCode
urls=[
(r'/api/piccode',VerifyCode.PicCodeHandler),
]

captcha.py

  1 #coding:utf-8
  2 
  3 import random
  4 from PIL import Image, ImageDraw, ImageFont, ImageFilter
  5 
  6 _letter_cases = "abcdefghjkmnpqrstuvwxy"  # 小写字母,去除可能干扰的i,l,o,z
  7 _upper_cases = _letter_cases.upper()  # 大写字母
  8 _numbers = ''.join(map(str, range(3, 10)))  # 数字
  9 init_chars = ''.join((_letter_cases, _upper_cases, _numbers))
 10 
 11 def create_validate_code(size=(120, 30),
 12                          chars=init_chars,
 13                          img_type="GIF",
 14                          mode="RGB",
 15                          bg_color=(255, 255, 255),
 16                          fg_color=(0, 0, 255),
 17                          font_size=18,
 18                          font_type="simkai.ttf",   ##在Windows环境,字体一般位于C:\WINDOWS\Fonts文件夹下
 19                          # font_type=r"..\fonts\simfang.ttf",
 20                          length=4,
 21                          draw_lines=True,
 22                          n_line=(1, 2),
 23                          draw_points=True,
 24                          point_chance = 2):
 25     '''
 26     @todo: 生成验证码图片
 27     @param size: 图片的大小,格式(宽,高),默认为(120, 30)
 28     @param chars: 允许的字符集合,格式字符串
 29     @param img_type: 图片保存的格式,默认为GIF,可选的为GIF,JPEG,TIFF,PNG
 30     @param mode: 图片模式,默认为RGB
 31     @param bg_color: 背景颜色,默认为白色
 32     @param fg_color: 前景色,验证码字符颜色,默认为蓝色#0000FF
 33     @param font_size: 验证码字体大小
 34     @param font_type: 验证码字体,默认为 ae_AlArabiya.ttf
 35     @param length: 验证码字符个数
 36     @param draw_lines: 是否划干扰线
 37     @param n_lines: 干扰线的条数范围,格式元组,默认为(1, 2),只有draw_lines为True时有效
 38     @param draw_points: 是否画干扰点
 39     @param point_chance: 干扰点出现的概率,大小范围[0, 100]
 40     @return: [0]: PIL Image实例
 41     @return: [1]: 验证码图片中的字符串
 42     '''
 43 
 44     width, height = size # 宽, 高
 45     img = Image.new(mode, size, bg_color) # 创建图形
 46     draw = ImageDraw.Draw(img) # 创建画笔
 47 
 48     def get_chars():
 49         '''生成给定长度的字符串,返回列表格式'''
 50         return random.sample(chars, length)
 51 
 52     def create_lines():
 53         '''绘制干扰线'''
 54         line_num = random.randint(*n_line) # 干扰线条数
 55 
 56         for i in range(line_num):
 57             # 起始点
 58             begin = (random.randint(0, size[0]), random.randint(0, size[1]))
 59             #结束点
 60             end = (random.randint(0, size[0]), random.randint(0, size[1]))
 61             draw.line([begin, end], fill=(0, 0, 0))
 62 
 63     def create_points():
 64         '''绘制干扰点'''
 65         chance = min(100, max(0, int(point_chance))) # 大小限制在[0, 100]
 66 
 67         for w in range(width):
 68             for h in range(height):
 69                 tmp = random.randint(0, 100)
 70                 if tmp > 100 - chance:
 71                     draw.point((w, h), fill=(0, 0, 0))
 72 
 73     def create_strs():
 74         '''绘制验证码字符'''
 75         c_chars = get_chars()
 76         strs = ' %s ' % ' '.join(c_chars) # 每个字符前后以空格隔开
 77 
 78         font = ImageFont.truetype(font_type, font_size)
 79         font_width, font_height = font.getsize(strs)
 80 
 81         draw.text(((width - font_width) / 3, (height - font_height) / 3),
 82                     strs, font=font, fill=fg_color)
 83 
 84         return ''.join(c_chars)
 85 
 86     if draw_lines:
 87         create_lines()
 88     if draw_points:
 89         create_points()
 90     strs = create_strs()
 91 
 92     # 图形扭曲参数
 93     params = [1 - float(random.randint(1, 2)) / 100,
 94               0,
 95               0,
 96               0,
 97               1- float(random.randint(1, 10)) / 100,
 98               float(random.randint(1, 2)) / 500,
 99               0.001,
100               float(random.randint(1, 2)) / 500
101               ]
102     img = img.transform(size, Image.PERSPECTIVE, params) # 创建扭曲
103 
104     img = img.filter(ImageFilter.EDGE_ENHANCE_MORE) # 滤镜,边界加强(阈值更大)
105 
106     return img, strs
VerifyCode.py
 1 from .BaseHandler import BaseHandler
 2 import logging
 3 import io
 4 import re
 5 import random
 6 
 7 from utils.captcha.captcha import create_validate_code
 8 from constants import *
 9 
10 
11 class PicCodeHandler(BaseHandler):
12     # #验证图形验证码
13     # def get(self, *args, **kwargs):
14     #     # 创建一个文件流
15     #     imgio = io.BytesIO()
16     #     # 生成图片对象和对应字符串
17     #     img, code = create_validate_code()
18     #     # 将图片信息保存到文件流
19     #     img.save(imgio, 'GIF')
20     #     # 返回图片
21     #     self.set_header("Content-Type", "image/jpg")
22     #     self.write(imgio.getvalue())
23 
24 
25     """图片验证码"""
26     def get(self):
27         """获取图片验证码"""
28         pre_code_id = self.get_argument("pre", "")
29         cur_code_id = self.get_argument("cur","")
30         # 创建一个文件流
31         imgio = io.BytesIO()
32         # 生成图片对象和对应字符串
33         pic, text= create_validate_code()
34         # 将图片信息保存到文件流
35         pic.save(imgio, 'GIF')
36 
37         try:
38             if pre_code_id:
39                 self.redis.delete("pic_code_%s" % pre_code_id)
40                 # self.redis.delete("")
41             # self.redis.setex(name, expries, value)
42             self.redis.setex("pic_code_%s" % cur_code_id, PIC_CODE_EXPIRES_SECONDS, text)
43         except Exception as e:
44             logging.error(e)
45             self.write("")
46         else:
47             self.set_header("Content-Type", "image/jpg")
48             # 返回图片
49             self.write(imgio.getvalue())

register.html

1 <div class="input-group">
2                     <div class="input-group-addon"><i class="fa fa-image fa-lg fa-fw"></i></div>
3                     <input type="text" class="form-control" name="imagecode" id="imagecode" placeholder="图片验证码" required>
4                     <div class="input-group-addon image-code" onclick="generateImageCode();"><img src=""></div>
5                 </div>

register.js

 1 var imageCodeId = "";
 2 
 3 function generateUUID() {
 4     var d = new Date().getTime();
 5     if(window.performance && typeof window.performance.now === "function"){
 6         d += performance.now(); //use high-precision timer if available
 7     }
 8     var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
 9         var r = (d + Math.random()*16)%16 | 0;
10         d = Math.floor(d/16);
11         return (c=='x' ? r : (r&0x3|0x8)).toString(16);
12     });
13     return uuid;
14 }
15 
16 function generateImageCode() {
17     var picId = generateUUID();
18     $(".image-code img").attr("src", "/api/piccode?pre="+imageCodeId+"&cur="+picId);
19     imageCodeId = picId;
20 }

 

 

 

 

posted on 2020-04-15 20:05  cherry_ning  阅读(123)  评论(0)    收藏  举报

导航