#!/usr/bin/env python3 """Generate professional icon.png and banner.png assets for Community OS modules.""" import os from PIL import Image, ImageDraw, ImageFont MODULES = [ { 'dir': 'community_membership', 'title': 'Community Membership', 'subtitle': 'Tiers, Terms, Expiry, Family Plans & Digital Cards', 'color_primary': (18, 7, 53), # Deep Navy 'color_secondary': (229, 169, 60), # Gold 'badge': 'MEMBERSHIP', }, { 'dir': 'community_school', 'title': 'Community School', 'subtitle': 'Classrooms, Tamil School Rosters, Attendance & Teachers', 'color_primary': (15, 60, 45), # Deep Emerald 'color_secondary': (229, 169, 60), # Gold 'badge': 'TAMIL SCHOOL', }, { 'dir': 'event_qr_ticketing', 'title': 'Event QR Ticketing', 'subtitle': 'Fast QR Code Check-in, Attendee Badges & Scanner', 'color_primary': (40, 15, 80), # Deep Violet 'color_secondary': (243, 198, 105),# Light Gold 'badge': 'EVENTS & QR', }, { 'dir': 'community_portal', 'title': 'Community Portal', 'subtitle': 'Self-Service Member Portal, Digital Cards & School Roster', 'color_primary': (20, 30, 75), # Deep Indigo 'color_secondary': (70, 190, 200), # Teal 'badge': 'PORTAL', }, { 'dir': 'community_benefits', 'title': 'Community Benefits', 'subtitle': 'Member Discounts, Partner Perks & Entitlement Verification', 'color_primary': (25, 45, 100), # Royal Blue 'color_secondary': (229, 169, 60), # Gold 'badge': 'BENEFITS', }, { 'dir': 'community_classifieds', 'title': 'Community Classifieds', 'subtitle': 'Community Marketplace, Volunteer Listings & Housing', 'color_primary': (20, 70, 70), # Dark Teal 'color_secondary': (255, 140, 60), # Tangerine 'badge': 'CLASSIFIEDS', }, { 'dir': 'community_interac', 'title': 'Community Interac', 'subtitle': 'Canadian Interac e-Transfer Direct Payment Provider', 'color_primary': (80, 50, 10), # Dark Bronze 'color_secondary': (255, 190, 40), # Amber 'badge': 'INTERAC CAD', }, { 'dir': 'community_theme_base', 'title': 'Community Theme Base', 'subtitle': 'Unified Theme Tokens, Typography, Colors & Branding', 'color_primary': (35, 25, 60), # Deep Slate Purple 'color_secondary': (180, 140, 230),# Lavender 'badge': 'THEME BASE', }, { 'dir': 'tncsc_deployment', 'title': 'TNCSC Deployment', 'subtitle': 'Tamil Nadu Cultural Society of Canada Production Platform', 'color_primary': (18, 7, 53), # TNCSC Navy 'color_secondary': (229, 169, 60), # TNCSC Gold 'badge': 'TNCSC CANADA', }, ] def make_gradient(width, height, color1, color2): base = Image.new('RGB', (width, height), color1) top = Image.new('RGB', (width, height), color2) mask = Image.new('L', (width, height)) mask_data = [] for y in range(height): for x in range(width): mask_data.append(int(255 * (x / width * 0.5 + y / height * 0.5))) mask.putdata(mask_data) base.paste(top, (0, 0), mask) return base def generate_icon(mod, target_dir): width, height = 128, 128 c1 = mod['color_primary'] c2 = tuple(min(255, c + 35) for c in c1) im = make_gradient(width, height, c1, c2) draw = ImageDraw.Draw(im) # Gold accent border gold = mod['color_secondary'] draw.rounded_rectangle([4, 4, width - 4, height - 4], radius=24, outline=gold, width=3) # Center monogram/symbol words = mod['badge'].split() monogram = "".join(w[0] for w in words[:3]) # Inner badge pill draw.rounded_rectangle([20, 46, width - 20, 82], radius=8, fill=gold) draw.text((width // 2, 64), monogram, fill=c1, anchor="mm") # Bottom bar draw.line([30, 100, width - 30, 100], fill=gold, width=2) os.makedirs(target_dir, exist_ok=True) icon_path = os.path.join(target_dir, 'icon.png') im.save(icon_path, 'PNG') print(f"Generated {icon_path}") def generate_banner(mod, target_dir): width, height = 800, 400 c1 = mod['color_primary'] c2 = tuple(min(255, c + 25) for c in c1) im = make_gradient(width, height, c1, c2) draw = ImageDraw.Draw(im) gold = mod['color_secondary'] # Elegant decorative borders draw.rectangle([0, 0, width, 8], fill=gold) draw.rectangle([0, height - 8, width, height], fill=gold) # Subtle geometric grid / card background draw.rounded_rectangle([40, 40, width - 40, height - 40], radius=16, outline=gold, width=2) draw.rounded_rectangle([48, 48, width - 48, height - 48], radius=12, outline=(60, 60, 80), width=1) # Badge Pill at top badge_text = f"★ {mod['badge']} MODULE ★" draw.rounded_rectangle([280, 70, 520, 102], radius=16, fill=gold) draw.text((400, 86), badge_text, fill=c1, anchor="mm") # Main Title draw.text((400, 170), mod['title'], fill=(255, 255, 255), anchor="mm") # Gold separator line draw.line([250, 220, 550, 220], fill=gold, width=3) # Subtitle draw.text((400, 260), mod['subtitle'], fill=(210, 215, 230), anchor="mm") # Footer attribution draw.text((400, 330), "Community OS • Odoo 19 Edition", fill=gold, anchor="mm") os.makedirs(target_dir, exist_ok=True) banner_path = os.path.join(target_dir, 'banner.png') im.save(banner_path, 'PNG') print(f"Generated {banner_path}") def main(): if os.path.exists('/mnt/extra-addons'): root = '/mnt/extra-addons' else: root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'addons')) for mod in MODULES: desc_dir = os.path.join(root, mod['dir'], 'static', 'description') generate_icon(mod, desc_dir) generate_banner(mod, desc_dir) if __name__ == '__main__': main()