芯片制造企业里,文档系统、评审记录、问题追踪单基本都是Web化的,TinyMCE是使用率很高的富文本编辑器。但有一个场景一直让人头疼:工程师在CAD软件里画好的版图、封装图、设备结构图,需要贴到TinyMCE里写工艺评审报告或异常分析单,直接Ctrl+V一贴,放大一看全是马赛克,关键尺寸、焊盘位置、走线细节全糊了。很多团队最后只能“截图另存为PNG再上传”,这不仅效率低,而且严格来说已经丢掉了图纸的矢量精度。这篇文章我会从剪贴板协议、TinyMCE的粘贴处理机制、后端转换服务搭建,一步一步拆解如何让CAD图纸以真正的矢量SVG形式进入TinyMCE,并且能正常保存、预览、导出。芯片行业对精度的敏感度极高,这个方案同样适用于其他需要处理工程图纸的Web系统。
1. 芯片工厂的图纸,为什么不能“截图粘贴”了事
1.1 一张失真的图纸在评审记录里意味着什么
在芯片制造企业里,TinyMCE通常不是孤立存在的,它嵌在PLM系统、NPI(新产品导入)评审系统、设备异常报告系统或工艺变更管理系统里。工程师写完一段分析,配上一张晶圆缺陷图或封装引线框架图,保存后这份记录就进入审批流,最后归档。
这里面有一个被很多人忽视的问题:图纸一旦以位图形式进入文档,它的计量价值就基本归零了。芯片行业的图纸精细到微米甚至纳米级,一个焊盘22um,画在屏幕上是10个像素,打印出来或者投到评审大屏上可能就只有3个像素。你没法从一张模糊的位图里去确认“这个尺寸是否真的符合规格”。更重要的是,很多企业的质量体系要求图纸必须可测量、可追溯,位图不满足这个要求。
我见过不止一次这样的场景:封装工程师贴了一张放大后全是锯齿的BGA封装图到异常分析单里,质量经理在审批时为了确认一个间距尺寸,不得不把原始CAD文件重新调出来对照。这一来一回,可能半天时间就耗掉了。所以问题不是“好不好看”,而是“这份文档作为工程记录,是否还具备有效性和可追溯性”。
1.2 TinyMCE默认粘贴管道对矢量图做了什么
TinyMCE的粘贴行为,核心逻辑是把操作系统剪贴板里的内容转换成HTML再插入编辑器。官方paste插件提供了paste_preprocess和paste_postprocess两个钩子供开发者干预。但不加任何配置时,它面对CAD软件复制出来的数据,走的是一条“向下兼容”的路径。
这里有个关键点:当你从AutoCAD、KiCad、Cadence Virtuoso或者SolidWorks里复制图形时,剪贴板里并存着好几种格式的数据。有矢量格式(比如EMF),有源文件格式(比如DWG的OLE对象),也有最通用的位图格式(BMP/PNG)。TinyMCE无法理解DWG或DXF,它唯一能稳定读取的就是位图。
所以默认情况下,TinyMCE会把位图这一份“兜底数据”提取出来,转成dataURL或Blob插入编辑器。结果就是:矢量信息被丢弃,精度信息被丢弃,图层信息被丢弃,只留下一张静态图片。
注意:TinyMCE这里并没有做错什么,它是在“通用性优先”的前提下做一个合理选择。真正的问题在于,CAD软件往剪贴板里塞的矢量数据(EMF)在浏览器端不原生支持,而TinyMCE又没有能力去调用外部转换工具。
1.3 问题的本质:剪贴板协议里没有“CAD原生格式”
要解决这个题目,首先要接受一个事实:浏览器没有能力直接用DWG或DXF格式。你想让TinyMCE原生识别CAD文件,目前不现实。但矢量输出是可以做到的,路径就藏在“剪贴板里至少有矢量格式数据”和“后端服务器可以完成格式转换”这两个条件下面。
如果把整个问题拆开,其实就是三个子问题:
- 提取:如何在粘贴事件发生时,拿到剪贴板里那份矢量或源文件数据;
- 转换:如何把拿到的数据转成浏览器能渲染的SVG;
- 注入:如何让TinyMCE接受SVG,并且保存时不被过滤掉。
这三个子问题没有一个是“依赖TinyMCE魔法就能解决”的,都需要在集成层自己动手。下面我会分别展开讲。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 先搞清CAD软件往剪贴板里放的是什么
2.1 剪贴板的多格式并存机制
Windows剪贴板支持在一个复制操作中同时放置多种格式的数据,从上到下按优先级排列。常见的格式有CF_BITMAP(位图)、CF_ENHMETAFILE(增强型图元文件,也就是EMF)、CF_HDROP(文件列表)、OLE私有格式等。
当你按下Ctrl+C复制CAD图形时,CAD软件会“尽力而为”地往剪贴板里塞它认为有用的格式:
| CAD软件 | 复制图形时剪贴板里通常存在的内容 |
|---|---|
| AutoCAD | EMF矢量图、BMP位图、可能还有DWG的OLE对象 |
| Cadence Virtuoso | 位图(多数是屏幕截图级),支持导出DXF后复制文件 |
| KiCad | SVG/PNG,取决于复制方式,可选择复制为图片 |
| SolidWorks / Creo | EMF、BMP、还有3D模型的预览位图 |
| Altium Designer | EMF、BMP、PCB的OLE对象 |
这个表格想说明的核心问题是:EMF是Windows生态里最常出现的CAD矢量交换格式,但浏览器不认它。 而真正的DWG/DXF源文件,很少直接被复制进剪贴板,除非用户主动从文件管理器里复制文件(即CF_HDROP格式)。
2.2 浏览器端能拿到哪一部分
浏览器里的剪贴板事件(paste事件)提供了clipboardData对象,通过它我们只能读取到浏览器“允许读取”的格式。对于Web应用来说,能稳定读取的是:
text/plain:纯文本;text/html:富文本HTML;text/uri-list:链接;Files:文件对象(当复制的是文件时)。
而EMF这类系统格式,浏览器不会直接暴露给JavaScript。这就意味着,你不能指望纯前端方案从剪贴板里抠出EMF矢量数据。能做的是:要么用户通过“粘贴为文件”或“拖拽上传”的方式把DWG/DXF文件交给系统;要么走OLE对象提取,但这条路在Web端同样走不通。
2.3 在浏览器里摸清剪贴板底细的方法
在写正式代码之前,我建议你先做一个探针页面,把粘贴事件里能看到的类型全部打印出来。这个页面很简单,但信息量很大:
javascript复制document.addEventListener('paste', (e) => {
const items = e.clipboardData.items;
for (let i = 0; i < items.length; i++) {
const item = items[i];
console.log('kind:', item.kind, 'type:', item.type);
if (item.kind === 'file') {
const file = item.getAsFile();
console.log('file name:', file.name, 'size:', file.size);
// 这里不要急着读,先确认类型
}
}
console.log('HTML:', e.clipboardData.getData('text/html'));
console.log('Text:', e.clipboardData.getData('text/plain'));
});
实测下来常见的几种情况:
- 从AutoCAD复制图形后直接粘贴,浏览器大概率只看到一份BMP或PNG位图,类型是
image/png或image/bmp,没有文件对象。 - 从文件管理器复制DWG文件再粘贴,则会看到
kind: file,type可能是空或application/octet-stream,文件对象的名字就是xxx.dwg。 - 从浏览器页面复制SVG图片,会看到
text/html字符串里包含<svg>标签,这个可以直接用。
2.4 哪些数据能作为矢量来源
说完探测结果,把可行矢量来源理一理。在实际项目中,我总结出三条有效的获取链路:
- 用户以文件形式上传/粘贴DWG、DXF源文件:这是最可靠的一条路。文件到了后端,转换工具任你挑,精度有保证。
- 从剪贴板的HTML片段中提取SVG:适用于从网页端、SVG素材库复制的图纸,这种情况比较少,但处理逻辑简单。
- 从系统级复制得到的EMF位图对,转换后重新矢量化:这条路工程价值低,因为EMF在Web端不可读,需要后端解析,而且EMF本身对一些实体支持有限。
所以,别在“纯前端从剪贴板抠矢量”这条路上死磕。真正靠谱的架构是:前端负责拦截粘贴事件并收拢文件,后端负责转换矢量为SVG,TinyMCE负责展示和保存。
3. 整体架构:前端拦截 + 内网转换服务
3.1 候选方案对比
来挑方案。基于“能让TinyMCE输出SVG”这个目标,市面上的做法大概有四种,我直接给对比。
| 方案 | 精度保障 | 开发成本 | 用户操作负担 | 适用场景 |
|---|---|---|---|---|
| 纯前端解析DXF生成SVG | 中等 | 中高 | 需要用户上传文件 | 图纸不太复杂、无内网服务可用的场景 |
| 后端微服务转换 | 高 | 中 | 低,粘贴即转换 | 芯片制造企业的标准选择 |
| 前端调用桌面插件 | 高 | 高 | 需要装桌面程序 | 极少用,维护成本过高 |
| 直接放弃矢量,用高分辨率位图 | 低 | 低 | 低 | 精度要求不高的初步方案 |
芯片制造企业,我的建议非常直接:选后端转换服务。不是因为前端方案技术上做不到,而是因为芯片图纸普遍大、图层多、单位精度要求高,纯前端的JS解析库在这种场景下性能容易失控。而且很多芯片企业内部本来就有解析DXF/DWG的桌面工具或库,封装成服务是顺理成章的事。
3.2 架构分层与数据流
整个系统做下来,大概是这样的分层:
code复制浏览器端(TinyMCE编辑器页面)
├── Paste拦截模块:监听paste事件,识别文件或位图
├── 上传/转换请求:把源文件发到内网转换服务
└── 插入SVG:拿到转换结果后插入编辑器
内网转换服务(可独立部署)
├── 接口层:接收DWG/DXF文件,返回SVG
├── 转换引擎:ODA File Converter / LibreCAD / 自研解析
└── 后处理:图层合并、精度校验、SVG净化
存储层
├── 原始文件:DWG/DXF按版本归档
└── 转换产物:SVG单独存储,或Base64内嵌进HTML
这个流程里有一个很多人会忽略的关键点:原始CAD文件一定要存下来。即使TinyMCE里已经插入了SVG,评审、审批、审计过程中依然可能需要原始DWG文件。所以不要把转换服务设计成“上传后只返回SVG、原始文件丢弃”,而要同时做归档。
3.3 与TinyMCE生命周期的衔接点
TinyMCE的粘贴流程里,有多个可以干预的节点。我的做法是这样分工:
paste_preprocess:在TinyMCE把剪贴板内容变成HTML之前拦截。这里适合做两件事:一是判断剪贴板里有没有文件对象,有的话直接走上传转换;二是如果是纯位图,提示用户“请用上传图纸功能”。paste_postprocess:在HTML插入编辑器之前对内容做最后清洗。这里适合放一些SVG的合规性检查和修正。- 自定义工具栏按钮:提供一个“插入CAD图纸”按钮,走文件选择器上传,路径和粘贴完全复用。
提示:
paste_postprocess里拿到的已经是TinyMCE解析过的HTML树,此时再想做“把位图替换成SVG”这类操作会非常别扭。所以文件判定逻辑尽量前置到paste_preprocess,能够拿到原始DataTransfer对象,最顺手。
4. 代码级实现——把矢量图纸塞进TinyMCE
4.1 粘贴事件的拦截与数据解析
我用TinyMCE 6作为示例,但思路在TinyMCE 5同样适用。核心拦截逻辑分两步:第一步,在setup回调里监听paste事件,判断是否有文件;第二步,如果有文件,发送到转换服务,并阻止TinyMCE默认插入行为。
javascript复制tinymce.init({
selector: '#editor',
plugins: 'paste',
paste_preprocess: (plugin, args) => {
// args.content 是TinyMCE即将插入的HTML字符串
// 我们先在这里处理文件上传
},
setup(editor) {
editor.on('paste', (e) => {
const items = e.clipboardData ? e.clipboardData.items : [];
const files = [];
for (let i = 0; i < items.length; i++) {
if (items[i].kind === 'file') {
const f = items[i].getAsFile();
if (f && /\.(dwg|dxf)$/i.test(f.name)) {
files.push(f);
}
}
}
if (files.length > 0) {
e.preventDefault(); // 阻止默认行为
files.forEach((file) => uploadAndInsert(editor, file));
}
});
}
});
实际开发中你要注意一个细节:clipboardData.items在某些浏览器(尤其老版本Safari)支持不完整。建议对不支持items的场景做降级,直接判断clipboardData.files有没有文件。
4.2 后端转换服务怎么选型与封装
转换服务是整条链路的命门。芯片企业内网通常有现成的ODA File Converter(把DWG转成DXF),也有用LibreCAD做批处理转换的。我这里给出一套我验证过的思路:
- DWG转DXF:用ODA File Converter命令行批量转,转成DXF格式后便于后续解析。
- DXF转SVG:可以走命令行调用LibreCAD,或者用Python库
ezdxf做更精细的控制。 - 高度定制需求:如果你需要对图层做筛选、对单位做换算,推荐直接用
ezdxf读取DXF并用svgwrite输出SVG。
后端接口封装成很简单的样子:
python复制from flask import Flask, request, jsonify
import os
import uuid
import subprocess
app = Flask(__name__)
@app.route('/convert', methods=['POST'])
def convert_cad_to_svg():
f = request.files['file']
ext = os.path.splitext(f.filename)[1].lower()
task_id = str(uuid.uuid4())
tmp_dir = f'/tmp/{task_id}'
os.makedirs(tmp_dir, exist_ok=True)
raw_path = os.path.join(tmp_dir, 'source' + ext)
f.save(raw_path)
dxf_path = raw_path
if ext == '.dwg':
dxf_path = os.path.join(tmp_dir, 'converted.dxf')
subprocess.run([
'ODAFileConverter',
tmp_dir, tmp_dir,
'ACAD2018', 'DXF', '0', '1', 'source.dwg'
], check=True, capture_output=True)
svg_path = os.path.join(tmp_dir, 'output.svg')
subprocess.run([
'librecad', '-autostart', '-r', dxf_path, '-o', svg_path
], check=True, capture_output=True)
# 实际项目中这里还需要做SVG净化、图层合并、坐标换算等后处理
from svgutils.transform import fromfile
fig = fromfile(svg_path)
fig.save(os.path.join(tmp_dir, 'clean.svg'))
return jsonify({
'svg': open(os.path.join(tmp_dir, 'clean.svg'), encoding='utf-8').read()
})
这段代码故意写得比较简略,实际生产你要加鉴权、限流、任务队列。但核心思想是清楚的:前端发文件,后端回SVG字符串。唯一要提醒的是,ODA File Converter的命令行参数各家版本略有差异,封装的时候要通过接口抽象掉这一层,免得以后换转换引擎时动所有调用方。
4.3 将生成的SVG安全注入编辑器
后端拿到了干净的SVG字符串,前端要把它插入TinyMCE,并且保存时要确保SVG不被剥离。这一步踩坑概率最高,我给你一个可以直接抄的配置:
javascript复制tinymce.init({
selector: '#editor',
plugins: 'paste',
// 允许SVG相关标签
extended_valid_elements: [
'svg[*]',
'defs[*]',
'g[*]',
'path[*]',
'circle[*]',
'rect[*]',
'line[*]',
'polyline[*]',
'polygon[*]',
'text[*]',
'tspan[*]',
'use[*]',
'symbol[*]',
'metadata[*]'
].join(','),
// 自定义元素也要声明,防止被当作非法标签处理
custom_elements: 'svg,defs,g,path,circle,rect,line,polyline,polygon,text,tspan,use,symbol,metadata',
// 关闭对SVG的XSS检查里的“危险标签”误伤
// 但注意:不要随意开这个,只在你确实需要内联SVG时使用
// (TinyMCE 5/6的xss过滤对svg标签比较严格)
paste_postprocess: (editor, args) => {
args.node.querySelectorAll('svg').forEach((svg) => {
// 补充命名空间,防止部分浏览器下SVG渲染异常
svg.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
});
},
setup(editor) {
// 上传转换完成后,直接插入SVG
editor.on('init', () => {
window.uploadAndInsert = (svgString) => {
editor.insertContent(svgString);
};
});
}
});
插入方式上有两种区别,很多人没区分清楚。insertContent适合插入一段HTML字符串,TinyMCE会走过滤流程;insertContent配合skip_validation选项可以跳过部分校验,但在SVG场景下会引入XSS风险,不建议轻易使用。
4.4 无SVG时的降级策略
不是所有图纸都能成功转换成SVG。有些DWG文件加密了,有些DXF格式太老,有些图纸里嵌入了外部引用(Xref),转换服务都会返回失败。这时候不能给用户弹一个“转换失败”就结束,要有合理的降级。
我的做法是:
- 后端转换失败时,返回一个位图版本的PNG(可以先在服务端用渲染工具设置一个固定DPI渲染)。
- 前端拿到PNG,在TinyMCE里插入一张图片,并附带一个标记属性,比如
data-cad-original="true"。 - 在
submit保存时,检测这种图片,给用户提示“当前图纸以位图形式保存,精度可能不足,是否确认?”,如果用户确认,记录日志备用。
这样既保证了流程不中断,又保留了精度的“知情权”。
5. 精度、性能与多图纸合并的工程化处理
5.1 单位与坐标精度不能丢
芯片场景里最敏感的就是单位换算。很多CAD图纸内部用的是毫米(mm),但芯片封装图纸里常用的单位是微米(um)。DWG源文件里记录的是图形数据,单位信息往往写在外部或由约定决定。
在转换SVG时,我强烈建议你做好三件事:
- 读取DXF的
$INSUNITS字段,明确图纸单位; - 在SVG的根元素里写入
data-unit、data-scale自定义属性,方便下游系统解析; - 不要为了“显示合适”去随意缩放SVG的
viewBox或width/height,尽量让SVG本身的数据坐标和图纸原始坐标保持一致,展示层缩放交给CSS或preserveAspectRatio。
这样下游如果要做尺寸标注或自动量测,直接读取SVG坐标换算就行。我见过某些团队图省事,在转换时直接把单位毫米当成像素输出,结果坐标偏移了好几个数量级,这是工程事故级别的错误。
5.2 大图纸SVG的性能优化
芯片图纸动辄几十MB的DXF,转换成SVG后也经常是10MB以上的文本。直接把这种大SVG塞进TinyMCE,编辑器会明显卡顿,保存时如果不做压缩,数据库也会告警。
工程上的解决方案是“分层降载”:
- 预览层:插入编辑器的是SVG,但可以限制初始渲染尺寸,不影响编辑体验;
- 懒加载层:SVG内部可以拆分为多个
<g>组,配合display:none按图层懒渲染,不过TinyMCE环境中做这个成本较高; - 导出层:真正生成最终PDF或打印件时,使用完整SVG,保证精度;
- 存储层:TinyMCE内容保存到数据库时,可以把原始SVG存为独立字段或对象存储,HTML正文里只保留SVG的引用或压缩后的内容。
另外,SVG字符串插入编辑器之前,做一个“简化”处理也很有价值。用svgo做SVG压缩,删除注释、空属性、不必要的元数据,文件体积能普遍减少40%以上。
5.3 多张CAD图纸合并进同一个文档的方法
工程变更单里常常需要同时贴多张图纸,比如“修改前”和“修改后”对比图。单个粘贴没问题,多张时要考虑“合并”问题。我遇到的实际需求有两种:
第一种需求:多张图纸并列展示
把多个SVG依次插入TinyMCE即可,简单直接。但要注意:多个SVG如果坐标体系不一致,读者容易产生误解。我的做法是在生成SVG时,在根元素上标注data-cad-name和图号,并在SVG上方插入一个由后端生成的标题说明块。
第二种需求:多张图纸合成一张总图
这是真正的“cad图纸合并”。比如把版图各层(Metal层、Poly层、Via层)分别从不同DXF文件里提取,叠加生成一张总览图。这个操作放在后端做,不要在TinyMCE里做。我的实现思路是:
python复制import ezdxf
from svgwrite import Drawing
def merge_dxf_layers(dxf_path, layer_configs, output_svg):
doc = ezdxf.readfile(dxf_path)
msp = doc.modelspace()
dwg = Drawing(output_svg, profile='full')
for config in layer_configs:
layer_name = config['name']
color = config['color']
group = dwg.g(id=f'layer_{layer_name}')
for entity in msp.query(f'*[layer=="{layer_name}"]'):
# 按实体类型分别处理
if entity.dxftype() == 'LINE':
group.add(dwg.line(
(entity.dxf.start.x, entity.dxf.start.y),
(entity.dxf.end.x, entity.dxf.end.y),
stroke=color
))
elif entity.dxftype() == 'CIRCLE':
group.add(dwg.circle(
center=(entity.dxf.center.x, entity.dxf.center.y),
r=entity.dxf.radius,
stroke=color
))
dwg.add(group)
# 合并时统一viewport,防止各图层坐标基准不一致
dwg.viewbox(units='mm', size=(width_mm, height_mm))
dwg.save()
这里的核心思路是:读取DXF时,按图层分组建SVG,并且在合并总图时统一viewBox,让各图层叠加在同一个坐标基准上。TinyMCE端插入的总图包含全部图层,可以被图层管理器按需开关图层。
图层合并还有个连带问题:因为芯片图纸通常有几十个图层,直接合并会让SVG体积爆炸。所以我的建议是,默认只合并当前视图相关的可见图层,或者提供“仅合并选中图层”的选项给用户。
5.4 权限、版本与安全底线
能接触到CAD图纸的工程师、工艺员、质检员角色不同,权限也不同。TinyMCE本身不管权限,但我建议在保存时需要做到:
- 记录“原始图纸文件版本号”:CAD文件会频繁改版,SVG必须能对应到具体的源文件版本;
- 路径级权限:转换服务要有鉴权,防止未经授权的人把他人的图纸文件上传转换并下载;
- SVG内容安全:SVG是XML,允许
script、foreignObject、外部实体引用,如果不过滤,插入TinyMCE后可能触发XSS。我前面配置extended_valid_elements时特意没有放开foreignObject和script,这是刻意的。
6. 实际项目中踩过的坑
6.1 SVG被TinyMCE“净化”得体无完肤
第一次接入时,我把SVG字符串直接交给insertContent,结果插入后编辑器里只剩一堆空标签,图形全丢了。排查后发现是TinyMCE的sanitize机制干掉了SVG里的style属性和transform属性。
解决办法就是我前面给的extended_valid_elements配置,明确允许style和transform属性:
javascript复制extended_valid_elements: 'svg[*],path[style|transform|d|fill|stroke],g[style|transform],...'
注意这里[*]只匹配普通属性,像style、transform这类全局属性通常会被TinyMCE特殊对待,需要显式声明。如果发现某些元素还是被剥离,可以在paste_postprocess里拿到args.node后,手工把outerHTML里的SVG替换进去。这一步是最后的手段,能不用就不用。
6.2 中文图层名称导致的编码事故
芯片企业很多工程师是直接用中文命名图层的。DXF文件在转换时,如果后端代码没有统一字符编码,很容易出现乱码或转换失败。这个坑很隐蔽,因为有时本地测试正常,部署到Linux服务器就挂。
我的经验是:转换服务里所有文件读写encoding='utf-8',如果图纸来源是Windows系统,读DXF时要兼容gbk编码。ezdxf底层对编码处理得不错,但LibreCAD命令行方式偶尔会有问题,所以我会在转换前先用Python探测编码再调用外部工具。
6.3 EMF解析的单位换算陷阱
有段时间我尝试走“从剪贴板提取EMF转SVG”的路线,被单位换算折磨得够呛。Windows EMF记录的单位是0.01毫米,但部分CAD软件写入EMF时,已经按当前视口缩放重新计算了坐标。也就是说,EMF里的坐标不一定等于图纸真实坐标,它更接近“截图时的屏幕坐标”而非“图纸坐标”。
这个发现让我彻底放弃了“从剪贴板位图/EMF恢复精度”的想法。如果你要保证精度,只能拿源文件,没有其他捷径。
6.4 大面积图纸粘贴后浏览器直接卡死
有一个极端案例,用户粘贴了一张完整的掩模版图(DXF文件45MB),后端转换出了18MB的SVG。前端插入TinyMCE后,页面线程直接崩溃,Chrome提示“Aw, Snap”。后来做了两个改进才解决:
- 后端为超大SVG生成一个低精度预览SVG(去掉细碎曲线,只保留轮廓),供编辑器内展示;
- 原始SVG不内联,而是存为独立文件,编辑器内插入一个
<embed>标签引用。
但<embed>或<iframe>在TinyMCE里又涉及信任问题,最终我选了“低精度预览SVG + 链接查看原图”的模式。这也说明了一个现实:不要试图让TinyMCE承载所有大尺寸SVG,编辑态和归档态要分开设计。
做了这个方案之后,我再回看最初的需求,其实“芯片制造企业解决CAD图纸粘贴到TinyMCE的矢量输出”本质上不是一个编辑器问题,而是一个“数据流程设计”问题。剪贴板只是入口,转换服务是核心,TinyMCE是载体。如果你正在做类似集成,我建议先别急着写插件,先把图纸源文件归档、版本对应、单位约定这些基础规则定义好,否则就算SVG成功插入,后面也会有越来越多精度不可控的隐患。工具层面的坑都有解,流程层面的漏洞才最致命。
