176 lines
5.9 KiB
Python
176 lines
5.9 KiB
Python
#!/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()
|