Amit9011's picture
Update utils/generators/base.py
865cb1a verified
Raw
History Blame Contribute Delete
5.25 kB
# utils/generators/base.py
import io
import os
from PIL import Image, ImageDraw, ImageFont
class BaseGenerator:
CANVAS_W, CANVAS_H = (660, 900)
CARD_W, CARD_H = (580, 820)
CORNER_RAD = 16
BANNER_H = 160
OFFSET_X, OFFSET_Y = (40, 40)
ELEMENT_COLORS = {
"Solstice": (239, 68, 68), "Equinox": (59, 130, 246), "Eclipse": (147, 197, 253),
"Zenith": (168, 85, 247), "Aether": (16, 185, 129), "Nadir": (250, 204, 21),
"Genesis": (34, 197, 94), "Light": (255, 255, 224), "Dark": (30, 27, 75), "None": (156, 163, 175),
"Pyro": (239, 68, 68), "Fire": (239, 68, 68), "Hydro": (59, 130, 246), "Water": (59, 130, 246),
"Cryo": (147, 197, 253), "Ice": (147, 197, 253), "Electro": (168, 85, 247),
"Anemo": (16, 185, 129), "Wind": (16, 185, 129), "Geo": (250, 204, 21), "Earth": (250, 204, 21),
"Dendro": (34, 197, 94)
}
@staticmethod
def get_font(size: int):
base_dir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
font_path = os.path.join(base_dir, "assets", "font.ttf")
try:
if os.path.exists(font_path): return ImageFont.truetype(font_path, size)
except: pass
return ImageFont.load_default()
@staticmethod
def create_rounded_mask(size, radius):
scale = 3
mask = Image.new('L', (size[0]*scale, size[1]*scale), 0)
draw = ImageDraw.Draw(mask)
draw.rounded_rectangle((0, 0, size[0]*scale, size[1]*scale), radius=radius*scale, fill=255)
return mask.resize(size, Image.Resampling.LANCZOS)
@staticmethod
def create_bottom_rounded_mask(size, radius):
scale = 3
mask = Image.new('L', (size[0]*scale, size[1]*scale), 0)
draw = ImageDraw.Draw(mask)
draw.rounded_rectangle((0, 0, size[0]*scale, size[1]*scale), radius=radius*scale, fill=255)
draw.rectangle((0, 0, size[0]*scale, radius*scale), fill=255)
return mask.resize(size, Image.Resampling.LANCZOS)
@staticmethod
def draw_text_with_glow(uid, position, text, font, core_color="white", glow_color=(0,0,0)):
uid.text(position, text, font=font, fill=core_color, stroke_width=3, stroke_fill=glow_color)
def apply_text(self, blank_template: Image.Image, char_name: str, print_num: int, element: str, rarity: str) -> io.BytesIO:
canvas = blank_template.copy()
uid = ImageDraw.Draw(canvas)
r_color = self.ELEMENT_COLORS.get(element, (250, 204, 21) if rarity in ["Legendary", "Mythic", "SSR", "UR"] else (156, 163, 175))
light_r = tuple(min(255, c + 150) for c in r_color)
glow_solid = r_color[:3]
base_sz = int(self.CARD_W * 0.085)
num_font = self.get_font(base_sz)
num_text = str(print_num)
# ==========================================
# 1. Standard Number Box (100% UNTOUCHED LOGIC)
# ==========================================
try:
num_w = num_font.getlength(num_text)
except:
num_w = 20
box_w = num_w + 24
box_h = 46
box_x2 = self.OFFSET_X + self.CARD_W - 30
box_x1 = box_x2 - box_w
box_y1 = self.OFFSET_Y + self.CARD_H - self.BANNER_H + (self.BANNER_H - box_h) // 2
box_y2 = box_y1 + box_h
uid.rounded_rectangle((box_x1, box_y1, box_x2, box_y2), radius=10, fill=(10, 10, 10, 180), outline=light_r, width=2)
num_x = box_x1 + (box_w - num_w) / 2
num_y = box_y1 - 6
self.draw_text_with_glow(uid, (num_x, num_y), num_text, num_font, core_color="white", glow_color=glow_solid)
# ==========================================
# 2. Dynamic Centered Character Name
# ==========================================
final_char_name = char_name.title()
available_name_w = (box_x1 - self.OFFSET_X) - 20
name_sz = base_sz
min_sz = 20
name_font = self.get_font(name_sz)
# ⚡ THE FIX: Dynamic Scaler Loop. Shrink font until it fits the available width.
while True:
try:
n_w = name_font.getlength(final_char_name)
except AttributeError:
n_w = 20
if n_w <= available_name_w or name_sz <= min_sz:
break
name_sz -= 2
name_font = self.get_font(name_sz)
try:
n_bbox = uid.textbbox((0, 0), final_char_name, font=name_font, stroke_width=3)
except:
n_bbox = (0, 0, n_w, name_sz)
n_w_final = n_bbox[2] - n_bbox[0]
n_h_final = n_bbox[3] - n_bbox[1]
# Center horizontally in the available space, and perfectly vertically in the banner
name_x = self.OFFSET_X + 10 + (available_name_w - n_w_final) // 2 - n_bbox[0]
name_y = self.OFFSET_Y + self.CARD_H - self.BANNER_H + (self.BANNER_H - n_h_final) // 2 - n_bbox[1]
self.draw_text_with_glow(uid, (name_x, name_y), final_char_name, name_font, core_color="white", glow_color=glow_solid)
buf = io.BytesIO()
canvas.save(buf, format="WEBP", quality=85, method=0)
buf.seek(0)
return buf