标签:enc org except nat size 重写 box aci cti
1、验证码生成代码
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 [‘Arial.ttf‘, ‘Georgia.ttf‘, ‘actionj.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 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=50, level=2, 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, (text, StringIO.value). For example: (‘JGW9‘, ‘\x89PNG\r\n\x1a\n\x00\x00\x00\r...‘) """ 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) text = "".join(self._text) out = BytesIO() image.save(out, format=fmt) return text, out.getvalue() def generate_captcha(self): self.initialize() return self.captcha("") captcha = Captcha.instance()
2、如果生成图片验证码
如果需要的验证码的尺寸刚好是默认的200x75,那么就直接可以使用
# 返回验证码和验证码二进制图片元组 code, imgBytes = captcha.generate_captcha()
如果需要的验证码的尺寸需要自己设定,那就直接重写generate_captcha方法,再引用上面的代码
def generate_captcha(self, width, height, *args, **kwargs): self.initialize(width, height) return self.captcha("")
3、如果使用图片验证码
标签:enc org except nat size 重写 box aci cti
原文地址:https://www.cnblogs.com/loveprogramme/p/13211142.html