mirror of
https://github.com/lepture/captcha.git
synced 2026-03-13 09:43:22 +08:00
fix: use strict mypy mode
This commit is contained in:
@@ -64,6 +64,7 @@ exclude_lines = [
|
||||
]
|
||||
|
||||
[tool.mypy]
|
||||
strict = true
|
||||
python_version = "3.8"
|
||||
files = ["src/captcha"]
|
||||
show_error_codes = true
|
||||
|
||||
@@ -188,12 +188,12 @@ class AudioCaptcha:
|
||||
"""
|
||||
return random.sample(self.choices, length)
|
||||
|
||||
def load(self):
|
||||
def load(self) -> None:
|
||||
"""Load voice data into memory."""
|
||||
for name in self.choices:
|
||||
self._load_data(name)
|
||||
|
||||
def _load_data(self, name: str):
|
||||
def _load_data(self, name: str) -> None:
|
||||
dirname = os.path.join(self._voicedir, name)
|
||||
data: t.List[bytearray] = []
|
||||
for f in os.listdir(dirname):
|
||||
@@ -227,7 +227,7 @@ class AudioCaptcha:
|
||||
voice = change_sound(voice, level)
|
||||
return voice
|
||||
|
||||
def create_background_noise(self, length: int, chars: str):
|
||||
def create_background_noise(self, length: int, chars: str) -> bytearray:
|
||||
noise = create_noise(length, 4)
|
||||
pos = 0
|
||||
while pos < length:
|
||||
@@ -268,7 +268,7 @@ class AudioCaptcha:
|
||||
body = self.create_wave_body(chars)
|
||||
return patch_wave_header(body)
|
||||
|
||||
def write(self, chars: str, output: str):
|
||||
def write(self, chars: str, output: str) -> None:
|
||||
"""Generate and write audio CAPTCHA data to the output.
|
||||
|
||||
:param chars: text to be generated.
|
||||
@@ -276,4 +276,4 @@ class AudioCaptcha:
|
||||
"""
|
||||
data = self.generate(chars)
|
||||
with open(output, 'wb') as f:
|
||||
return f.write(data)
|
||||
f.write(data)
|
||||
|
||||
@@ -10,7 +10,7 @@ import os
|
||||
import random
|
||||
import typing as t
|
||||
from PIL.Image import new as createImage, Image, QUAD, BILINEAR
|
||||
from PIL.ImageDraw import Draw
|
||||
from PIL.ImageDraw import Draw, ImageDraw
|
||||
from PIL.ImageFilter import SMOOTH
|
||||
from PIL.ImageFont import FreeTypeFont, truetype
|
||||
from io import BytesIO
|
||||
@@ -24,11 +24,6 @@ DATA_DIR = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'data')
|
||||
DEFAULT_FONTS = [os.path.join(DATA_DIR, 'DroidSansMono.ttf')]
|
||||
|
||||
|
||||
table: t.List[int] = []
|
||||
for i in range(256):
|
||||
table.append(int(i * 1.97))
|
||||
|
||||
|
||||
class ImageCaptcha:
|
||||
"""Create an image CAPTCHA.
|
||||
|
||||
@@ -49,6 +44,8 @@ class ImageCaptcha:
|
||||
:param fonts: Fonts to be used to generate CAPTCHA images.
|
||||
:param font_sizes: Random choose a font size from this parameters.
|
||||
"""
|
||||
lookup_table: t.List[int] = [int(i * 1.97) for i in range(256)]
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
width: int = 160,
|
||||
@@ -73,7 +70,7 @@ class ImageCaptcha:
|
||||
return self._truefonts
|
||||
|
||||
@staticmethod
|
||||
def create_noise_curve(image: Image, color: ColorTuple):
|
||||
def create_noise_curve(image: Image, color: ColorTuple) -> Image:
|
||||
w, h = image.size
|
||||
x1 = random.randint(0, int(w / 5))
|
||||
x2 = random.randint(w - int(w / 5), w)
|
||||
@@ -100,6 +97,38 @@ class ImageCaptcha:
|
||||
number -= 1
|
||||
return image
|
||||
|
||||
def _draw_character(self, c: str, draw: ImageDraw, color: ColorTuple) -> Image:
|
||||
font = random.choice(self.truefonts)
|
||||
_, _, w, h = draw.textbbox((1, 1), c, font=font)
|
||||
|
||||
dx1 = random.randint(0, 4)
|
||||
dy1 = random.randint(0, 6)
|
||||
im = createImage('RGBA', (w + dx1, h + dy1))
|
||||
Draw(im).text((dx1, dy1), c, font=font, fill=color)
|
||||
|
||||
# rotate
|
||||
im = im.crop(im.getbbox())
|
||||
im = im.rotate(random.uniform(-30, 30), BILINEAR, expand=True)
|
||||
|
||||
# warp
|
||||
dx2 = w * random.uniform(0.1, 0.3)
|
||||
dy2 = h * random.uniform(0.2, 0.3)
|
||||
x1 = int(random.uniform(-dx2, dx2))
|
||||
y1 = int(random.uniform(-dy2, dy2))
|
||||
x2 = int(random.uniform(-dx2, dx2))
|
||||
y2 = int(random.uniform(-dy2, dy2))
|
||||
w2 = w + abs(x1) + abs(x2)
|
||||
h2 = h + abs(y1) + abs(y2)
|
||||
data = (
|
||||
x1, y1,
|
||||
-x1, h2 - y2,
|
||||
w2 + x2, h2 + y2,
|
||||
w2 - x2, -y1,
|
||||
)
|
||||
im = im.resize((w2, h2))
|
||||
im = im.transform((w, h), QUAD, data)
|
||||
return im
|
||||
|
||||
def create_captcha_image(
|
||||
self,
|
||||
chars: str,
|
||||
@@ -116,43 +145,11 @@ class ImageCaptcha:
|
||||
image = createImage('RGB', (self._width, self._height), background)
|
||||
draw = Draw(image)
|
||||
|
||||
def _draw_character(c: str):
|
||||
font = random.choice(self.truefonts)
|
||||
_, _, w, h = draw.textbbox((1, 1), c, font=font)
|
||||
|
||||
dx1 = random.randint(0, 4)
|
||||
dy1 = random.randint(0, 6)
|
||||
im = createImage('RGBA', (w + dx1, h + dy1))
|
||||
Draw(im).text((dx1, dy1), c, font=font, fill=color)
|
||||
|
||||
# rotate
|
||||
im = im.crop(im.getbbox())
|
||||
im = im.rotate(random.uniform(-30, 30), BILINEAR, expand=True)
|
||||
|
||||
# warp
|
||||
dx2 = w * random.uniform(0.1, 0.3)
|
||||
dy2 = h * random.uniform(0.2, 0.3)
|
||||
x1 = int(random.uniform(-dx2, dx2))
|
||||
y1 = int(random.uniform(-dy2, dy2))
|
||||
x2 = int(random.uniform(-dx2, dx2))
|
||||
y2 = int(random.uniform(-dy2, dy2))
|
||||
w2 = w + abs(x1) + abs(x2)
|
||||
h2 = h + abs(y1) + abs(y2)
|
||||
data = (
|
||||
x1, y1,
|
||||
-x1, h2 - y2,
|
||||
w2 + x2, h2 + y2,
|
||||
w2 - x2, -y1,
|
||||
)
|
||||
im = im.resize((w2, h2))
|
||||
im = im.transform((w, h), QUAD, data)
|
||||
return im
|
||||
|
||||
images: t.List[Image] = []
|
||||
for c in chars:
|
||||
if random.random() > 0.5:
|
||||
images.append(_draw_character(" "))
|
||||
images.append(_draw_character(c))
|
||||
images.append(self._draw_character(" ", draw, color))
|
||||
images.append(self._draw_character(c, draw, color))
|
||||
|
||||
text_width = sum([im.size[0] for im in images])
|
||||
|
||||
@@ -165,7 +162,7 @@ class ImageCaptcha:
|
||||
|
||||
for im in images:
|
||||
w, h = im.size
|
||||
mask = im.convert('L').point(table)
|
||||
mask = im.convert('L').point(self.lookup_table)
|
||||
image.paste(im, (offset, int((self._height - h) / 2)), mask)
|
||||
offset = offset + w + random.randint(-rand, 0)
|
||||
|
||||
|
||||
0
src/captcha/py.typed
Normal file
0
src/captcha/py.typed
Normal file
Reference in New Issue
Block a user