Skip to content

Instantly share code, notes, and snippets.

@vvanglro
Created May 17, 2024 06:43
Show Gist options
  • Save vvanglro/4d1887375ace5a595a564031a1ccac98 to your computer and use it in GitHub Desktop.
Save vvanglro/4d1887375ace5a595a564031a1ccac98 to your computer and use it in GitHub Desktop.
import base64
from io import BytesIO
from random import choice, randint, uniform
from PIL import Image, ImageDraw, ImageFont
def random_color(start: int, end: int):
red = randint(start, end)
green = randint(start, end)
blue = randint(start, end)
return red, green, blue
def draw_rotated_text(draw, image, text, position, font, color):
left, top, right, bottom = draw.textbbox((0, 0), text, font=font)
w = int((right - left) * 1.7) or 1
h = int((bottom - top) * 1.7) or 1
dx1 = randint(0, 4)
dy1 = randint(0, 6)
text_image = Image.new('RGBA', (w + dx1, h + dy1))
text_draw = ImageDraw.Draw(text_image)
# Place text in the center of the image
dx1 = randint(0, 4)
dy1 = randint(0, 6)
text_draw.text((dx1, dy1), text, font=font, fill=color)
# Rotate picture
rotated_image = text_image.rotate(uniform(-10, 10), Image.BILINEAR, expand=True)
image.paste(rotated_image, position, rotated_image)
def generate_captcha(width, height, save):
operators = {"+": lambda x, y: x + y, "-": lambda x, y: x - y, "×": lambda x, y: x * y, "÷": lambda x, y: x / y}
x = randint(1, 10)
y = randint(1, 10)
operator = choice(list(operators.keys()))
# Make sure the result of division is an integer.
if operator == "÷":
x *= y
if operator == "-":
x += y
question = f"{x} {operator} {y} = ?"
answer = int(operators[operator](x, y))
image = Image.new("RGB", (width, height), color=(random_color(238, 255)))
draw = ImageDraw.Draw(image)
font = ImageFont.truetype("Arial Bold.ttf", 35)
# font = ImageFont.load_default(35)
for i, char in enumerate(question):
x = int(len(question) / 2) + i * (int((width - 15) / len(question)))
y = randint(int((height / 2 / 2 / 2) * 1.5), int(height / 2 / 2 / 2) * 3)
draw_rotated_text(draw, image, char, (x, y), font, color=random_color(0, 200))
# Draw random lines
for _ in range(5):
start = (randint(0, image.width), randint(0, image.height))
end = (randint(0, image.width), randint(0, image.height))
draw.line([start, end], fill=random_color(0, 255))
# Add random points
for _ in range(100):
dot = (randint(0, image.width), randint(0, image.height))
draw.point(dot, fill=random_color(0, 255))
if save:
image.save("blurry_captcha.png")
return answer, question
else:
out = BytesIO()
image.save(out, format="png")
out.seek(0)
bytes_like = out.read()
return answer, base64.b64encode(bytes_like)
answer, question = generate_captcha(width=150, height=70, save=True)
print(answer)
print(question)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment