Many websites require you to enter a verification code when registering. This is done to prevent malicious registration by programs and to ensure website security.
1. Pillow
PIL(Python Imaging Library)
It is a powerful python image processing library, but it only supports it python2.7
. Although Pillow is a branch of PIL, pillow supports python3.x and has developed into a more dynamic image processing library than PIL itself. We use Pillow to generate verification codes. The installation method is
pip install Pillow
2. Generate a picture of a specified size and random color
2.1 Random Color
The color processing uses (r, g, b) format, the range of r, g, b is [0, 255], use the random
module randint
method to generate 3 random numbers
def random_color():
c1 = random.randint(0, 255)
c2 = random.randint(0, 255)
c3 = random.randint(0, 255)
return c1, c2, c3
2.2 Generate a picture of a specified size
def random_color():
c1 = random.randint(0, 255)
c2 = random.randint(0, 255)
c3 = random.randint(0, 255)
return c1, c2, c3
def generate_picture(width=120, height=35):
image = Image.new('RGB', (width, height), random_color())
return image
if __name__ == '__main__':
image = generate_picture()
image.save('test.png')
Now just generate a picture with random colors, and then write random numbers and letters on the picture
3. Write random numbers and letters on the picture
3.1 Generating random numbers and letters
def get_random_str():
'''
获取一个随机字符, 数字或小写字母
:return:
'''
random_num = str(random.randint(0, 9))
random_low_alpha = chr(random.randint(97, 122))
random_char = random.choice([random_num, random_low_alpha])
return random_char
Use the random function provided by the random module to generate a string of specified length
3.2 Drawing numbers and letters on image objects
def draw_str(count, image, font_size):
"""
在图片上写随机字符
:param count: 字符数量
:param image: 图片对象
:param font_size: 字体大小
:return:
"""
draw = ImageDraw.Draw(image)
# 获取一个font字体对象参数是ttf的字体文件的目录,以及字体的大小
font_file = os.path.join('Andale Mono.ttf')
font = ImageFont.truetype(font_file, size=font_size)
temp = []
for i in range(count):
random_char = random_str()
draw.text((10+i*30, -2), random_char, random_color(), font=font)
temp.append(random_char)
valid_str = "".join(temp) # 验证码
return valid_str, image
if __name__ == '__main__':
image = generate_picture()
valid_str, image = draw_str(4, image, 35)
image.save('test.png')
Create an ImageDraw.Draw
object, draw random characters on the image, you can set the font, I used it, find the font in the directory Andale Mono.ttf
on the mac computer /System/Library/Fonts
, other systems also have their own font files, copy the font files to the same directory as the script.
4. Create noise
In order to prevent the verification code from being easily cracked, you should also create some noise on the picture, draw a few lines at random, and draw a few points at random
def noise(image, width=120, height=35, line_count=3, point_count=20):
'''
:param image: 图片对象
:param width: 图片宽度
:param height: 图片高度
:param line_count: 线条数量
:param point_count: 点的数量
:return:
'''
draw = ImageDraw.Draw(image)
for i in range(line_count):
x1 = random.randint(0, width)
x2 = random.randint(0, width)
y1 = random.randint(0, height)
y2 = random.randint(0, height)
draw.line((x1, y1, x2, y2), fill=random_color())
# 画点
for i in range(point_count):
draw.point([random.randint(0, width), random.randint(0, height)], fill=random_color())
x = random.randint(0, width)
y = random.randint(0, height)
draw.arc((x, y, x + 4, y + 4), 0, 90, fill=random_color())
return image
if __name__ == '__main__':
image = generate_picture()
valid_str, image = draw_str(4, image, 35)
image = noise(image)
image.save('test.png')
5. Generate a base64 encoded image
In practice, if you are generating a verification code image for website registration, generally speaking, you will not save it in an image file, because this will generate a large number of small images, which is completely unnecessary. We can save the content of the picture into BytesIO
the object, and finally generate base64
an encoded picture. In this way, what is sent back to the front end is a string in the format of
data:image/jpeg;base64,iVBORw0KGgoAAAANSUhEUgAAAH...
data:image/jpeg;base64
This section is written in a fixed way, and the rest of the comma is the base64 encoded string of the image
def valid_code():
"""
生成图片验证码,并对图片进行base64编码
:return:
"""
image = generate_picture()
valid_str, image = draw_str(4, image, 35)
image = noise(image)
f = BytesIO()
image.save(f, 'png') # 保存到BytesIO对象中, 格式为png
data = f.getvalue()
f.close()
encode_data = base64.b64encode(data)
data = str(encode_data, encoding='utf-8')
img_data = "data:image/jpeg;base64,{data}".format(data=data)
return valid_str, img_data
if __name__ == '__main__':
print(valid_code())
6. All code
In order to explain the process of generating verification code pictures to you, I will disassemble the whole process, so the code is disassembled and messy, you can integrate these codes for use in practical applications
import os
import random
import base64
from io import BytesIO
from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont
def random_color():
c1 = random.randint(0, 255)
c2 = random.randint(0, 255)
c3 = random.randint(0, 255)
return c1, c2, c3
def generate_picture(width=120, height=35):
image = Image.new('RGB', (width, height), random_color())
return image
def random_str():
'''
获取一个随机字符, 数字或小写字母
:return:
'''
random_num = str(random.randint(0, 9))
random_low_alpha = chr(random.randint(97, 122))
random_char = random.choice([random_num, random_low_alpha])
return random_char
def draw_str(count, image, font_size):
"""
在图片上写随机字符
:param count: 字符数量
:param image: 图片对象
:param font_size: 字体大小
:return:
"""
draw = ImageDraw.Draw(image)
# 获取一个font字体对象参数是ttf的字体文件的目录,以及字体的大小
font_file = os.path.join('Andale Mono.ttf')
font = ImageFont.truetype(font_file, size=font_size)
temp = []
for i in range(count):
random_char = random_str()
draw.text((10+i*30, -2), random_char, random_color(), font=font)
temp.append(random_char)
valid_str = "".join(temp) # 验证码
return valid_str, image
def noise(image, width=120, height=35, line_count=3, point_count=20):
'''
:param image: 图片对象
:param width: 图片宽度
:param height: 图片高度
:param line_count: 线条数量
:param point_count: 点的数量
:return:
'''
draw = ImageDraw.Draw(image)
for i in range(line_count):
x1 = random.randint(0, width)
x2 = random.randint(0, width)
y1 = random.randint(0, height)
y2 = random.randint(0, height)
draw.line((x1, y1, x2, y2), fill=random_color())
# 画点
for i in range(point_count):
draw.point([random.randint(0, width), random.randint(0, height)], fill=random_color())
x = random.randint(0, width)
y = random.randint(0, height)
draw.arc((x, y, x + 4, y + 4), 0, 90, fill=random_color())
return image
def valid_code():
"""
生成图片验证码,并对图片进行base64编码
:return:
"""
image = generate_picture()
valid_str, image = draw_str(4, image, 35)
image = noise(image)
f = BytesIO()
image.save(f, 'png') # 保存到BytesIO对象中, 格式为png
data = f.getvalue()
f.close()
encode_data = base64.b64encode(data)
data = str(encode_data, encoding='utf-8')
img_data = "data:image/jpeg;base64,{data}".format(data=data)
return valid_str, img_data
if __name__ == '__main__':
print(valid_code())