Spaces:
Sleeping
Sleeping
File size: 6,220 Bytes
a966aaa | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 | from PIL import Image, ImageDraw, ImageFont
import textwrap
import io
def create_quote_card(text, card_type="joke", title="Memory Forever"):
"""
Generate a beautiful quote card image.
Args:
text (str): The quote/joke/memory text to display
card_type (str): Type of card - "joke", "memory", or "motivation"
title (str): Optional title text
Returns:
BytesIO: Image buffer that can be downloaded
"""
# Card dimensions
width, height = 1080, 1080
# Create image
img = Image.new('RGB', (width, height), color='white')
draw = ImageDraw.Draw(img)
# Define color schemes for different card types
gradients = {
'joke': {
'top': (255, 75, 75), # Red/Pink
'bottom': (255, 120, 150),
'accent': (255, 255, 255),
'text': (255, 255, 255),
'icon': 'π'
},
'memory': {
'top': (255, 215, 100), # Yellow/Gold
'bottom': (255, 180, 120),
'accent': (139, 69, 19),
'text': (80, 50, 20),
'icon': 'π'
},
'motivation': {
'top': (100, 220, 150), # Green
'bottom': (80, 200, 180),
'accent': (255, 255, 255),
'text': (255, 255, 255),
'icon': 'β¨'
}
}
colors = gradients.get(card_type, gradients['joke'])
# Draw gradient background
for y in range(height):
r = int(colors['top'][0] + (colors['bottom'][0] - colors['top'][0]) * y / height)
g = int(colors['top'][1] + (colors['bottom'][1] - colors['top'][1]) * y / height)
b = int(colors['top'][2] + (colors['bottom'][2] - colors['top'][2]) * y / height)
draw.rectangle([(0, y), (width, y + 1)], fill=(r, g, b))
# Add decorative elements
add_decorative_elements(draw, width, height, colors['accent'], card_type)
# Load fonts (fallback to default if custom not available)
try:
title_font = ImageFont.truetype("arial.ttf", 60)
text_font = ImageFont.truetype("arial.ttf", 45)
footer_font = ImageFont.truetype("arial.ttf", 35)
icon_font = ImageFont.truetype("seguiemj.ttf", 80) # For emoji
except:
# Fallback to default font
title_font = ImageFont.load_default()
text_font = ImageFont.load_default()
footer_font = ImageFont.load_default()
icon_font = ImageFont.load_default()
# Draw icon at top
icon = colors['icon']
icon_bbox = draw.textbbox((0, 0), icon, font=icon_font)
icon_width = icon_bbox[2] - icon_bbox[0]
draw.text(((width - icon_width) // 2, 100), icon, font=icon_font, fill=colors['text'])
# Draw title
title_bbox = draw.textbbox((0, 0), title, font=title_font)
title_width = title_bbox[2] - title_bbox[0]
draw.text(((width - title_width) // 2, 220), title, font=title_font, fill=colors['text'])
# Draw quote text with wrapping
margin = 100
max_width = width - (margin * 2)
# Wrap text
wrapped_text = wrap_text(text, text_font, max_width, draw)
# Calculate text block height
line_height = 60
text_block_height = len(wrapped_text) * line_height
# Start position for text (centered vertically)
y_text = (height - text_block_height) // 2 + 50
# Draw each line
for line in wrapped_text:
line_bbox = draw.textbbox((0, 0), line, font=text_font)
line_width = line_bbox[2] - line_bbox[0]
x = (width - line_width) // 2
draw.text((x, y_text), line, font=text_font, fill=colors['text'])
y_text += line_height
# Draw footer
footer_text = "Made with π by Aman"
footer_bbox = draw.textbbox((0, 0), footer_text, font=footer_font)
footer_width = footer_bbox[2] - footer_bbox[0]
draw.text(((width - footer_width) // 2, height - 120), footer_text, font=footer_font, fill=colors['text'])
# Save to buffer
buffer = io.BytesIO()
img.save(buffer, format='PNG')
buffer.seek(0)
return buffer
def wrap_text(text, font, max_width, draw):
"""Wrap text to fit within max_width."""
words = text.split()
lines = []
current_line = []
for word in words:
test_line = ' '.join(current_line + [word])
bbox = draw.textbbox((0, 0), test_line, font=font)
text_width = bbox[2] - bbox[0]
if text_width <= max_width:
current_line.append(word)
else:
if current_line:
lines.append(' '.join(current_line))
current_line = [word]
else:
# Word is too long, force it
lines.append(word)
if current_line:
lines.append(' '.join(current_line))
return lines
def add_decorative_elements(draw, width, height, color, card_type):
"""Add decorative elements to the card."""
# Add subtle corner decorations
corner_size = 100
# Top left corner
draw.arc([20, 20, corner_size, corner_size], start=180, end=270, fill=color, width=3)
# Top right corner
draw.arc([width - corner_size, 20, width - 20, corner_size], start=270, end=360, fill=color, width=3)
# Bottom left corner
draw.arc([20, height - corner_size, corner_size, height - 20], start=90, end=180, fill=color, width=3)
# Bottom right corner
draw.arc([width - corner_size, height - corner_size, width - 20, height - 20], start=0, end=90, fill=color, width=3)
# Add small hearts or stars based on card type
if card_type == 'memory':
# Add small heart shapes
for i in range(3):
x = 80 + (i * 300)
y = height - 200
draw.ellipse([x, y, x + 20, y + 20], fill=color)
elif card_type == 'motivation':
# Add star-like dots
for i in range(4):
x = 100 + (i * 250)
y = 320
draw.ellipse([x, y, x + 15, y + 15], fill=color)
|