Skip to content
Open
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 24 additions & 8 deletions captcha/image.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@

import os
import random
import string

from PIL import Image
from PIL import ImageFilter
from PIL.ImageDraw import Draw
from PIL.ImageFont import truetype

try:
from cStringIO import StringIO as BytesIO
except ImportError:
Expand Down Expand Up @@ -157,19 +160,20 @@ def create_noise_dots(image, color, width=3, number=30):
number -= 1
return image

def create_captcha_image(self, chars, color, background):
def create_captcha_image(self, chars: str, color: tuple, background: tuple, rotate: bool = True):
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this tuple type hint is not compatible with 3.8.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I use Python 3.8 in almost all of my projects and this hint works fine. The project using this library with my modifications is no exception.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is working if not parametrized, but using tuple[...] is 3.9+.

(It is usually recommended to parametrize generic types, if you don't know the structure of the color argument, you can use typing.Tuple[T, ...])

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why dont yall just from __future__ import annotations

"""Create the CAPTCHA image itself.

:param chars: text to be generated.
:param color: color of the text.
:param background: color of the background.
:param rotate: whether to rotate the text?

The color should be a tuple of 3 numbers, such as (0, 255, 255).
"""
image = Image.new('RGB', (self._width, self._height), background)
draw = Draw(image)

def _draw_character(c):
def _draw_character(c: str, rotate: bool = True):
font = random.choice(self.truefonts)
try:
_, _, w, h = draw.textbbox((1, 1), c, font=font)
Expand All @@ -182,8 +186,9 @@ def _draw_character(c):
Draw(im).text((dx, dy), c, font=font, fill=color)

# rotate
im = im.crop(im.getbbox())
im = im.rotate(random.uniform(-30, 30), _BILINEAR, expand=1)
if rotate:
im = im.crop(im.getbbox())
im = im.rotate(random.uniform(-30, 30), _BILINEAR, expand=1)

# warp
dx = w * random.uniform(0.1, 0.3)
Expand All @@ -208,7 +213,12 @@ def _draw_character(c):
for c in chars:
if random.random() > 0.5:
images.append(_draw_character(" "))
images.append(_draw_character(c))

if c in string.punctuation:
images.append(_draw_character(c, False))

else:
images.append(_draw_character(c, rotate))

text_width = sum([im.size[0] for im in images])

Expand All @@ -230,17 +240,23 @@ def _draw_character(c):

return image

def generate_image(self, chars):
def generate_image(self, chars: str, rotate: bool = True, filters: list = None):
"""Generate the image of the given characters.

:param chars: text to be generated.
:param rotate: whether to rotate the text?
:param filters: filter list from which a random one will be taken and applied to the image.
"""
background = random_color(238, 255)
color = random_color(10, 200, random.randint(220, 255))
im = self.create_captcha_image(chars, color, background)
im = self.create_captcha_image(chars, color, background, rotate)
self.create_noise_dots(im, color)
self.create_noise_curve(im, color)
im = im.filter(ImageFilter.SMOOTH)
filter = ImageFilter.SMOOTH
if filters:
filter = random.choice(filters)

im = im.filter(filter)
return im


Expand Down