Refactor default.py to streamline profile card rendering, including adjustments to background layers, improved stats layout, and enhanced visibility of XP and progress percentage. Simplify the design by removing unnecessary elements and optimizing positioning for a cleaner aesthetic.
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
b3cf61b4ec
commit
bf4fbe7248
1 changed files with 64 additions and 169 deletions
|
@ -197,169 +197,79 @@ def generate_default_profile(
|
||||||
if square:
|
if square:
|
||||||
desired_card_size = (450, 450)
|
desired_card_size = (450, 450)
|
||||||
else:
|
else:
|
||||||
# Slightly increase height to accommodate larger fonts
|
|
||||||
desired_card_size = (1050, 320)
|
desired_card_size = (1050, 320)
|
||||||
|
|
||||||
# Define profile picture size and positions
|
# Define profile picture size and positions
|
||||||
pfp_size = (270, 270) # Slightly smaller profile picture
|
pfp_size = (270, 270)
|
||||||
pfp_x = 55
|
pfp_x = 15 # Slight padding from left
|
||||||
pfp_y = (desired_card_size[1] - pfp_size[1]) // 2
|
pfp_y = (desired_card_size[1] - pfp_size[1]) // 2
|
||||||
circle_x = pfp_x
|
circle_x = pfp_x
|
||||||
circle_y = pfp_y
|
circle_y = pfp_y
|
||||||
|
|
||||||
# Define the stats area to cover entire image
|
# Create the dark background layer that covers everything
|
||||||
stats_area = (
|
dark_bg = Image.new("RGBA", desired_card_size, (0, 0, 0, 0))
|
||||||
0, # x1 - Start from very left edge
|
dark_bg_draw = ImageDraw.Draw(dark_bg)
|
||||||
0, # y1 - Start from very top
|
dark_bg_draw.rectangle((0, 0, desired_card_size[0], desired_card_size[1]), fill=(0, 0, 0, 180))
|
||||||
desired_card_size[0], # x2 - End at right edge
|
|
||||||
desired_card_size[1] # y2 - End at bottom
|
|
||||||
)
|
|
||||||
|
|
||||||
# Create the stats layer with glass effect
|
|
||||||
stats_layer = Image.new("RGBA", desired_card_size, (0, 0, 0, 0))
|
|
||||||
|
|
||||||
# Create a darker glass morphism effect for entire background
|
|
||||||
glass = Image.new("RGBA", desired_card_size, (0, 0, 0, 0))
|
|
||||||
glass_draw = ImageDraw.Draw(glass)
|
|
||||||
glass_draw.rounded_rectangle(stats_area, radius=15, fill=(0, 0, 0, 160)) # Darker background for better readability
|
|
||||||
|
|
||||||
# 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(40):
|
|
||||||
opacity = int(35 * (1 - i/40)) # Reduced opacity for subtler effect
|
|
||||||
gradient_draw.rounded_rectangle(
|
|
||||||
(stats_area[0], stats_area[1]+i, stats_area[2], stats_area[3]),
|
|
||||||
radius=15,
|
|
||||||
fill=(255, 255, 255, opacity)
|
|
||||||
)
|
|
||||||
|
|
||||||
# Composite the glass effect
|
|
||||||
stats_layer = Image.alpha_composite(stats_layer, glass)
|
|
||||||
stats_layer = Image.alpha_composite(stats_layer, gradient)
|
|
||||||
|
|
||||||
# Draw stats with improved styling
|
# Create the stats layer
|
||||||
|
stats_layer = Image.new("RGBA", desired_card_size, (0, 0, 0, 0))
|
||||||
draw = ImageDraw.Draw(stats_layer)
|
draw = ImageDraw.Draw(stats_layer)
|
||||||
|
|
||||||
|
# Stats positioning
|
||||||
|
stats_x = pfp_x + pfp_size[0] + 30 # Start stats after profile picture
|
||||||
|
stats_y = 40 # Top padding
|
||||||
|
|
||||||
# Add level text with enhanced modern styling
|
# Draw stats with consistent spacing
|
||||||
|
title_font = ImageFont.truetype(str(font_path or imgtools.DEFAULT_FONT), 32)
|
||||||
|
value_font = ImageFont.truetype(str(font_path or imgtools.DEFAULT_FONT), 32)
|
||||||
|
|
||||||
|
# Balance and Rank stats
|
||||||
|
balance_y = stats_y
|
||||||
|
draw.text((stats_x + 400, balance_y), "BALANCE:", font=title_font, fill=(200, 200, 200))
|
||||||
|
draw.text((stats_x + 550, balance_y), f"{humanize_number(balance)} CREDITS", font=value_font, fill=stat_color or (255, 255, 255))
|
||||||
|
|
||||||
|
rank_y = balance_y + 50
|
||||||
|
draw.text((stats_x + 400, rank_y), "RANK:", font=title_font, fill=(200, 200, 200))
|
||||||
|
draw.text((stats_x + 550, rank_y), f"#{humanize_number(position)}", font=value_font, fill=stat_color or (255, 255, 255))
|
||||||
|
|
||||||
|
# XP Text
|
||||||
|
xp_y = rank_y + 50
|
||||||
|
xp_text = f"XP: {humanize_number(current_xp)} / {humanize_number(next_xp)}"
|
||||||
|
draw.text((stats_x + 400, xp_y), xp_text, font=value_font, fill=(255, 255, 255))
|
||||||
|
|
||||||
|
# Progress bar
|
||||||
|
progress = (current_xp - previous_xp) / (next_xp - previous_xp) if next_xp > previous_xp else 0
|
||||||
|
progress = max(0, min(1, progress)) # Ensure progress is between 0 and 1
|
||||||
|
|
||||||
|
bar_width = desired_card_size[0] - 30 # Full width with padding
|
||||||
|
bar_height = 40
|
||||||
|
bar_x = 15
|
||||||
|
bar_y = desired_card_size[1] - bar_height - 15 # Bottom padding
|
||||||
|
|
||||||
|
# Progress bar background
|
||||||
|
draw.rectangle((bar_x, bar_y, bar_x + bar_width, bar_y + bar_height), fill=(50, 50, 50))
|
||||||
|
|
||||||
|
# Progress bar fill
|
||||||
|
if progress > 0:
|
||||||
|
progress_width = int(bar_width * progress)
|
||||||
|
draw.rectangle((bar_x, bar_y, bar_x + progress_width, bar_y + bar_height), fill=level_bar_color or user_color)
|
||||||
|
|
||||||
|
# Progress percentage
|
||||||
|
percent_text = f"{int(progress * 100)}%"
|
||||||
|
percent_font = ImageFont.truetype(str(font_path or imgtools.DEFAULT_FONT), 24)
|
||||||
|
percent_w = draw.textlength(percent_text, font=percent_font)
|
||||||
|
percent_x = bar_x + 10 # Left align percentage
|
||||||
|
percent_y = bar_y + (bar_height - 24) // 2 # Center in bar
|
||||||
|
|
||||||
|
# Draw percentage
|
||||||
|
draw.text((percent_x, percent_y), percent_text, font=percent_font, fill=(255, 255, 255))
|
||||||
|
|
||||||
|
# Level text
|
||||||
|
level_font = ImageFont.truetype(str(font_path or imgtools.DEFAULT_FONT), 48)
|
||||||
level_text = f"LEVEL {level}"
|
level_text = f"LEVEL {level}"
|
||||||
if prestige > 0:
|
if prestige > 0:
|
||||||
level_text = f"P{prestige} • {level_text}"
|
level_text = f"P{prestige} • {level_text}"
|
||||||
|
draw.text((15, 15), level_text, font=level_font, fill=user_color or (255, 255, 255))
|
||||||
# Use larger font for level display
|
|
||||||
level_font = ImageFont.truetype(str(font_path or imgtools.DEFAULT_FONT), 64) # Increased size
|
|
||||||
level_y = stats_area[1] + 20
|
|
||||||
|
|
||||||
# Add subtle text shadow for depth
|
|
||||||
shadow_offset = 2
|
|
||||||
level_x = stats_area[0] + 30 # Move level text to left side
|
|
||||||
|
|
||||||
# Draw level text with improved shadow
|
|
||||||
draw.text(
|
|
||||||
(level_x + shadow_offset, level_y + shadow_offset),
|
|
||||||
level_text,
|
|
||||||
font=level_font,
|
|
||||||
fill=(0, 0, 0, 60) # More subtle shadow
|
|
||||||
)
|
|
||||||
draw.text(
|
|
||||||
(level_x, level_y),
|
|
||||||
level_text,
|
|
||||||
font=level_font,
|
|
||||||
fill=user_color
|
|
||||||
)
|
|
||||||
|
|
||||||
# Stats section with improved layout
|
|
||||||
title_font_size = 26 # Slightly smaller for better hierarchy
|
|
||||||
value_font_size = 30 # Kept larger for emphasis
|
|
||||||
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 = 50 # Increased spacing between stats
|
|
||||||
|
|
||||||
# Starting positions - moved down and left
|
|
||||||
start_x = stats_area[0] + 40
|
|
||||||
start_y = level_y + 100 # More space after level text
|
|
||||||
|
|
||||||
# Helper function for stat rendering with improved spacing
|
|
||||||
def draw_stat(x_pos, y_pos, icon, title, value, color=stat_color):
|
|
||||||
# Draw icon with subtle glow
|
|
||||||
draw.text((x_pos, y_pos), icon, font=value_font, fill=color)
|
|
||||||
|
|
||||||
# Draw title with modern styling
|
|
||||||
title_x = x_pos + 40
|
|
||||||
draw.text((title_x, y_pos), f"{title}:", font=title_font, fill=(200, 200, 200)) # Slightly dimmer
|
|
||||||
|
|
||||||
# Calculate value position
|
|
||||||
title_width = draw.textlength(f"{title}:", font=title_font)
|
|
||||||
value_x = title_x + title_width + 15
|
|
||||||
|
|
||||||
# Draw value with subtle shadow
|
|
||||||
draw.text((value_x + 1, y_pos + 1), value, font=value_font, fill=(0, 0, 0, 40))
|
|
||||||
draw.text((value_x, y_pos), value, font=value_font, fill=color)
|
|
||||||
return spacing
|
|
||||||
|
|
||||||
# Draw stats in two columns with better spacing
|
|
||||||
left_column_x = start_x
|
|
||||||
right_column_x = start_x + 380 # Increased column separation
|
|
||||||
current_y = start_y
|
|
||||||
|
|
||||||
# Left column stats
|
|
||||||
current_y += draw_stat(left_column_x, current_y, "💬", "Messages", f"{humanize_number(messages)}")
|
|
||||||
current_y += draw_stat(left_column_x, current_y, "🎤", "Voice", imgtools.abbreviate_time(voicetime))
|
|
||||||
current_y += draw_stat(left_column_x, current_y, "⭐", "Stars", humanize_number(stars))
|
|
||||||
|
|
||||||
# Right column stats
|
|
||||||
current_y = start_y
|
|
||||||
if balance is not None:
|
|
||||||
current_y += draw_stat(right_column_x, current_y, "💰", "Balance", f"{humanize_number(balance)} {currency_name}")
|
|
||||||
current_y += draw_stat(right_column_x, current_y, "🏆", "Rank", f"#{humanize_number(position)}")
|
|
||||||
|
|
||||||
# Progress bar with modern design - moved to bottom
|
|
||||||
bar_width = stats_area[2] - stats_area[0] - 60 # Full width progress bar
|
|
||||||
bar_height = 25 # Slightly thinner
|
|
||||||
bar_x = stats_area[0] + 30
|
|
||||||
bar_y = stats_area[3] - 60 # Move up from bottom
|
|
||||||
|
|
||||||
# Progress bar background with modern blur effect
|
|
||||||
draw.rounded_rectangle(
|
|
||||||
(bar_x, bar_y, bar_x + bar_width, bar_y + bar_height),
|
|
||||||
radius=bar_height//2,
|
|
||||||
fill=(0, 0, 0, 40) # Very subtle background
|
|
||||||
)
|
|
||||||
|
|
||||||
# Calculate progress
|
|
||||||
progress = (current_xp - previous_xp) / (next_xp - previous_xp) if next_xp > previous_xp else 0
|
|
||||||
progress = max(0, min(1, progress)) # Ensure progress is between 0 and 1
|
|
||||||
|
|
||||||
# Progress bar fill with gradient effect
|
|
||||||
if progress > 0:
|
|
||||||
progress_width = int(bar_width * progress)
|
|
||||||
draw.rounded_rectangle(
|
|
||||||
(bar_x, bar_y, bar_x + progress_width, bar_y + bar_height),
|
|
||||||
radius=bar_height//2,
|
|
||||||
fill=level_bar_color or user_color
|
|
||||||
)
|
|
||||||
|
|
||||||
# XP Text with improved visibility
|
|
||||||
xp_font = ImageFont.truetype(str(font_path or imgtools.DEFAULT_FONT), 22)
|
|
||||||
xp_text = f"XP: {humanize_number(current_xp)} / {humanize_number(next_xp)}"
|
|
||||||
xp_w = draw.textlength(xp_text, font=xp_font)
|
|
||||||
xp_x = bar_x + (bar_width - xp_w) / 2
|
|
||||||
xp_y = bar_y - 30
|
|
||||||
|
|
||||||
# Draw XP text with improved shadow
|
|
||||||
draw.text((xp_x + 1, xp_y + 1), xp_text, font=xp_font, fill=(0, 0, 0, 80))
|
|
||||||
draw.text((xp_x, xp_y), xp_text, font=xp_font, fill=(255, 255, 255))
|
|
||||||
|
|
||||||
# Progress percentage with improved visibility
|
|
||||||
percent_text = f"{int(progress * 100)}%"
|
|
||||||
percent_font = ImageFont.truetype(str(font_path or imgtools.DEFAULT_FONT), 20)
|
|
||||||
percent_w = draw.textlength(percent_text, font=percent_font)
|
|
||||||
percent_x = bar_x + progress_width - percent_w - 10
|
|
||||||
percent_y = bar_y + 2
|
|
||||||
|
|
||||||
# Draw percentage with improved shadow
|
|
||||||
draw.text((percent_x + 1, percent_y + 1), percent_text, font=percent_font, fill=(0, 0, 0, 80))
|
|
||||||
draw.text((percent_x, percent_y), percent_text, font=percent_font, fill=(255, 255, 255))
|
|
||||||
|
|
||||||
# Composite the layers
|
# Composite the layers
|
||||||
if not render_gif or (not pfp_animated and not bg_animated):
|
if not render_gif or (not pfp_animated and not bg_animated):
|
||||||
|
@ -371,32 +281,17 @@ def generate_default_profile(
|
||||||
# Fit the background to the desired size
|
# Fit the background to the desired size
|
||||||
card = imgtools.fit_aspect_ratio(card, desired_card_size)
|
card = imgtools.fit_aspect_ratio(card, desired_card_size)
|
||||||
|
|
||||||
# Round the card corners
|
|
||||||
card = imgtools.round_image_corners(card, 20)
|
|
||||||
|
|
||||||
# Create circular profile picture
|
# Create circular profile picture
|
||||||
pfp = pfp.resize(pfp_size, Image.Resampling.LANCZOS)
|
pfp = pfp.resize(pfp_size, Image.Resampling.LANCZOS)
|
||||||
pfp = imgtools.make_profile_circle(pfp)
|
pfp = imgtools.make_profile_circle(pfp)
|
||||||
|
|
||||||
# Position profile picture on the left
|
# Create final image
|
||||||
pfp_x = 55
|
|
||||||
pfp_y = (desired_card_size[1] - pfp_size[1]) // 2
|
|
||||||
|
|
||||||
# Define circle positions for animated profiles
|
|
||||||
circle_x = pfp_x
|
|
||||||
circle_y = pfp_y
|
|
||||||
|
|
||||||
# Create a new image for final composition
|
|
||||||
final_image = Image.new("RGBA", desired_card_size, (0, 0, 0, 0))
|
final_image = Image.new("RGBA", desired_card_size, (0, 0, 0, 0))
|
||||||
|
|
||||||
# Add blur effect if enabled
|
# Layer order: card -> dark background -> stats -> profile picture
|
||||||
if blur:
|
|
||||||
blur_section = imgtools.blur_section(card, (stats_area[0], 0, card.width, card.height))
|
|
||||||
card.paste(blur_section, (stats_area[0], 0), blur_section)
|
|
||||||
|
|
||||||
# Paste layers in correct order
|
|
||||||
final_image.paste(card, (0, 0), card)
|
final_image.paste(card, (0, 0), card)
|
||||||
final_image.paste(stats_layer, (0, 0), stats_layer)
|
final_image = Image.alpha_composite(final_image, dark_bg)
|
||||||
|
final_image = Image.alpha_composite(final_image, stats_layer)
|
||||||
final_image.paste(pfp, (pfp_x, pfp_y), pfp)
|
final_image.paste(pfp, (pfp_x, pfp_y), pfp)
|
||||||
|
|
||||||
if debug:
|
if debug:
|
||||||
|
|
Loading…
Add table
Reference in a new issue