Files
afilmory/scripts/generate-favicon.ts
Innei e4fde5ae74 feat: integrate PWA support and update manifest configuration
- Added PWA support using vite-plugin-pwa, including configuration for service worker and caching strategies.
- Updated index.html to include necessary meta tags for iOS Safari PWA support.
- Changed references from site.webmanifest to manifest.webmanifest for consistency.
- Removed redundant manifest generation from the favicon script, as it is now handled by vite-plugin-pwa.

Signed-off-by: Innei <tukon479@gmail.com>
2025-07-01 16:02:28 +08:00

122 lines
3.3 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { existsSync, mkdirSync, writeFileSync } from 'node:fs'
import path, { join } from 'node:path'
import sharp from 'sharp'
const __dirname = path.dirname(new URL(import.meta.url).pathname)
// 创建圆角遮罩
function createRoundedCornersMask(size: number, cornerRadius: number) {
const r = cornerRadius
return `
<svg width="${size}" height="${size}" xmlns="http://www.w3.org/2000/svg">
<rect x="0" y="0" width="${size}" height="${size}" rx="${r}" ry="${r}" fill="white"/>
</svg>
`
}
// 为图片添加圆角
async function addRoundedCorners(
imageBuffer: Buffer,
size: number,
): Promise<Buffer> {
// 计算圆角半径,约为尺寸的 12%
const cornerRadius = Math.round(size * 0.12)
const maskSvg = createRoundedCornersMask(size, cornerRadius)
const maskBuffer = Buffer.from(maskSvg)
return sharp(imageBuffer)
.composite([
{
input: maskBuffer,
blend: 'dest-in',
},
])
.png()
.toBuffer()
}
// 生成不同尺寸的 favicon
export async function generateFavicons() {
const logoPath = join(__dirname, '../logo.jpg')
const outputDir = join(process.cwd(), 'public')
// 检查 logo 文件是否存在
if (!existsSync(logoPath)) {
throw new Error('Logo file not found: logo.jpg')
}
if (!existsSync(outputDir)) {
mkdirSync(outputDir, { recursive: true })
}
const sizes = [
{ size: 16, name: 'favicon-16x16.png' },
{ size: 32, name: 'favicon-32x32.png' },
{ size: 48, name: 'favicon-48x48.png' },
{ size: 180, name: 'apple-touch-icon.png' },
{ size: 192, name: 'android-chrome-192x192.png' },
{ size: 512, name: 'android-chrome-512x512.png' },
]
try {
// 读取原始 logo 图片
const logoBuffer = await sharp(logoPath).jpeg({ quality: 100 }).toBuffer()
// 生成各种尺寸的 PNG 文件
for (const { size, name } of sizes) {
const resizedBuffer = await sharp(logoBuffer)
.resize(size, size, {
fit: 'cover',
position: 'center',
})
.png({
quality: 100,
compressionLevel: 6,
})
.toBuffer()
// 添加圆角效果
const roundedBuffer = await addRoundedCorners(resizedBuffer, size)
const outputPath = join(outputDir, name)
writeFileSync(outputPath, roundedBuffer)
console.info(`✅ Generated favicon: ${name} (${size}x${size})`)
}
// 生成主 favicon.ico使用 32x32
const faviconResizedBuffer = await sharp(logoBuffer)
.resize(32, 32, {
fit: 'cover',
position: 'center',
})
.png({
quality: 100,
compressionLevel: 6,
})
.toBuffer()
// 为 favicon.ico 添加圆角
const faviconBuffer = await addRoundedCorners(faviconResizedBuffer, 32)
const faviconPath = join(outputDir, 'favicon.ico')
writeFileSync(faviconPath, faviconBuffer)
console.info(`✅ Generated main favicon: favicon.ico`)
// PWA manifest 由 vite-plugin-pwa 生成,这里不再生成重复的文件
console.info(
`🎨 All favicons generated successfully from logo.jpg with rounded corners!`,
)
} catch (error) {
console.error('❌ Error generating favicons:', error)
throw error
}
}
// 如果直接运行此脚本
if (import.meta.url === `file://${process.argv[1]}`) {
generateFavicons().catch(console.error)
}