Spaces:
Paused
Paused
| from flask import Flask, send_file, request, abort | |
| from PIL import Image, ImageDraw, ImageFont, ImageFilter, ImageEnhance | |
| from io import BytesIO | |
| from datetime import datetime | |
| import os | |
| import requests | |
| import math | |
| app = Flask(__name__) | |
| def download_font(url, filename): | |
| """Download font from URL if it doesn't exist locally""" | |
| if not os.path.exists(filename): | |
| try: | |
| response = requests.get(url) | |
| response.raise_for_status() | |
| with open(filename, 'wb') as f: | |
| f.write(response.content) | |
| return True | |
| except: | |
| return False | |
| return True | |
| def get_text_dimensions(text, font): | |
| """Get text dimensions using the new textbbox method""" | |
| bbox = font.getbbox(text) | |
| width = bbox[2] - bbox[0] | |
| height = bbox[3] - bbox[1] | |
| return width, height | |
| def create_gradient_background(width, height, start_color, end_color): | |
| """Create a beautiful gradient background""" | |
| gradient = Image.new('RGB', (width, height), start_color) | |
| draw = ImageDraw.Draw(gradient) | |
| for y in range(height): | |
| # Calculate the blend ratio | |
| ratio = y / height | |
| # Interpolate between start and end colors | |
| r = int(start_color[0] * (1 - ratio) + end_color[0] * ratio) | |
| g = int(start_color[1] * (1 - ratio) + end_color[1] * ratio) | |
| b = int(start_color[2] * (1 - ratio) + end_color[2] * ratio) | |
| draw.line([(0, y), (width, y)], fill=(r, g, b)) | |
| return gradient | |
| def add_glow_effect(img, text, font, position, color, glow_radius=3): | |
| """Add a glow effect to text""" | |
| # Create a larger image for the glow | |
| glow_img = Image.new('RGBA', (img.width + glow_radius * 4, img.height + glow_radius * 4), (0, 0, 0, 0)) | |
| glow_draw = ImageDraw.Draw(glow_img) | |
| # Draw the text multiple times with slight offsets for glow | |
| glow_x = position[0] + glow_radius * 2 | |
| glow_y = position[1] + glow_radius * 2 | |
| for offset_x in range(-glow_radius, glow_radius + 1): | |
| for offset_y in range(-glow_radius, glow_radius + 1): | |
| if offset_x != 0 or offset_y != 0: | |
| alpha = max(0, 100 - int(math.sqrt(offset_x**2 + offset_y**2) * 30)) | |
| glow_color = (*color[:3], alpha) | |
| glow_draw.text((glow_x + offset_x, glow_y + offset_y), text, font=font, fill=glow_color) | |
| # Apply blur to the glow | |
| glow_img = glow_img.filter(ImageFilter.GaussianBlur(radius=1)) | |
| # Composite the glow with the original image | |
| img_rgba = img.convert('RGBA') | |
| combined = Image.alpha_composite(img_rgba, glow_img.crop((glow_radius * 2, glow_radius * 2, | |
| glow_img.width - glow_radius * 2, | |
| glow_img.height - glow_radius * 2))) | |
| return combined.convert('RGB') | |
| def add_embossed_effect(draw, text, font, position, color, shadow_color): | |
| """Add an embossed/3D effect to text""" | |
| x, y = position | |
| # Draw bigger shadow (offset down and right) - scale with font size | |
| shadow_offset = 6 | |
| draw.text((x + shadow_offset, y + shadow_offset), text, font=font, fill=shadow_color) | |
| # Draw highlight (offset up and left) | |
| highlight_color = tuple(min(255, c + 60) for c in color) | |
| highlight_offset = 3 | |
| draw.text((x - highlight_offset, y - highlight_offset), text, font=font, fill=highlight_color) | |
| # Draw main text | |
| draw.text((x, y), text, font=font, fill=color) | |
| def generate_card(): | |
| # Get code from query string | |
| code = request.args.get("code") | |
| if not code: | |
| return abort(400, description="Missing ?code= parameter") | |
| # Format the code with hyphens every 4 characters | |
| code = code.replace("-", "").upper() | |
| formatted_code = '-'.join([code[i:i+4] for i in range(0, len(code), 4)]) | |
| # Create card dimensions | |
| card_width, card_height = 1200, 750 | |
| # Try to load background image, otherwise create gradient | |
| try: | |
| img = Image.open("image.png").convert("RGB") | |
| img = img.resize((card_width, card_height), Image.Resampling.LANCZOS) | |
| # Enhance the background image | |
| enhancer = ImageEnhance.Contrast(img) | |
| img = enhancer.enhance(1.2) | |
| enhancer = ImageEnhance.Color(img) | |
| img = enhancer.enhance(1.1) | |
| except FileNotFoundError: | |
| # Create a stunning gradient background | |
| img = create_gradient_background( | |
| card_width, card_height, | |
| start_color=(15, 32, 68), # Deep navy blue | |
| end_color=(45, 12, 35) # Deep purple | |
| ) | |
| # Add some texture/noise | |
| overlay = Image.new('RGBA', (card_width, card_height), (0, 0, 0, 0)) | |
| overlay_draw = ImageDraw.Draw(overlay) | |
| # Add subtle geometric patterns | |
| for i in range(0, card_width, 100): | |
| for j in range(0, card_height, 100): | |
| overlay_draw.rectangle([i, j, i+2, j+2], fill=(255, 255, 255, 20)) | |
| img = Image.alpha_composite(img.convert('RGBA'), overlay).convert('RGB') | |
| draw = ImageDraw.Draw(img) | |
| # Initialize fonts with defaults first | |
| code_font = ImageFont.load_default() | |
| timestamp_font = ImageFont.load_default() | |
| title_font = ImageFont.load_default() | |
| fonts_loaded = False | |
| # Try to load premium fonts | |
| try: | |
| # Try to download Google Fonts | |
| font_urls = { | |
| 'orbitron_bold.ttf': 'https://github.com/google/fonts/raw/main/ofl/orbitron/Orbitron-Bold.ttf', | |
| 'roboto_mono.ttf': 'https://github.com/google/fonts/raw/main/apache/robotomono/RobotoMono-Regular.ttf' | |
| } | |
| for filename, url in font_urls.items(): | |
| download_font(url, filename) | |
| # Load the downloaded fonts with ULTRA MASSIVE code size for 16:9 aspect ratio | |
| code_font = ImageFont.truetype('orbitron_bold.ttf', 350) | |
| timestamp_font = ImageFont.truetype('roboto_mono.ttf', 52) | |
| title_font = ImageFont.truetype('orbitron_bold.ttf', 75) | |
| fonts_loaded = True | |
| print("✅ Premium fonts loaded successfully!") | |
| except Exception as e: | |
| print(f"⚠️ Premium font loading failed: {e}") | |
| # Fallback to system fonts | |
| try: | |
| system_fonts = [ | |
| "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", | |
| "/usr/share/fonts/truetype/liberation/LiberationSans-Bold.ttf", | |
| "/System/Library/Fonts/Helvetica.ttc", | |
| "/System/Library/Fonts/Arial.ttf", | |
| "C:\\Windows\\Fonts\\arial.ttf", | |
| "C:\\Windows\\Fonts\\calibri.ttf", | |
| "arial.ttf" | |
| ] | |
| for font_path in system_fonts: | |
| if os.path.exists(font_path): | |
| try: | |
| code_font = ImageFont.truetype(font_path, 350) | |
| timestamp_font = ImageFont.truetype(font_path, 52) | |
| title_font = ImageFont.truetype(font_path, 75) | |
| fonts_loaded = True | |
| print(f"✅ System font loaded: {font_path}") | |
| break | |
| except Exception as font_error: | |
| print(f"❌ Failed to load {font_path}: {font_error}") | |
| continue | |
| except Exception as system_error: | |
| print(f"⚠️ System font loading failed: {system_error}") | |
| print("📝 Using default fonts") | |
| print(f"🎨 Fonts loaded: {'Premium' if fonts_loaded else 'Default'}") | |
| # Enhanced color scheme | |
| primary_color = (0, 255, 136) # Bright green | |
| secondary_color = (255, 215, 0) # Gold | |
| accent_color = (64, 224, 255) # Sky blue | |
| text_color = (240, 240, 240) # Light gray | |
| shadow_color = (20, 20, 20) # Dark shadow | |
| # Add title with better positioning for huge code | |
| title_text = "DIGITAL ACCESS CARD" | |
| title_width, title_height = get_text_dimensions(title_text, title_font) | |
| title_x = (card_width - title_width) // 2 | |
| title_y = 40 | |
| # Add embossed effect to title | |
| add_embossed_effect(draw, title_text, title_font, (title_x, title_y), secondary_color, shadow_color) | |
| # Add bigger decorative lines around title | |
| line_y = title_y + title_height + 25 | |
| draw.rectangle([60, line_y, card_width - 60, line_y + 8], fill=primary_color) | |
| draw.rectangle([100, line_y + 15, card_width - 100, line_y + 18], fill=accent_color) | |
| # Position ULTRA MASSIVE code in center (NO CONTAINER!) | |
| code_width, code_height = get_text_dimensions(formatted_code, code_font) | |
| code_x = (card_width - code_width) // 2 | |
| code_y = (card_height - code_height) // 2 - 20 # Slight adjustment for better balance | |
| # Add ULTRA MASSIVE embossed effect directly to code (no background container) | |
| add_embossed_effect(draw, formatted_code, code_font, (code_x, code_y), primary_color, shadow_color) | |
| # Add timestamp with better positioning for massive code | |
| timestamp = datetime.now().strftime("Generated: %Y-%m-%d %H:%M:%S UTC") | |
| ts_width, ts_height = get_text_dimensions(timestamp, timestamp_font) | |
| ts_x = (card_width - ts_width) // 2 | |
| ts_y = code_y + code_height + 60 | |
| # Add bigger subtle background for timestamp | |
| ts_bg_coords = [ts_x - 30, ts_y - 18, ts_x + ts_width + 30, ts_y + ts_height + 18] | |
| draw.rectangle(ts_bg_coords, fill=(0, 0, 0, 60)) | |
| draw.text((ts_x, ts_y), timestamp, font=timestamp_font, fill=text_color) | |
| # Add bigger corner decorations | |
| corner_size = 80 | |
| corner_thickness = 8 | |
| # Top-left corner | |
| draw.rectangle([20, 20, 20 + corner_size, 20 + corner_thickness], fill=accent_color) | |
| draw.rectangle([20, 20, 20 + corner_thickness, 20 + corner_size], fill=accent_color) | |
| # Top-right corner | |
| draw.rectangle([card_width - 20 - corner_size, 20, card_width - 20, 20 + corner_thickness], fill=accent_color) | |
| draw.rectangle([card_width - 20 - corner_thickness, 20, card_width - 20, 20 + corner_size], fill=accent_color) | |
| # Bottom-left corner | |
| draw.rectangle([20, card_height - 20 - corner_thickness, 20 + corner_size, card_height - 20], fill=accent_color) | |
| draw.rectangle([20, card_height - 20 - corner_size, 20 + corner_thickness, card_height - 20], fill=accent_color) | |
| # Bottom-right corner | |
| draw.rectangle([card_width - 20 - corner_size, card_height - 20 - corner_thickness, card_width - 20, card_height - 20], fill=accent_color) | |
| draw.rectangle([card_width - 20 - corner_thickness, card_height - 20 - corner_size, card_width - 20, card_height - 20], fill=accent_color) | |
| # Add bigger serial number | |
| serial = f"SN: {datetime.now().strftime('%Y%m%d%H%M%S')}" | |
| serial_width, serial_height = get_text_dimensions(serial, timestamp_font) | |
| draw.text((card_width - serial_width - 40, card_height - serial_height - 40), | |
| serial, font=timestamp_font, fill=(150, 150, 150)) | |
| # Apply final enhancement | |
| enhancer = ImageEnhance.Sharpness(img) | |
| img = enhancer.enhance(1.1) | |
| # Return image in memory | |
| buffer = BytesIO() | |
| img.save(buffer, format="PNG", quality=95, optimize=True) | |
| buffer.seek(0) | |
| return send_file(buffer, mimetype="image/png", as_attachment=False, download_name="premium_access_card.png") | |
| def health_check(): | |
| return {"status": "healthy", "timestamp": datetime.now().isoformat()} | |
| if __name__ == '__main__': | |
| print("🚀 Premium Card Generator Starting...") | |
| print("📱 Access your cards at: http://localhost:7860/generate?code=YOUR_CODE") | |
| app.run(host='0.0.0.0', port=7860, debug=True) |