← 返回信息流
AI 资讯Hacker News·23 小时前

浏览器中运行的LibreCAD

原标题:LibreCAD in the Browser

速览

LibreCAD是专为Linux系统开发的专业开源矢量图形编辑器,支持DWG、SVG等多种格式。浏览器版本克服了以往桌面版依赖系统库的问题,用户无需下载安装即可直接在网页上进行设计。

AI 深度解读

LibreCAD in the Browser:AI辅助端口与WebAssembly技术的突破

背景

在桌面端使用CAD工具时,用户经常需要下载、安装、启动应用才能完成少量绘图任务,如绘制简易平面图。这类桌面应用适合本地使用,但在2026年“开一个标签页就能画图”却显得不够便利,尤其是在没有登录的场景下。作者此前从未实际使用过LibreCAD,也不是其目标用户,只想进行快速草图。

为此,作者通过在OpenCode中提示GLM-5.2模型,将开源应用LibreCAD移植至WebAssembly。整个过程相对“手把手”且易于操作,这得益于Qt团队对WebAssembly支持的持续投入,以及成熟的WebAssembly生态。

核心内容

LibreCAD是一款免费的GPL许可的2D CAD应用,基于Qt构建,曾从QCAD时代延续至今。它支持读取和写入DXF和DWG文件,具备图层、块、尺寸、填充等功能,以及2D CAD工具的绝大部分常见特性。

作者通过Emscripten和Qt官方WebAssembly平台支持,将LibreCAD的完整C++源代码编译为WebAssembly,无需JavaScript重实现、无网络端渲染,仅运行桌面版应用在浏览器标签页中。整个应用(非查看器或子集)直接在该站点运行,点击即可加载。

首次加载约18 MB(Brotli压缩后),后续浏览器缓存。需Chromium-based浏览器(Chrome或Edge 137+),依赖WebAssembly JSPI特性,Firefox和Safari尚未支持。源代码托管于github.com/magik6k/LibreCAD-Web。

内容由LLM撰写但大致技术准确,应用在浏览器中大致运行,但可能存在较严重的bug。项目风格为FAFO(Fuck Around Find Out)式,无额外努力。

端口过程分为前90%机械工作和最后10%困难部分:

  • 工具链准备:使用Docker镜像包含Ubuntu 24.04、Emscripten和Qt。LibreCAD完整源代码通过Qt自己的qt.toolchain.cmake编译链接为.wasm二进制文件。桌面专用启动路径(如CLI参数解析、启动画面、首次运行对话框、网络版本检查)用#ifndef Q_OS_WASM保护,未影响桌面构建。

  • GUI启动与事件:Qt for WebAssembly通过WebGL渲染,通过平台插件处理浏览器事件。主窗口、工具栏和停靠面板出现,画布接收鼠标和键盘输入。

  • 模态对话框问题:LibreCAD作为桌面应用,持续进入事件循环。QDialog::exec()会阻塞直到关闭,对话框内的下拉框或颜色选择器会嵌套新循环。在Web上无法阻塞主线程,exec()直接不返回。Emscripten的Asyncify可重写二进制使阻塞调用在浏览器间恢复,但仅支持单个调用深度。点击对话框内的combo-box或从首选项中打开颜色选择器时,第二个suspend无处容纳,整个应用卡住。

  • JSPI解决方案:Qt 6.9可使用JSPI(WebAssembly JavaScript Promise Integration),通过-device-option QT_EMSCRIPTEN_ASYNCIFY=2开启,但需native WebAssembly exceptions(-fwasm-exceptions),预构建Qt包不包含。端口从源代码构建Qt 6.9 WebAssembly,支持JSPI + Wasm exceptions。

  • JSPI兼容性难题:JSPI仅允许WebAssembly栈通过“promising”函数suspend,且Emscripten仅标记main()。main()返回后,每一个浏览器事件(打开对话框的点击)都进入独立栈,suspend会因缺少WebAssembly.promising而中止。

通过三项协同修改解决:

  • 将Qt的DOM事件处理器注册为emscripten::async() embind函数,所有鼠标/键盘事件在promising框架内运行(需Emscripten 4.0+;旧版本有embind+JSPI启动bug)。
  • 同样包装Qt定时器和posted-event回调,确保事件循环触发的suspend也能工作。
  • 将main()重构为async形式:创建应用并返回;浏览器驱动循环。-fwasm-exceptions与旧的“模拟无限循环”技巧不兼容。

经此调整,QDialog::exec()、combo-box下拉、嵌套颜色选择器和上下文子菜单均可任意嵌套,无需应用级对话框重写,平台自动处理。

首版构建在可用窗口大小时仅4–5 fps。分析发现帧时间几乎全部用于Qt函数blend_untransformed_generic_rgb64。原因是Qt WebAssembly后备存储的像素格式为直角透明RGBA8888(HTML canvas所需),非Qt快速路径光栅格式,每次绘制blit回退到通用64位/像素混合,每帧三次。切换为预乘透明ARGB32(Qt优化格式,匹配绘制图层)后,合成走SIMD路径,flush时单一格式转换产生canvas需要的RGBA字节,帧率大致翻三倍——这是全引擎收益,非画布 hack。

浏览器无真实文件系统,Qt的getOpenFileContent / saveFileContent API在此JSPI构建上不可靠(open返回空缓冲,save尝试分块可写流从未产出下载)。两者通过薄JavaScript shim实现:open选择文件,JS读取字节写入Emscripten内存文件系统(MEMFS),然后按路径加载;save序列化至MEMFS,生成Blob并创建合成下载链接。CAD字体(47个.lff文件)和填充图案打包为30 MB数据包,预加载至MEMFS,应用设置通过IndexedDB跨重载持久化。

Brotli压缩将传输从约70 MB降至约18 MB。PDF导出通过QPdfWriter(QtGui模块,PrintSupport不可用时仍存活)实现并下载。自定义HTML shell替换Qt默认加载器,添加启动画面和进度条,无JSPI支持时显示友好提示。

加载后操作示例:

  • 打开DXF:File → Open → 从电脑选择DXF(无文件时,LibreCAD仓库有示例)。
  • 绘制线条和圆形(原文末尾截断,但意为快速草图)。

关键要点

  • 项目纯开源端口,无重实现,仅编译原C++代码为WebAssembly。
  • 依赖Qt官方Wasm支持,全面保留桌面功能(文件读写、图层、块等)。
  • 核心技术障碍是模态对话框(exec()阻塞)与JSPI的嵌套支持,通过注册async embind函数和重构main()解决。
  • 性能优化:切换像素格式至预乘ARGB32,帧率从4-5 fps提升至可使用水平。
  • 文件系统与持久化:使用MEMFS + IndexedDB + Brotli,兼容浏览器限制。
  • 浏览器兼容性:仅Chromium 137+,需JSPI支持。
  • 整体过程“手握”易操作,LLM辅助但技术大致准确,存在潜在bug。

意义与影响

此端口证明了在2026年,WebAssembly已成为运行完整桌面应用的新路径,无需下载安装或网络依赖,适合快速草图、原型设计等场景。Qt团队对Wasm的支持成熟,生态成熟度高,启发开发者将其他C++桌面工具移植至浏览器。

GLM-5.2等AI模型辅助“prompt-to-port”加速了流程,但仍需人工调试(模型缺乏原生视觉和计算机使用能力)。尽管非官方项目,但展示了开源社区与AI结合的潜力:无需重写代码即可获得浏览器原生体验。

潜在局限包括浏览器兼容性要求、性能在复杂图层下仍需优化,以及FAFO风格的bug风险。长远看,此类项目可降低CAD门槛,推动浏览器端协作设计和跨设备使用,推动Qt等框架在Wasm领域的生态扩张。

查看原文 →magik.net