208 lines
7.2 KiB
Python
208 lines
7.2 KiB
Python
"""
|
|
Archetype: First Spark - App Icon Generator
|
|
1024x1024 PNG 앱 아이콘 생성 스크립트
|
|
주 색상: #FF6B35 (불꽃-주황)
|
|
"""
|
|
|
|
from PIL import Image, ImageDraw, ImageFilter
|
|
import math
|
|
|
|
def hex_to_rgb(hex_color):
|
|
hex_color = hex_color.lstrip('#')
|
|
return tuple(int(hex_color[i:i+2], 16) for i in (0, 2, 4))
|
|
|
|
def create_app_icon(size=1024, output_path="app-icon.png"):
|
|
img = Image.new('RGBA', (size, size), (0, 0, 0, 0))
|
|
draw = ImageDraw.Draw(img)
|
|
|
|
# === 배경: 깊은 다크 네이비 → 다크 퍼플 그라디언트 ===
|
|
bg = Image.new('RGBA', (size, size))
|
|
bg_draw = ImageDraw.Draw(bg)
|
|
for y in range(size):
|
|
t = y / size
|
|
# #0D0D1A (top) → #1A0A2E (bottom)
|
|
r = int(13 + (26 - 13) * t)
|
|
g = int(13 + (10 - 13) * t)
|
|
b = int(26 + (46 - 26) * t)
|
|
bg_draw.line([(0, y), (size, y)], fill=(r, g, b, 255))
|
|
img = Image.alpha_composite(img, bg)
|
|
draw = ImageDraw.Draw(img)
|
|
|
|
cx, cy = size // 2, size // 2
|
|
|
|
# === 외곽 글로우 링 (주황빛 오라) ===
|
|
glow_layer = Image.new('RGBA', (size, size), (0, 0, 0, 0))
|
|
glow_draw = ImageDraw.Draw(glow_layer)
|
|
for i in range(12, 0, -1):
|
|
alpha = int(15 * (i / 12))
|
|
radius = int(size * 0.42) + i * 8
|
|
glow_draw.ellipse(
|
|
[cx - radius, cy - radius, cx + radius, cy + radius],
|
|
fill=(255, 107, 53, alpha)
|
|
)
|
|
img = Image.alpha_composite(img, glow_layer)
|
|
draw = ImageDraw.Draw(img)
|
|
|
|
# === 메인 원형 배경 (진한 그라디언트 구체) ===
|
|
circle_layer = Image.new('RGBA', (size, size), (0, 0, 0, 0))
|
|
circle_draw = ImageDraw.Draw(circle_layer)
|
|
base_r = int(size * 0.42)
|
|
for i in range(base_r, 0, -1):
|
|
t = 1 - (i / base_r)
|
|
# 어두운 중심부에서 불꽃 주황으로
|
|
r = int(20 + (120 - 20) * (1 - t**2))
|
|
g = int(8 + (40 - 8) * (1 - t**2))
|
|
b = int(35 + (15 - 35) * (1 - t**2))
|
|
circle_draw.ellipse(
|
|
[cx - i, cy - i, cx + i, cy + i],
|
|
fill=(r, g, b, 255)
|
|
)
|
|
img = Image.alpha_composite(img, circle_layer)
|
|
draw = ImageDraw.Draw(img)
|
|
|
|
# === 불꽃 파티클 (배경 장식) ===
|
|
spark_layer = Image.new('RGBA', (size, size), (0, 0, 0, 0))
|
|
spark_draw = ImageDraw.Draw(spark_layer)
|
|
sparks = [
|
|
(cx - 180, cy - 200, 6, 180),
|
|
(cx + 200, cy - 160, 5, 160),
|
|
(cx - 220, cy + 100, 4, 140),
|
|
(cx + 180, cy + 180, 5, 150),
|
|
(cx - 60, cy - 280, 7, 200),
|
|
(cx + 80, cy - 260, 6, 180),
|
|
(cx - 260, cy - 40, 4, 130),
|
|
(cx + 260, cy - 60, 5, 150),
|
|
(cx - 100, cy + 270, 6, 160),
|
|
(cx + 120, cy + 260, 4, 140),
|
|
]
|
|
for sx, sy, sr, alpha in sparks:
|
|
for gi in range(sr, 0, -1):
|
|
ga = int(alpha * (gi / sr) ** 2)
|
|
spark_draw.ellipse(
|
|
[sx - gi, sy - gi, sx + gi, sy + gi],
|
|
fill=(255, 180, 80, ga)
|
|
)
|
|
img = Image.alpha_composite(img, spark_layer)
|
|
draw = ImageDraw.Draw(img)
|
|
|
|
# === 중앙 불꽃 형상 (메인 심볼) ===
|
|
flame_layer = Image.new('RGBA', (size, size), (0, 0, 0, 0))
|
|
flame_draw = ImageDraw.Draw(flame_layer)
|
|
|
|
# 불꽃 외형 (여러 레이어로 깊이 표현)
|
|
# 레이어 1: 큰 불꽃 (오렌지-레드)
|
|
flame1 = [
|
|
(cx, cy - 270), # 꼭대기
|
|
(cx + 120, cy - 140), # 오른쪽 상단
|
|
(cx + 160, cy + 30), # 오른쪽 중간
|
|
(cx + 90, cy + 200), # 오른쪽 하단
|
|
(cx, cy + 240), # 바닥 중앙
|
|
(cx - 90, cy + 200), # 왼쪽 하단
|
|
(cx - 160, cy + 30), # 왼쪽 중간
|
|
(cx - 120, cy - 140), # 왼쪽 상단
|
|
]
|
|
flame_draw.polygon(flame1, fill=(255, 90, 20, 230))
|
|
|
|
# 레이어 2: 중간 불꽃 (밝은 오렌지)
|
|
flame2 = [
|
|
(cx, cy - 220),
|
|
(cx + 90, cy - 100),
|
|
(cx + 120, cy + 40),
|
|
(cx + 60, cy + 180),
|
|
(cx, cy + 200),
|
|
(cx - 60, cy + 180),
|
|
(cx - 120, cy + 40),
|
|
(cx - 90, cy - 100),
|
|
]
|
|
flame_draw.polygon(flame2, fill=(255, 140, 40, 220))
|
|
|
|
# 레이어 3: 내부 불꽃 (밝은 노란 오렌지)
|
|
flame3 = [
|
|
(cx, cy - 160),
|
|
(cx + 60, cy - 60),
|
|
(cx + 80, cy + 60),
|
|
(cx + 35, cy + 150),
|
|
(cx, cy + 160),
|
|
(cx - 35, cy + 150),
|
|
(cx - 80, cy + 60),
|
|
(cx - 60, cy - 60),
|
|
]
|
|
flame_draw.polygon(flame3, fill=(255, 200, 80, 210))
|
|
|
|
# 레이어 4: 핵심 (흰색-노란색 빛)
|
|
flame4 = [
|
|
(cx, cy - 80),
|
|
(cx + 30, cy - 20),
|
|
(cx + 40, cy + 50),
|
|
(cx, cy + 80),
|
|
(cx - 40, cy + 50),
|
|
(cx - 30, cy - 20),
|
|
]
|
|
flame_draw.polygon(flame4, fill=(255, 240, 180, 200))
|
|
|
|
# 중심 빛 (흰색 글로우)
|
|
for i in range(30, 0, -1):
|
|
alpha = int(180 * (i / 30) ** 2)
|
|
flame_draw.ellipse(
|
|
[cx - i, cy + 10 - i, cx + i, cy + 10 + i],
|
|
fill=(255, 255, 240, alpha)
|
|
)
|
|
|
|
# 불꽃 블러 (부드럽게)
|
|
flame_blurred = flame_layer.filter(ImageFilter.GaussianBlur(radius=3))
|
|
img = Image.alpha_composite(img, flame_blurred)
|
|
draw = ImageDraw.Draw(img)
|
|
|
|
# === 원소 심볼 (아크 형태의 빛나는 링) ===
|
|
arc_layer = Image.new('RGBA', (size, size), (0, 0, 0, 0))
|
|
arc_draw = ImageDraw.Draw(arc_layer)
|
|
|
|
# 4개의 원소 호 (불, 물, 바람, 땅 의미)
|
|
ring_r = int(size * 0.35)
|
|
element_colors = [
|
|
(255, 80, 20, 180), # 불
|
|
(60, 160, 255, 160), # 물
|
|
(160, 240, 120, 140), # 바람
|
|
(200, 160, 60, 150), # 땅
|
|
]
|
|
for i, color in enumerate(element_colors):
|
|
start_angle = i * 90 - 30
|
|
end_angle = start_angle + 60
|
|
for w in range(6, 0, -1):
|
|
arc_draw.arc(
|
|
[cx - ring_r - w, cy - ring_r - w, cx + ring_r + w, cy + ring_r + w],
|
|
start=start_angle, end=end_angle,
|
|
fill=(*color[:3], int(color[3] * w / 6)),
|
|
width=w * 2
|
|
)
|
|
|
|
arc_blurred = arc_layer.filter(ImageFilter.GaussianBlur(radius=2))
|
|
img = Image.alpha_composite(img, arc_blurred)
|
|
draw = ImageDraw.Draw(img)
|
|
|
|
# === 상단 광택 효과 (입체감) ===
|
|
gloss_layer = Image.new('RGBA', (size, size), (0, 0, 0, 0))
|
|
gloss_draw = ImageDraw.Draw(gloss_layer)
|
|
gloss_r = int(size * 0.38)
|
|
gloss_draw.ellipse(
|
|
[cx - gloss_r, cy - gloss_r, cx + gloss_r, cy - gloss_r // 3],
|
|
fill=(255, 255, 255, 25)
|
|
)
|
|
gloss_blurred = gloss_layer.filter(ImageFilter.GaussianBlur(radius=20))
|
|
img = Image.alpha_composite(img, gloss_blurred)
|
|
|
|
# === 저장 ===
|
|
final = img.convert('RGBA')
|
|
final.save(output_path, 'PNG', optimize=True)
|
|
print(f"[OK] 아이콘 저장: {output_path} ({size}x{size}px)")
|
|
return final
|
|
|
|
# 1024x1024 메인 아이콘
|
|
create_app_icon(1024, "C:/Users/jaeoh/Desktop/workspace/Archetype-FirstSpark/app-icon.png")
|
|
|
|
# 512x512 앱스토어용
|
|
icon_1024 = Image.open("C:/Users/jaeoh/Desktop/workspace/Archetype-FirstSpark/app-icon.png")
|
|
icon_512 = icon_1024.resize((512, 512), Image.LANCZOS)
|
|
icon_512.save("C:/Users/jaeoh/Desktop/workspace/Archetype-FirstSpark/app-icon-512.png", 'PNG', optimize=True)
|
|
print("[OK] 512x512 앱스토어용 저장 완료")
|