From c10f7591debf160c23cdaae0fc9ca36130e1eb60 Mon Sep 17 00:00:00 2001 From: Lilac-Rose Date: Mon, 20 Oct 2025 12:28:42 +0200 Subject: [PATCH] Made it so obama runs async --- image/obama.py | 69 +++++++++++++++++++++++--------------------------- 1 file changed, 31 insertions(+), 38 deletions(-) diff --git a/image/obama.py b/image/obama.py index 787c729..1381f26 100644 --- a/image/obama.py +++ b/image/obama.py @@ -2,11 +2,12 @@ import os import io import aiohttp -from PIL import Image, ImageEnhance +from PIL import Image import discord from discord import app_commands from discord.ext import commands import numpy as np +import asyncio class Obamaify(commands.Cog): def __init__(self, bot): @@ -20,6 +21,33 @@ class Obamaify(commands.Cog): data = await resp.read() return Image.open(io.BytesIO(data)).convert("RGB") + def _generate_mosaic(self, avatar_img: Image.Image, obama_img: Image.Image, tile_count: int) -> io.BytesIO: + obama_img = obama_img.convert("RGB") + obama_w, obama_h = obama_img.size + + tile_w = obama_w // tile_count + tile_h = obama_h // tile_count + + avatar_tile = avatar_img.resize((tile_w, tile_h)) + output = Image.new("RGB", (tile_w * tile_count, tile_h * tile_count)) + obama_array = np.array(obama_img) + + for y in range(tile_count): + for x in range(tile_count): + tile_array = obama_array[y*tile_h:(y+1)*tile_h, x*tile_w:(x+1)*tile_w] + avg_color = tile_array.mean(axis=(0,1)) + tile = avatar_tile.copy() + tile_arr = np.array(tile).astype(np.float32) + tint_factor = avg_color / (tile_arr.mean(axis=(0,1)) + 1e-6) + tile_arr = np.clip(tile_arr * tint_factor, 0, 255).astype(np.uint8) + tile = Image.fromarray(tile_arr) + output.paste(tile, (x*tile_w, y*tile_h)) + + buf = io.BytesIO() + output.save(buf, format="PNG") + buf.seek(0) + return buf + @app_commands.command(name="obamify", description="Turn your avatar into a tile-based Obama mosaic") @app_commands.describe(tile_count="Number of tiles per row/column (default 32)") async def obamify(self, interaction: discord.Interaction, tile_count: int = 32, user: discord.User = None): @@ -31,48 +59,13 @@ class Obamaify(commands.Cog): return try: - # Load user avatar avatar_url = user.display_avatar.url avatar_img = await self._fetch_avatar(avatar_url) - - # Load Obama image obama_img = Image.open(self.obama_path).convert("RGB") - obama_w, obama_h = obama_img.size - # Determine tile size - tile_w = obama_w // tile_count - tile_h = obama_h // tile_count + # Run image generation in a separate thread + buf = await asyncio.to_thread(self._generate_mosaic, avatar_img, obama_img, tile_count) - # Resize avatar to tile size - avatar_tile = avatar_img.resize((tile_w, tile_h)) - - # Create output image - output = Image.new("RGB", (tile_w * tile_count, tile_h * tile_count)) - - # Convert Obama to NumPy array for faster average color computation - obama_array = np.array(obama_img) - - for y in range(tile_count): - for x in range(tile_count): - # Get the tile from Obama - tile_array = obama_array[y*tile_h:(y+1)*tile_h, x*tile_w:(x+1)*tile_w] - # Compute average color - avg_color = tile_array.mean(axis=(0,1)) - # Tint the avatar tile to match the average color - tile = avatar_tile.copy() - # Convert to float for multiplication - tile_arr = np.array(tile).astype(np.float32) - # Compute tint factor per channel - tint_factor = avg_color / (tile_arr.mean(axis=(0,1)) + 1e-6) - tile_arr = np.clip(tile_arr * tint_factor, 0, 255).astype(np.uint8) - tile = Image.fromarray(tile_arr) - # Paste into output - output.paste(tile, (x*tile_w, y*tile_h)) - - # Save and send - buf = io.BytesIO() - output.save(buf, format="PNG") - buf.seek(0) await interaction.followup.send(file=discord.File(buf, filename="obama_mosaic.png")) except Exception as e: