导出 Figma 的设计文件,我们会得到一个 fig 文件。fig 是一种二进制的格式。它没有使用 XML 或是 JSON 的格式,而是选择使用了 Figma 自己实现的特殊编码工具进行了序列化编码,并做了封装,最后得到一个二进制文件。
大家好,我是前端西瓜哥。
上周图形编辑器交流群里有人问,对于 Figma 导出的 fig 文件,该如何解析其格式,拿到可读数据。
经过群友的一番讨论,这个问题最后算是解决了。
fig 文件
导出 Figma 的设计文件,我们会得到一个 fig 文件。
fig 是一种二进制的格式。
它没有使用 XML 或是 JSON 的格式,而是选择使用了 Figma 自己实现的特殊编码工具进行了序列化编码,并做了封装,最后得到一个二进制文件。
二进制相比明文格式(JSON 和 XML),优点有:
- 体积更小,因为数据更紧凑;
- 解析速度快,像是 JSON 这种,要逐个字符解析然后构建 AST,考虑转义、空格等特殊情况,对于大文件,解析效率很差;
- 高保真,比如一些类型明文格式其实是不好表达的,需要多做一层转换(比如 Float32Array 类型,要保存为字符串就要转为普通数组);
- 安全性。因为编码规则是应用自己实现的,此外方便做加密(比如异或加密)。编码和解码的规则我们是无法知道的,除非它主动公布出来,否则只能尝试去做逆向。
先用 Figma 随便画几个基本图形。
然后导出 fig 文件,拿到了一个名为fig-file.fig的文件。
先用 vscode 打开看看。
不是文本文件,应该就是二进制文件了。
不管怎样,强行用文本格式打开。
PK打头,应该就是 ZIP 格式文件头的标识。
顺便再查看一下这个文件的二进制内容,看到开头这个50 4B 03 04,说明确确实实是个 ZIP 文件。
基本上很多应用的导出文件都选择 ZIP 格式,然后再把后缀名改成自己定义的,比如 fig、xmind。
使用 ZIP 格式有以下好处:
- 进行了文件压缩,体积更小,并且是单文件;
- 保留了目录结构;
- 跨平台,基本所有主流操作系统都支持 ZIP。虽然用户一般来说并不会手动解压它,但用户安装的应用程序能直接使用操作系统的底层 API 去解压,有助于减少应用程序包体积;
解压一下。
unzip fig-file.fig
解压内容
解压后的内容为:
.
├── canvas.fig
├── fig-file.fig # 这个是压缩源文件
├── images
│ └── 0b15125516ae308a2d819f2970e851c0402949d2
├── meta.json
└── thumbnail.png
需要注意的是,解压出来的内容,并没有一个根文件夹存放这些内容。
但如果你用可视化界面去解压,通常会解压出一个文件夹,这个文件夹和压缩包同名。
这个其实是操作系统的额外操作,目的是防止解压出大量文件和当前文件夹的其他文件混在一起了,可能还会有文件同名的问题。
canvas.fig 是真正的 Figma 数据内容,记录图形树中图形的关系,以及图形的属性。
images 文件夹,存放的是图片,给里面的文件加上.png后缀可查看图片。
meta.json 是一些图纸的基本信息,比如导出的客户端使用的背景色,文件名等。
thumbnail.png 是预览图图片,如果你装了 figma 桌面端,则在会从 fig 提取出这个图片给文件预览器预览。
等下,不对,canvas.fig?怎么又是 fig 文件,这是在玩套娃?
经识别,也是个二进制文件,但它的文件格式却是。。。fig-kiwi?
Kiwi
这个叫做 Kiwi 的特殊格式被 Figma 的前 CTO,Evan Wallace 开源了。
https://github.com/evanw/kiwi。
Kiwi 是一种基于 Schecha 的二进制格式,用于高效地对树形数据结构进行编码。
它受到 Google 的 Protoclol Buffer 格式的启发,但更简单,编码更紧凑,且对自定义字段有更好的支持。
Kiwi 库提供了工具,能够解析二进制文件转换为编程语言中的对象,目前支持 JavaScript (TypeScript)、C++、Rust、Skew。
但要提供一个 Schecha,来进行类型的映射。
好在这个 Schecha 有保存在 fig 文件里的。
canvas.fig 文件
实际上这个 canvas.fig 文件并不是 Kiwi,它是一个复合产物。
首先开头的fig-kiwi字符串是一个注释,表示它是一个 fig 文件(毕竟前面也看到了,fig 文件可能也是 ZIP),并使用了 kiwi 进行编码。
文件里有 Kiwi 的二进制数据部分,也有 Schecha 部分,需要把它们提取出来。
这里要做切片了。
有个开源项目Figma-To-JSON成功解析了 fig,我们看看它怎么做的。
看了下,貌似是切在50 89这个地方,切好几刀,得到一些切片。我们需要前两个切片。
第一个切片是 Schecha,第二个是 Kiwi 数据。
每个切片都是 ZIP 压缩的,需要先给它们解压,然后再做 Kiwi 解码。
import { ByteBuffer, compileSchema, decodeBinarySchema } from "kiwi-schema"
export const figToJson = (fileBuffer: Buffer | ArrayBuffer): object => {
// 提取 fig 文件的 schema 和 kiwi 格式数据
const [schemaByte, dataByte] = figToBinaryParts(fileBuffer)
const schemaBB = new ByteBuffer(schemaByte)
const schema = decodeBinarySchema(schemaBB)
const dataBB = new ByteBuffer(dataByte)
const schemaHelper = compileSchema(schema)
// 这个 json 对象就是最终结果了
const json = schemaHelper[`decodeMessage`](dataBB)
return convertBlobsToBase64(json)
}
流程总结一下,大致如下:
Figma-To-JSON
上面都是在说解码 fig 文件的过程。
如果你只是想要得到 fig 的结构,对过程不感兴趣,可以直接用一个名为 Figma-To-JSON 的开源项目去解析。
https://github.com/yagudaev/figma-to-json。
下面是转换结果,是一个一维数组,风格类似 quill 的 delta。
每个节点保存有父节点的 id,可以关联构建出一棵图形树。
拿到 fig 数据格式有什么好处呢?
首先如果你开发自己的图形编辑器,或者直接就是 Figma 的竞品,你是要设计数据结构的,那 fig 数据格式就有很好的参考价值。
然后就是做二次开发,写一些工具做一些离线的批处理操作,比如提取 fig 的一些文本数据转换为 excal 之类的奇怪操作。
这样你就不用联网打开 Figma 网站,使用插件去进行这些操作。
Figma 官方的看法
Figma 的 fig 格式算是半公开的,在网上找找能找到不少蛛丝马迹。因为 Figma 还是比较开放的,使用的 Kiwi 编码格式也公开了。
但 Figma 不会主动提供在客户端转换 fig 的方式(但可以使用开发者 API 请求服务端数据),因为这和它所希望的生态稳定相悖。
如果 Figma 主动提供 fig 的内部格式出来,那它就要对这个格式负责,且 Figma 在开发新的功能时,fig 文件在未来发展中结构大概率会有破坏性改变的。
当然如果你想和 Photopea 一样,尝试去解析它转换成的结构,那也是可以的,但你自己要对这个数据结构负责。
©本文为清一色官方代发,观点仅代表作者本人,与清一色无关。清一色对文中陈述、观点判断保持中立,不对所包含内容的准确性、可靠性或完整性提供任何明示或暗示的保证。本文不作为投资理财建议,请读者仅作参考,并请自行承担全部责任。文中部分文字/图片/视频/音频等来源于网络,如侵犯到著作权人的权利,请与我们联系(微信/QQ:1074760229)。转载请注明出处:清一色财经