Spaces:
Sleeping
Sleeping
| 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) | |