fix(pwa): preserve transparency in browser favicons (#745)

This commit is contained in:
InfinityPacer
2026-09-03 03:16:27 +08:00
committed by GitHub
parent 3f5768dc38
commit c5d4b9ee98
5 changed files with 17 additions and 8 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 708 B

After

Width:  |  Height:  |  Size: 672 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 50 KiB

+5 -5
View File
@@ -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,
})),
)
+12 -3
View File
@@ -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', () => {