Lynxie/lynxie/commands/image.py
2023-09-09 00:45:26 +01:00

148 lines
5.6 KiB
Python

import os
import datetime
import requests
from io import BytesIO
from PIL import Image
import discord
from discord.ext import commands
from lynxie.config import IMAGE_EXTENSIONS, IMAGE_OVERLAYS, ASSETS_PATH
from lynxie.utils import error_message
class Img(commands.Cog):
def __init__(self, bot):
self.bot = bot
self._overlays = {
"bubble": Image.open(os.path.join(ASSETS_PATH, "bubble.png")),
"gang": Image.open(os.path.join(ASSETS_PATH, "gang.png")),
}
@commands.command()
async def overlay(self, ctx, style: str = None):
start_time = datetime.datetime.now()
style = style.lower().strip() if style else None
image_attachments = None
if ctx.message.attachments:
image_attachments = ctx.message.attachments[0]
elif ctx.message.reference and ctx.message.reference.resolved.attachments:
image_attachments = ctx.message.reference.resolved.attachments[0]
elif ctx.message.embeds and ctx.message.embeds[0].image:
image_attachments = ctx.message.embeds[0].image
else:
async for message in ctx.guild.get_channel(ctx.channel.id).history(limit=10):
if message.attachments:
image_attachments = message.attachments[0]
break
elif message.embeds and message.embeds[0].image:
image_attachments = message.embeds[0].image
break
# Check if image should be processed
async with ctx.typing():
if not style or style not in IMAGE_OVERLAYS:
error = (
"That is not a valid option! Valid options are:\n"
f"`{', '.join(IMAGE_OVERLAYS)}`"
)
await ctx.reply(embed=error_message(error))
return
if not image_attachments:
error = "You need to attach an image to use this command!"
await ctx.reply(embed=error_message(error))
return
# Extracts file extension from filename or url
if (
image_attachments.filename
and not image_attachments.filename.split(".")[-1].lower()
in IMAGE_EXTENSIONS
):
error = (
"Unsupported file type! Supported file types are:\n"
f"`{', '.join(IMAGE_EXTENSIONS)}`"
)
await ctx.reply(embed=error_message(error))
return
elif (
image_attachments.url
and not image_attachments.url.split(".")[-1].lower()
in IMAGE_EXTENSIONS
):
error = (
"Unsupported file type! Supported file types are:\n"
f"`{', '.join(IMAGE_EXTENSIONS)}`"
)
await ctx.reply(embed=error_message(error))
return
if (
image_attachments.size
and image_attachments.size > 8 * 1024 * 1024
):
error = (
"That image is too big! Please use an image that is less than 8MB."
)
await ctx.reply(embed=error_message(error))
return
if (
not 0 < image_attachments.width <= 3500
or not 0 < image_attachments.height <= 3500
):
error = "Image must be at least 1x1 and under 3500x3500!"
await ctx.reply(embed=error_message(error))
return
response = requests.get(image_attachments.url)
message_attachment = Image.open(BytesIO(response.content))
if message_attachment.width < message_attachment.height:
message_attachment.thumbnail((200, message_attachment.height))
else:
message_attachment.thumbnail((message_attachment.width, 200))
if style == "bubble":
# The bubble is resized twice as for some reason .copy() doesn't work
message_attachment.paste(
self._overlays["bubble"].resize(
(message_attachment.width, self._overlays["bubble"].height)
),
(0, 0),
self._overlays["bubble"].resize(
(message_attachment.width, self._overlays["bubble"].height)
),
)
elif style == "gang":
message_attachment.paste(
self._overlays["gang"],
(
(
(message_attachment.width - self._overlays["gang"].width)
// 2
),
(message_attachment.height - self._overlays["gang"].height),
),
self._overlays["gang"],
)
message_file = BytesIO()
message_attachment.save(message_file, format="PNG")
message_file.seek(0)
message_file = discord.File(message_file, filename="image.png")
time_taken = datetime.datetime.now() - start_time
embed = (
discord.Embed(title=style.capitalize(), colour=discord.Colour.orange())
.set_image(url="attachment://image.png")
.set_footer(
text=f"{message_attachment.width}x{message_attachment.height}, "
f"{time_taken.microseconds / 1000}ms"
)
)
await ctx.reply(embed=embed, file=message_file, mention_author=False)