安裝
pip install pillow
完整生成流程
from PIL import Image, ImageDraw, ImageFont
import random, math
# 畫布設置
width, height = 120, 40
bgcolor = (255, 255, 255)
image = Image.new('RGB', (width, height), bgcolor)
# 字體(需確保字體文件存在)
try:
font = ImageFont.truetype('DejaVuSans.ttf', 28)
except:
font = ImageFont.load_default()
fontcolor = (0, 0, 0)
draw = ImageDraw.Draw(image)
# 生成隨機驗證碼
code = ''.join(random.choices('ABCDEFGHJKLMNPQRSTUVWXYZ23456789', k=4))
draw.text((10, 5), code, font=font, fill=fontcolor)
# 釋放 draw(繪製扭曲前需重建)
del draw
# 扭曲變形
new_image = Image.new('RGB', (width, height), bgcolor)
new_pix = new_image.load()
pix = image.load()
offset = 0
for y in range(height):
offset += 1
for x in range(width):
new_x = x + offset
# 正弦波扭曲:new_x = x + math.sin(y/10)*10
if new_x < width:
new_pix[new_x, y] = pix[x, y]
# 仿射變形
new_image = new_image.transform((width+20, height+10), Image.AFFINE, (1, -0.3, 0, -0.1, 1, 0))
# 干擾線
draw = ImageDraw.Draw(new_image)
line_color = (0, 0, 0)
for _ in range(8):
x1, x2 = random.randint(0, width), random.randint(0, width)
y1, y2 = random.randint(0, height), random.randint(0, height)
draw.line([(x1, y1), (x2, y2)], fill=line_color)
# 保存
new_image.save('captcha.png')
print(f'驗證碼: {code}')
關鍵技術點
- 字體:生產環境請打包 TTF 字體,避免系統缺失;
- 字符集:排除易混淆字符(O/0, I/1, l/1);
- 扭曲:像素偏移或
Image.AFFINE 仿射變換;
- 干擾線/點:適量即可,過多影響用戶識別;
- Session 存儲:驗證碼需存入 Session/Redis,驗證時比對並刪除。
Flask 集成示例
from flask import Flask, session, send_file
from io import BytesIO
app = Flask(__name__)
app.secret_key = 'your_secret'
@app.route('/captcha')
def captcha():
img, code = generate_captcha() # 返回 Image 對象與字符串
session['captcha'] = code.lower()
buf = BytesIO()
img.save(buf, 'PNG')
buf.seek(0)
return send_file(buf, mimetype='image/png')
@app.route('/verify', methods=['POST'])
def verify():
if request.form.get('captcha', '').lower() == session.pop('captcha', ''):
return 'OK'
return 'FAIL', 400