164 lines
9.3 KiB
Markdown
164 lines
9.3 KiB
Markdown
# DWG / DXF 网页查看器
|
||
|
||
浏览器端直接打开 DWG / DXF 图纸,**不经过任何转换服务**。界面沿用新迪 2D 查看器的模板
|
||
(顶栏 + 左侧图层面板 + 底部大图标工具栏 + 浮动子面板 + 状态栏)。
|
||
|
||
配套的 3D 版本在 `../STEPViewer/`;两者的统一入口在 `../index.html`(按文件后缀自动分发,
|
||
入口也支持拖拽打开,文件只在本机流转、不落地)。
|
||
|
||
---
|
||
|
||
## 一、能力
|
||
|
||
| | |
|
||
|---|---|
|
||
| **格式** | `.dwg`(LibreDWG 覆盖 R13 ~ R2018,越新的版本支持度越低)、`.dxf`(ASCII,UTF-8 / GBK 自动识别) |
|
||
| **实体** | LINE / CIRCLE / ARC / ELLIPSE / LWPOLYLINE / POLYLINE / SPLINE(NURBS+拟合点) / POINT / SOLID / 3DFACE / HATCH / TEXT / MTEXT / ATTRIB / DIMENSION / LEADER / MULTILEADER / INSERT(含阵列、嵌套、块内 0 层继承) |
|
||
| **显示** | 图层开关与单层隔离、真实线宽、线型(虚线/中心线)、ACI 与真彩色、**三种背景(浅灰/米白/黑,同新迪 2D)**、过暗/过亮线色按背景自动调整(可关)、剖面线(含 ANSI31~38 内置图案)、文字(中文、MTEXT 格式码/堆叠分数/按框宽折行) |
|
||
| **交互** | 滚轮定点缩放、拖动平移、框选放大、双击全图、**视图旋转(设置里左转/右转 90° + 角度滑杆,旋转后拾取/测量/平移仍然准确)**、点选查属性、对象捕捉(端点/中点/圆心/象限点/最近点) |
|
||
| **测量** | 坐标、点到点、连续、线段长、弧长、点到线、线到线(平行间距 / 夹角)、线性(ΔX/ΔY)、角度、半径直径、面积周长、结果统计;单位/小数位可调,已有结果跟着变 |
|
||
| **批注** | 文字、自由线、直线、箭头、矩形、圆、云线;颜色与线宽可调、可撤销(批注存世界坐标,跟着图纸缩放旋转) |
|
||
| **其它** | 文字全图查找并定位、模型/布局切换、PNG 截图、打印/导出 PDF、全屏(顶栏 + 底部工具栏各一个)、iframe 嵌入模式、上传加密存服务器并生成随机文件名的嵌入链接 |
|
||
|
||
实测(Edge headless,1500×950):
|
||
|
||
| 图纸 | 实体数 | 解析+展平 | 每帧重绘 |
|
||
|---|---|---|---|
|
||
| XQD601线图.dwg(542 KB,CAXA) | 3 865 | 340 ms | 3.1 ms |
|
||
| 行星滚柱丝杠专利图.dwg(2.0 MB) | 29 097 | 991 ms | 6.3 ms |
|
||
| 气垫调整机构.dxf(4.3 MB) | 21 732 | ~1.5 s | 8.8 ms |
|
||
|
||
---
|
||
|
||
## 二、目录
|
||
|
||
```
|
||
DWGViewer/
|
||
├── index.html 界面骨架(新迪 2D 模板)
|
||
├── style.css
|
||
├── app.js UI 装配:加载、图层面板、工具切换、面板、导出
|
||
├── js/
|
||
│ ├── source.js 文件 → 统一文档模型(分发 dwg / dxf,角度统一成弧度)
|
||
│ ├── dxfHatch.js DXF 的 HATCH 补丁解析(dxf-parser 不支持 HATCH)
|
||
│ ├── flatten.js 文档 → 显示列表(INSERT 递归展开、变换烘焙进坐标)
|
||
│ ├── curves.js 圆弧/椭圆/NURBS/bulge 离散化、二维仿射、紧包围盒
|
||
│ ├── hatch.js 填充边界提取 + 图案线生成(奇偶规则裁剪)+ 内置 acad.pat 图案表
|
||
│ ├── mtext.js MTEXT 格式码解析(\P \H \S \F {} 等)
|
||
│ ├── render.js Canvas2D 渲染器、空间索引、拾取
|
||
│ └── tools.js 对象捕捉、测量、批注
|
||
├── libs/
|
||
│ ├── dxf-parser/ MIT,DXF 解析(已改成浏览器可直接 import 的相对路径)
|
||
│ ├── shims/loglevel.js dxf-parser 依赖的 loglevel 替身(importmap 映射)
|
||
│ └── libredwg/ GPL-3.0,DWG 解析(dist 包装 + 10 MB wasm),只在打开 .dwg 时才加载
|
||
├── icons/ 取自新迪 2D/3D 案例的图标
|
||
└── samples/ 测试图纸
|
||
```
|
||
|
||
**数据流**:文件 → `source.js` → `flatten.js` → `render.js`。
|
||
展平只在加载时做一次,把 INSERT 的变换全部烘焙进世界坐标;之后缩放平移只重算屏幕坐标,
|
||
所以三万实体也能保持 6 ms 一帧。
|
||
|
||
---
|
||
|
||
## 三、本地运行
|
||
|
||
```powershell
|
||
python $env:TEMP\nds_server_dwg.py # 端口 8920,服务 dev/ 根目录,日志 %TEMP%\req_log_dwg.txt
|
||
```
|
||
|
||
浏览器打开统一入口 `http://127.0.0.1:8920/index.html`,支持:
|
||
|
||
- 直接带参数(按后缀自动进 2D / 3D 查看器):
|
||
`?file=DWGViewer/samples/XQD601.dwg`、`?file=STEPViewer/samples/as1-oc-214.stp`
|
||
- 落地页选文件 / 拖拽:文件内容经 postMessage 直接送进查看器,只在本机流转
|
||
- 单独打开查看器也行:`/DWGViewer/index.html?file=samples/XQD601.dwg`
|
||
|
||
把 dwg/dxf 直接拖进页面也可以。
|
||
|
||
---
|
||
|
||
## 四、部署
|
||
|
||
纯静态站点,把整个目录传上去即可,**没有服务端依赖**。两个必须确认的点:
|
||
|
||
1. **`.wasm` 的 MIME 必须是 `application/wasm`**,否则 DWG 解析加载不起来。
|
||
Apache 用同目录的 `.htaccess`;nginx 在 `mime.types` 里加 `application/wasm wasm;`。
|
||
2. **开 gzip/br 压缩**。`libredwg-web.wasm` 原始 10 MB,压缩后约 3 MB,差别很大。
|
||
|
||
嵌入到别的页面:
|
||
|
||
```html
|
||
<iframe src="https://你的域名/DWGViewer/index.html?file=图纸路径.dwg&embed=1"
|
||
width="100%" height="640" frameborder="0" allowfullscreen></iframe>
|
||
```
|
||
|
||
`embed=1` 会隐藏顶栏。页面里的「嵌入」按钮可以直接生成这段代码。
|
||
|
||
> 启用防下载(api/*.php + .htaccess)后,图纸文件必须放在 DWGViewer 目录内(如
|
||
> `samples/xxx.dwg`),路径写 `file=samples/xxx.dwg`;`../` 逃出查看器目录的路径
|
||
> 会被令牌通道拒绝(防目录穿越)。
|
||
|
||
---
|
||
|
||
## 五、许可证(重要)
|
||
|
||
| 模块 | 许可证 | 何时加载 |
|
||
|---|---|---|
|
||
| 本项目自身代码 | 自有 | 总是 |
|
||
| `dxf-parser` | **MIT** | 打开 .dxf 时 |
|
||
| `libredwg-web`(LibreDWG) | **GPL-3.0** | **只有打开 .dwg 时**才动态 import |
|
||
|
||
GPL-3.0 的传染性对前端是成立的:wasm 和 js 会下发到浏览器,这构成「分发」。
|
||
商用前请评估。三条可选路线:
|
||
|
||
1. **只对内 / 接受 GPL** —— 按 GPL-3.0 公开本查看器源码,最省事。
|
||
2. **只支持 DXF** —— 删掉 `libs/libredwg/`,`source.js` 里的 `loadDwg` 直接抛错,整套依赖就只剩 MIT。
|
||
代价是用户得先把 DWG 另存成 DXF。
|
||
3. **DWG 解析挪到服务端** —— 用 LibreDWG 的 `dwg2dxf` 命令行做 DWG→DXF(以独立进程调用,
|
||
通常被认为是「聚合」而非衍生作品),前端只留 MIT 的 DXF 路径;或换成 ODA SDK(商业授权)。
|
||
|
||
代码结构已经为此做了准备:`source.js` 里 DWG 只有 `loadDwg()` 一个入口,换掉它不影响其余任何模块。
|
||
|
||
---
|
||
|
||
## 六、已知限制
|
||
|
||
- **SHX 字体不渲染真实字形**。DWG 里的 `.shx` 是矢量字库,浏览器读不了,这里按字体名映射到
|
||
系统字体(`gbcbig`/`hztxt` → 宋体,`txt`/`romans`/`isocp` → Arial)。字形和 AutoCAD 里有差异,
|
||
但内容、大小、位置、对齐都是对的。
|
||
- **DIMENSION 画的是它的匿名块**,也就是文件里存的那份图形,不会按标注样式重新排。
|
||
绝大多数情况这就是 AutoCAD 里看到的样子;只有别的软件生成的、没写块的标注会缺失。
|
||
- **DXF 只支持 ASCII 格式**。二进制 DXF 会给出明确提示,让用户另存。
|
||
- **非等比缩放 + 旋转的 INSERT 里的圆弧**会退化成折线(等比或无旋转时保留解析曲线,
|
||
任意放大都不出锯齿)。这种组合在机械图里极少见。
|
||
- **OLE、光栅图像(IMAGE)、代理实体(PROXY)不显示**,会计入「跳过」统计。
|
||
- `$INSUNITS` 在国内图纸里常年是默认值,所以测量单位默认按毫米,可在「设置」里改。
|
||
|
||
---
|
||
|
||
## 七、防下载(已实现)
|
||
|
||
查看器读站内图纸时走「令牌 → 解密接口」,同时 `.htaccess` 封掉 `.dwg/.dxf/.enc` 的直接 GET:
|
||
|
||
1. 上传(嵌入面板的「上传当前图纸」):`api/upload.php` 把图纸 gzip 后 XOR 加密落盘,
|
||
**落盘名是纯随机 hex**(`uploads/ab12cd34….enc`),原文件名藏在加密体里——
|
||
链接里看不出是哪张图、属于哪个项目,也没法按名字猜其它图纸;
|
||
2. 读取:`api/token.php` 同源校验 + HMAC 短时令牌(5 分钟),`api/model.php` 校验后
|
||
解密流式返回,原文件名通过 `X-Filename` 头带回来显示;
|
||
3. `.htaccess`(站点根 + `api/` 目录双层)禁止源文件直链。
|
||
|
||
`app.js` 的 `fetchDrawing()` 会自动走令牌流程;接口没部署(纯静态托管/本地 python)
|
||
时自动退回直连,不影响开发。部署 PHP 后无需任何前端改动。
|
||
|
||
**部署注意**:`token.php` / `model.php` / `upload.php` 里的 `SECRET` 三个文件必须一致,
|
||
并且要改掉默认值。`uploads/` 目录要有写权限。
|
||
|
||
**群晖/nginx(.htaccess 不生效)**:`upload.php` 和 `model.php` 已预设
|
||
`$PRIVATE_DIR = '/volume1/dwgviewer_private';`——在 File Station 里于 Web 目录外建这个
|
||
文件夹并给 `http` 用户组读写权限(路径不对就改成实际路径)。图纸存私有目录,嵌入链接写
|
||
`?file=纯文件名.dwg`;留在 Web 目录里的样例按原路径仍可打开,但可被直链下载,
|
||
要保护的文件必须移进私有目录。
|
||
|
||
网页端无法绝对防抓包(数据最终要进浏览器内存,懂行的人总能从调试台把解密后的字节导出来),
|
||
这套方案挡的是直接下载、批量爬取和链接外传后的猜名。
|