FLIC文件解析须先通过magic(0xAF11/fli或0xAF12/flc)区分格式,再按对应header结构读取帧数、帧率字段;chunk需逐type dispatch解析,delta帧须基于完整上一帧buffer原地patch;调色板更新仅限指定区间且注意BGR字节序;内存应预分配裸指针buffer,避免vector频繁realloc。

FLIC 文件头解析要先确认 magic 和帧率字段
FLIC 动画(.fli/.flc)不是标准图像格式,没有统一的 MIME 类型或现代库原生支持,必须手动解析文件头。关键不是“读到数据就行”,而是得立刻区分 fli(Autodesk Animator)和 flc(Autodesk Animator Pro)——两者 header 大小不同(128 字节 vs 112 字节),且 frames 字段位置、speed 或 frame_rate 含义也不同。
常见错误是硬编码 offset 读 speed:在 fli 中它是 16-bit 延迟(单位:1/70 秒),而在 flc 中它常被忽略,实际帧率由 frame_rate(32-bit,Hz)决定。不先判断 magic(0xAF11 或 0xAF12)就解析,后续所有帧解码都会错位。
- 用
fread读前 4 字节,比对是否为0xAF11(fli)或0xAF12(flc) -
fli的帧数在 offset 0x0A,flc在 offset 0x06;别直接跳 128 字节 - 若
frame_rate为 0(尤其老fli),回退用speed计算:delay_ms = (speed * 1000) / 70.0
FLIC 帧块(chunks)必须按 type 字段逐个 dispatch 解析
FLIC 没有固定帧结构,每帧由多个 chunk 组成,每个 chunk 以 4 字节 type 开头(如 0xF100 是 FLI_COLOR_256,0xF101 是 FLI_SS2,0xF110 是 FLI_DELTA_FLC)。不能假设某类 chunk 一定存在,也不能跳过未知 type —— 有些播放器会把未知 chunk 当作 padding 跳过,但规范要求“忽略并继续”,否则会误判后续 chunk 边界。
典型陷阱是把 FLI_DELTA_FLC(0xF110)当成完整帧数据:它只是 delta 编码,需基于上一帧 buffer 做原地 patch,且其内部又含子 chunk(如 0xF102 FLI_LC,即 “line compressed”),必须递归 dispatch。
- 每个 chunk 先读 4 字节
type,再读 4 字节size(含这 8 字节本身) - 遇到未实现的
type(如0xF109FLI_BLACK)时,用fseek(fp, size - 8, SEEK_CUR)跳过,不要 break -
FLI_DELTA_FLC必须维护一个全局current_framebuffer,并确保上一帧已完全解码完成
FLIC 调色板(color map)更新逻辑容易导致颜色错乱
FLIC 不带全局调色板,调色板数据以 chunk 形式内嵌在帧流中(FLI_COLOR_256 / FLI_COLOR_64),且可能只更新部分条目(partial palette update)。很多实现错误地“全量覆盖”整个 256-entry 数组,结果是旧颜色被清空,新动画出现色块闪烁。
正确做法是:读取 chunk 中的 first_color(起始索引)和 colors(数量),仅更新对应区间。还要注意字节序:RGB 数据是 BGR 存储(即每个 entry 是 0xBBGGRR),需手动翻转。
-
FLI_COLOR_256chunk 中,offset 6 是first_color(uint16),offset 8 是colors(uint16) - 后续紧接
colors * 3字节的 BGR 数据,每 3 字节转成一个0xRRGGBB的uint32_t - 若
first_color + colors > 256,截断处理,不要越界写入调色板数组
C++ 实现时优先用 uint8_t* 手动内存操作,别依赖 std::vector 自动 resize
FLIC 解码性能瓶颈不在算法,而在内存访问模式:chunk 数据长度不固定,频繁 resize vector 会触发多次 realloc + memcpy,尤其处理大 flc(>10MB)时帧延迟明显。更严重的是,delta 解码(FLI_DELTA_FLC)需要对当前帧 buffer 做原地修改,而 vector 的 data() 可能因 resize 失效。
实际工程中,应预分配足够大的 buffer(根据 header 中 width × height × 1 算最大帧尺寸),全程用裸指针 + offset 管理;调色板、帧 buffer、临时行缓冲区都用 std::unique_ptr<uint8_t></uint8_t> 管理生命周期,避免 new/delete 配对出错。
- 帧 buffer 分配大小 =
width * height(字节),不是width * height * sizeof(uint32_t)—— FLIC 是 8-bit 索引,非 RGB - 解码后转 RGB 时再 malloc 一个
width * height * 4的输出 buffer,用调色板查表填充 - 所有
fread调用后必须检查返回值是否等于预期字节数,FLIC 文件损坏很常见
最易被忽略的是:FLIC 的 width/height 在 header 里是 uint16,但某些老工具生成的文件会把 height 设为 0 表示“使用上一帧尺寸”,此时必须缓存上一帧的尺寸并 fallback 使用——不处理这个,第一帧之后所有帧都会解码失败。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











