
我们厂最近上线了一套ECN工程变更通知线上评审系统Web端富文本用的TinyMCE。工程师习惯把CAD图纸直接复制粘贴到单据里结果不出所料——粘贴进去的全是马赛克级别的位图。版图评审要看的是1μm以下的线宽和间距这种图贴上去等于没贴。于是项目组被问了一个直接的问题能不能让CAD图纸粘贴到TinyMCE时保持矢量输出这个需求在芯片制造企业里非常典型但网上的资料大多停留在“TinyMCE图片粘贴插件”层面没有专门讲CAD矢量输出的。这篇文章把我从需求分析、方案选型、后端转换、前端配置到实际压测踩坑的完整过程整理出来给后续做类似CAD图纸Web化改造的同行一个参考。1. 芯片工厂里的“复制-粘贴”为什么就那么难1.1 一个真实的评审场景我们厂的信息化团队接到的实际需求是工程师在发起ECN工程变更通知时要把CAD图纸作为依据贴到变更说明里——不是给个附件了事是要求在单据正文里直接看到图、能缩放、能测量。第一次试水时工程师直接从AutoCAD里框选图形CtrlC再切到浏览器里CtrlV。结果贴进去的是位图放大到150%就开始糊拉到500%连引脚间距都看不清更别提让人在线阅读审查版图细节了。这不是个案芯片行业里几乎每个产线都会碰到工艺菜单、掩膜版图、封装框架图、量测点位图全都要贴到MES/PLM/ECN系统里做评审。我们当时的第一反应很简单是不是TinyMCE不支持其实问题没这么浅根子在CAD复制的剪贴板格式和Web端渲染机制之间原本就有一段很大的断层。1.2 剪贴板里的“多格式竞争”AutoCAD在复制对象时会往剪贴板里写一组格式列表。Windows下通常包括AutoCAD Object私有OLE格式包含完整的CAD实体数据Enhanced MetafileEMFWindows增强型图元文件矢量性质但只保留绘图指令BitmapBMP位图栅格有些场景还带AutoCAD Drawing、CF_DIB等Web浏览器读剪贴板时能碰到的通常是text/html、text/plain、image/png这类几乎拿不到AutoCAD的私有OLE实体数据也无法直接把AutoCAD Object解释成网页可渲染的内容。绝大多数富文本编辑器包括TinyMCE在拿到剪贴板里的EMF/BMP时往往会转成位图或者直接舍弃。于是“粘贴CAD图纸”这个动作在Web侧天然就会降级成一张粗糙的位图。为什么不能接受位图芯片行业的图纸不是给人“看个大概”的它是制造依据。评审时要量线宽、比间距、看标注位图打印到A3纸上一放大就掉精度而且位图里的文字不可检索、不可搜索后期追溯非常痛苦。更麻烦的是位图无法支持自动比对审完一张图发现“视频模糊”根本无法满足ISO审计对证据链的要求。所以项目经理当时下了死要求必须实现矢量输出至少得让我能放大看清。这个“矢量”两个字把所有截图方案全部否掉了。2. 三个可选技术路线与取舍既然确定了目标下一步就是方案选型。我们当时梳理出三条可落地的路线每一条都各有利弊这里我把选择逻辑也讲清楚方便你结合自己的环境做判断。2.1 路线ACAD客户端插件导出SVG在AutoCAD里通过.NET/ARX写一个插件用户在CAD中选择对象后一键导出成SVG字符串再自动写入剪贴板或者通过本地HTTP服务推给浏览器。优点是数据最完整直接从CAD内核拿实体可以随意控制图层、颜色、比例理论上精度最高。缺点是团队要维护CAD插件版本受AutoCAD版本绑定插件分发到上百台工程师电脑也不轻松而且操作链路变长先开CAD、再插件、再粘到Web系统。对产线IT来说接一个“必须装客户端才能正常用”的流程后续维护成本不低。2.2 路线B上传DWG/DXF服务端转换SVG用户在Web端直接把DWG/DXF文件上传后端调转换引擎生成SVG再把SVG插进TinyMCE正文。这条路径对用户最友好不用装任何东西在浏览器里选择文件上传即可。它的优势对企业级应用特别明显转换过程留在服务端可以做审计日志、可以做水印、可以做权限校验业务数据不会散落到个人电脑。缺点是服务端要部署转换服务商业引擎通常有授权费用而且要处理好大文件的超时、并发和缓存。从工程角度讲这套架构其实是在“用户体验”和“管控要求”之间找到了一个平衡点。2.3 路线C拦截粘贴事件解析EMF转SVG保留原本“CtrlC → CtrlV”的习惯。在TinyMCE的粘贴事件里拦截如果检测到剪贴板里有EMF格式就把EMF二进制传给后端的转换服务例如Inkscape命令行或其他EMF解析库转为SVG再回到前端插入。这条路用户体验最好用户完全无感但它有几个坑首先剪贴板里的EMF可能已经丢失部分CAD精确语义比如某些文字实体、线型信息会被简化为绘制指令其次EMF的坐标精度虽好但经过系统剪贴板传递后不同AutoCAD版本导出的EMF质量参差不齐第三要兼容各浏览器对剪贴板数据的暴露方式Chrome和Edge暴露EMF的时机并不完全一致。整体实现难度和不确定性在三条路线里最高。2.4 让我做出决定的那些理由对比下来在芯片工厂的实际场景里我优先推荐路线B作为主链路路线C作为体验增强路线A看团队人力情况决定做不做。原因是芯片企业内部系统对合规和审计看得非常重所有关键图纸都必须留痕。上传转换的方式天然把“谁传了哪个文件、转换成什么结果”记在系统日志里而且原始DWG/DXF可以作为附件一起归档SVG只负责在Web端做可视化。这在外部供应商审计、内部质量内审时都站得住脚。路线C可以保留用户习惯但EMF的解析质量不稳定建议只对“快速看图”场景开放不允许作为正式评审依据。我们最后采取的组合是主入口做上传转换同时把EMF解析做成一个隐藏的增强能力在支持的浏览器里顺手接住。3. 后端DWG→SVG转换引擎的选型与集成细节3.1 转换引擎横向对比这一步是整个项目的核心。业内主要转SVG的方案我用一个表简单说清楚方案类型对DWG的支持转换质量成本Aspose.CAD商业库.NET/JavaDWG/DXF/DWF全支持高图层/文本/块处理完善有授权费用可按年订阅ODAOpen Design AllianceFile Converter免费命令行工具支持DWG各种版本兼容性较好但输出SVG需要再处理免费但要注册并遵守其许可条款LibreDWG开源C库主要支持DXFDWG支持有限偏基础解析复杂实体可能丢失开源免费dxf2svgnpm开源包仅DXF轻量几何转换对复杂文字/线型支持一般开源免费坦白讲没有任何一个工具能开箱即用地保留DWG全部语义到SVG。CAD世界里版本多、实体类型多、第三方扩展实体更是千奇百怪转出来多少会打折扣。我们需要在精度和可用性之间找平衡。综合评估后我们选了“ODA转DXF dxf2svg/自研解析出SVG”的轻量链路这个组合免费、可控而且对常见的版图和封装图效果已经足够。如果你的预算充裕且对转换质量要求极高可以直接评估Aspose.CAD省去自己造轮子的时间。3.2 我踩过的转换链路坑第一次搭建时我天真地想一步到位DWG直接转SVG。结果发现ODA虽然免费但它的SVG输出模式并不总能满足TinyMCE的嵌入需要坐标原点、颜色映射、图层命名都对不上。后来改成了两步DWG → DXF用ODA File Converter的批处理命令行 DXF → SVG用dxf2svg按需要做二次清洗批处理命令大概是这样的ODAFileConverter D:/projects/cad/dxf_out D:/projects/cad/svg_in ACAD2018 DXF 0 1 *.dwg注意ODAFileConverter的工作方式输入输出目录是分开配置的它会扫描输入目录里的文件转换成目标格式放到输出目录而且要求输入和输出目录不能相互包含。这个细节当年折腾了我一晚上老是在批处理里报“目录冲突”。如果你也用它先把目录结构准备好再跑命令能省掉很多排查时间。DXF转SVG阶段先过滤无用图层和不可见的块引用再遍历ENTITIES段转为SVG的path/polyline/circle等元素。其实dxf2svg的开源代码里已经帮我们处理了大部分基础实体但文字部分太粗糙后来我改成自行解析TEXT/MTEXT把DXF里面的字符串、高度、旋转角映射为SVG的text元素这样中文字体和旋转角度才能对上。3.3 单位、比例与图层最容易被忽略的精度问题芯片行业图纸的单位非常乱。有的用mm有的用mil部分版图环境甚至用纳米当量单位。SVG本身没有物理单位的强概念显示的尺寸由width、height和viewBox共同决定。我的做法是在转换时读取DXF的$INSUNITS变量和图纸比例统一转成毫米然后把“1mm对应多少SVG单位”写进viewBox里前端再根据图纸实际物理尺寸设定显示宽度。比例换算写出来很简单但实际工程里我吃了一次亏。有一张封装图纸标注是“长度10.00mm”转完SVG用截图工具一量宽度撑满屏幕却只有标称值的一半。排查半天发现DXF里$INSUNITS是0未指定ODA输出时按英寸默认值处理了。最后我加了一道保险策略转换前先强制把图纸单位归一化到毫米再写一个校验任务自动比较已知距离标注和SVG实测的比例系数是否一致不一致直接告警。这个校验必须自动化否则在几十张图纸里人工核对会疯掉。字体也是一个高频坑。图纸里的仿宋、HZ、SHX字体在服务器转换环境里大概率没有安装结果转出来的SVG里中文全变成方块或乱码。后来我把常用的中文字体TTF统一打到服务器转换环境里并维护了一张“CAD字体名→服务器字体名”的映射表这才基本解决。这个映射表一定要跟着项目走每遇到一种新字体乱码就补一条后面越来越顺畅。4. TinyMCE侧的关键配置放开SVG并保持可编辑4.1 默认行为TinyMCE会剥掉SVG即使后端把SVG生成了前端TinyMCE默认也不会放行。TinyMCE有一套schema白名单机制普通配置里不包含svg、path这些标签直接把SVG HTML塞进editor.insertContent()的结果就是所有标签被剥离只留下一堆不可见的文本或空内容。这个坑非常典型社区论坛上经常有人问“为什么我SVG粘贴不进去”。解决方案是显式告诉TinyMCE允许哪些元素。我的配置大致如下tinymce.init({ selector: #contentEditor, extended_valid_elements: svg[*],defs[*],g[*],path[*],line[*],circle[*],rect[*],polyline[*],polygon[*],text[*],tspan[*], custom_elements: svg,defs,g,path,line,circle,rect,polyline,polygon,text,tspan, paste_preprocess: function(editor, args) { // 在这里处理剪贴板中的非SVG格式比如识别EMF并转发给后端转换 } });extended_valid_elements是追加白名单custom_elements是告诉编辑器这些是自定义或非标准元素两者缺一不可。只配前者的话部分浏览器版本里SVG依然会被改写成奇怪的HTML结构。另外如果你的TinyMCE版本比较老4.x早期可能对custom_elements的支持有差异建议先做一次最小Demo验证。4.2 插入SVG的推荐姿势拿到后端返回的SVG字符串后我不建议用editor.setContent()全量覆盖那样会把用户已经写好的正文清掉。正确做法是使用editor.insertContent()插入到光标位置fetch(/api/dwg-to-svg, { method: POST, body: formData // 包含上传的DWG/DXF文件 }) .then(res res.json()) .then(data { const svgWrapper div classcad-svg-wrapper>