• python3 图片验证码


    python3+Django

    1.首先需要在项目根目录下有一个这样的目录结构:

        

         notes: fonts中的字体可以字体可以是随意的字体,按照规范命名即可

    2.captcha.py

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    
    # refer to `https://bitbucket.org/akorn/wheezy.captcha`
    
    import random
    import string
    import os.path
    from io import BytesIO
    
    from PIL import Image
    from PIL import ImageFilter
    from PIL.ImageDraw import Draw
    from PIL.ImageFont import truetype
    
    
    class Bezier:
        def __init__(self):
            self.tsequence = tuple([t / 20.0 for t in range(21)])
            self.beziers = {}
    
        def pascal_row(self, n):
            """ Returns n-th row of Pascal's triangle
            """
            result = [1]
            x, numerator = 1, n
            for denominator in range(1, n // 2 + 1):
                x *= numerator
                x /= denominator
                result.append(x)
                numerator -= 1
            if n & 1 == 0:
                result.extend(reversed(result[:-1]))
            else:
                result.extend(reversed(result))
            return result
    
        def make_bezier(self, n):
            """ Bezier curves:
                http://en.wikipedia.org/wiki/B%C3%A9zier_curve#Generalization
            """
            try:
                return self.beziers[n]
            except KeyError:
                combinations = self.pascal_row(n - 1)
                result = []
                for t in self.tsequence:
                    tpowers = (t ** i for i in range(n))
                    upowers = ((1 - t) ** i for i in range(n - 1, -1, -1))
                    coefs = [c * a * b for c, a, b in zip(combinations,
                                                          tpowers, upowers)]
                    result.append(coefs)
                self.beziers[n] = result
                return result
    
    
    class Captcha(object):
        def __init__(self):
            self._bezier = Bezier()
            self._dir = os.path.dirname(__file__)
            # self._captcha_path = os.path.join(self._dir, '..', 'static', 'captcha')
    
        @staticmethod
        def instance():
            if not hasattr(Captcha, "_instance"):
                Captcha._instance = Captcha()
            return Captcha._instance
    
        def initialize(self, width=200, height=75, color=None, text=None, fonts=None):
            # self.image = Image.new('RGB', (width, height), (255, 255, 255))
            self._text = text if text else random.sample(string.ascii_uppercase + string.ascii_uppercase + '3456789', 4)
            self.fonts = fonts if fonts else [os.path.join(self._dir, 'fonts', font) for font in
                                              ['tt1.ttf', 'tt2.TTF', 'tt3.ttf']]
            self.width = width
            self.height = height
            self._color = color if color else self.random_color(0, 200, random.randint(220, 255))
    
        @staticmethod
        def random_color(start, end, opacity=None):
            red = random.randint(start, end)
            green = random.randint(start, end)
            blue = random.randint(start, end)
            if opacity is None:
                return red, green, blue
            return red, green, blue, opacity
    
        # draw image
    
        def background(self, image):
            Draw(image).rectangle([(0, 0), image.size], fill=self.random_color(238, 255))
            return image
    
        @staticmethod
        def smooth(image):
            return image.filter(ImageFilter.SMOOTH)
    
        def curve(self, image, width=4, number=6, color=None):
            dx, height = image.size
            dx /= number
            path = [(dx * i, random.randint(0, height))
                    for i in range(1, number)]
            bcoefs = self._bezier.make_bezier(number - 1)
            points = []
            for _ in range(5):
                for coefs in bcoefs:
                    points.append(tuple(sum([coef * p for coef, p in zip(coefs, ps)])
                                        for ps in zip(*path)))
                Draw(image).line(points, fill=color if color else self._color, width=width)
            return image
    
        def noise(self, image, number=600, level=0, color=None):
            width, height = image.size
            dx = width / 10
            width -= dx
            dy = height / 10
            height -= dy
            draw = Draw(image)
            for i in range(number):
                x = int(random.uniform(dx, width))
                y = int(random.uniform(dy, height))
                draw.line(((x, y), (x + level, y)), fill=color if color else self._color, width=level)
            return image
    
        def text(self, image, fonts, font_sizes=None, drawings=None, squeeze_factor=0.75, color=None):
            color = color if color else self._color
            fonts = tuple([truetype(name, size)
                           for name in fonts
                           for size in font_sizes or (65, 70, 75)])
            draw = Draw(image)
            char_images = []
            for c in self._text:
                font = random.choice(fonts)
                c_width, c_height = draw.textsize(c, font=font)
                char_image = Image.new('RGB', (c_width, c_height), (0, 0, 0))
                char_draw = Draw(char_image)
                char_draw.text((0, 0), c, font=font, fill=color)
                char_image = char_image.crop(char_image.getbbox())
                for drawing in drawings:
                    d = getattr(self, drawing)
                    char_image = d(char_image)
                char_images.append(char_image)
            width, height = image.size
            offset = int((width - sum(int(i.size[0] * squeeze_factor)
                                      for i in char_images[:-1]) -
                          char_images[-1].size[0]) / 2)
            for char_image in char_images:
                c_width, c_height = char_image.size
                mask = char_image.convert('L').point(lambda i: i * 1.97)
                image.paste(char_image,
                            (offset, int((height - c_height) / 2)),
                            mask)
                offset += int(c_width * squeeze_factor)
            return image
    
        # draw text
        @staticmethod
        def warp(image, dx_factor=0.27, dy_factor=0.21):
            width, height = image.size
            dx = width * dx_factor
            dy = height * dy_factor
            x1 = int(random.uniform(-dx, dx))
            y1 = int(random.uniform(-dy, dy))
            x2 = int(random.uniform(-dx, dx))
            y2 = int(random.uniform(-dy, dy))
            image2 = Image.new('RGB',
                               (width + abs(x1) + abs(x2),
                                height + abs(y1) + abs(y2)))
            image2.paste(image, (abs(x1), abs(y1)))
            width2, height2 = image2.size
            return image2.transform(
                (width, height), Image.QUAD,
                (x1, y1,
                 -x1, height2 - y2,
                 width2 + x2, height2 + y2,
                 width2 - x2, -y1))
    
        @staticmethod
        def offset(image, dx_factor=0.1, dy_factor=0.2):
            width, height = image.size
            dx = int(random.random() * width * dx_factor)
            dy = int(random.random() * height * dy_factor)
            image2 = Image.new('RGB', (width + dx, height + dy))
            image2.paste(image, (dx, dy))
            return image2
    
        @staticmethod
        def rotate(image, angle=25):
            return image.rotate(
                random.uniform(-angle, angle), Image.BILINEAR, expand=1)
    
        def captcha(self, path=None, fmt='JPEG'):
            """Create a captcha.
    
            Args:
                path: save path, default None.
                fmt: image format, PNG / JPEG.
            Returns:
                A tuple, (name, text, StringIO.value).
                For example:
                    ('fXZJN4AFxHGoU5mIlcsdOypa', 'JGW9', 'x89PNG
    x1a
    x00x00x00
    ...')
    
            """
            image = Image.new('RGB', (self.width, self.height), (255, 255, 255))
            image = self.background(image)
            image = self.text(image, self.fonts, drawings=['warp', 'rotate', 'offset'])
            image = self.curve(image)
            image = self.noise(image)
            image = self.smooth(image)
            name = "".join(random.sample(string.ascii_lowercase + string.ascii_uppercase + '3456789', 24))
            text = "".join(self._text)
            out = BytesIO()
            image.save(out, format=fmt)
            if path:
                image.save(os.path.join(path, name), fmt)
            return name, text, out.getvalue()
    
        def generate_captcha(self):
            self.initialize()
            return self.captcha("")
    
    captcha = Captcha.instance()
    
    if __name__ == '__main__':
        print(captcha.generate_captcha())

    3.调用

    from utils.captcha.captcha import captcha
    
    name, text, image = captcha.generate_captcha()  # 生成图片验证码 name:名字 text:图片验证码内容
    with open(w_image_url, 'wb') as f:  # w_image_url是你存放图片的地址
        f.write(image)
    
    # 查看w_image_url路径下的图片,就是生成的图片验证码了
  • 相关阅读:
    git常用操作命令
    如何编写高质量代码
    Chrome调试工具简单介绍
    使用eclipse+tomcat搭建本地环境
    chrome设置--disable-web-security解决跨域
    利用Maven管理工程项目本地启动报错及解决方案
    用户输入验证【提升篇】
    简单【用户输入验证】
    【消息框】的返回值
    【消息框】的4种显示形式
  • 原文地址:https://www.cnblogs.com/lab-zj/p/14077991.html
Copyright © 2020-2023  润新知