diff --git a/levelup/generator/styles/default.py b/levelup/generator/styles/default.py index 5a730b1..4533a8f 100644 --- a/levelup/generator/styles/default.py +++ b/levelup/generator/styles/default.py @@ -197,169 +197,79 @@ def generate_default_profile( if square: desired_card_size = (450, 450) else: - # Slightly increase height to accommodate larger fonts desired_card_size = (1050, 320) # Define profile picture size and positions - pfp_size = (270, 270) # Slightly smaller profile picture - pfp_x = 55 + pfp_size = (270, 270) + pfp_x = 15 # Slight padding from left pfp_y = (desired_card_size[1] - pfp_size[1]) // 2 circle_x = pfp_x circle_y = pfp_y - # Define the stats area to cover entire image - stats_area = ( - 0, # x1 - Start from very left edge - 0, # y1 - Start from very top - 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) + # Create the dark background layer that covers everything + dark_bg = Image.new("RGBA", desired_card_size, (0, 0, 0, 0)) + dark_bg_draw = ImageDraw.Draw(dark_bg) + dark_bg_draw.rectangle((0, 0, desired_card_size[0], desired_card_size[1]), fill=(0, 0, 0, 180)) - # 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) + + # 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}" if prestige > 0: level_text = f"P{prestige} • {level_text}" - - # 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)) + draw.text((15, 15), level_text, font=level_font, fill=user_color or (255, 255, 255)) # Composite the layers 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 card = imgtools.fit_aspect_ratio(card, desired_card_size) - # Round the card corners - card = imgtools.round_image_corners(card, 20) - # Create circular profile picture pfp = pfp.resize(pfp_size, Image.Resampling.LANCZOS) pfp = imgtools.make_profile_circle(pfp) - # Position profile picture on the left - 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 + # Create final image final_image = Image.new("RGBA", desired_card_size, (0, 0, 0, 0)) - # Add blur effect if enabled - 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 + # Layer order: card -> dark background -> stats -> profile picture 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) if debug: