captcha.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. # -*- coding: UTF-8 -*-
  2. import random,time
  3. from PIL import Image,ImageDraw,ImageFont,ImageFilter
  4. from django.conf import settings
  5. def create_validate_with_conf():
  6. '''
  7. @生成验证码图片
  8. @configItem size: 图片的大小,格式(宽,高),默认为(120, 30)
  9. @configItem img_type: 图片保存的格式,可选的为GIF,JPEG,TIFF,PNG
  10. @configItem mode: 图片模式,例如RGB
  11. @configItem bg_color: 背景颜色,默认为白色
  12. @configItem font_size: 验证码字体大小
  13. @configItem fontType: 验证码字体
  14. @configItem tipFontType: 提示文本字体
  15. @configItem draw_lines: 是否绘制干扰线
  16. @configItem line_range: 干扰线的条数范围,格式为tuple,例如(1, 2),只有draw_lines为True时有效
  17. @configItem draw_points: 是否绘制干扰点
  18. @configItem point_chance: 干扰点出现的概率,大小范围
  19. @return: [0]: PIL Image实例
  20. @return: [1]: 验证码图片中的字符串
  21. '''
  22. size = settings.CAPTCHA_CONF['size']
  23. img_type = settings.CAPTCHA_CONF['img_type']
  24. mode = settings.CAPTCHA_CONF['mode']
  25. bg_color = settings.CAPTCHA_CONF['bg_color']
  26. font_size = settings.CAPTCHA_CONF['font_size']
  27. font_type = settings.CAPTCHA_CONF['fontType']
  28. TipFontType = settings.CAPTCHA_CONF['tipFontType']
  29. draw_lines = settings.CAPTCHA_CONF['draw_lines']
  30. n_line = settings.CAPTCHA_CONF['line_range']
  31. draw_points = settings.CAPTCHA_CONF['draw_points']
  32. point_chance = settings.CAPTCHA_CONF['point_chance']
  33. random.seed(hash(time.time()))
  34. width, height = size # 宽, 高
  35. img = Image.new(mode, size, bg_color) # 创建图形
  36. draw = ImageDraw.Draw(img) # 创建画笔
  37. if draw_lines:
  38. create_lines(draw, n_line, width, height)
  39. if draw_points:
  40. create_points(draw, point_chance, width, height)
  41. ft_color = random.sample(settings.CAPTCHA_CONF['colorList'], 2)
  42. #text = u"请输入和这句话一样颜色的字"
  43. text = u"请输入和图中弧线一样颜色的字"
  44. realline = random.choice([True, False])
  45. subj = random.choice(settings.CAPTCHA_DICT['nouns'])
  46. obj = random.choice(settings.CAPTCHA_DICT['nouns'])
  47. pred = random.choice(settings.CAPTCHA_DICT['verbs'])
  48. rst = subj + pred + obj
  49. subj = random.choice(settings.CAPTCHA_DICT['nouns'])
  50. obj = random.choice(settings.CAPTCHA_DICT['nouns'])
  51. pred = random.choice(settings.CAPTCHA_DICT['verbs'])
  52. fst = subj + pred + obj
  53. if realline:
  54. create_strs(draw, font_type, font_size, width,height, ft_color[0], rst, 8)
  55. create_strs(draw, font_type, font_size, width,height, ft_color[1], fst, 2)
  56. else:
  57. create_strs(draw, font_type, font_size, width,height, ft_color[0], fst, 8)
  58. create_strs(draw, font_type, font_size, width,height, ft_color[1], rst, 2)
  59. # 图形扭曲参数
  60. # params = [1 - float(random.randint(1, 2)) / 100,
  61. # 0,
  62. # 0,
  63. # 0,
  64. ## 1 - float(random.randint(1, 10)) / 100,
  65. ## float(random.randint(1, 2)) / 500,
  66. # 0.001,
  67. ## float(random.randint(1, 2)) / 500
  68. # ]
  69. params = [1 - float(random.randint(1, 2)) / 10000,
  70. 0,
  71. 0,
  72. 0,
  73. 1 - float(random.randint(1, 2)) / 10000,
  74. float(random.randint(1, 2)) / 50000,
  75. 0.001,
  76. float(random.randint(1, 2)) / 50000
  77. ]
  78. # img = img.transform(size, Image.PERSPECTIVE, params) # 创建扭曲
  79. # img = img.filter(ImageFilter.RankFilter(size = 3, rank = 3))
  80. # draw = ImageDraw.Draw(img)
  81. # if realline:
  82. # create_tip_strs(draw, TipFontType, 14, width,height, ft_color[0], text, 1.1)
  83. # else:
  84. # create_tip_strs(draw, TipFontType, 14, width,height, ft_color[1], text, 1.1)
  85. if realline:
  86. create_color_arc(draw, ft_color[0], width, height)
  87. else:
  88. create_color_arc(draw, ft_color[1], width, height)
  89. create_tip_strs(draw, TipFontType, 14, width,height, (0,0,0), text, 1.1)
  90. return img, rst
  91. def create_lines(draw, n_line, width, height):
  92. '''绘制干扰线'''
  93. line_num = random.randint(n_line[0], n_line[1]) # 干扰线条数
  94. for i in range(line_num):
  95. # 起始点
  96. fclr = random.choice(settings.CAPTCHA_CONF['colorList'])
  97. begin = (random.randint(0, width), random.randint(0, height))
  98. # 结束点
  99. end = (random.randint(0, width), random.randint(0, height))
  100. draw.line([begin, end], fill=fclr)
  101. def create_color_arc(draw, color, width, height):
  102. '''显色弧'''
  103. # 起始点
  104. beginx,beginy = random.randint(0, width/2), random.randint(0, height/2)
  105. # 结束点
  106. #endx,endy = (beginx+random.randint(0, width-beginx)), beginy+random.randint(0, height-beginy)
  107. endx,endy = random.randint(width/2, width),random.randint(height/2, height-20)
  108. draw.arc([beginx,beginy,endx,endy],0,120,fill=color)
  109. draw.arc([beginx+1,beginy,endx+1,endy],0,120,fill=color)
  110. draw.arc([beginx-1,beginy,endx-1,endy],0,120,fill=color)
  111. draw.arc([beginx,beginy+1,endx,endy+1],0,120,fill=color)
  112. draw.arc([beginx,beginy-1,endx,endy-1],0,120,fill=color)
  113. def create_points(draw, point_chance, width, height):
  114. '''绘制干扰点'''
  115. chance = min(100, max(0, int(point_chance))) # 大小限制在[0, 100]
  116. for w in xrange(width):
  117. for h in xrange(height):
  118. tmp = random.randint(0, 100)
  119. fclr = random.choice(settings.CAPTCHA_CONF['colorList'])
  120. if tmp > 100 - chance:
  121. draw.point((w, h), fill=fclr)
  122. def create_strs(draw, font_type, font_size, width, height, fg_color, strs, ofs):
  123. '''绘制验证码字符'''
  124. #c_chars = random.sample(chars, length)
  125. # c_chars=random.sample(rjs, length)
  126. # strs = ' %s ' % ' '.join(c_chars) # 每个字符前后以空格隔开
  127. font = ImageFont.truetype(font_type, font_size)
  128. font_width, font_height = font.getsize(strs)
  129. draw.text(((width - font_width) / 3, (height - font_height) / ofs), strs, font=font, fill=fg_color)
  130. def create_tip_strs(draw, font_type, font_size, width, height, fg_color, strs, ofs):
  131. '''绘制验证码字符'''
  132. font = ImageFont.truetype(font_type, font_size)
  133. font_width, font_height = font.getsize(strs)
  134. beginx , beginy = (width - font_width) / 8, (height - font_height) / ofs
  135. draw.rectangle((beginx,beginy,beginx+font_width,beginy+font_height),fill=(255,255,255))
  136. draw.text((beginx,beginy), strs, font=font, fill=fg_color)