SVG转Blob再生成imageUrl异常,无法渲染至Canvas求助
问题
我有一个文件输入框,需要将选中的文件转换为imageUrl后添加到Canvas中。发现SVG是特殊情况,需要先转为Blob再生成imageUrl,但Blob转换看似正常,生成的url却返回异常结果。
相关代码
JavaScript代码
function initiate() { var canvas = $("#canvas").get(0); var context = canvas.getContext("2d"); var img = new Image(); var imageSrcUrl; img.onload = function() { URL.revokeObjectURL(imageSrcUrl), {once: true} context.drawImage( img, 0, 0, img.width, img.height, 0, 0 ); } var extension = $("#logo").get(0).files[0].name.split('.').pop().toLowerCase(); if(extension == 'svg') { var reader = new FileReader(); reader.onload = function() { console.log(reader.result); var blob = new Blob([reader.result.toString()], {type: 'image/svg+xml'}); console.log(blob); imageSrcUrl = URL.createObjectURL(blob); console.log(imageSrcUrl); img.src = imageSrcUrl; }; reader.readAsText($("#logo").get(0).files[0]); } else { img.src = URL.createObjectURL( $("#logo").get(0).files[0] ); } }
HTML代码
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script> <form id="form"> Select file here <input type="file" id="logo"> </form> <br><br> Canvas goes here <canvas width="400" height="200" id="canvas"></canvas> <br><br> <button onclick="initiate();">Get svg into canvas</button>
控制台日志
- reader.result:
< svg version="1.1" id="Laag_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 605.3 146.4" style="enable-background:new 0 0 605.3 146.4;" xml:space="preserve">...(为格式调整添加了开头空格) - blob:
Blob { size: 50643, type: "image/svg+xml" } - imageSrcUrl:
blob:https://ourdomain.be/a64506fb-00db-459a-8e17-1aab67dadd9b
解决方案
你的代码存在两个核心问题,导致SVG无法正常加载到Canvas:
1. 错误的Blob URL回收时机与语法
img.onload中的URL.revokeObjectURL(imageSrcUrl), {once: true}是错误写法:逗号运算符会忽略{once: true}参数,且你在图片刚触发load事件就立即回收了Blob URL——此时图片还未完成绘制,URL被回收后浏览器无法读取SVG内容,导致加载失败。
正确做法是:使用addEventListener绑定单次触发的load事件,在绘制完成后再回收URL。
2. SVG内容的无效处理
控制台日志显示reader.result开头有额外单引号,这会导致SVG格式无效;另外reader.result本身就是字符串,无需调用toString(),多余的转换可能引入意外格式问题。
修正后的代码
JavaScript代码
function initiate() { var canvas = $("#canvas").get(0); var context = canvas.getContext("2d"); var img = new Image(); var imageSrcUrl; // 绑定单次触发的load事件,确保事件只执行一次 img.addEventListener('load', function() { // 绘制完成后再回收Blob URL URL.revokeObjectURL(imageSrcUrl); // 适配Canvas尺寸绘制图片 context.drawImage(img, 0, 0, img.width, img.height, 0, 0, canvas.width, canvas.height); }, {once: true}); // 校验是否选择了文件 var fileInput = $("#logo").get(0); if (!fileInput.files || fileInput.files.length === 0) { alert('请先选择文件'); return; } var file = fileInput.files[0]; var extension = file.name.split('.').pop().toLowerCase(); if (extension === 'svg') { var reader = new FileReader(); reader.onload = function() { // 清理SVG内容首尾的空格和可能的引号,确保格式有效 var svgContent = reader.result.trim().replace(/^['"]|['"]$/g, ''); var blob = new Blob([svgContent], {type: 'image/svg+xml'}); imageSrcUrl = URL.createObjectURL(blob); img.src = imageSrcUrl; }; reader.readAsText(file); } else { imageSrcUrl = URL.createObjectURL(file); img.src = imageSrcUrl; } }
额外优化说明
- 添加了文件选择校验,避免未选文件时触发错误
- 绘制时指定了Canvas目标宽高,确保SVG适配Canvas尺寸显示
- 清理SVG内容的首尾冗余字符,避免格式错误导致加载失败
内容的提问来源于stack exchange,提问作者Mats Raemen
相关产品推荐
相关产品推荐

