| |
| 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) |
|
|
| |
| |
| |
| 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) |
|
|
| |
| |
| |
| 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) |
| |
| |
| 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] |
| |
| |
| 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 |
|
|