解读拓竹激光雕刻数据文件 lac 格式

172 阅读11分钟

大家好,我是前端西瓜哥。

前段时间,拓竹出了个新的 3合1 的设备,把 3D打印、激光雕刻、刀切 放到一台机器里,貌似是对标 snapmaker。

虽然本人没用过拓竹的产品,但里面的激光雕刻和刀切需要 用到 2D 图形编辑器,这个我就感兴趣了。

所以今天西瓜哥就带大家一起来解读这个编辑器导出文件格式 lac。

Bambu Suite 的编辑器

在解读格式前,我们还是来简单看看 Bambu Suite 图形编辑器。

官方网站可以下载,然后它是 纯桌面端应用,离线单机,数据保存在本地的 lac 文件上

虽然可以登录,但是完全没有任何需要后端的功能,图纸也不能上传下载。看起来和后端有关的就右上角的铃铛图标,大概能接收公告通知的功能,不过应该也不需要登录。应该以后才会做相关功能,眼下先收集一下用户信息。

看看编辑器主界面。

图片

左边工具栏、右边图层面板、顶部操作栏,比较标准的图形编辑器界面。

做一些简单的操作,画几个简单图形,交互上感觉还可以。

查看包内容,可以看到很多 Qt 开头的文件夹,所以应该是用了 C++ 的 Qt UI 框架,也就说 图形编辑器大概也是使用 C++ 写的

图片

基本的功能基本都有的,但是一些地方可以看出,这款产品还有很多地方没打磨好。比如:

  1. 一次只能打开一个图纸,有点无语了这个;

  2. 只有一个画布,但图纸文件中有画布数据已经是数组形式了,虽然只有一个元素,应该是没来得及做;

  3. 双击 lac 文件,虽然会打开软件,但不会打开图纸;

  4. 图形发生斜切后再和其他图形一起选中然后 rezise,选中框会对不上(不少图形编辑器都有这个问题,所以我都会测这个);

图形编辑器的简评就到这里,我们回到正题,先做 lac 文件格式的解析。

lac 格式

文件后缀

Bambu Suite 导出的文件,后缀是 lac。

我没猜错的话,是 laser cutter(激光切割机)里面找了几个字母的缩写。

他们的技术多半是 AutoCAD 出身,因为很有 AutoCAD 的味道,AutoCAD 的文件格式是 dwg,是 drawing(图纸)的缩写。

此外 AutoCAD 特有的框选方式也可以证明,即往右选是包围选中,往左是相交选中。

两种获取文件内容的思路

当我们看到一个图形编辑器的文件,我们会有两种思路来尝试获得文件内容。

第一种就是它可能是 明文文件,常见的是 json 格式,稍微少见点的是 xml。json 是后来才流行的,一些老软件的文件可能还是用的 xml 格式。

第二种是它可能是 zip 压缩文件,可以放更多的文件,且体积更小,通常解压后通常会得到至少以下文件:

  1. 图形树数据结构的明文文件,通常是 json ;

  2. 一张缩略图图片,用于在用户操作系统的文件列表中直接显示出来;

  3. 一个元数据文件,比如保存图纸的真正图纸名。

需要注意的是,有些软件已经开始用压缩效果更好的 Zstandard 格式了(我说的是 Figma)。

最后一种就是用了自定义的二进制格式,就不好解析了。

有些简单的可能可猜出来,比如会将不同的内容组合在一起,需要我们理解里面的标志位去做切片,或是用一个字符串做一个异或操作的加密,这个相对来说好做逆向,工作量不大。

复杂的有发明了自己的一套二进制格式(比如 dwg),如果不公开格式说明书就没有很好办法解析,通常要利用对应的软件做逆向,并需要进行大工作量的推测验证,遇到只好放弃。

lac 是个 zip 文件

我们来看看 lac 文件怎么个事。

我们用 vscode 打开 lac 文件试试,提示是二进制文件,我们强行用文本形式打开。

图片

PK 打头,太好了,是 zip 文件,我们有救了。

将 lac 后缀名改为 zip,然后解压,得到下面文件:

├── 2D
│   ├── 2dmodel.json
│   ├── Objects
│   │   └── image 07606e1b-9e39-4244-b186-05670517f1a0.png
│   ├── design_thumbnail.png
│   └── entry.json
├── Metadata2D
│   ├── 200g Kraft Paper Process @BBL H2D 10W.config
│   ├── 200g Kraft Paper.config
│   ├── 200g Kraft Paper.png
│   ├── 200g Kraft Paper_translation.json
│   ├── Bambu Lab H2D-10W.config
│   ├── c1_b1_p1.png
│   ├── full_c1_b1_p1.png
│   ├── making_result.json
│   └── project_settings.json
├── [Content_Types].xml
└── _rels
    └── .rels

有一些和激光有关的文件,这些我们都不管了,我们只看 2D/2dmodel.json 文件。

2dmodel.json

2dmodel.json 保存了图纸的图形树数据。

先看看整体的的结构。

{
  "Application": "Bambu Suite",
"FileVersion": "01.00.01.03",
"canvas_list": [
    {
      "components": [
        {
          "obj_id": 25,
          "transform": "1.26746 1.10555 -0.704917 0.808153 164.908 147.323"
        },
        // ...
      ],
      "index": 1,
      "name": "",
      "obj_list": [
        {
          "color": "63 81 181 255",
          "flags": ["FreeAspectRatio"],
          "height": 57.22422790527344,
          "name": "矩形 5",
          "obj_id": 25,
          "start_x": 0,
          "start_y": 0,
          "type": "RectObject",
          "width": 65.14258575439453
        }
        // ...
      ],
      "type_count": {
        "RectObject": "5",
        // ...
      }
    }
  ]
}


  • Application:文件来自的软件;

  • FileVersion:文件版本号;

  • canvas_list:画布列表,目前只有一个画布;

  • canvas_list[number].components:图形树的第一层图形列表;

  • canvas_list[number].index:画布索引值;

  • canvas_list[number].name:画布名;

  • canvas_list[number]obj_list:画布下的所有对象。

  • type_count:不同类型图形的最大 count,创建图形命名用的,比如创建 "矩形 5",对应会记录 5,然后出创建下一个新矩形就 +1,然后矩形名为 "矩形 6",一开始看着命名还以为统计每种图形类型的数量。

有个很明显的问题:命名风格不统一,一些是大驼峰,一些是连字符的。最好统一一下,个人更喜欢小驼峰。

然后是对图形树的表达和我平时见的不太一样。

lac 是用 obj_list 数据保存图形树中所有的图形,然后 components 是图形树的第一层,会引用对应的 id,并设置一个 transform 形变。

看起来像是 3D 图形编辑器的概念

obj_list 好比保存了一堆的 3d 模型,然后 components 其实就是 3d 的世界主舞台,将 3d 模型拖拽进去,然后移动到世界的某个位置或者放大一些(做 transform 变换)。

或者我们用面向对象的代码风格举例,obj_list 放的是所有的类,components 是类的实例化。

一般来说这个 transform 应该放到子节点的属性完全没问题,但是并没有。

我猜这样写可能是想 让所有节点都可以复用,但目前看来图形编辑器并没有这个能力,大概是先占个位置,以后再支持。

图形类型

图形类型有很多种。

  1. RectObject:矩形。通过 start_x、start_y、width、height 表达;

  2. EllipseObject:椭圆。通过 center_x、center_y、radius_x、radius_y 表达;

  3. TextObject:文本。看起来只支持纯文本,不支持富文本,使用 text(字符串格式)、font_setting 表达。对了还有个 path_data,作用是在字体不存在时也能把字体渲染出来;

  4. ThreePointsArcObject:三点圆弧。用 point_0_x、point_0_y、point_1_x、point_1_y、point_2_x、point_2_y 表达,通过三个点确定圆弧。但目前图形编辑器中不支持修改这些属性,只能双击转换为 path 进行编辑;

  5. CenterPointArcObject:中心圆弧,用 point_0_x、point_0_y、point_1_x、point_1_y、point_2_x、point_2_y 表达。和前者的区别是,第一个点是圆心。同样不能修改属性,只能转换为 path 编辑;

  6. RasterImage:图片,通过 width、height、file_name、image_settings 表达。没有 x 和 y,用了默认的 (0, 0)。

  7. MultiLineObject:多段线。通过 path_data、is_closed 表达,path_data 大概对应 svg 的路径表达,但貌似有点不同。已知支持直线(L)和三阶贝塞尔(C)表达;

  8. PathGroup:路径。看起来和 MultiLineObject 差别不大,双击矩形、等基本图形会转换为 PathGroup,path_data 出现了一个特殊的 AC 命令,应该代表圆弧的终点和圆形,格式为 AC endX endY centerX centerY

  9. ModelGroup:组。通过 components 数组表达,和 canvas 的 componets 一样的写法。

  10. BooleanGroup:布尔组。对图形进行布尔运行的组形式,可以修改布尔源。通过 components、boolean_type 来表达。

  11. StickerGroup:贴纸组。作用是给指定的图形加一个轮廓。通过 components、creating_additional_frame、frame_thickness、result_setting 等表达。

目前只简单测试了这些图形类型,应该还有其他的,感兴趣的读者可自行研究。

通用属性

再看看通用属性。

  • obj_id:图形 id,数字递增;

  • name:图形名;

  • type:图形类型;

  • flags:标识符数组,比如 ["FreeAspectRatio"] 说明开启宽高比锁定;

  • color:颜色,格式为 "r g b a",取值都是 0 到 255。颜色会用来填充或是描边,具体哪个看图形使用的工艺类型,这个保存在另外的 project_settings.json 文件中;

  • printable:是否可见,默认为 true(可见),有可见属性,但没有锁定属性;

位移、旋转、缩放这些都用 transform 表达,而且是 componets 上引用并设置的,图形本身没有 transform。

没有圆角属性,顶部栏有个圆角功能,其实就是把图形转为 path,然后找两条相邻的直线,往它们中间新增一条圆弧线,这不就是 AutoCAD 的圆角功能嘛。

组的嵌套

Bambu Suie 支持组的嵌套,之前我实现过组嵌套的功能,相比只有一层的情况,要麻烦复杂很多,联动关系过多,所以挺在意它的数据结构的设计的。

嵌套的表达

我们去看 obj_list,会发现 图形树是拍平的,里面的 ModelGroup 对象,会使用 components 数组储存它的直接子节点的 id,另外附带一个 transform 表示特定的形变。

子节点如果是 ModelGroup,继续用 components 保存它的子节点,不断嵌套递归,直到非 group 节点。

image-20250428112247809

图片

这是一种 自上而下 的嵌套表达。

既然有自上而下,自然就有另一种 自下而上 的嵌套表达,代表是 Figma。

Figma 的图形树也是拍平的,但不同的是,每个节点会有一个 parentId 指向父节点,和一个 index 表示自己相对兄弟节点的位置。这样实现是为了方便做多人协同。

Bambu Suite 不需要做多人协同,这样设计也是没有问题的。

transform 的问题

我之前聊过,对图形进行 transform,为了保持图形的线宽不变不能只修改 transform,还要同步调整图形的宽高(size),这是为了保持 resize 后图形的线宽以及圆角等不跟随等比改变。

不过对类 AutoCAD 的线框类图形编辑器,可以不考虑改图形宽高了。

原因很简单,线宽永远都是不变的,不需要线宽信息,渲染基于 line 的模式即可。然后这种图形编辑器下的图形也 不会去支持圆角,看起来是圆角,本质是多段线上的一段。

结尾

lac 的图形树的数据结构意外的挺少的,不像 figma 有非常多的属性,而且还在不断发展,不断增加新属性。

一些业务相关的数据(比如雕刻类型)保存到其他文件里。

另外需要注意,导出的文件和实际的编辑器运行时的数据结构不一定是一致的,一些属性做了序列化或是属于计算属性移除掉了等等,但有一定参考价值。

我是前端西瓜哥,关注我,学习更多图形编辑器知识。


相关阅读,

Figma 的编组功能,比你想象的要复杂得多

剖析 Figma 图形对象的基本属性

Figma 数据结构:容器类图形的属性

本文使用 文章同步助手 同步