使用 PIL 生成验证码图片

标签: pil 验证码 图片 | 发表时间:2011-07-18 23:46 | 作者:(author unknown) HarryHan
出处:http://simple-is-better.com/

现在的网页中,为了防止机器人提交表单,图片验证码是很常见的应对手段之一。这里就不详细介绍了,相信大家都遇到过。

现在就给出用Python的PIL库实现验证码图片的代码。代码中有详细注释。

#!/usr/bin/env python
#coding=utf-8

import random
from PIL import Image, ImageDraw, ImageFont, ImageFilter

_letter_cases = "abcdefghjkmnpqrstuvwxy" # 小写字母,去除可能干扰的i,l,o,z
_upper_cases = _letter_cases.upper() # 大写字母
_numbers = ''.join(map(str, range(3, 10))) # 数字
init_chars = ''.join((_letter_cases, _upper_cases, _numbers))

def create_validate_code(size=(120, 30),
                         chars=init_chars,
                         img_type="GIF",
                         mode="RGB",
                         bg_color=(255, 255, 255),
                         fg_color=(0, 0, 255),
                         font_size=18,
                         font_type="ae_AlArabiya.ttf",
                         length=4,
                         draw_lines=True,
                         n_line=(1, 2),
                         draw_points=True,
                         point_chance = 2):
    '''
    @todo: 生成验证码图片
    @param size: 图片的大小,格式(宽,高),默认为(120, 30)
    @param chars: 允许的字符集合,格式字符串
    @param img_type: 图片保存的格式,默认为GIF,可选的为GIF,JPEG,TIFF,PNG
    @param mode: 图片模式,默认为RGB
    @param bg_color: 背景颜色,默认为白色
    @param fg_color: 前景色,验证码字符颜色,默认为蓝色#0000FF
    @param font_size: 验证码字体大小
    @param font_type: 验证码字体,默认为 ae_AlArabiya.ttf
    @param length: 验证码字符个数
    @param draw_lines: 是否划干扰线
    @param n_lines: 干扰线的条数范围,格式元组,默认为(1, 2),只有draw_lines为True时有效
    @param draw_points: 是否画干扰点
    @param point_chance: 干扰点出现的概率,大小范围[0, 100]
    @return: [0]: PIL Image实例
    @return: [1]: 验证码图片中的字符串
    '''

    width, height = size # 宽, 高
    img = Image.new(mode, size, bg_color) # 创建图形
    draw = ImageDraw.Draw(img) # 创建画笔

    def get_chars():
        '''生成给定长度的字符串,返回列表格式'''
        return random.sample(chars, length)

    def create_lines():
        '''绘制干扰线'''
        line_num = random.randint(*n_line) # 干扰线条数

        for i in range(line_num):
            # 起始点
            begin = (random.randint(0, size[0]), random.randint(0, size[1]))
            #结束点
            end = (random.randint(0, size[0]), random.randint(0, size[1]))
            draw.line([begin, end], fill=(0, 0, 0))

    def create_points():
        '''绘制干扰点'''
        chance = min(100, max(0, int(point_chance))) # 大小限制在[0, 100]
       
        for w in xrange(width):
            for h in xrange(height):
                tmp = random.randint(0, 100)
                if tmp > 100 - chance:
                    draw.point((w, h), fill=(0, 0, 0))

    def create_strs():
        '''绘制验证码字符'''
        c_chars = get_chars()
        strs = ' %s ' % ' '.join(c_chars) # 每个字符前后以空格隔开
       
        font = ImageFont.truetype(font_type, font_size)
        font_width, font_height = font.getsize(strs)

        draw.text(((width - font_width) / 3, (height - font_height) / 3),
                    strs, font=font, fill=fg_color)
       
        return ''.join(c_chars)

    if draw_lines:
        create_lines()
    if draw_points:
        create_points()
    strs = create_strs()

    # 图形扭曲参数
    params = [1 - float(random.randint(1, 2)) / 100,
              0,
              0,
              0,
              1 - float(random.randint(1, 10)) / 100,
              float(random.randint(1, 2)) / 500,
              0.001,
              float(random.randint(1, 2)) / 500
              ]
    img = img.transform(size, Image.PERSPECTIVE, params) # 创建扭曲

    img = img.filter(ImageFilter.EDGE_ENHANCE_MORE) # 滤镜,边界加强(阈值更大)

    return img, strs

if __name__ == "__main__":
    code_img = create_validate_code()
    code_img.save("validate.gif", "GIF")

最后结果返回一个元组,第一个返回值是Image类的实例,第二个参数是图片中的字符串(比较是否正确的作用)。 

最后结果返回一个元组,第一个返回值是Image类的实例,第二个参数是图片中的字符串(比较是否正确的作用)。

需要提醒的是,如果在生成ImageFont.truetype实例的时候抛出IOError异常,有可能是运行代码的电脑没有包含指定的字体,需要下载安装。

生成的验证码图片效果:

这时候,细心的同学可能要问,如果每次生成验证码,都要先保存生成的图片,再显示到页面。这么做让人太不能接受了。这个时候,我们需要使用python内置的StringIO模块,它有着类似file对象的行为,但是它操作的是内存文件。于是,我们可以这么写代码:

try:
    import cStringIO as StringIO
except ImportError:
    import StringIO

mstream = StringIO.StringIO()
    
img = create_validate_code()[0]
img.save(mstream, "GIF") 

 这样,我们需要输出的图片的时候只要使用“mstream.getvalue()”即可。比如在Django里,我们首先定义这样的url:

from django.conf.urls.defaults import *

urlpatterns = patterns('example.views',
    url(r'^validate/$', 'validate', name='validate'),
)

在views中,我们把正确的字符串保存在session中,这样当用户提交表单的时候,就可以和session中的正确字符串进行比较。

from django.shortcuts import HttpResponse

from validate import create_validate_code

def validate(request):
    mstream = StringIO.StringIO()
    
    validate_code = create_validate_code()
    img = validate_code[0]
    img.save(mstream, "GIF")
    
    request.session['validate'] = validate_code[1]
    
    return HttpResponse(mstream.getvalue(), "image/gif")

# 来源:残阳似血的博客


在微博上关注: 新浪, 腾讯   投稿

最新招聘

更多>>

相关 [pil 验证码 图片] 推荐:

使用 PIL 生成验证码图片

- HarryHan - python.cn(jobs, news)
现在的网页中,为了防止机器人提交表单,图片验证码是很常见的应对手段之一. 这里就不详细介绍了,相信大家都遇到过. 现在就给出用Python的PIL库实现验证码图片的代码. _letter_cases = "abcdefghjkmnpqrstuvwxy" # 小写字母,去除可能干扰的i,l,o,z. _upper_cases = _letter_cases.upper() # 大写字母.

response生成图片验证码

- - ITeye博客
服务器对客户端浏览器做出的响应被封装成一个HttpResponse对象. 要对浏览器进行操作,只需要操作HttpRespones对象,通过HttpServletResponse.getWriter()获得PrintWriter,该对象为outputStream的子类.     本例将使用Servlet输出图片验证码.

伯克利大学学生开发图片验证码Picatcha终结文字验证码CAPTCHA

- bamerl - 36氪
不知道朋友们会不会遇到,反正我会经常看不清楚一些安全验证码中的字母. Picatcha则打算用图片验证来击败过时而且难以分辨的CAPTCHA. 比如说某网站采用了Picatcha的解决方案,那么你在注册时就会看到选择图片验证. 一般情况是呈现给你8张图片,让你选出其中“带有一本书或者以上的所有图片”或者“一张CD或者以上的所有图片”等等.

java 验证码

- - ITeye博客
// 创建字体,字体的大小应该根据图片的高度来定. // 随机产生160条干扰线,使图象中的认证码不易被其它程序探测到. // randomCode用于保存随机产生的验证码,以便用户登录后进行验证. // 随机产生codeCount数字的验证码. // 得到随机产生的验证码数字. // 产生随机的颜色分量来构造颜色值,这样输出的每位数字的颜色值都将不同.

验证码新趋势:NuCaptcha推出动态验证码

- Mac.Baby - 36氪
曾开发过提供视频验证码服务的加拿大创业公司NuCaptcha刚刚发布了动态验证码,可为网站提供新的安全保证,有望为验证码市场带来新气象. 验证码是人们在网站上最常见的安全问题,只要是上网的人都会遇到被要求辨认和输入数字或者单词的情况. 网站通过验证码来区分人和恶意程序. 而我们所见的大部分的验证码都是基于文字的.

10种用户友好的验证码

- Liang - cnBeta.COM
众所周知,验证码就是帮助我们确定答案不是由电脑自己生成的. 今天我推荐给大家10种用户体验绝佳、令人意想不到的验证码设计风格.

验证码的现在与未来

- Yishen - 爱范儿 · Beats of Bits
”验证码“( CAPTCHA )其实并不是各位网友总是在不同网站上看到的难以辨认的字母组合的代名词,而是“全自动区分计算机和人类的图灵测试”的俗称,顾名思义,它的作用是区分计算机和人类. 在 CAPTCHA 测试中,作为服务器的计算机会自动生成一个问题由用户来解答. 这个问题可以由计算机生成并评判,但是必须只有人类才能解答.

jsp+servlet实现验证码功能

- - CSDN博客推荐文章
验证码的功能大多数人可能不都理解,但几乎每个安全网站都会有. 验证码是用来防止非人为因素操作的行为,例如一个黑客要黑一个网站,怎么弄呢. 最简单的思路当然是造成其网路拥堵直至系统瘫痪掉. 如果没有验证码,那么我就可以在注册页面,写一个程序,只有注册表单,不断更换主键或不可重复的内容,不停的提交. 那这样每秒可以注册几万次都有可能,这样服务器就大量负载,很容易就瘫痪并死掉.

Servlet实现图形验证码

- - CSDN博客推荐文章
|-- 配置开发图形验证码Servlet. // 设置响应头 Content-type类型. // 以下三句是用于设置页面不缓存. // 建立指定宽、高和BufferedImage对象. Graphics g = image.getGraphics(); // 该画笔画在image上. Color c = g.getColor(); // 保存当前画笔的颜色,用完画笔后要回复现场.

SimpleCaptcha验证码组件使用

- - 企业架构 - ITeye博客
最近需要做一个验证码信息,在网上找了些验证码组件,选择了SimpleCaptcha组件,java服务器端代码,简单方便使用.       对于此组件里的中文字的验证码,不是很合适,有时候会出现乱码情况,我认为如果想要加入中文字的验证,自己实现匹配就行了.      我这里只做抛砖引玉,贴出主要代码,源码包,SimpleCaptcha组件的源码和DOCS供参考使用(全包超过10mb,不让上传啊).