Chrome中SVG绘制到canvas录制webm报origin-clean错误问题咨询
问题原因
该问题是Chrome 102及后续版本的安全策略变更导致,和你在同源窗口创建blob资源的操作本身无关,触发canvas被标记为非源干净(origin-clean)的常见原因如下:
- 你序列化后的SVG内容中存在外部资源引用:包括但不限于外链图片、外链字体、外链CSS、
<use>标签引用SVG外的DOM元素、内嵌<foreignObject>标签引用外部内容,Chrome针对作为Image源加载的SVG新增了限制,只要存在外部引用就会触发canvas污染,该限制目前Firefox未跟进。 - 序列化后的SVG根节点缺失
xmlns="http://www.w3.org/2000/svg"声明,Chrome无法正确识别为SVG图片,也会触发污染。 - 你的MediaRecorder初始化时机错误:你在调用
DrawToCanvas之后就立刻初始化了录制器,但canvas绘制是异步操作(需要等img.onload触发后才会完成绘制),此时canvas要么是空的、要么已经被污染,captureStream生成的流是无效的,自然后续dataavailable事件返回的data.size为0。
修复方案
方案1:修改现有实现
- 序列化SVG前先给根节点补全XMLNS声明,代码示例:
if (!node.hasAttribute('xmlns')) { node.setAttribute('xmlns', 'http://www.w3.org/2000/svg'); }
- 把SVG内部所有引用的外部资源全部转成base64内联,不要留任何外链资源,移除不需要的
<script>、<foreignObject>标签。 - 给Image对象显式设置crossOrigin属性,放在设置src之前,同时把MediaRecorder的初始化逻辑挪到绘制完成之后:
DrawToCanvas(node) { var serializer = new XMLSerializer(); // 补全xmlns声明 if (!node.hasAttribute('xmlns')) node.setAttribute('xmlns', 'http://www.w3.org/2000/svg'); var source = serializer.serializeToString(node); var cv = this.Elem("canvas"); var blob = new Blob([source], { type: 'image/svg+xml;charset=utf-8' }); var url = window.URL.createObjectURL(blob); var ctx = cv.getContext('2d'); var img = new Image(); // 显式设置跨域属性 img.crossOrigin = 'anonymous'; img.onload = function() { ctx.fillStyle = "#f9f9f9"; ctx.fillRect(0, 0, cv.width, cv.height); ctx.drawImage(img, 0, 0, cv.width, cv.height); window.URL.revokeObjectURL(url); // 绘制完成后再初始化录制器 if (!this.recorder) { this.recorder = new MediaRecorder(cv.captureStream(), { mimeType: 'video/webm' }); this.recorder.ondataavailable = (ev) => { if (ev.data && ev.data.size > 0) this.chunks.push(ev.data); }; } }.bind(this) img.src = url; }
方案2:绕开Image加载限制(更稳定)
直接使用canvg等SVG解析绘制库,直接把SVG内容解析后绘制到canvas,完全绕开Chrome对SVG作为Image源的安全限制,不会触发canvas污染问题。
内容的提问来源于stack exchange,提问作者user164179
相关产品推荐
相关产品推荐

