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)