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
Some checks are pending
Run pre-commit / Run pre-commit (push) Waiting to run
This commit is contained in:
parent
6c5f48fcd7
commit
4c99430d95
1 changed files with 107 additions and 101 deletions
|
@ -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")
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue