Ufoptg's picture
Upload 93 files
78b07ad verified
raw
history blame
11.5 kB
import calendar
import logging
import os
import random
import textwrap
import time
import httpx
from icrawler.builtin import BingImageCrawler
from PIL import Image, ImageDraw, ImageEnhance, ImageFont, ImageOps
from unidecode import unidecode
from .formatter import format_text, limit_per_page
def convert_to_png(image: str) -> str:
output_img = f"png_{round(time.time())}.png"
img = Image.open(image)
img.save(output_img, "PNG")
img.close()
os.remove(image)
return output_img
def add_rounded_corners(img: Image.Image, radius: int = 80):
circle = Image.new("L", (radius * 2, radius * 2), 0)
draw = ImageDraw.Draw(circle)
draw.ellipse((0, 0, radius * 2, radius * 2), fill=255)
alpha = Image.new("L", img.size, 255)
w, h = img.size
alpha.paste(circle.crop((0, 0, radius, radius)), (0, 0))
alpha.paste(circle.crop((radius, 0, radius * 2, radius)), (w - radius, 0))
alpha.paste(circle.crop((0, radius, radius, radius * 2)), (0, h - radius))
alpha.paste(
circle.crop((radius, radius, radius * 2, radius * 2)), (w - radius, h - radius)
)
img.putalpha(alpha)
return img
def generate_alive_image(
username: str, profile_pic: str, del_img: bool, font_path: str
) -> str:
if not profile_pic.endswith(".png"):
profile_pic = convert_to_png(profile_pic)
img = Image.open(profile_pic).convert("RGBA")
img_rotated = img.rotate(45, expand=True)
width, height = img_rotated.size
left = width / 2 - 480 / 2
top = height / 2 - 480 / 2
right = width / 2 + 480 / 2
bottom = height / 2 + 480 / 2
cropped_img = img_rotated.crop((left, top, right, bottom))
img_rotated = ImageOps.fit(
cropped_img, (480, 480), method=0, bleed=0.0, centering=(0.5, 0.5)
)
img_rounded = add_rounded_corners(img_rotated)
img = img_rounded.rotate(-45, expand=True)
background = Image.open("./Hellbot/resources/images/hellbot_alive.png").convert(
"RGBA"
)
background.paste(img, (383, 445), img)
draw = ImageDraw.Draw(background)
text = format_text(username[:25] + ("..." if len(username) > 25 else ""))
font_size = width // 15
font = ImageFont.truetype(font_path, font_size, encoding="utf-8")
text_length = draw.textlength(text, font)
position = ((background.width - text_length) / 2, background.height - 145)
draw.text(
position,
unidecode(text),
(255, 255, 255),
font,
)
output_img = f"alive_{int(time.time())}.png"
background.save(output_img, "PNG")
background.close()
if del_img:
os.remove(profile_pic)
return output_img
async def get_wallpapers(
access: str,
limit: int,
query: str = "",
isRandom: bool = False,
) -> list[str]:
headers = {"Authorization": f"Client-ID {access}"}
if isRandom:
api = f"https://api.unsplash.com/photos/random?count={limit}"
response = httpx.get(api, headers=headers)
results = response.json()
urls = [i["urls"]["raw"] for i in results]
else:
api = f"https://api.unsplash.com/search/photos?query={query}&page={limit_per_page(limit)}"
response = httpx.get(api, headers=headers)
result = response.json()
urls = [i["urls"]["raw"] for i in result["results"]]
random.shuffle(urls)
return urls[:limit]
async def deep_fry(img: Image.Image) -> Image.Image:
colours = (
(random.randint(50, 200), random.randint(40, 170), random.randint(40, 190)),
(random.randint(190, 255), random.randint(170, 240), random.randint(180, 250)),
)
img = img.copy().convert("RGB")
img = img.convert("RGB")
width, height = img.width, img.height
img = img.resize(
(
int(width ** random.uniform(0.8, 0.9)),
int(height ** random.uniform(0.8, 0.9)),
),
resample=Image.LANCZOS,
)
img = img.resize(
(
int(width ** random.uniform(0.85, 0.95)),
int(height ** random.uniform(0.85, 0.95)),
),
resample=Image.BILINEAR,
)
img = img.resize(
(
int(width ** random.uniform(0.89, 0.98)),
int(height ** random.uniform(0.89, 0.98)),
),
resample=Image.BICUBIC,
)
img = img.resize((width, height), resample=Image.BICUBIC)
img = ImageOps.posterize(img, random.randint(3, 7))
overlay = img.split()[0]
overlay = ImageEnhance.Contrast(overlay).enhance(random.uniform(1.0, 2.0))
overlay = ImageEnhance.Brightness(overlay).enhance(random.uniform(1.0, 2.0))
overlay = ImageOps.colorize(overlay, colours[0], colours[1])
img = Image.blend(img, overlay, random.uniform(0.1, 0.4))
img = ImageEnhance.Sharpness(img).enhance(random.randint(5, 300))
return img
async def make_logo(background: str, text: str, font_path: str) -> str:
if not background.endswith(".png"):
background = convert_to_png(background)
bg = Image.open(background).convert("RGBA")
bgWidth, bgHeight = bg.size
text = format_text(text)
font_size = bgWidth // len(text)
font = ImageFont.truetype(font_path, font_size, encoding="utf-8")
draw = ImageDraw.Draw(bg)
text_length = draw.textlength(text, font)
x = (bgWidth - text_length) // 2
y = (bgHeight - font_size) // 2
draw.text(
(x, y),
unidecode(text),
(255, 255, 255),
font,
stroke_fill=(0, 0, 0),
stroke_width=2,
)
output_img = f"logo_{int(time.time())}.png"
bg.save(output_img, "PNG")
bg.close()
os.remove(background)
return output_img
async def draw_meme(
image_path: str, upper_text: str = "", lower_text: str = ""
) -> list[str]:
image = Image.open(image_path)
width, height = image.size
draw = ImageDraw.Draw(image)
font_size = int((30 / 500) * width)
font = ImageFont.truetype("./Hellbot/resources/fonts/Montserrat.ttf", font_size)
curr_height, padding = 20, 5
for utext in textwrap.wrap(upper_text, 25):
upper_width = draw.textlength(utext, font=font)
draw.text(
((width - upper_width) / 2, curr_height),
unidecode(utext),
(255, 255, 255),
font,
stroke_width=3,
stroke_fill=(0, 0, 0),
)
curr_height += font_size + padding
curr_height = height - font_size
for ltext in reversed(textwrap.wrap(lower_text, 25)):
lower_width = draw.textlength(ltext, font=font)
draw.text(
((width - lower_width) / 2, curr_height - font_size),
ltext,
(255, 255, 255),
font,
stroke_width=3,
stroke_fill=(0, 0, 0),
)
curr_height -= font_size + padding
filename = f"meme_{int(time.time())}"
image.save(f"{filename}.png", "PNG", optimize=True)
image.save(f"{filename}.webp", "WEBP", optimize=True)
image.close()
return [f"{filename}.png", f"{filename}.webp"]
async def remove_bg(api_key: str, image: str) -> str:
response = httpx.post(
"https://api.remove.bg/v1.0/removebg",
files={"image_file": open(image, "rb")},
data={"size": "auto"},
headers={"X-Api-Key": api_key},
)
filename = f"removedbg_{int(time.time())}.png"
if response.is_success:
with open(filename, "wb") as f:
f.write(response.content)
else:
raise Exception(
f"RemoveBGError: [{response.status_code}] {response.content.decode('utf-8')}"
)
return filename
def create_gradient(
size: tuple[int, int],
color_start: tuple[int, int, int],
color_end: tuple[int, int, int],
) -> Image.Image:
gradient = Image.new("RGB", (size))
draw = ImageDraw.Draw(gradient)
for x in range(size[0]):
r = int(color_start[0] + (color_end[0] - color_start[0]) * (x / size[0]))
g = int(color_start[1] + (color_end[1] - color_start[1]) * (x / size[0]))
b = int(color_start[2] + (color_end[2] - color_start[2]) * (x / size[0]))
draw.line([(x, 0), (x, size[1])], fill=(r, g, b))
return gradient
async def create_calendar(year: int, month: int) -> str:
cal = calendar.monthcalendar(year, month)
month_name = calendar.month_name[month]
calendar_image = create_gradient((500, 500), (140, 200, 250), (0, 150, 200))
draw = ImageDraw.Draw(calendar_image)
month_font = ImageFont.truetype("./Hellbot/resources/fonts/Montserrat.ttf", 40)
month_x = (
calendar_image.width - draw.textlength(f"{month_name} {year}", month_font)
) // 2
month_y = 30
draw.text(
(month_x, month_y),
f"{month_name} {year}",
(43, 255, 136),
month_font,
stroke_width=2,
stroke_fill=(255, 40, 40),
)
week_font = ImageFont.truetype("./Hellbot/resources/fonts/Montserrat.ttf", 23)
weekdays_text = " ".join([day[:3] for day in calendar.day_name])
textsize = draw.textlength(weekdays_text, week_font)
draw.text(
((calendar_image.width - textsize) // 2, month_y + 80),
weekdays_text,
(150, 190, 200),
week_font,
stroke_width=2,
stroke_fill=(200, 150, 250),
)
scale_factor = 1.5
cell_size = 30
padding = 15
font = ImageFont.truetype("./Hellbot/resources/fonts/Montserrat.ttf", 30)
for week_num, week in enumerate(cal):
for day_num, day in enumerate(week):
x = int(day_num * (cell_size + padding) * scale_factor)
y = int((week_num + 3) * (cell_size + padding) * scale_factor)
cell_width = int(cell_size * scale_factor)
cell_height = int(cell_size * scale_factor)
text_x = (
int(x + (cell_width - draw.textlength(str(day), font=font)) // 2)
+ cell_size
)
text_y = (
int(y + (cell_height - draw.textlength(str(day), font=font)) // 2) - 55
)
if day != 0:
draw.text(
(text_x, text_y),
str(day),
(240, 200, 100),
font,
stroke_width=1,
stroke_fill=(0, 0, 0),
)
filename = f"calendar_{int(time.time())}.png"
calendar_image.save(filename, "PNG")
calendar_image.close()
return filename
async def create_thumbnail(photo: str, xy: tuple[int, int], file_size: int):
img = Image.open(photo)
img.thumbnail(xy)
size_in_bytes = file_size * 1024
quality = 90
while True:
img.save(photo, "JPEG", quality=quality, optimize=True)
if os.path.getsize(photo) <= size_in_bytes:
break
quality -= 5
return photo
async def download_images(query: str, limit: int) -> list[str]:
offset = random.randint(0, 20)
crawler = BingImageCrawler(log_level=logging.ERROR)
crawler.crawl(query, offset=offset, max_num=limit)
return [os.path.join("images", image) for image in os.listdir("images")]