Python script for generating Chinese graphic verification code

Posted by ligraci on Sat, 05 Oct 2019 13:25:36 +0200

Links to the original text: https://www.cnblogs.com/whu-zeng/p/4855480.html

Note: this script is not original, just a little adjustment based on the original author's code. Original links: https://www.cnblogs.com/whu-zeng/p/4855480.html

Many scripts that generate Chinese verification code on the Internet can not be used, or the python interpreter version is too old, or all kinds of unknown bug. After two hours, we finally found a suitable one. Let's share the following:

# -*- coding: utf-8 -*-

import codecs
import random
from io import BytesIO
from PIL import Image, ImageDraw, ImageFont
import math, string
from django.utils.six import unichr


class RandomChar():
    @staticmethod
    def Unicode():
        val = random.randint(0x4E00, 0x9FBF)
        return unichr(val)

    @staticmethod
    def GB2312():
        head = random.randint(0xB0, 0xCF)
        body = random.randint(0xA, 0xF)
        tail = random.randint(0, 0xF)
        val = (head << 8) | (body << 4) | tail
        str = "%x" % val
        #   return str.decode('hex').decode('gb2312')
        # return str.encode('gb2312').decode('gb2312')
        return codecs.decode(str, 'hex_codec').decode('gb2312')


class ImageChar():
    def __init__(self, fontColor=(0, 0, 0),
                 size=(150, 60),
                 # fontPath='C:/Windows/Fonts/wqy.ttc',
                 fontPath='C:/Windows/Fonts/simsun.ttc',
                 bgColor=(255, 255, 255),
                 fontSize=25):
        self.size = size
        self.fontPath = fontPath
        self.bgColor = bgColor
        self.fontSize = fontSize
        self.fontColor = fontColor
        self.font = ImageFont.truetype(self.fontPath, self.fontSize)
        self.image = Image.new('RGB', size, bgColor)
        self.char_list = []

    def rotate(self):
        self.image.rotate(random.randint(0, 30), expand=0)

    def drawText(self, pos, txt, fill):
        draw = ImageDraw.Draw(self.image)
        #  print(pos)
        # print(txt)
        # print(self.font)
        # print(fill)
        draw.text(pos, txt, font=self.font, fill=fill)
        del draw

    def randRGB(self):
        return (random.randint(0, 255),
                random.randint(0, 255),
                random.randint(0, 255))

    def randPoint(self):
        (width, height) = self.size
        return (random.randint(0, width), random.randint(0, height))

    def randLine(self, num):
        draw = ImageDraw.Draw(self.image)
        for i in range(0, num):
            draw.line([self.randPoint(), self.randPoint()], self.randRGB())
        del draw

    def randChinese(self, num):
        gap = 5
        start = 0
        char_list = []
        while True:
            try:
                for i in range(0, num):
                    char_list.append(RandomChar().GB2312())
                    x = start + self.fontSize * i + random.randint(0, gap) + gap * i
                    self.drawText((x, random.randint(-5, 5)), char_list[-1], self.randRGB())
                    self.rotate()
                self.randLine(18)
                self.char_list = char_list
                break
            except:
                continue

    def output(self):
        output_buffer = BytesIO()
        self.image.save(output_buffer, format='JPEG')
        byte_data = output_buffer.getvalue()
        return byte_data
        

def generate_code():
    ic = ImageChar(fontColor=(100, 211, 90))
    ic.randChinese(4)
    byte_data = ic.output()
    chars = ''.join(ic.char_list)
    return (byte_data, chars)


if __name__ == '__main__':
    generate_code()

By calling the generate_code function, we can get the binary stream of the picture verification code and the corresponding Chinese character content.

But!
My script has a problem:
Is the try statement in the following code strange? Because in the process of my script running, I found that some specific Chinese characters will generate bug when they are generated. There is no time to find out the reason, so in order to meet the emergency, the try statement is used (if it fails once in a while, it will be regenerated). When I am free, I will study it again.

def randChinese(self, num):
        gap = 5
        start = 0
        char_list = []
        while True:
            try:
                for i in range(0, num):
                    char_list.append(RandomChar().GB2312())
                    x = start + self.fontSize * i + random.randint(0, gap) + gap * i
                    self.drawText((x, random.randint(-5, 5)), char_list[-1], self.randRGB())
                    self.rotate()
                self.randLine(18)
                self.char_list = char_list
                break
            except:
                continue

Note again: this script is not original, just a little adjustment based on the original author's code. Original links: https://www.cnblogs.com/whu-zeng/p/4855480.html

Topics: Windows Python Django