81 lines
3.5 KiB
Python
81 lines
3.5 KiB
Python
# 生成 Electron 两个资源:
|
||
# 1) build/icons/icon.icns —— 真正的 ICNS 容器(原文件其实是改了扩展名的 PNG,属坏文件)
|
||
# 2) resources/app.png —— 启动背景稿,按甄房品牌重做
|
||
# 用法: python _design-test/build-electron-assets.py (预演)
|
||
# python _design-test/build-electron-assets.py --write (真写)
|
||
import os, sys, struct, io
|
||
from PIL import Image
|
||
|
||
SRC = r'D:\SGP_KF\DrawLogo\_design-test\logo\png'
|
||
ZF = r'e:\KF_7\ZhenOS-ZF'
|
||
WRITE = '--write' in sys.argv
|
||
ICNS_OUT = f'{ZF}/xiaohuju/build/icons/icon.icns'
|
||
APP_OUT = f'{ZF}/xiaohuju/resources/app.png'
|
||
|
||
# ── 1. ICNS:容器 = 'icns' + 总长度 + [type(4) + 长度(4, 含头) + PNG 数据] ──
|
||
# 类型码为 Apple 官方定义;PNG 载荷自 macOS 10.7 起原生支持
|
||
ICNS_TYPES = [
|
||
('icp4', 16), ('icp5', 32), ('icp6', 64),
|
||
('ic07', 128), ('ic08', 256), ('ic09', 512), ('ic10', 1024),
|
||
('ic11', 32), ('ic12', 64), ('ic13', 256), ('ic14', 512),
|
||
]
|
||
|
||
base = Image.open(os.path.join(SRC, 'appicon-1024.png')).convert('RGBA')
|
||
chunks = []
|
||
for tag, size in ICNS_TYPES:
|
||
buf = io.BytesIO()
|
||
base.resize((size, size), Image.LANCZOS).save(buf, format='PNG', optimize=True)
|
||
data = buf.getvalue()
|
||
chunks.append(tag.encode('ascii') + struct.pack('>I', len(data) + 8) + data)
|
||
body = b''.join(chunks)
|
||
icns = b'icns' + struct.pack('>I', len(body) + 8) + body
|
||
print(' icon.icns %d 个尺寸 %d 字节 容器合法=%s'
|
||
% (len(ICNS_TYPES), len(icns), icns[:4] == b'icns' and struct.unpack('>I', icns[4:8])[0] == len(icns)))
|
||
|
||
# ── 2. app.png:启动背景稿重做 ──
|
||
# 原稿是 3.2MB 的满幅蓝色装饰图(2208x2048,全宽 + 上下白边),且全仓库零代码引用(孤儿资源)。
|
||
# 重做思路:与 splash.html / 应用图标统一到「墨蓝深色外壳」语言 —— 墨蓝渐变底 + 顶部品牌蓝辉光 + 居中白色横版锁定标。
|
||
W, H = 2208, 2048
|
||
|
||
# 底色:墨蓝渐变(#0C2340 → #071527)
|
||
bg = Image.new('RGB', (W, H))
|
||
top, bot = (0x0C, 0x23, 0x40), (0x07, 0x15, 0x27)
|
||
for y in range(H):
|
||
k = y / (H - 1)
|
||
bg.paste(tuple(round(top[i] + (bot[i] - top[i]) * k) for i in range(3)), (0, y, W, y + 1))
|
||
|
||
# 顶部品牌蓝辉光(呼应 splash.html 的 .splash::before)—— 1/8 分辨率算完再放大,纯 Python 逐像素太慢
|
||
gw, gh = W // 8, H // 8
|
||
glow = Image.new('L', (gw, gh), 0)
|
||
gp = glow.load()
|
||
cx0, cy0, rx, ry = gw / 2, gh * 0.28, gw * 0.62, gh * 0.34
|
||
for y in range(gh):
|
||
dy = (y - cy0) / ry
|
||
row = dy * dy
|
||
for x in range(gw):
|
||
dx = (x - cx0) / rx
|
||
d = (row + dx * dx) ** 0.5
|
||
if d < 1:
|
||
gp[x, y] = int(255 * (1 - d) ** 1.6)
|
||
glow = glow.resize((W, H), Image.BILINEAR)
|
||
bg = Image.composite(Image.new('RGB', (W, H), (0x00, 0x70, 0xF2)), bg, glow.point(lambda v: v // 6))
|
||
|
||
# 居中横版锁定标(反白),宽度占画布 42%
|
||
lock = Image.open(os.path.join(SRC, 'logo-reverse-800.png')).convert('RGBA')
|
||
lb = lock.getchannel('A').getbbox()
|
||
lock = lock.crop(lb)
|
||
k = (W * 0.42) / lock.width
|
||
lock = lock.resize((round(lock.width * k), round(lock.height * k)), Image.LANCZOS)
|
||
|
||
canvas = bg.convert('RGBA')
|
||
canvas.paste(lock, ((W - lock.width) // 2, (H - lock.height) // 2), lock)
|
||
out = canvas.convert('RGB')
|
||
print(' app.png 新稿 %dx%d 锁定标 %dx%d 居中' % (W, H, lock.width, lock.height))
|
||
|
||
if WRITE:
|
||
open(ICNS_OUT, 'wb').write(icns)
|
||
out.save(APP_OUT, optimize=True)
|
||
print('\n已写入 icon.icns / app.png')
|
||
else:
|
||
print('\n预演,未写入(加 --write 生效)')
|