尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

CAD图纸无损嵌入TinyMCE:SVG矢量转换方案与工程实践

CAD图纸无损嵌入TinyMCE:SVG矢量转换方案与工程实践 很多芯片制造厂的工程师都遇到过这个场景在工艺问题单、设备异常报告或者技术评审文档里需要把CAD图纸贴进去让同事一眼看清问题位置。可TinyMCE富文本编辑器默认吃进去的是一张位图缩放了模糊图层信息直接丢失在产线上看一个晶圆缺陷位置还得翻来覆去比对坐标。后来我把这套流程彻底重构了让CAD图纸以SVG矢量形式进入TinyMCE不仅在浏览器里可以无限放大看细节还能保留图层、标注和精确坐标。这篇就分享一下我的完整方案和踩坑记录。1. 位图粘贴的行业痛点晶圆厂图纸为什么不能将就1.1 芯片制造场景下CAD图纸的特殊性芯片制造企业的CAD图纸和普通机械加工厂有很大不同。Fab里的图纸不只是画了一条线或者一个孔它往往包含掩膜版图Mask Layout、晶圆划片槽结构、封装基板布线、设备腔体法兰接口等。这些图纸里最关键的信息是坐标精度和层叠关系。比如一个缺陷分析报告工程师需要贴一张晶圆缺陷分布图图上每个点的XY坐标偏差要在微米级。如果用截屏方式把CAD视图粘到TinyMCE变成一张PNG读图的人放大到200%还能勉强看清放大到500%基本就是马赛克。更致命的是位图不会带原始坐标信息无法通过点击图上的某个点直接读到设计坐标整个缺陷定位流程就断了。而在TinyMCE这种Web富文本编辑器里默认的图片粘贴行为就是把剪贴板里的位图数据通常是PNG转成data:image/png;base64,...然后插入img标签。这个机制在普通办公场景没问题但到了半导体工程环境就变成了一条不可接受的死路。1.2 位图方案在实际使用中的四个问题我归纳了位图粘贴在芯片制造企业里一定会遇到的四个问题这四个问题基本覆盖了从产线到质量、从工艺到设备的全部场景。第一精度丢失。CAD图纸的核心是尺寸和坐标位图每个像素对应一个固定的物理尺寸当你把图缩小再放大像素点的插值会让边缘变得模糊原本0.5um的线宽在视觉上可能变成1.5um对于做工艺窗口分析的人来说这是致命误导。第二图层信息全没了。CAD图纸里通常把设备层、结构层、标注层、辅助层分开管理位图粘贴出来是一张合并的图无法单独关闭某一层。工程师想只看金属走线层对不起只能看到一张大杂烩。第三文件体量失控。高分辨率的位图一张可能几MB甚至十几MB如果一份报告里有几十张图TinyMCE保存到服务器后整个页面加载会变得极其缓慢。而且以base64形式塞进HTML还会额外膨胀33%。第四不可交互。位图只能看不能点选图元不能悬停查看属性不能测量距离。这等于把一个原本是“活”的CAD图纸变成了一张“死”的图片。这些痛点叠加在芯片制造的工程协同场景里会导致一个结果大家为了看图纸细节还是得回到CAD软件里打开原始文件TinyMCE里的图只是一个“占位符”几乎没有信息价值。所以矢量输出不是一种锦上添花而是工程协作的刚性需求。2. 核心思路让CAD数据以SVG形态进入TinyMCE2.1 为什么选择SVG而不是其他矢量格式要解决位图问题首先得确定“矢量输出”到底用什么格式。市面上有几种选择EMF/WMFWindows图元文件、SVG可缩放矢量图形、PDF嵌入、DXF/DWG原始数据。EMF是很多Windows版CAD复制到剪贴板时的默认格式也是直接从CAD软件复制图纸然后粘贴到TinyMCE时编辑器最先收到的数据格式。但EMF不能直接在浏览器里渲染TinyMCE不识别它往往会在后台转成位图导致矢量信息被抹掉。而且EMF对不同平台的兼容性不好Mac和Linux上的浏览器基本无法原生显示。PDF可以作为矢量载体但在HTML编辑器里嵌入PDF的交互体验并不好浏览器要么直接下载要么用插件展示无法和正文文字流畅地混排。DXF/DWG原始数据虽然信息最全但浏览器不能直接渲染需要前端做大量解析和坐标系转换。最终我选了SVG。原因很直接SVG是HTML原生支持的矢量格式能内联到DOM里不需要额外的查看器体积比位图小得多支持图层通过g分组、文本、路径、事件绑定甚至可以在SVG内部挂自定义的>POST /api/cad/to-svg Content-Type: multipart/form-data file: demo.dwg pageWidth: 1200 scale: auto layers: METAL1, METAL2, PAD, TEXT outputMode: inline_svg后端核心代码片段Java Aspose.CADpublic String dwgToSvg(MultipartFile file, int pageWidth, ListString layers) { Image cadImage Image.load(file.getInputStream()); SvgOptions svgOptions new SvgOptions(); // 关键参数设置SVG画布宽度 svgOptions.setWidth(pageWidth); // 如果指定了图层则过滤显示 if (layers ! null !layers.isEmpty()) { CadRasterizationOptions rasterizationOptions new CadRasterizationOptions(); rasterizationOptions.setLayers(layers.toArray(new String[0])); svgOptions.setRasterizationOptions(rasterizationOptions); } ByteArrayOutputStream baos new ByteArrayOutputStream(); cadImage.save(baos, svgOptions); return baos.toString(StandardCharsets.UTF_8.name()); }这里有两个参数需要特别注意。一是pageWidth不能随便设。图纸原始比例是1:1的物理坐标输出到SVG时要确定一个显示基准宽度否则插入TinyMCE后可能小得看不到或者大到撑破页面。我这里根据CAD图纸的外包围盒BoundingBox自动计算合适的pageWidth让图纸长边换算成1200px短边按比例缩放。二是layers过滤。芯片制造厂的图往往包含几十个图层但一份问题报告通常只关心其中两三个图层。把所有图层都导出会让SVG文件很大而且信息太杂。我在转换前提供图层列表让用户在TinyMCE的图片属性面板里勾选需要导出的层默认只导出主要结构层。还有一个隐藏细节CadRasterizationOptions里有个setDrawType参数可以控制是输出矢量还是栅格。这里必须设置成UseObjectColor或UseDrawColor之类的矢量绘制模式如果走成了DrawType.Raster那又会得到位图前功尽弃。3.3 转换结果的体积与清晰度实测拿一份典型的3英寸晶圆划片槽布局DWG做测试原始文件大小是2.4MB含约85个图层、42000多个图元。用上面的转换服务导出指定只保留METAL1、METAL2、PAD、TEXT四个图层输出SVG大小约86KB是原始DWG的3.5%是同等分辨率PNG的1/8左右。用浏览器打开缩放到8000%依然可以看到清晰的直角线和圆弧边界这个精度和灵活度对于缺陷定位来说足够了。那一份带高度填充的多边形区域在SVG里会转成path填充虽然文件体积略有上升但整体仍然在可控范围。4. TinyMCE的SVG插入与安全策略4.1 配置TinyMCE允许SVG标签和自定义插件转换服务返回的SVG是一段完整的XML字符串。直接往TinyMCE的HTML里怼默认会被TinyMCE的valid_elements过滤掉因为TinyMCE只认为img、iframe等标签是合法的媒体元素不认识svg、g、path这些。解决办法是在TinyMCE初始化时扩展valid_children和extended_valid_elements把SVG相关的标签和属性加进白名单。我的初始化配置里做了两件事允许根节点下直接放SVG以及允许SVG标签携带标准属性。tinymce.init({ selector: #engineer-doc-editor, valid_children: body[svg], extended_valid_elements: svg[version|xmlns|width|height|viewbox|x|y|enable-background|xml|space|preserveaspectratio],g[transform|fill|stroke|stroke-width],path[d|fill|stroke|stroke-width|fill-rule],polygon[points|fill|stroke],polyline[points|fill|stroke],rect[x|y|width|height|rx|ry|fill|stroke],text[x|y|font-family|font-size|fill], fullpage: false, paste_data_images: true, ... });注意viewbox属性在HTML里虽然不区分大小写但SVG标准是驼峰命名。TinyMCE的extended_valid_elements里如果写成viewbox它存储的是小写浏览器解析时同样能识别。实际测试没问题但为了严谨建议在HTML源码里保留viewbox。4.2 拦截粘贴事件从剪贴板EMF到SVG的完整链路用户从AutoCAD里CtrlC复制一张视图切到浏览器CtrlV粘贴到TinyMCE时浏览器剪贴板里通常有多个类型的数据文本、HTML、DIB设备无关位图、EMF增强型图元文件。TinyMCE默认取位图数据塞进img。我的做法是在TinyMCE的init里监听paste事件在它执行默认逻辑之前拦截下来判断剪贴板里有没有EMF数据如果有走自定义流程。editor.on(paste, function(e) { const clipboardData e.clipboardData || window.clipboardData; const items clipboardData.items; let hasEmf false; let emfBlob null; for (let i 0; i items.length; i) { if (items[i].type image/x-emf) { hasEmf true; emfBlob items[i].getAsFile(); break; } } if (hasEmf) { e.preventDefault(); uploadEmfForSvgConversion(emfBlob, function(svgString) { editor.insertContent(svgString); }); } });这里有一个很关键的坑Chromium浏览器暴露出来的EMF类型是image/x-emf但Safari和Firefox并不能直接读到EMF格式它们只给image/png。如果你是在Mac上测试大概率拿不到EMF。所以这条拦截逻辑并不能覆盖所有终端。我们的做法有两条腿一是在Windows PC上走EMF拦截转换因为FAB和工艺工程师绝大多数用Windows二是对Mac用户提供另一条路——拖拽DWG/DXF文件上传到TinyMCE后端转换后插入SVG。这样两条腿走路覆盖完整。4.3 防XSSSVG净化不是可选项SVG本质上是XML里面可以嵌入script标签、onload事件、hrefjavascript:等危险内容。一个恶意的DWG文件在导出时被注入了恶意SVG或者一个包含外部实体的图纸被转换后嵌入页面都可能造成XSS攻击。在半导体的内网环境里这不仅是网络安全问题还可能变成产线数据泄露的入口。所以在把SVG插入TinyMCE之前必须做一次严格的净化。我的处理是后端转换时已经过滤了大部分危险元素但前端还会用DOMPurify再兜一层。import DOMPurify from dompurify; const cleanSvg DOMPurify.sanitize(svgString, { USE_PROFILES: { svg: true, svgFilters: true }, FORBID_TAGS: [script, foreignObject, iframe, object, embed], FORBID_ATTR: [onload, onerror, onclick, href, xlink:href] }); editor.insertContent(cleanSvg);要注意的是USE_PROFILES里的svgFilters: true因为我们有的图纸需要滤镜效果比如高亮缺陷区域。如果不需要滤镜可以关闭来减少风险面。4.4 在TinyMCE里让SVG“可感知图层”把SVG插入编辑器只是第一步更实用的是让用户能调整SVG显示属性。我给TinyMCE写了一个插件插入SVG时自动在SVG外层包一层.cad-svg-wrapper的div并用>FontSettings.setDefaultFontName(SimSun);但如果图纸里指定了特殊字体还需要手动设置CadRasterizationOptions.setFontNameList做映射。测试下来只要字体映射正确中文标注在SVG里完全正常而且因为是文本矢量保存的SVG里依然是可选中、可搜索的文本节点这一条对于后续做内容检索非常有价值。5.2 问题二超大图纸转换超时或服务卡死芯片厂偶尔会有几百MB的大型版图文件用于整片晶圆或者整个掩膜版的分析。这种文件传到转换服务后Aspose.CAD的转换时间可能长达几分钟如果中间有人重复提交服务内存直接溢出。我做了三件事限制上传文件最大50MB超过的走异步任务队列不占用HTTP线程。在转换前读取DWG的包围盒如果图元数量预估超过10万个自动降低SVG路径精度简化曲线点密度避免生成超大SVG。转换服务部署时限制Java堆外内存并设置单任务超时时间为120秒超时后杀掉任务并返回明确错误信息。实测一份48MB的晶圆版图DWG经过简化后输出SVG 2.1MB转换耗时17秒虽然不算快但是功能可用。5.3 问题三TinyMCE过滤机制把SVG的部分属性吃掉我在第4.1节已经加了extended_valid_elements但测试时发现一个诡异现象插入的SVG在TinyMCE源代码视图里是完整的但切换回可视化视图再切回来fill-rule属性消失了导致某些图形填充区域显示异常。原因是TinyMCE内部的Schema对HTML属性有大小写归一化处理fill-rule会被识别为无效属性并剥离。解决方法是把属性名改成符合HTML5语法的fillRule然后在渲染到浏览器时SVG会自动识别驼峰形式。但要注意如果SVG要在别的标准XML环境里使用驼峰写法可能不兼容。我最终采取的方法是在TinyMCE内通过自定义的init_content钩子把保存时的fillRule临时转换成fill-rule做到对TinyMCE内部和SVG标准都友好。这个细节如果不是做了一遍完整测试根本发现不了。5.4 问题四坐标数据在SVG里的精确度保留芯片制造讲究坐标精确到微米甚至纳米级。CAD图纸的数据模型使用64位浮点数但SVG在浏览器里绘制时受限于屏幕分辨率过大的数值比如1e7可能导致渲染抖动或路径断裂。处理方式是在后端转换时做坐标归一化。我把所有坐标减去图纸左下角的最小坐标形成相对坐标然后按合适比例缩放。这样既保留了相对位置关系又避免数值过大。原始绝对坐标则作为自定义属性保存比如>svg>
返回列表