Files
cube/apps/werewolf/frontend/scripts/gen-icons.mjs
T

47 lines
1.9 KiB
JavaScript
Raw Normal View History

// 从 public/werewolf/back.jpg 生成 PWA 图标。
// 运行: npm run gen:icons
import sharp from 'sharp'
import { mkdir } from 'node:fs/promises'
import { fileURLToPath } from 'node:url'
import { dirname, resolve } from 'node:path'
const here = dirname(fileURLToPath(import.meta.url))
const pub = resolve(here, '../public')
const src = resolve(pub, 'werewolf/back.jpg')
// 卡背是竖图,狼头菱形大致在水平居中、垂直 ~46% 处。
// 裁一个聚焦狼头 logo 的方形区域作为图标基底(按实际尺寸夹紧,避免越界)。
const meta = await sharp(src).metadata()
const SIDE = Math.min(meta.width, Math.round(meta.width * 0.82), meta.height)
const left = Math.round(Math.max(0, Math.min(meta.width - SIDE, meta.width / 2 - SIDE / 2)))
const top = Math.round(Math.max(0, Math.min(meta.height - SIDE, meta.height * 0.46 - SIDE / 2)))
const square = await sharp(src)
.extract({ left, top, width: SIDE, height: SIDE })
.toBuffer()
const RED = { r: 0xc0, g: 0x39, b: 0x2b, alpha: 1 } // 贴近卡面红,用于 maskable 安全区留白
async function out(name, size, { maskable = false } = {}) {
await mkdir(pub, { recursive: true })
const target = resolve(pub, name)
if (maskable) {
// maskable: 内容缩到 ~80%,四周用卡红留白,保证安全区不被裁切
const inner = Math.round(size * 0.8)
const fg = await sharp(square).resize(inner, inner).toBuffer()
await sharp({ create: { width: size, height: size, channels: 4, background: RED } })
.composite([{ input: fg, gravity: 'center' }])
.png()
.toFile(target)
} else {
await sharp(square).resize(size, size).png().toFile(target)
}
console.log('wrote', name)
}
await out('pwa-192x192.png', 192)
await out('pwa-512x512.png', 512)
await out('maskable-icon-512x512.png', 512, { maskable: true })
await out('apple-touch-icon-180x180.png', 180)
await out('favicon-48x48.png', 48)
console.log('done')