Commit 77983842 authored by kaiyou's avatar kaiyou

Add a sample image captcha

parent ae838ad8
Pipeline #403 failed with stage
......@@ -2,6 +2,10 @@ from wtforms import widgets
from hiboo.captcha import fields
import random
import string
import io
import base64
from PIL import Image, ImageDraw, ImageFont
class DummyCaptchaField(fields.CaptchaField):
......@@ -35,3 +39,57 @@ class DummyCaptchaField(fields.CaptchaField):
field.data.isdigit() and
challenge == int(field.data)
)
class GeneratedTextImageCaptchaField(fields.CaptchaField):
""" Generate a random text and build a fuzzy image based on that text.
This is the most common historical captcha type, although pretty easily
defeated by OCR nowadays.
"""
widget = widgets.TextInput()
charset = string.ascii_uppercase + string.digits
def _value(self):
return ""
def challenge(self):
self.label = "Please copy the following text: "
length = random.randint(5,8)
return "".join(random.choice(self.charset) for _ in range(length))
def check(self, challenge, form, field):
return challenge.lower() == field.data.lower()
def make_image(self, text):
font = ImageFont.truetype("captcha.ttf", 14)
size = font.getsize(text)
size = (size[0] * 2, int(size[1] * 1.4))
image = Image.new("RGB", size, "#ffffff")
xpos = 2
for char in text:
drawn = " {} ".format(char)
fgimage = Image.new("RGB", size, "#000000")
charimage = Image.new("L", font.getsize(drawn), "#000000")
chardraw = ImageDraw.Draw(charimage)
chardraw.text((0, 0), drawn, font=font, fill="#ffffff")
charimage = charimage.rotate(random.randrange(-15,15), expand=0, resample=Image.BICUBIC)
charimage = charimage.crop(charimage.getbbox())
maskimage = Image.new("L", size)
maskimage.paste(charimage, (xpos, 4, xpos + charimage.size[0], 4 + charimage.size[1]))
size = maskimage.size
image = Image.composite(fgimage, image, maskimage)
xpos = xpos + 2 + charimage.size[0]
image = image.crop((0, 0, xpos + 1, size[1]))
return image
def __call__(self, **kwargs):
image = self.make_image(self.context["challenge"])
image_png = io.BytesIO()
image.save(image_png, "PNG")
image_string = base64.b64encode(image_png.getvalue()).decode("ascii")
return widgets.HTMLString(
'<img src="data:image/png;base64,{}">'.format(image_string) +
super(GeneratedTextImageCaptchaField, self).__call__(**kwargs)
)
......@@ -6,5 +6,5 @@ import flask_wtf
class DisplayForm(flask_wtf.FlaskForm):
test = fields.StringField()
captcha = captcha.DummyCaptchaField()
captcha = captcha.GeneratedTextImageCaptchaField()
submit = fields.SubmitField()
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment