# 生成 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 生效)')