159 lines
5.4 KiB
Python
159 lines
5.4 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
"""
|
|
Generate high-quality celestial gradient star launcher icons for Android.
|
|
"""
|
|
|
|
from PIL import Image, ImageDraw, ImageFilter
|
|
import math
|
|
import os
|
|
|
|
def create_star_icon(size=512):
|
|
# Create high-res canvas (1024 for supersampling)
|
|
canvas_size = 1024
|
|
img = Image.new('RGBA', (canvas_size, canvas_size), (0, 0, 0, 0))
|
|
draw = ImageDraw.Draw(img)
|
|
|
|
center = canvas_size / 2.0
|
|
radius = canvas_size * 0.46
|
|
|
|
# 1. Background squircle / rounded rect or circle with deep mystical dark gradient
|
|
bg = Image.new('RGBA', (canvas_size, canvas_size), (0, 0, 0, 0))
|
|
bg_draw = ImageDraw.Draw(bg)
|
|
|
|
# Draw rounded rectangle background (squircle)
|
|
corner_radius = canvas_size * 0.22
|
|
margin = canvas_size * 0.04
|
|
bg_box = [margin, margin, canvas_size - margin, canvas_size - margin]
|
|
|
|
# Base cosmic background color #0E1020
|
|
bg_draw.rounded_rectangle(bg_box, radius=corner_radius, fill=(14, 16, 32, 255))
|
|
|
|
# Add subtle radial inner glow in the background
|
|
for r in range(int(canvas_size * 0.4), 0, -4):
|
|
alpha = int(45 * (1.0 - r / (canvas_size * 0.4)))
|
|
bg_draw.ellipse(
|
|
[center - r, center - r, center + r, center + r],
|
|
fill=(42, 45, 74, alpha)
|
|
)
|
|
|
|
# Outer golden border on the squircle
|
|
bg_draw.rounded_rectangle(
|
|
bg_box,
|
|
radius=corner_radius,
|
|
outline=(255, 213, 79, 140),
|
|
width=int(canvas_size * 0.018)
|
|
)
|
|
|
|
img.paste(bg, (0, 0), bg)
|
|
|
|
# 2. Golden aura / glow behind the star
|
|
glow = Image.new('RGBA', (canvas_size, canvas_size), (0, 0, 0, 0))
|
|
glow_draw = ImageDraw.Draw(glow)
|
|
glow_radius = canvas_size * 0.30
|
|
for r in range(int(glow_radius), 0, -6):
|
|
alpha = int(70 * (1.0 - r / glow_radius)**1.5)
|
|
glow_draw.ellipse(
|
|
[center - r, center - r, center + r, center + r],
|
|
fill=(255, 213, 79, alpha)
|
|
)
|
|
glow = glow.filter(ImageFilter.GaussianBlur(15))
|
|
img.paste(glow, (0, 0), glow)
|
|
|
|
# 3. Draw 5-pointed celestial star polygon with white-to-yellow gradient
|
|
star_img = Image.new('RGBA', (canvas_size, canvas_size), (0, 0, 0, 0))
|
|
star_draw = ImageDraw.Draw(star_img)
|
|
|
|
r_outer = canvas_size * 0.33
|
|
r_inner = r_outer * 0.42
|
|
points = []
|
|
num_points = 5
|
|
|
|
# Rotate by -90 degrees so top point points straight up
|
|
start_angle = -math.pi / 2.0
|
|
|
|
for i in range(num_points * 2):
|
|
angle = start_angle + i * math.pi / num_points
|
|
r = r_outer if i % 2 == 0 else r_inner
|
|
x = center + r * math.cos(angle)
|
|
y = center + r * math.sin(angle)
|
|
points.append((x, y))
|
|
|
|
# Mask for star gradient
|
|
star_mask = Image.new('L', (canvas_size, canvas_size), 0)
|
|
mask_draw = ImageDraw.Draw(star_mask)
|
|
mask_draw.polygon(points, fill=255)
|
|
|
|
# Create gradient fill image for star (pure white at top-left to bright golden yellow at bottom)
|
|
gradient = Image.new('RGBA', (canvas_size, canvas_size), (0, 0, 0, 0))
|
|
for y in range(canvas_size):
|
|
ratio = y / float(canvas_size)
|
|
# Interpolate from #FFFFFF (top) -> #FFF9C4 -> #FFD54F -> #FFB300 (bottom)
|
|
if ratio < 0.3:
|
|
# White to light lemon
|
|
t = ratio / 0.3
|
|
r = int(255)
|
|
g = int(255 - (255 - 249) * t)
|
|
b = int(255 - (255 - 196) * t)
|
|
elif ratio < 0.7:
|
|
# Light lemon to golden yellow
|
|
t = (ratio - 0.3) / 0.4
|
|
r = int(255)
|
|
g = int(249 - (249 - 213) * t)
|
|
b = int(196 - (196 - 79) * t)
|
|
else:
|
|
# Golden yellow to deep amber
|
|
t = (ratio - 0.7) / 0.3
|
|
r = int(255)
|
|
g = int(213 - (213 - 179) * t)
|
|
b = int(79 - (79 - 0) * t)
|
|
|
|
for x in range(canvas_size):
|
|
gradient.putpixel((x, y), (r, g, b, 255))
|
|
|
|
# Apply star mask to gradient
|
|
star_colored = Image.new('RGBA', (canvas_size, canvas_size), (0, 0, 0, 0))
|
|
star_colored.paste(gradient, (0, 0), star_mask)
|
|
|
|
# Subtle inner facets (diamond lines from center to outer/inner points)
|
|
facet_draw = ImageDraw.Draw(star_colored)
|
|
for i in range(num_points * 2):
|
|
pt = points[i]
|
|
if i % 2 == 0:
|
|
facet_draw.line([center, center, pt[0], pt[1]], fill=(255, 255, 255, 90), width=3)
|
|
else:
|
|
facet_draw.line([center, center, pt[0], pt[1]], fill=(200, 140, 0, 70), width=2)
|
|
|
|
# Star outline
|
|
facet_draw.polygon(points, outline=(255, 255, 255, 180), width=4)
|
|
|
|
# Composite star over canvas
|
|
img.paste(star_colored, (0, 0), star_colored)
|
|
|
|
# Resize with Lanczos downsampling to target size
|
|
return img.resize((size, size), Image.Resampling.LANCZOS)
|
|
|
|
def main():
|
|
densities = {
|
|
'android/app/src/main/res/mipmap-mdpi': 48,
|
|
'android/app/src/main/res/mipmap-hdpi': 72,
|
|
'android/app/src/main/res/mipmap-xhdpi': 96,
|
|
'android/app/src/main/res/mipmap-xxhdpi': 144,
|
|
'android/app/src/main/res/mipmap-xxxhdpi': 192,
|
|
}
|
|
|
|
# Generate master 512x512
|
|
master = create_star_icon(512)
|
|
master.save('scripts/app_icon_master.png')
|
|
print("Created scripts/app_icon_master.png (512x512)")
|
|
|
|
for dir_path, sz in densities.items():
|
|
os.makedirs(dir_path, exist_ok=True)
|
|
icon = create_star_icon(sz)
|
|
out_file = os.path.join(dir_path, 'ic_launcher.png')
|
|
icon.save(out_file, 'PNG')
|
|
print(f"Saved {out_file} ({sz}x{sz})")
|
|
|
|
if __name__ == '__main__':
|
|
main()
|