gacha-bot2 / utils /generators /profile.py
Amit9011's picture
Update utils/generators/profile.py
d08f1d4 verified
Raw
History Blame Contribute Delete
4.38 kB
# utils/generators/profile.py
import io
from PIL import Image, ImageOps, ImageFilter, ImageDraw
from .base import BaseGenerator
from .legendary import PremiumGenerator
from .common import CommonGenerator
from .custom import CustomGenerator
class ProfileGenerator(BaseGenerator):
def build_profile(self, username: str, stats: dict, showcase_bytes: bytes = None, team_data: list = None, avatar_bytes: bytes = None) -> io.BytesIO:
card_w, card_h = 580, 820
gap = 10
margin = 15
columns, rows = 4, 2
padding = 40
W = (margin * 2) + (card_w * columns) + (gap * (columns - 1))
H = (margin * 2) + (card_h * rows) + (gap * (rows - 1))
canvas = Image.new("RGBA", (W, H), (0, 0, 0, 255))
cleanup = [canvas]
try:
shadow = Image.new("RGBA", (card_w + 20, card_h + 20), (0, 0, 0, 0))
shadow_draw = ImageDraw.Draw(shadow)
shadow_draw.rectangle([4, 4, card_w + 16, card_h + 16], fill=(0, 0, 0, 180))
pre_rendered_shadow = shadow.filter(ImageFilter.GaussianBlur(12))
cleanup.append(pre_rendered_shadow)
if team_data:
# ⚡ THE FIX: Filter out empty slots so cards automatically shift left and fill gaps!
active_cards = [card for card in team_data if card and card.get('bytes')]
for i, t_char in enumerate(active_cards):
if i >= 8: break # Max 8 cards on the grid
col = i % columns
row = i // columns
inner_x = margin + col * (card_w + gap)
inner_y = margin + row * (card_h + gap)
try:
if t_char.get('custom_frame_url') and t_char.get('frame_bytes'):
generator = CustomGenerator()
full_card = generator.build_template(t_char['bytes'], t_char['frame_bytes'], t_char['name'])
elif t_char.get('rarity') in ["SSR", "UR"]:
generator = PremiumGenerator()
full_card = generator.build_template(t_char['bytes'], t_char.get('element', 'None'))
else:
generator = CommonGenerator()
full_card = generator.build_template(t_char['bytes'], t_char.get('element', 'None'))
cleanup.append(full_card)
text_io = generator.apply_text(
full_card,
t_char.get('name', 'Unknown'),
t_char.get('print_num', 1),
t_char.get('element', 'None'),
t_char.get('rarity', 'C')
)
cleanup.append(text_io)
finished_card = Image.open(text_io).convert("RGBA")
cleanup.append(finished_card)
if finished_card.size == (660, 900):
cropped_card = finished_card.crop((
padding,
padding,
finished_card.width - padding,
finished_card.height - padding
))
else:
cropped_card = finished_card
cleanup.append(cropped_card)
if cropped_card.size != (card_w, card_h):
cropped_card = cropped_card.resize((card_w, card_h), Image.Resampling.LANCZOS)
cleanup.append(cropped_card)
canvas.paste(pre_rendered_shadow, (inner_x - 6, inner_y - 6), pre_rendered_shadow)
canvas.paste(cropped_card, (inner_x, inner_y), cropped_card)
except Exception as e:
print(f"Failed to build card {i}: {e}")
buf = io.BytesIO()
canvas.save(buf, format="WEBP", quality=95)
buf.seek(0)
return buf
finally:
for img in cleanup:
try:
img.close()
except:
pass