- 桌面应用
- CLI
【免费下载链接】battery
CLI/GUI for managing the battery charging status for Apple silicon (M1, M2, M3) Macs
本指南以仓库 assets 目录下的“Logo compiler”工具为主体,讲解其存在原因(Electron 托盘不支持直接使用 SVG 图片)、一行命令的运行方式(npm start)、以及配置入口 assets/modules/compile-images.js 中百分比步长、DPI 倍率、active/inactive 透明度等核心参数。读完本文,你将掌握该图标编译器从 SVG 模板生成、批量栅格化 PNG 到被 app/modules/theme.js 消费的完整链路,并能在修改“电量百分比显示粒度”这类需求时正确地重新生成全部图标。
背景:为什么 Electron 托盘图标需要一个“图标编译器”
原文档开宗明义:“Because Electron does not support SCG images”(原文此处为笔误,实指 SVG)。Electron 的nativeImageAPI 并不支持直接加载 SVG,而本项目(一款用于 Apple silicon Mac 电池充电限制的托盘应用)需要在菜单栏托盘上按电量百分比动态显示不同的电池图标,因此必须先把矢量图源批量渲染成 PNG。
为了让托盘图标能覆盖“从 0% 到 100%”的每一个展示档位,同时兼顾 macOS 菜单栏在不同屏幕 DPI 下的清晰度,仓库在 assets 目录里维护了一个独立的小工具项目(asset-compiler):
- 它读取“百分比”作为输入,调用 SVG 模板函数生成图标;
- 通过 @resvg/resvg-js(Rust 实现的 SVG 渲染库)将 SVG 栅格化为 PNG;
- 一次性输出数百张命名规范的图标文件,供 Electron 应用直接引用。
这套流程在 app/README.md 的开发者说明中也被印证:图标由脚本自动生成,应用侧无需再处理任何 SVG。
快速上手:安装依赖与运行
工具本身的工程信息定义在 assets/package.json 中,运行命令极其简单:
cd assets npm install # 安装 @resvg/resvg-js 等依赖 npm start # 等价于 node index.jsnpm start对应 assets/package.json 中的"start": "node index.js",入口文件 assets/index.js 只有寥寥几行——引入 assets/modules/compile-images.js 并调用其导出的render_and_write_template_files():
const render_and_write_template_files = require( './modules/compile-images' ) render_and_write_template_files()整个渲染过程是同步等待完成的,命令执行完毕后,所有 PNG 会写入 app/assets 目录(源码中export_directory = ${ __dirname }/../../app/assets)。原文档特别强调:这个工具只在“图标百分比支持范围发生变化”时才需要重新运行,日常开发无需反复执行。
核心配置解析:百分比、倍率与命名规范
配置的真正“大脑”是 assets/modules/compile-images.js,它集中了全部渲染参数:
| 配置项 | 源码位置 | 取值 | 说明 |
|---|---|---|---|
| 百分比步长 | compile-images.js | 5 | 从 0 到 100 每 5% 生成一档,共 21 个百分比 |
| DPI 倍率集合 | compile-images.js | ['1.25','1.33','1.4','1.5','1.8','2','2.5','3','4','5'] | 对应 ElectronnativeImage支持的高分辨率表示(High-resolution image),注释中说明了依据 |
| 图标状态 | compile-images.js | active/inactive | 每种百分比都同时生成激活态与未激活态 |
| 透明度 | compile-images.js 与 L59 | active 用bake_logo(percentage, 1),inactive 用bake_logo(percentage, .5) | 与 app/README.md 中“100% vs 50% for active inactive”的说明一致 |
| 输出目录 | compile-images.js | ../../app/assets | 相对assets/modules,即仓库根下的 app/assets |
渲染组合逻辑为:每个百分比生成 22 张图 = 1 张基础图(1x,无倍率后缀)+ 10 张@Nx倍率图,且 active/inactive 各一套。21 个百分比 × 22 张 =共 462 张 PNG,全部通过Promise.all并发栅格化写入磁盘(见 compile-images.js)。
文件名遵循统一模板(见 compile-images.js):
battery-{active|inactive}-{percentage}-Template{@Nx}.png例如:
battery-active-80-Template.png(1x 基础图,18×18)battery-active-80-Template@2x.png(2 倍图,36×36)battery-inactive-50-Template@1.5x.png
文件名的Template后缀并非装饰:macOS 会把名称带Template的图片当作模板图像处理,自动适配菜单栏的深色/浅色主题,这正是本项目图标能随系统外观切换的原因之一。
栅格化核心函数render_and_write_png使用 Resvg 的fitTo.zoom模式按倍率放大输出:
const resvg = new Resvg( svg_string, { fitTo: { mode: 'zoom', value: Number( size ) } } ) const png_data = resvg.render() const png_buffer = png_data.asPng() return fs.writeFile( `${ export_directory }/${ filename }.png`, png_buffer )因此基础图 18×18 的@2x版本即为 36×36、@5x即为 90×90,这与 app/assets 中实际存在的各倍率图片尺寸完全吻合。
SVG 模板的生成原理
SVG 模板由 assets/modules/logo.js 的bake_logo(percentage, opacity)函数生成,它是整个图标系统的“画布”。核心几何逻辑如下:
const max_height = 12 const min_y_position = 3.5 const percentage_as_decimal = percentage / 100 const current_height = max_height * percentage_as_decimal const current_y_position = min_y_position + ( max_height - current_height )- 画布为
viewBox="0 0 18 18",即 18×18 的逻辑坐标系; - 电池内部的电量填充矩形(
<rect id="content">)宽度固定为 7.25、圆角半径 1.5; - 填充高度
current_height随百分比线性变化:0% 时高度为 0(只有空电池轮廓),100% 时高度为 12(充满); - 填充矩形纵坐标
current_y_position随高度反向移动:电量越低越靠下,电量越高越靠上,从而让电量条始终“从底部开始生长”。
<svg>根节点上施加的opacity参数则直接控制了 active(1.0)与 inactive(0.5)两种状态的视觉差异,这也是 app/README.md 所述“图标内部电量填充部分在激活/未激活时透明度不同”的实现来源。电池外壳则由一段预置的path路径绘制,配合两重matrix变换缩放到 18×18 画布内。
生成的图标如何被应用消费
编译产物最终被 Electron 应用侧读取。关键代码在 app/modules/theme.js 的get_logo_template(percent, active):
const percentage_increment_to_render = 5 const display_percentage = Math.floor( percent / percentage_increment_to_render ) * percentage_increment_to_render const image_path = path.join( asset_path, `/battery-${ active ? 'active' : 'inactive' }-${ display_percentage }-Template.png` ) return nativeImage.createFromPath( image_path )这里有两个值得注意的联动点:
- 百分比取整对齐:
display_percentage会把任意实时电量(如 83%)向下取整到 5 的倍数(80%)。由于编译器恰好以 5 为步长生成图标,取整后总能命中已存在的文件;反过来,若想提高展示精度(例如改为 1% 一档),就必须同步修改compile-images.js中的percentage_increment_to_render并重新运行编译器。 - 资源路径切换:
asset_path = app.isPackaged ? resourcesPath : './assets'——开发态直接读 app/assets,打包后则读取资源目录。
消费端 app/modules/interface.js 在生成托盘菜单时调用tray.setImage( get_logo_template( percentage, limiter_on ) )(见 interface.js),并在启用/停用充电限制时分别用active/inactive强制刷新图标(见 interface.js 的enable_limiter/disable_limiter)。整套流程形成了“实时电量 → 取整到 5 的倍数 → 查表选 PNG → 设置托盘图像”的完整数据链路。
打包与资源路径
打包配置位于 app/package.json 的build.extraFiles:
"extraFiles": { "from": "./assets", "to": "resources", "filter": [ "**/*" ] }编译生成的 app/assets 下全部 PNG 会被原样打入应用包内的resources目录,运行时通过resourcesPath读取——这解释了为什么这 462 张图片必须作为静态资源随包发布,而不是在运行时动态生成。
何时需要重新运行编译器
原文档给出的原则非常明确:“This only needs to be done if icon percentage support changes.”结合源码可以归纳出需要重新执行npm start的典型场景:
- 修改了百分比步长(如把 5% 一档改为 1% 一档),需要同时改 compile-images.js 与 theme.js 中的
percentage_increment_to_render; - 调整了图标倍率集合(增删 DPI 档位,见 compile-images.js);
- 修改了 logo.js 中的几何参数(填充条尺寸、坐标、透明度策略等),需要重新栅格化全部档位;
- 调整了图标命名规则(前缀、后缀),此时还需同步更新 theme.js 中的文件名拼接逻辑。
日常使用、只改应用业务逻辑(如菜单文案、刷新频率)时,均无需触碰编译流程。
注意事项小结
- 原文档中配置文件名写作
comile-images.js,为笔误,实际文件为 assets/modules/compile-images.js。 - app/README.md 提到图标可通过在
app/assets下运行node index.js生成;而编译器工程实际位于仓库根的 assets 目录,产物输出到 app/assets,运行入口以npm start为准。 - 渲染依赖仅一个运行时包
@resvg/resvg-js(^2.4.1),整个工具非常轻量;npm test目前仅输出占位提示(见 assets/package.json),功能验证可直接检查输出目录中的 PNG 数量与尺寸。
- 桌面应用
- CLI
【免费下载链接】battery
CLI/GUI for managing the battery charging status for Apple silicon (M1, M2, M3) Macs
相关推荐
OpenMontage 中的 Beautiful Mermaid:将 Mermaid 图表渲染为 4K 级 SVG/PNG 的完整实战指南
OpenMontage 中的 Beautiful Mermaid:将 Mermaid 图表渲染为 4K 级 SVG/PNG 的完整实战指南 本文以 OpenMo
人工智能AI Agent音视频媒体生成工作流自动化FontForge 实战:用 svg2glyph 将 Inkscape SVG 图标批量转换为 FontForge 字形
FontForge 实战:用 svg2glyph 将 Inkscape SVG 图标批量转换为 FontForge 字形 导读 svg2glyph 是 Font
桌面应用图形学@antv/g6-ssr 服务端渲染实践:在 Node.js 中将 G6 5.0 图导出为 PNG / JPEG / SVG / PDF
@antv/g6 ssr 服务端渲染实践:在 Node.js 中将 G6 5.0 图导出为 PNG / JPEG / SVG / PDF 本指南围绕 G6 官方
数据可视化前端图表库
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考