forked from Rockachopa/Timmy-time-dashboard
This commit is contained in:
@@ -270,20 +270,8 @@ async def create_gitea_issue_via_mcp(title: str, body: str = "", labels: str = "
|
|||||||
return f"Failed to create issue via MCP: {exc}"
|
return f"Failed to create issue via MCP: {exc}"
|
||||||
|
|
||||||
|
|
||||||
def _generate_avatar_image() -> bytes:
|
def _draw_background(draw: "ImageDraw.ImageDraw", size: int) -> None:
|
||||||
"""Generate a Timmy-themed avatar image using Pillow.
|
"""Draw radial gradient background with concentric circles."""
|
||||||
|
|
||||||
Creates a 512x512 wizard-themed avatar with emerald/purple/gold palette.
|
|
||||||
Returns raw PNG bytes. Falls back to a minimal solid-color image if
|
|
||||||
Pillow drawing primitives fail.
|
|
||||||
"""
|
|
||||||
from PIL import Image, ImageDraw
|
|
||||||
|
|
||||||
size = 512
|
|
||||||
img = Image.new("RGB", (size, size), (15, 25, 20))
|
|
||||||
draw = ImageDraw.Draw(img)
|
|
||||||
|
|
||||||
# Background gradient effect — concentric circles
|
|
||||||
for i in range(size // 2, 0, -4):
|
for i in range(size // 2, 0, -4):
|
||||||
g = int(25 + (i / (size // 2)) * 30)
|
g = int(25 + (i / (size // 2)) * 30)
|
||||||
draw.ellipse(
|
draw.ellipse(
|
||||||
@@ -291,33 +279,45 @@ def _generate_avatar_image() -> bytes:
|
|||||||
fill=(10, g, 20),
|
fill=(10, g, 20),
|
||||||
)
|
)
|
||||||
|
|
||||||
# Wizard hat (triangle)
|
|
||||||
|
def _draw_wizard(draw: "ImageDraw.ImageDraw") -> None:
|
||||||
|
"""Draw wizard hat, face, eyes, smile, monogram, and robe."""
|
||||||
hat_color = (100, 50, 160) # purple
|
hat_color = (100, 50, 160) # purple
|
||||||
draw.polygon(
|
hat_outline = (180, 130, 255)
|
||||||
[(256, 40), (160, 220), (352, 220)],
|
gold = (220, 190, 50)
|
||||||
fill=hat_color,
|
pupil = (30, 30, 60)
|
||||||
outline=(180, 130, 255),
|
|
||||||
)
|
|
||||||
|
|
||||||
# Hat brim
|
# Hat + brim
|
||||||
draw.ellipse([140, 200, 372, 250], fill=hat_color, outline=(180, 130, 255))
|
draw.polygon([(256, 40), (160, 220), (352, 220)], fill=hat_color, outline=hat_outline)
|
||||||
|
draw.ellipse([140, 200, 372, 250], fill=hat_color, outline=hat_outline)
|
||||||
|
|
||||||
# Face circle
|
# Face
|
||||||
draw.ellipse([190, 220, 322, 370], fill=(60, 180, 100), outline=(80, 220, 120))
|
draw.ellipse([190, 220, 322, 370], fill=(60, 180, 100), outline=(80, 220, 120))
|
||||||
|
|
||||||
# Eyes
|
# Eyes (whites + pupils)
|
||||||
draw.ellipse([220, 275, 248, 310], fill=(255, 255, 255))
|
draw.ellipse([220, 275, 248, 310], fill=(255, 255, 255))
|
||||||
draw.ellipse([264, 275, 292, 310], fill=(255, 255, 255))
|
draw.ellipse([264, 275, 292, 310], fill=(255, 255, 255))
|
||||||
draw.ellipse([228, 285, 242, 300], fill=(30, 30, 60))
|
draw.ellipse([228, 285, 242, 300], fill=pupil)
|
||||||
draw.ellipse([272, 285, 286, 300], fill=(30, 30, 60))
|
draw.ellipse([272, 285, 286, 300], fill=pupil)
|
||||||
|
|
||||||
# Smile
|
# Smile
|
||||||
draw.arc([225, 300, 287, 355], start=10, end=170, fill=(30, 30, 60), width=3)
|
draw.arc([225, 300, 287, 355], start=10, end=170, fill=pupil, width=3)
|
||||||
|
|
||||||
# Stars around the hat
|
# "T" monogram on hat
|
||||||
|
draw.text((243, 100), "T", fill=gold)
|
||||||
|
|
||||||
|
# Robe
|
||||||
|
draw.polygon(
|
||||||
|
[(180, 370), (140, 500), (372, 500), (332, 370)],
|
||||||
|
fill=(40, 100, 70),
|
||||||
|
outline=(60, 160, 100),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _draw_stars(draw: "ImageDraw.ImageDraw") -> None:
|
||||||
|
"""Draw decorative gold stars around the wizard hat."""
|
||||||
gold = (220, 190, 50)
|
gold = (220, 190, 50)
|
||||||
star_positions = [(120, 100), (380, 120), (100, 300), (400, 280), (256, 10)]
|
for sx, sy in [(120, 100), (380, 120), (100, 300), (400, 280), (256, 10)]:
|
||||||
for sx, sy in star_positions:
|
|
||||||
r = 8
|
r = 8
|
||||||
draw.polygon(
|
draw.polygon(
|
||||||
[
|
[
|
||||||
@@ -333,18 +333,26 @@ def _generate_avatar_image() -> bytes:
|
|||||||
fill=gold,
|
fill=gold,
|
||||||
)
|
)
|
||||||
|
|
||||||
# "T" monogram on the hat
|
|
||||||
draw.text((243, 100), "T", fill=gold)
|
|
||||||
|
|
||||||
# Robe / body
|
def _generate_avatar_image() -> bytes:
|
||||||
draw.polygon(
|
"""Generate a Timmy-themed avatar image using Pillow.
|
||||||
[(180, 370), (140, 500), (372, 500), (332, 370)],
|
|
||||||
fill=(40, 100, 70),
|
|
||||||
outline=(60, 160, 100),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
Creates a 512x512 wizard-themed avatar with emerald/purple/gold palette.
|
||||||
|
Returns raw PNG bytes. Falls back to a minimal solid-color image if
|
||||||
|
Pillow drawing primitives fail.
|
||||||
|
"""
|
||||||
import io
|
import io
|
||||||
|
|
||||||
|
from PIL import Image, ImageDraw
|
||||||
|
|
||||||
|
size = 512
|
||||||
|
img = Image.new("RGB", (size, size), (15, 25, 20))
|
||||||
|
draw = ImageDraw.Draw(img)
|
||||||
|
|
||||||
|
_draw_background(draw, size)
|
||||||
|
_draw_wizard(draw)
|
||||||
|
_draw_stars(draw)
|
||||||
|
|
||||||
buf = io.BytesIO()
|
buf = io.BytesIO()
|
||||||
img.save(buf, format="PNG")
|
img.save(buf, format="PNG")
|
||||||
return buf.getvalue()
|
return buf.getvalue()
|
||||||
|
|||||||
Reference in New Issue
Block a user