Update profile card generation in default.py by changing default text color to white, refining layout dimensions for better proportions, and enhancing visual elements such as the stats area and progress bar. Implement improved text shadowing and spacing for a more polished appearance.
Some checks are pending
Run pre-commit / Run pre-commit (push) Waiting to run

This commit is contained in:
Valerie 2025-05-25 21:58:36 -04:00
parent 6c5f48fcd7
commit 4c99430d95

View file

@ -190,77 +190,39 @@ def generate_default_profile(
log.debug(f"PFP animated: {pfp_animated}, BG animated: {bg_animated}")
# Setup
default_fill = (0, 0, 0) # Default fill color for text
default_fill = (255, 255, 255) # Default fill color for text
stroke_width = 2 # Width of the stroke around text
if square:
desired_card_size = (450, 450)
# aspect_ratio = imgtools.calc_aspect_ratio(*desired_card_size)
name_y = 35 # Upper bound of username placement
stats_y = 160 # Upper bound of stats texts
blur_edge = 450 # Left bound of blur edge
bar_width = 550 # Length of level bar
bar_height = 40 # Height of level bar
bar_start = 475 # Left bound of level bar
bar_top = 380 # Top bound of level bar
stat_bottom = bar_top - 10 # Bottom bound of all stats
stat_start = bar_start + 10 # Left bound of all stats
stat_split = stat_start + 210 # Split between left and right stats
stat_end = 990 # Right bound of all stats
stat_offset = 45 # Offset between stats
circle_x = 60 # Left bound of profile circle
circle_y = 60 # Top bound of profile circle
star_text_x = 910 # Left bound of star text
star_text_y = 35 # Top bound of star text
star_icon_x = 850 # Left bound of star icon
star_icon_y = 35 # Top bound of star icon
else:
# Ensure the card is the correct size and aspect ratio
desired_card_size = (1050, 450)
# aspect_ratio = imgtools.calc_aspect_ratio(*desired_card_size)
name_y = 35 # Upper bound of username placement
stats_y = 160 # Upper bound of stats texts
blur_edge = 450 # Left bound of blur edge
bar_width = 550 # Length of level bar
bar_height = 40 # Height of level bar
bar_start = 475 # Left bound of level bar
bar_top = 380 # Top bound of level bar
stat_bottom = bar_top - 10 # Bottom bound of all stats
stat_start = bar_start + 10 # Left bound of all stats
stat_split = stat_start + 210 # Split between left and right stats
stat_end = 990 # Right bound of all stats
stat_offset = 45 # Offset between stats
circle_x = 60 # Left bound of profile circle
circle_y = 60 # Top bound of profile circle
star_text_x = 910 # Left bound of star text
star_text_y = 35 # Top bound of star text
star_icon_x = 850 # Left bound of star icon
star_icon_y = 35 # Top bound of star icon
# Create the stats layer with glass effect
stats_layer = Image.new("RGBA", desired_card_size, (0, 0, 0, 0))
# Reduce height for better proportions
desired_card_size = (1050, 350)
# Define the stats area with a modern glass effect
stats_area = (
400, # x1 - Start after profile picture
20, # y1 - Start near top
1000 if not square else 430, # x2 - End near right edge
430 # y2 - End near bottom
330 if not square else 430 # y2 - End near bottom
)
# Create a semi-transparent background for stats
# Create the stats layer with glass effect
stats_layer = Image.new("RGBA", desired_card_size, (0, 0, 0, 0))
# Create a semi-transparent background for stats with modern blur effect
glass = Image.new("RGBA", desired_card_size, (0, 0, 0, 0))
glass_draw = ImageDraw.Draw(glass)
glass_draw.rounded_rectangle(stats_area, radius=20, fill=(0, 0, 0, 80))
glass_draw.rounded_rectangle(stats_area, radius=25, fill=(0, 0, 0, 95))
# Add a subtle gradient overlay
# Add a subtle gradient overlay for depth
gradient = Image.new("RGBA", desired_card_size, (0, 0, 0, 0))
gradient_draw = ImageDraw.Draw(gradient)
for i in range(20):
opacity = int(80 * (1 - i/20))
for i in range(30):
opacity = int(60 * (1 - i/30))
gradient_draw.rounded_rectangle(
(stats_area[0], stats_area[1]+i, stats_area[2], stats_area[3]),
radius=20,
radius=25,
fill=(255, 255, 255, opacity)
)
@ -268,14 +230,15 @@ def generate_default_profile(
stats_layer = Image.alpha_composite(stats_layer, glass)
stats_layer = Image.alpha_composite(stats_layer, gradient)
# Add a subtle border
# Add a subtle glow border
border_draw = ImageDraw.Draw(stats_layer)
border_draw.rounded_rectangle(
stats_area,
radius=20,
outline=(255, 255, 255, 100),
width=2
)
for i in range(3):
border_draw.rounded_rectangle(
(stats_area[0]-i, stats_area[1]-i, stats_area[2]+i, stats_area[3]+i),
radius=25,
outline=(155, 17, 30, 100-i*30),
width=1
)
# Draw stats with improved styling
draw = ImageDraw.Draw(stats_layer)
@ -285,54 +248,78 @@ def generate_default_profile(
if prestige > 0:
level_text = f"P{prestige}{level_text}"
level_font = ImageFont.truetype(str(font_path or imgtools.DEFAULT_FONT), 48)
level_y = stats_area[1] + 20
# Use larger font for level display
level_font = ImageFont.truetype(str(font_path or imgtools.DEFAULT_FONT), 56)
level_y = stats_area[1] + 15
# Add subtle text shadow for depth
shadow_offset = 2
draw.text(
(stats_area[0] + 20 + shadow_offset, level_y + shadow_offset),
level_text,
font=level_font,
fill=(0, 0, 0, 100)
)
draw.text(
(stats_area[0] + 20, level_y),
level_text,
font=level_font,
fill=user_color,
stroke_width=2,
stroke_fill=(0, 0, 0)
fill=user_color
)
# Stats section
font_size = 32
font = ImageFont.truetype(str(font_path or imgtools.DEFAULT_FONT), font_size)
spacing = 50 # Vertical spacing between stats
# Stats section with improved layout
title_font_size = 24
value_font_size = 28
title_font = ImageFont.truetype(str(font_path or imgtools.DEFAULT_FONT), title_font_size)
value_font = ImageFont.truetype(str(font_path or imgtools.DEFAULT_FONT), value_font_size)
spacing = 45 # Vertical spacing between stats
# Starting positions
start_x = stats_area[0] + 20
start_y = level_y + 80
# Messages stat
draw.text((start_x, start_y), "💬", font=font, fill=stat_color)
draw.text((start_x + 40, start_y), f"{humanize_number(messages)}", font=font, fill=stat_color)
# Voice time stat
draw.text((start_x, start_y + spacing), "🎤", font=font, fill=stat_color)
draw.text((start_x + 40, start_y + spacing), imgtools.abbreviate_time(voicetime), font=font, fill=stat_color)
# Stars stat
draw.text((start_x, start_y + spacing * 2), "", font=font, fill=stat_color)
draw.text((start_x + 40, start_y + spacing * 2), f"{humanize_number(stars)}", font=font, fill=stat_color)
# Helper function for stat rendering
def draw_stat(y_pos, icon, title, value, color=stat_color):
# Draw icon
draw.text((start_x, y_pos), icon, font=value_font, fill=color)
# Draw title
draw.text((start_x + 40, y_pos), f"{title}:", font=title_font, fill=(200, 200, 200))
# Draw value with shadow for depth
value_x = start_x + 40
value_y = y_pos + title_font_size + 2
draw.text((value_x + 1, value_y + 1), value, font=value_font, fill=(0, 0, 0, 100))
draw.text((value_x, value_y), value, font=value_font, fill=color)
return spacing + title_font_size + 5
# Progress bar
progress = (current_xp - previous_xp) / (next_xp - previous_xp)
bar_width = stats_area[2] - stats_area[0] - 40
bar_height = 25
bar_y = stats_area[3] - 60
# Draw each stat with title and value
current_y = start_y
current_y += draw_stat(current_y, "💬", "Messages", f"{humanize_number(messages)} sent")
current_y += draw_stat(current_y, "🎤", "Voice Time", imgtools.abbreviate_time(voicetime))
current_y += draw_stat(current_y, "", "Stars", humanize_number(stars))
# Create progress bar background
# Right column stats
right_x = stats_area[0] + 300
current_y = start_y
if balance is not None:
current_y += draw_stat(current_y, "💰", "Balance", f"{humanize_number(balance)} {currency_name}")
current_y += draw_stat(current_y, "🏆", "Rank", f"#{humanize_number(position)}")
# Progress bar with modern design
bar_width = stats_area[2] - stats_area[0] - 40
bar_height = 30
bar_y = stats_area[3] - 60
progress = (current_xp - previous_xp) / (next_xp - previous_xp)
# Create progress bar background with gradient
bar_bg = Image.new("RGBA", (bar_width, bar_height), (0, 0, 0, 100))
progress_width = max(1, int(bar_width * progress)) # Ensure at least 1 pixel width
progress_width = max(1, int(bar_width * progress))
bar_progress = Image.new("RGBA", (progress_width, bar_height), level_bar_color + (200,))
# Add gradient to progress bar
# Add shine effect to progress bar
gradient = Image.new("RGBA", bar_progress.size, (0, 0, 0, 0))
gradient_draw = ImageDraw.Draw(gradient)
for i in range(bar_height):
opacity = int(100 * (1 - i/bar_height))
opacity = int(150 * (1 - abs(i - bar_height/2)/(bar_height/2)))
gradient_draw.rectangle(
(0, i, bar_progress.width, i+1),
fill=(255, 255, 255, opacity)
@ -354,13 +341,32 @@ def generate_default_profile(
stats_layer.paste(bar_bg, (start_x, bar_y), bar_bg)
stats_layer.paste(bar_progress_masked, (start_x, bar_y), bar_progress_masked)
# XP text
# XP text with improved styling
xp_font = ImageFont.truetype(str(font_path or imgtools.DEFAULT_FONT), 24)
xp_text = f"{humanize_number(current_xp)} / {humanize_number(next_xp)} XP"
xp_text = f"EXP: {humanize_number(current_xp)} / {humanize_number(next_xp)}"
xp_x = start_x + (bar_width - draw.textlength(xp_text, font=xp_font)) // 2
# Draw XP text with shadow
draw.text(
(start_x, bar_y + bar_height + 5),
(xp_x + 1, bar_y - 30 + 1),
xp_text,
font=xp_font,
fill=(0, 0, 0, 100)
)
draw.text(
(xp_x, bar_y - 30),
xp_text,
font=xp_font,
fill=(255, 255, 255)
)
# Progress percentage
percent_text = f"{int(progress * 100)}%"
percent_x = start_x + (bar_width - draw.textlength(percent_text, font=xp_font)) // 2
draw.text(
(percent_x, bar_y + bar_height + 5),
percent_text,
font=xp_font,
fill=stat_color,
stroke_width=1,
stroke_fill=(0, 0, 0)
@ -377,16 +383,16 @@ def generate_default_profile(
card = imgtools.fit_aspect_ratio(card, desired_card_size)
# Round the card corners
card = imgtools.round_image_corners(card, 20)
card = imgtools.round_image_corners(card, 25)
# Create circular profile picture
pfp_size = (320, 320) # Profile picture size
pfp_size = (300, 300) # Slightly smaller profile picture
pfp = pfp.resize(pfp_size, Image.Resampling.LANCZOS)
pfp = imgtools.make_profile_circle(pfp)
# Position profile picture on the left
pfp_x = 40
pfp_y = (card.height - pfp_size[1]) // 2
pfp_x = 50
pfp_y = (desired_card_size[1] - pfp_size[1]) // 2
# Create a new image for final composition
final_image = Image.new("RGBA", desired_card_size, (0, 0, 0, 0))
@ -414,9 +420,9 @@ def generate_default_profile(
card = card.convert("RGBA")
card = imgtools.fit_aspect_ratio(card, desired_card_size)
if blur:
blur_section = imgtools.blur_section(card, (blur_edge, 0, card.width, card.height))
blur_section = imgtools.blur_section(card, (stats_area[0], 0, card.width, card.height))
# Paste onto the stats
card.paste(blur_section, (blur_edge, 0), blur_section)
card.paste(blur_section, (stats_area[0], 0), blur_section)
card.paste(stats_layer, (0, 0), stats_layer)
@ -474,8 +480,8 @@ def generate_default_profile(
# Paste items onto the card
if blur:
blur_section = imgtools.blur_section(card_frame, (blur_edge, 0, card_frame.width, card_frame.height))
card_frame.paste(blur_section, (blur_edge, 0), blur_section)
blur_section = imgtools.blur_section(card_frame, (stats_area[0], 0, card_frame.width, card_frame.height))
card_frame.paste(blur_section, (stats_area[0], 0), blur_section)
card_frame.paste(pfp, (circle_x, circle_y), pfp)
card_frame.paste(stats_layer, (0, 0), stats_layer)
@ -547,9 +553,9 @@ def generate_default_profile(
card_frame = card_frame.convert("RGBA")
if blur:
blur_section = imgtools.blur_section(card_frame, (blur_edge, 0, card_frame.width, card_frame.height))
blur_section = imgtools.blur_section(card_frame, (stats_area[0], 0, card_frame.width, card_frame.height))
# Paste onto the stats
card_frame.paste(blur_section, (blur_edge, 0), blur_section)
card_frame.paste(blur_section, (stats_area[0], 0), blur_section)
if pfp_frame.mode != "RGBA":
pfp_frame = pfp_frame.convert("RGBA")