feat(brand): новый 3D-логотип (монограмма R) + лого/иконка под цветовую тему
Логотип: монограмма-R пользователя отрендерена в матовый 3D через routerai (gpt-5.4-image), один мастер перекрашен под 8 тем (recolor по яркости, форма идентична). - Внутри приложения: AppMark показывает перекрашенный 3D-логотип текущей палитры (LocalThemePalette + ThemePalette.logoRes, drawable logo_<тема>). - Иконка лаунчера следует теме: 8 adaptive-иконок (ic_fg_<тема> + ic_bg_<тема>) и 8 activity-alias в манифесте; LauncherIconManager включает alias выбранной темы, гасит остальные (ровно один активен, guard против лишних миганий). Переключение — в MainActivity по LaunchedEffect(paletteId). На ColorOS иконка может обновляться с задержкой — особенность системы. Скрипты генерации в design/logos (ключ routerai — вне репо, ~/.routerai_key).
This commit is contained in:
74
design/logos/recolor.py
Normal file
74
design/logos/recolor.py
Normal file
@@ -0,0 +1,74 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Один мастер-логотип → 8 тем. Изолируем букву по насыщенности, перекрашиваем по яркости."""
|
||||
from PIL import Image, ImageOps, ImageFilter, ImageDraw, ImageFont
|
||||
import os
|
||||
|
||||
GEN = r"C:\radiOLA\design\logos\gen"
|
||||
MASTER = os.path.join(GEN, "master_matte_0.png")
|
||||
OUTDIR = os.path.join(GEN, "themed"); os.makedirs(OUTDIR, exist_ok=True)
|
||||
|
||||
# (id, акцент, фон темы) — как в ThemePalette
|
||||
THEMES = [
|
||||
("forest", (0xA8,0xE0,0x5F), (0x0C,0x14,0x10)),
|
||||
("ocean", (0x4F,0xD6,0xE0), (0x0A,0x0F,0x1A)),
|
||||
("sunset", (0xFF,0x8A,0x5B), (0x1A,0x0F,0x0C)),
|
||||
("amethyst",(0xB3,0x88,0xFF), (0x12,0x0E,0x1A)),
|
||||
("neon", (0xFF,0x4D,0x9D), (0x0D,0x0A,0x12)),
|
||||
("amber", (0xFF,0xC2,0x47), (0x14,0x11,0x0A)),
|
||||
("ice", (0x7F,0xB3,0xFF), (0x0C,0x10,0x14)),
|
||||
("rose", (0xFF,0x7E,0xA8), (0x16,0x0E,0x12)),
|
||||
]
|
||||
|
||||
def lerp(a,b,t): return tuple(int(a[i]+(b[i]-a[i])*t) for i in range(3))
|
||||
|
||||
im = Image.open(MASTER).convert("RGB")
|
||||
hsv = im.convert("HSV")
|
||||
H,S,V = hsv.split()
|
||||
|
||||
# --- альфа-маска: буква насыщенная, шахматка-фон серый (низкая S) ---
|
||||
alpha = S.point(lambda s: 0 if s < 40 else min(255, int((s-40)*4)))
|
||||
alpha = alpha.filter(ImageFilter.MaxFilter(3)).filter(ImageFilter.GaussianBlur(0.8))
|
||||
|
||||
# --- яркость буквы (3D-тени), нормализуем в рабочий диапазон ---
|
||||
L = ImageOps.grayscale(im)
|
||||
# статистика только по букве
|
||||
import numpy as np
|
||||
la = np.asarray(L, dtype=float); aa = np.asarray(alpha, dtype=float)/255.0
|
||||
mask = aa > 0.5
|
||||
if mask.sum() > 0:
|
||||
lo, hi = np.percentile(la[mask], 4), np.percentile(la[mask], 96)
|
||||
else:
|
||||
lo, hi = 40, 150
|
||||
la = np.clip((la - lo)/(hi - lo), 0, 1) # 0..1 нормализованная яркость буквы
|
||||
Ln = Image.fromarray((la*255).astype("uint8"), "L")
|
||||
|
||||
def themed(accent):
|
||||
dark = lerp(accent, (0,0,0), 0.55) # тень/боковая грань
|
||||
light = lerp(accent, (255,255,255), 0.30) # свет фронта
|
||||
col = ImageOps.colorize(Ln, black=dark, white=light, mid=accent).convert("RGBA")
|
||||
col.putalpha(alpha)
|
||||
return col
|
||||
|
||||
# отдельные прозрачные PNG + превью-лист на фоне темы
|
||||
cell=300; pad=26; cols=4; rows=2
|
||||
W=cols*cell+(cols+1)*pad; Hh=rows*(cell+40)+(rows+1)*pad+56
|
||||
sheet=Image.new("RGB",(W,Hh),(8,12,10)); d=ImageDraw.Draw(sheet)
|
||||
def f(s):
|
||||
try: return ImageFont.truetype(r"C:\Windows\Fonts\segoeui.ttf",s)
|
||||
except: return ImageFont.load_default()
|
||||
d.text((pad,18),"radiOLA — один логотип, перекрашен под 8 тем",font=f(26),fill=(234,246,223))
|
||||
|
||||
for i,(name,acc,bg) in enumerate(THEMES):
|
||||
logo = themed(acc)
|
||||
logo.save(os.path.join(OUTDIR, f"logo_{name}.png"))
|
||||
# превью на фоне темы
|
||||
tile = Image.new("RGBA",(cell,cell), bg+(255,))
|
||||
lg = logo.resize((int(cell*0.74),)*2)
|
||||
tile.alpha_composite(lg, ((cell-lg.width)//2,(cell-lg.height)//2))
|
||||
r=i//cols; c=i%cols; x=pad+c*(cell+pad); y=56+pad+r*(cell+40+pad)
|
||||
sheet.paste(tile.convert("RGB"),(x,y))
|
||||
d.text((x+6,y+cell+8),name,font=f(20),fill=(150,170,150))
|
||||
|
||||
out=os.path.join(GEN,"_themed_sheet.png"); sheet.save(out)
|
||||
import shutil; shutil.copy(out, os.path.join(os.environ["LOCALAPPDATA"],"Temp","radiola_themed.png"))
|
||||
print("saved", len(THEMES), "themed logos ->", OUTDIR)
|
||||
Reference in New Issue
Block a user