diff --git a/public/favicon-16x16.png b/public/favicon-16x16.png index bcece130..ae1f46fd 100644 Binary files a/public/favicon-16x16.png and b/public/favicon-16x16.png differ diff --git a/public/favicon-32x32.png b/public/favicon-32x32.png index 1cac11f9..198cf74f 100644 Binary files a/public/favicon-32x32.png and b/public/favicon-32x32.png differ diff --git a/public/favicon.ico b/public/favicon.ico index 577510e0..23d055cc 100644 Binary files a/public/favicon.ico and b/public/favicon.ico differ diff --git a/scripts/generate-pwa-icons.mjs b/scripts/generate-pwa-icons.mjs index 678081b9..2331e603 100644 --- a/scripts/generate-pwa-icons.mjs +++ b/scripts/generate-pwa-icons.mjs @@ -137,10 +137,10 @@ async function createSquareIcon(mark, size, markScale, appearance = 'dark') { } /** - * 将透明母版缩放到指定画布,供页面、通知和主题标识作为无底图资源使用。 + * 将透明母版缩放到指定画布,供页面、通知和浏览器标签作为无底图资源使用。 */ -async function createTransparentLogo(mark, size) { - const markSize = Math.round(size * 0.88) +async function createTransparentIcon(mark, size, markScale = 0.88) { + const markSize = Math.round(size * markScale) const resizedMark = await sharp(mark) .resize(markSize, markSize, { background: { r: 0, g: 0, b: 0, alpha: 0 }, @@ -205,7 +205,7 @@ async function writeAsset(relativePath, buffer) { const sourceLogo = await readFile(sourceLogoPath) const cleanedLogo = await cleanLogoMaster(sourceLogo) -const transparentLogo = await createTransparentLogo(cleanedLogo, 512) +const transparentLogo = await createTransparentIcon(cleanedLogo, 512) const standardMaster = await createSquareIcon(cleanedLogo, 1024, 0.76) await Promise.all([ @@ -237,7 +237,7 @@ await Promise.all([ const icoEntries = await Promise.all( [16, 32, 48, 64, 128, 256].map(async size => ({ - buffer: await createSquareIcon(cleanedLogo, size, size <= 32 ? 0.84 : 0.78), + buffer: await createTransparentIcon(cleanedLogo, size, size <= 32 ? 0.84 : 0.78), size, })), ) diff --git a/tests/config/pwa-icons.spec.ts b/tests/config/pwa-icons.spec.ts index 6576088c..40dcdeb2 100644 --- a/tests/config/pwa-icons.spec.ts +++ b/tests/config/pwa-icons.spec.ts @@ -24,8 +24,8 @@ const iconSpecs = [ { alpha: false, path: 'public/apple-touch-icon-167x167.png', size: 167 }, { alpha: false, path: 'public/apple-touch-icon-152x152.png', size: 152 }, { alpha: false, path: 'public/mstile-150x150.png', size: 150 }, - { alpha: false, path: 'public/favicon-32x32.png', size: 32 }, - { alpha: false, path: 'public/favicon-16x16.png', size: 16 }, + { alpha: true, path: 'public/favicon-32x32.png', size: 32 }, + { alpha: true, path: 'public/favicon-16x16.png', size: 16 }, ] as const /** @@ -73,7 +73,7 @@ describe('PWA 跨平台图标资源', () => { ) }) - it('生成包含常见 Windows 尺寸的多分辨率 favicon', () => { + it('生成包含常见 Windows 尺寸的透明多分辨率 favicon', async () => { const favicon = readFileSync(resolve(projectRoot, 'public/favicon.ico')) const imageCount = favicon.readUInt16LE(4) const declaredSizes = Array.from({ length: imageCount }, (_, index) => { @@ -83,6 +83,15 @@ describe('PWA 跨平台图标资源', () => { expect(favicon.readUInt16LE(2)).toBe(1) expect(declaredSizes).toEqual([16, 32, 48, 64, 128, 256]) + + for (let index = 0; index < imageCount; index += 1) { + const entryOffset = 6 + index * 16 + const imageLength = favicon.readUInt32LE(entryOffset + 8) + const imageOffset = favicon.readUInt32LE(entryOffset + 12) + const metadata = await sharp(favicon.subarray(imageOffset, imageOffset + imageLength)).metadata() + + expect(metadata.hasAlpha, `favicon entry ${declaredSizes[index]}x${declaredSizes[index]}`).toBe(true) + } }) it('在构建前可重复生成图标,并让启动图消费最新矢量 Logo', () => {