feat(icons): enhance .ico generation to support multiple sizes for better clarity
This commit is contained in:
Binary file not shown.
|
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 22 KiB |
@@ -103,22 +103,36 @@ function b64(pngPath) {
|
||||
return fs.readFileSync(pngPath).toString('base64')
|
||||
}
|
||||
|
||||
/** Wrap a PNG buffer in a minimal (PNG-payload) .ico container. */
|
||||
function pngToIco(pngBuffer) {
|
||||
/**
|
||||
* Wrap N square PNG buffers into a multi-image (PNG-payload) .ico container.
|
||||
* Windows picks the closest size when rendering at 16/24/32/48/256 px, so a
|
||||
* single 256px entry forces a blurry downscale in the taskbar/Explorer — and
|
||||
* the old rcedit electron-builder ships with mis-stamps some single-entry ICOs.
|
||||
* Embedding every common size keeps the app icon crisp at all of them.
|
||||
*/
|
||||
function pngsToIco(pngBuffers) {
|
||||
const count = pngBuffers.length
|
||||
const header = Buffer.alloc(6)
|
||||
header.writeUInt16LE(0, 0) // reserved
|
||||
header.writeUInt16LE(1, 2) // type: icon
|
||||
header.writeUInt16LE(1, 4) // image count
|
||||
const entry = Buffer.alloc(16)
|
||||
entry.writeUInt8(0, 0) // width (0 => 256)
|
||||
entry.writeUInt8(0, 1) // height (0 => 256)
|
||||
entry.writeUInt8(0, 2) // palette
|
||||
entry.writeUInt8(0, 3) // reserved
|
||||
entry.writeUInt16LE(1, 4) // color planes
|
||||
entry.writeUInt16LE(32, 6) // bits per pixel
|
||||
entry.writeUInt32LE(pngBuffer.length, 8) // size of image data
|
||||
entry.writeUInt32LE(6 + 16, 12) // offset to image data
|
||||
return Buffer.concat([header, entry, pngBuffer])
|
||||
header.writeUInt16LE(count, 4) // image count
|
||||
const dir = Buffer.alloc(16 * count)
|
||||
let offset = 6 + 16 * count
|
||||
pngBuffers.forEach((png, i) => {
|
||||
const w = png.readUInt32BE(16) // PNG IHDR width (byte 16..19)
|
||||
const h = png.readUInt32BE(20) // PNG IHDR height (byte 20..23)
|
||||
const e = i * 16
|
||||
dir.writeUInt8(w >= 256 ? 0 : w, e + 0) // width (0 => 256)
|
||||
dir.writeUInt8(h >= 256 ? 0 : h, e + 1) // height (0 => 256)
|
||||
dir.writeUInt8(0, e + 2) // palette
|
||||
dir.writeUInt8(0, e + 3) // reserved
|
||||
dir.writeUInt16LE(1, e + 4) // color planes
|
||||
dir.writeUInt16LE(32, e + 6) // bits per pixel
|
||||
dir.writeUInt32LE(png.length, e + 8) // size of image data
|
||||
dir.writeUInt32LE(offset, e + 12) // offset to image data
|
||||
offset += png.length
|
||||
})
|
||||
return Buffer.concat([header, dir, ...pngBuffers])
|
||||
}
|
||||
|
||||
function buildAppIcons() {
|
||||
@@ -150,9 +164,12 @@ function buildAppIcons() {
|
||||
}
|
||||
execFileSync('iconutil', ['-c', 'icns', iconset, '-o', path.join(BUILD_DIR, 'icon.icns')])
|
||||
|
||||
// .ico from a 256px render.
|
||||
const ico256 = svgToPng(squareIconSvg(BRAND_BLUE), 'app-ico', ['-w', '256', '-h', '256'])
|
||||
fs.writeFileSync(path.join(BUILD_DIR, 'icon.ico'), pngToIco(fs.readFileSync(ico256)))
|
||||
// .ico with every size Windows asks for (taskbar/Explorer/Alt-Tab/tiles).
|
||||
const icoSizes = [16, 24, 32, 48, 64, 128, 256]
|
||||
const icoPngs = icoSizes.map((s) =>
|
||||
fs.readFileSync(svgToPng(squareIconSvg(BRAND_BLUE), `app-ico-${s}`, ['-w', String(s), '-h', String(s)])),
|
||||
)
|
||||
fs.writeFileSync(path.join(BUILD_DIR, 'icon.ico'), pngsToIco(icoPngs))
|
||||
}
|
||||
|
||||
function buildMainProcessIcons() {
|
||||
|
||||
Reference in New Issue
Block a user