完全指南:编译流程、命名规则与目录结构解析)
Flipper Zero 固件资产Firmware Assets完全指南编译流程、命名规则与目录结构解析【免费下载链接】flipperzero-firmwareFlipper Zero firmware source code项目地址: https://gitcode.com/GitHub_Trending/fl/flipperzero-firmware导读本文以 Flipper Zero 固件仓库根目录的 assets/ReadMe.md 为主体系统讲解固件资产的编译入口、图标与动画的命名规范、资产目录职责划分并结合 scripts/assets.py、assets/SConscript 等源码深入剖析 PNG 图标到 C 数组、Dolphin 动画到独立资源包的底层实现。读完本文你将掌握./fbt icons proto dolphin_internal dolphin_blocking dolphin_ext resources一条命令背后的完整资产管线能够为固件正确新增图标与动画资产并理解 assets/dolphin/ReadMe.md 所定义的 Dolphin 动画配置文件格式。一、什么是 Firmware Assets在 Flipper Zero 固件仓库中资产Assets泛指所有随固件打包的非代码资源包括图标Icons界面按钮、状态栏、应用菜单使用的单帧位图源文件为 PNG动画Animations多帧序列Icons 动画与桌面海豚Dolphin动画由多张 PNG 帧组合而成Protobuf 定义RPC 与存储等模块通信所用的.proto与.options文件Slideshow桌面系统一次性播放的引导/更新幻灯片Dolphin 游戏资产分 internal / blocking / external 三类的桌面海豚动画资源。这些资产集中在仓库的assets/目录构建时被编译成 C 头文件/源文件进入固件镜像或被打包为资源文件部署到 SD 卡。二、编译入口一条命令完成全部资产构建官方文档给出了资产编译的统一命令./fbt icons proto dolphin_internal dolphin_blocking dolphin_ext resources该命令实际包含 6 个构建目标alias其对应的真实构建逻辑在 assets/SConscript 中定义命令目标SConscript 对应别名实际产物iconsassetsenv.Alias(icons, icons)全部 PNG 图标/动画编译为assets_icons.[c,h]进入固件protoassetsenv.Alias(proto, proto)protobuf/*.proto经 nanopb 生成.c/.h同时生成protobuf_version.h对应proto_ver别名dolphin_internalassetsenv.Alias(dolphin_internal, dolphin_internal)空闲海豚动画编译为assets_dolphin_internal.[h,c]dolphin_blockingassetsenv.Alias(dolphin_blocking, dolphin_blocking)阻塞式系统通知动画编译为assets_dolphin_blocking.[h,c]dolphin_extassetsenv.Alias(dolphin_ext, dolphin_external)外部海豚动画打包为 SD 卡资源目录resources由DolphinExtBuilder与后续打包步骤共同产出SD 卡资源文件含 Manifest其中dolphin_ext仅在IS_BASE_FIRMWARE为真时构建assets/SConscript即只有基础固件才生成可部署到 SD 卡的外部动画资源。构建产物统一输出到assets/compiled/工作目录SConscript 中ASSETS_WORK_DIRenv.Dir(compiled)最终由assetslib assetsenv.Library(${FW_LIB_NAME}, assets_parts)汇总为一个名为assets的静态库参与固件链接。提示./fbt是仓库根目录的构建封装脚本见 fbt在 Linux 下直接执行即可Windows 对应fbt.cmd。三、图标与动画命名规则Asset naming rules官方文档规定图片与动画资产文件名必须符合以下三段式结构NAME_VARIANT_SIZE各段含义如下NAME必填资产名使用 CamelCase 驼峰命名仅允许字符[A-Za-z0-9]不允许特殊符号VARIANT可选图标变体用于表示状态或渲染条件例如active激活、inactive未激活、inverted反色SIZE必填像素尺寸。正方形如10、20、24长方形使用宽x高格式如10x8、19x5。命名完成后图标文件名会被自动加上I_前缀动画文件名自动加上A_前缀并统一汇入生成的icon.h与icon.c。这一规则可以在 scripts/assets.py 的icons()函数中看到完整实现普通图标icon_name I_ _.join(filename.split(.)[:-1])即去掉.png扩展名、用_连接各段、再补I_前缀动画目录内含frame_rate文件icon_name A_ os.path.split(dirpath)[1]即取目录名加A_前缀目录名中的-会替换为_。以仓库真实文件为例assets/icons/StatusBar 目录下的命名完全符合该规范Alert_9x8.png→I_Alert_9x8Battery_26x8.png→I_Battery_26x8Bluetooth_Connected_16x8.png→I_Bluetooth_Connected_16x8VARIANT 为ConnectedCharging-lightning_9x10.png→I_Charging_lightning_9x10文件名中的-被替换为_单帧图标 vs 多帧动画的判定scripts/assets.py 的遍历逻辑以目录中是否存在名为frame_rate的文件来区分两种类型图标目录内直接放置 PNG 文件每张图生成const uint8_t {name}[] {...}帧数据与const Icon {name} {...}图标描述符frame_count固定为 1动画目录内放置frame_XX.png帧序列与一个frame_rate文本文件内容为帧率数值如 assets/icons/Animations/Levelup1_128x64/frame_rate 中的2。所有帧必须尺寸一致脚本通过assert width temp_width强制校验并按文件名排序生成帧数组frame_rate从文件读取frame_count为帧数。生成产物格式最终icon.c/icon.h的骨架如下模板定义见 scripts/assets.py// icon.h #pragma once #include gui/icon.h extern const Icon I_Alert_9x8; extern const Icon A_Levelup1_128x64; // icon.c #include assets_icons.h #include gui/icon_i.h const uint8_t I_Alert_9x8_0[] {...}; // 帧数据 const uint8_t* const _I_Alert_9x8[] {_I_Alert_9x8_0}; // 帧指针数组 const Icon I_Alert_9x8 {.width9,.height8,.frame_count1,.frame_rate0,.frames_I_Alert_9x8};四、PNG 到 C 数组的底层实现原理scripts/flipper/assets/icon.py 实现了图标转换的完整管线共 4 步PNG → 1-bit XBM优先使用 Pillow 将 PNG 转换为 1 位色深的 XBM 格式im.convert(1)ImageOps.invertPillow 缺失时回退到 ImageMagick 的convertCLIXBM 解析从 XBM 文本中读取width、height与逐字节像素数据Heatshrink 压缩将像素数据用 heatshrink窗口 8、前瞻 4压缩优先使用heatshrink2Python 模块缺失时回退到heatshrink命令行工具编码选择比较压缩前后长度若压缩后更小含 2 字节长度头则采用\x01\x00 压缩数据格式否则使用未压缩的\x00 原始数据icon.py。此外脚本会对图像尺寸做上限校验MAX_IMAGE_WIDTH 2**16 - 1、MAX_IMAGE_HEIGHT 2**16 - 1scripts/assets.py超出即报错退出。五、Dolphin 与游戏资产按等级分组的扩展规则官方文档指出Dolphin桌面海豚资产与游戏资产的命名规则与图标动画相同但额外要求按等级level分组且等级作为NAME的前缀。以 assets/dolphin/internal 目录为例真实动画目录名L1_Tv_128x47、L1_NoSd_128x49即由L1等级 1Tv/NoSd名称128x47/128x49尺寸组成。Dolphin 资产分为三部分详见 assets/dolphin/ReadMe.md类型用途产物blocking阻塞式系统通知动画如低电量、无 SD 卡打包进assets_dolphin_blocking.[h,c]internal空闲状态的内置海豚动画转换为assets_dolphin_internal.[h,c]external空闲状态的外部海豚动画打包到资源目录部署至 SD 卡Dolphin 动画目录的必备文件每个 Dolphin 动画目录包含三类文件见 assets/dolphin/internal/L1_NoSd_128x49manifest.txt动画枚举清单用于随机动画选择是 Dolphin 的起始入口meta.txt描述动画如何绘制尺寸、帧序列、气泡对话框等frame_X.png动画帧位图编号从 0 开始。manifest.txt 格式采用 Flipper Format File有序键值对格式头部固定为Filetype: Flipper Animation Manifest Version: 1每条动画记录包含以下字段仓库真实示例见 assets/dolphin/internal/manifest.txt键含义仓库示例值Name动画名必须与动画目录名完全一致L1_NoSd_128x49Min butthurt/Max butthurt海豚不爽值butthurt的允许区间0/14Min level/Max level海豚等级的允许区间若为 0则该动画不参与随机空闲选择只能按名称精确触发1/3Weight随机选择时被选中的权重3、6文档特别说明某些动画可以被排除在随机选择之外如L1_NoSd_128x49这类需要特定硬件状态触发的动画。meta.txt 格式同样为 Flipper Format File头部固定为Filetype: Flipper Animation Version: 1字段包括仓库真实示例见 assets/dolphin/internal/L1_NoSd_128x49/meta.txt键含义Width/Height动画宽高宽 ≤ 128高 ≤ 64Passive frames被动状态位图帧数Active frames主动状态位图帧数可为 0Frames order帧播放顺序前 N 个为被动帧、后 M 个为主动帧X 对应frame_X.bm帧可重复引用同一帧Active cycles主动帧的重复周期数例如主动帧为 6、7 且 Active cycles3则完整主动段播放6 7 6 7 6 7被动 主动的完整周期称为total periodFrame rate每秒播放帧数Duration单次动画播放总秒数Active cooldown退出主动模式后、再次进入主动模式前需要等待的秒数Bubble slots气泡对话框序列的数量Slot同一序列气泡的分组号X/Y气泡左上角坐标Text气泡文本换行用\nAlignH/AlignV气泡角落的水平Left/Center/Right与垂直Top/Center/Bottom对齐方式StartFrame/EndFrame气泡在完整周期内显示所覆盖的帧索引范围帧索引的换算方法文档给出了一个关键示例帮助理解帧索引frame indexes与真实帧顺序real frames order的关系。假设配置为Passive frames: 6 Active frames: 2 Frames order: 0 1 2 3 4 5 6 7 Active cycles: 4则索引换算如下passive(6) active (2 * 4) Real frames order: 0 1 2 3 4 5 6 7 6 7 6 7 6 7 Frames indexes: 0 1 2 3 4 5 6 7 8 9 10 11 12 13即被动段 6 帧依次播放后主动段的 2 帧按Active cycles重复 4 次共 8 帧用于StartFrame/EndFrame的气泡帧索引为累计后的全局索引0–13。六、资产目录结构总览官方文档给出了assets/目录的结构划分结合仓库实际布局可汇总如下assets/ ├── ReadMe.md # 本文档 ├── SConscript # 资产构建脚本SCons 集成 ├── dolphin/ # Dolphin 游戏资产源 │ ├── blocking/ # 阻塞式通知动画 → 编译进固件 │ ├── external/ # 外部空闲动画 → 打包到 SD 卡 resources │ ├── internal/ # 内置空闲动画 → 编译进固件 │ └── ReadMe.md # Dolphin 动画格式规范 ├── icons/ # 图标/动画源PNG frame_rate │ ├── StatusBar/ # 状态栏图标如 I_Battery_26x8 │ ├── Animations/ # 多帧动画目录如 A_Levelup1_128x64 │ └── MainMenu/ NFC/ SubGhz/ ... # 按功能分组的图标 ├── protobuf/ # Protobuf 源.proto .options Changelog └── slideshow/ # 桌面一次性幻灯片first_start、update_default各目录的构建去向官方文档 assets/SConscript 双重印证dolphin→ 输出到 build 目录的compiled与resources两个文件夹分别对应编译进固件与部署到 SD 卡icons→ 输出到 build 目录的compiled文件夹生成assets_icons.[c,h]protobuf→ 输出到 build 目录的compiled文件夹生成 C 代码与版本头slideshow→ 桌面的单次播放幻灯片资源。七、重要注意事项官方文档强调了一条容易被忽视的构建约束不要引入未使用的资产编译器不会剥离未使用的资产。这意味着每一张 PNG、每一个动画目录最终都会以 C 数组形式被链接进固件镜像图标走I_/A_前缀进入icon.cDolphin 动画走DolphinSymBuilder进入assets_dolphin_*.c。从 assets/SConscript 可以看出所有资产部分icons、proto、dolphin_blocking、dolphin_internal、proto_ver被统一收进名为assets的静态库随固件链接因此资产会直接占用固件 Flash 空间。新增资产前应评估其体积与必要性尽量复用 assets/icons/Common 等目录下的通用图标。八、实战为固件新增一个图标或动画综合上述规则新增资产的完整流程如下新增单帧图标准备 1-bit黑白PNG按NAME_VARIANT_SIZE.png命名如MyIcon_Active_10x8.png放入 assets/icons 下对应功能目录如Common或自建目录执行./fbt icons或完整的./fbt icons proto dolphin_internal dolphin_blocking dolphin_ext resources重新生成assets_icons.[c,h]在代码中通过生成的符号I_MyIcon_Active_10x8引用含I_前缀该符号声明于生成的icon.h类型为const Icon。新增多帧动画自建目录命名如MyAnim_10x8目录名即动画名放入尺寸一致的frame_00.png、frame_01.png... 帧序列在目录内创建frame_rate文件内容为整数帧率如2参考 assets/icons/Animations/Levelup1_128x64/frame_rate重新编译后通过A_MyAnim_10x8符号引用。新增 Dolphin 动画在 assets/dolphin/internal或 blocking/external下创建Lx_Name_宽x高/目录放入frame_0.png、frame_1.png... 帧与meta.txt按第五节格式填写将动画条目追加到对应目录的manifest.txt重新执行./fbt dolphin_internal或完整构建命令internal/blocking 类型编译进固件external 类型由dolphin_ext打包至 SD 卡 resources。说明external 类型资产的打包依赖IS_BASE_FIRMWARE构建选项与 SD 卡部署流程普通固件构建默认只处理 internal 与 blocking 类型。九、延伸阅读assets/dolphin/ReadMe.mdDolphin 动画三类资源blocking/internal/external与 manifest.txt、meta.txt 的完整格式规范是本文第五节内容的原始出处assets/SConscript资产构建与固件静态库的 SCons 集成逻辑scripts/assets.py资产处理命令行工具icons、manifest、copro、dolphin四个子命令与图标/动画生成实现scripts/flipper/assets/icon.pyPNG → 1-bit XBM → heatshrink 压缩 → C 数组的转换管线fbt固件构建封装脚本资产编译命令./fbt ...的入口。通过本文你可以从按文档放置资产文件跨越到理解资产如何被编译、压缩、打包并最终进入固件镜像或 SD 卡资源为深度定制 Flipper Zero 固件打下扎实基础。【免费下载链接】flipperzero-firmwareFlipper Zero firmware source code项目地址: https://gitcode.com/GitHub_Trending/fl/flipperzero-firmware创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考