Files
iboard/scripts/gen-tray-icons.mjs
T

50 lines
2.1 KiB
JavaScript

#!/usr/bin/env node
// 生成托盘深浅色单色图标 (W-THE-01):
// src-tauri/icons/tray-light.png 深色字形 —— 浅色任务栏用
// src-tauri/icons/tray-dark.png 白色字形 —— 深色任务栏用
//
// 做法: 不能只用 alpha 通道做剪影 —— 源图标是「深色圆角方块 + 白色 i」,
// 整个方块都是不透明的, 只取 alpha 会得到一块纯色方块, i 字母细节全丢。
// 这里按**亮度**映射, 保留字母结构:
// 深色字形: alpha = (255-L)/255 → 方块保留深色, 白色 i 镂空透出任务栏
// 浅色字形: alpha = max(L,40)/255 → i 白色高亮, 方块留一点淡淡衬底
// 产物已提交进仓库, 仅图标变更时需要重跑: node scripts/gen-tray-icons.mjs
import sharp from 'sharp'
import { fileURLToPath } from 'node:url'
import path from 'node:path'
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..')
const src = path.join(root, 'src-tauri', 'icons', '128x128.png')
const outDir = path.join(root, 'src-tauri', 'icons')
const targets = [
{ file: 'tray-light.png', rgb: [31, 31, 31], mode: 'dark-glyph' }, // 深色字形 (浅色任务栏)
{ file: 'tray-dark.png', rgb: [250, 250, 250], mode: 'light-glyph' }, // 白色字形 (深色任务栏)
]
for (const t of targets) {
const { data, info } = await sharp(src)
.resize(32, 32, { fit: 'contain', background: { r: 0, g: 0, b: 0, alpha: 0 } })
.ensureAlpha()
.raw()
.toBuffer({ resolveWithObject: true })
const out = Buffer.alloc(info.width * info.height * 4)
for (let i = 0; i < info.width * info.height; i++) {
const r = data[i * 4]
const g = data[i * 4 + 1]
const b = data[i * 4 + 2]
const a = data[i * 4 + 3]
const lumi = 0.2126 * r + 0.7152 * g + 0.0722 * b
const alpha =
t.mode === 'dark-glyph' ? (a * (255 - lumi)) / 255 : (a * Math.max(lumi, 40)) / 255
out[i * 4] = t.rgb[0]
out[i * 4 + 1] = t.rgb[1]
out[i * 4 + 2] = t.rgb[2]
out[i * 4 + 3] = Math.round(alpha)
}
await sharp(out, { raw: { width: info.width, height: info.height, channels: 4 } })
.png()
.toFile(path.join(outDir, t.file))
console.log('generated', t.file)
}