diff --git a/ENSCardMakerWeb.py b/ENSCardMakerWeb.py index 6027c5b..06a62aa 100644 --- a/ENSCardMakerWeb.py +++ b/ENSCardMakerWeb.py @@ -4,6 +4,8 @@ from PIL import Image, ImageDraw, ImageFont, ImageSequence import textwrap import io +import pydenticon +from io import BytesIO app = Flask(__name__) @@ -19,41 +21,104 @@ def generate_card(user): profilejson = profilerequest.content.decode("utf-8") profile = json.loads(profilejson) + avatar = None + identicon_used = False + fallback = False if 'avatar' in profile: - avatar_response = requests.get(profile['avatar'], stream=True) - avatar = Image.open(avatar_response.raw) - - if avatar.format == 'GIF': - avatar = next(ImageSequence.Iterator(avatar)) # Get the first frame of the GIF - - avatar_size = (240, 240) # Specify the desired size of the avatar image - avatar = avatar.resize(avatar_size) # Resize the avatar image - + try: + avatar_response = requests.get(profile['avatar'], stream=True) + avatar = Image.open(avatar_response.raw) + + if avatar.format == 'GIF': + avatar = next(ImageSequence.Iterator(avatar)) # Get the first frame of the GIF + + avatar_size = (240, 240) # Specify the desired size of the avatar image + avatar = avatar.resize(avatar_size) # Resize the avatar image + + # Ensure the image is in RGB mode + if avatar.mode != 'RGB': + avatar = avatar.convert('RGB') + + # Get the dominant color of the avatar + dominant_color = avatar.getpixel((0, 0)) + + # Darken the dominant color + darkened_color = tuple(int(c * 0.5) for c in dominant_color) + + # Use the darkened color as the background color + img = Image.new('RGB', (740, 290), color=darkened_color) + + except Exception as e: + identicon_used = True + fallback = True + + # Generate the identicon image + identicon = pydenticon.Generator(5, 5).generate(profile['address'], 240, 240) + + # Convert the identicon image to PIL Image format + avatar = Image.open(BytesIO(identicon)) + + # Ensure the image is in RGB mode + if avatar.mode != 'RGB': + avatar = avatar.convert('RGB') + + # Get the dominant color of the avatar + dominant_color = avatar.getpixel((0, 0)) + + # Darken the dominant color + darkened_color = tuple(int(c * 0.5) for c in dominant_color) + + # Use the darkened color as the background color + img = Image.new('RGB', (740, 290), color=darkened_color) + else: + identicon_used = True + + # Generate the identicon image + identicon = pydenticon.Generator(5, 5).generate(profile['address'], 240, 240) + + # Convert the identicon image to PIL Image format + avatar = Image.fromarray(identicon) + # Ensure the image is in RGB mode if avatar.mode != 'RGB': avatar = avatar.convert('RGB') - + # Get the dominant color of the avatar dominant_color = avatar.getpixel((0, 0)) - + # Darken the dominant color darkened_color = tuple(int(c * 0.5) for c in dominant_color) - + # Use the darkened color as the background color img = Image.new('RGB', (740, 290), color=darkened_color) - else: - img = Image.new('RGB', (740, 290), color=(0, 0, 0)) + draw = ImageDraw.Draw(img) - if 'avatar' in profile: - avatar_response = requests.get(profile['avatar'], stream=True) - avatar = Image.open(avatar_response.raw) - if avatar.format == 'GIF': - avatar = next(ImageSequence.Iterator(avatar)) # Get the first frame of the GIF + + if avatar: avatar_size = (240, 240) # Specify the desired size of the avatar image avatar = avatar.resize(avatar_size) # Resize the avatar image img.paste(avatar, (20, 20)) - else: - draw.rectangle([20, 20, 260, 260], fill=(255, 255, 255)) + if profile['records']['avatar'].startswith("eip155:1/") and not identicon_used: + # Draw a small box in the corner of the avatar + box_position = (30, 30, 80, 60) # Define the position of the box + draw.rectangle(box_position, fill='#2081E2') + + # Draw the text "NFT" inside the box + font_size = 20 # Specify the desired font size for the NFT text + font_path = "./fonts/Inter-Bold.ttf" # Path to the Inter Bold font + font = ImageFont.truetype(font_path, font_size) # Load the desired font + draw.text((36, 33), "NFT", fill='white', font=font) # Draw the text inside the box + elif fallback: + # Draw a small box in the corner of the avatar + box_position = (30, 30, 150, 60) + draw.rectangle(box_position, fill='#FF0000') + + # Draw the text "FALLBACK" inside the box + font_size = 20 + font_path = "./fonts/Inter-Bold.ttf" + font = ImageFont.truetype(font_path, font_size) + draw.text((39, 33), "FALLBACK", fill='white', font=font) + # Display the user's nickname, or replace it with their ENS name they don't have a nickname if 'name' in profile['records']: name = profile['records']['name'] @@ -69,6 +134,7 @@ def generate_card(user): font_path = "./fonts/Inter-Bold.ttf" # Path to the Inter Bold font font = ImageFont.truetype(font_path, font_size) # Load the desired font draw.text((280, 20), name, fill=(255, 255, 255), font=font) # Draw the text with the specified font + # Display the user's ENS name and ETH address (truncated) if 'name' in profile and 'address' in profile: truncated_address = f"{profile['address'][:6]}...{profile['address'][-4:]}" @@ -77,6 +143,7 @@ def generate_card(user): font_path = "./fonts/Inter-Regular.ttf" # Path to the Inter Regular font font = ImageFont.truetype(font_path, font_size) # Load the desired font draw.text((280, 80), idstring, fill=(255, 255, 255), font=font) # Draw the text with the specified font + # Display the user's description with text wrapping description_y = 110 if 'description' in profile['records']: @@ -98,6 +165,7 @@ def generate_card(user): font = ImageFont.truetype(font_path, font_size) draw.text((280, description_y), f"[no description given]", fill=(255, 255, 255), font=font) description_y += font_size + 4 + # Social media social_media_spacing = 6 social_media_y = description_y + 10 @@ -112,6 +180,7 @@ def generate_card(user): font_path = "./fonts/Inter-Regular.ttf" font = ImageFont.truetype(font_path, font_size) draw.text((280, social_media_y), f"[no Twitter given]", fill=(255, 255, 255), font=font) + social_media_y += font_size + social_media_spacing if 'com.github' in profile['records']: github = profile['records']['com.github'] @@ -124,6 +193,7 @@ def generate_card(user): font_path = "./fonts/Inter-Regular.ttf" font = ImageFont.truetype(font_path, font_size) draw.text((280, social_media_y), f"[no GitHub given]", fill=(255, 255, 255), font=font) + social_media_y += font_size + social_media_spacing if 'com.discord' in profile['records']: discord = profile['records']['com.discord'] @@ -136,6 +206,7 @@ def generate_card(user): font_path = "./fonts/Inter-Regular.ttf" font = ImageFont.truetype(font_path, font_size) draw.text((280, social_media_y), f"[no Discord given]", fill=(255, 255, 255), font=font) + social_media_y += font_size + social_media_spacing if 'org.telegram' in profile['records']: telegram = profile['records']['org.telegram'] @@ -148,6 +219,7 @@ def generate_card(user): font_path = "./fonts/Inter-Regular.ttf" font = ImageFont.truetype(font_path, font_size) draw.text((280, social_media_y), f"[no Telegram given]", fill=(255, 255, 255), font=font) + social_media_y += font_size + social_media_spacing if 'email' in profile['records']: email = profile['records']['email'] @@ -160,6 +232,7 @@ def generate_card(user): font_path = "./fonts/Inter-Regular.ttf" font = ImageFont.truetype(font_path, font_size) draw.text((280, social_media_y), f"[no email given]", fill=(255, 255, 255), font=font) + social_media_y += font_size + social_media_spacing if 'url' in profile['records']: url = profile['records']['url'] diff --git a/requirements.txt b/requirements.txt index 3675ccd..3755571 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ Flask requests -Pillow \ No newline at end of file +Pillow +pydenticon \ No newline at end of file