IE11下使用canvas.toDataURL报SecurityError错误的解决方法


Posted in Javascript onNovember 19, 2017

发现问题

最近在项目中用到了 canvas 的 toDataURL 方法来获取图片的 base64 格式数据,用以上传到后台。由于之前也遇到过 canvas 被跨域图片污染不能获取数据的坑,因此这回一开始就机智的把 crossOrigin 属性值加上,代码大概如下:

const canvas = document.createElement("canvas");
const context = canvas.getContext("2d");
context.fillStyle = "black";
context.fillRect(0, 0, canvas.width, canvas.height);
const imageElement = document.createElement("img");
imageElement.crossOrigin = "Anonymous";
imageElement.onload = () => {
 context.drawImage(
 imageElement,
 params.left,
 params.top,
 canvas.width,
 canvas.height,
 0,
 0,
 canvas.width,
 canvas.height
 );

 const dataUrl = canvas.toDataURL("image/jpeg", 1);
}
imageElement.src = 'xxx';

本以为万无一失,而在 Chrome 浏览器上面也非常顺利;然而到了 IE11 上,却出现了一个莫名其妙的 SecurityError 错误:

IE11下使用canvas.toDataURL报SecurityError错误的解决方法

没有具体的报错信息,只通过提示定位到了执行 toDataURL 这一行,实在让人疑惑。

尝试

第一时间 Google 了一下,发现很多人遇到这个问题,但是并没有看到什么有效的解决办法,有些人建议使用 Fabric.js,但是看了一下觉得太麻烦了点。而在 caniuse 上,也明确标注了该方法在 IE11 上有问题。

看起来应该是 IE 上的一个 bug,于是想到了一个曲线救国的办法:获取图片 base64 数据的办法又不是只有一个,既然 toDataURL 方法支持不好,那就用别的办法:

  • 先将 canvas 转成 blob
  • 再用 FileReader 以 dataUrl 的方式读取

代码大概如下:

const reader = new FileReader();
reader.readAsDataURL(canvas.msToBlob());
reader.onloadend = () => {
 const base64data = reader.result;
};

然而这并没有什么卵用....

这回轮到了 msToBlob 方法报了 SecurityError 错误。我:???

解决

看起来可能真的是安全原因,唯一的安全原因,只可能是跨域图片了。寻思着可能在 IE 上安全策略比较严格,即使设置了 crossOrigin = "Anonymous" 还是不让读数据,于是想到了另外一个思路,既然是因为跨域,那就把跨域因素去除:

  • 使用 ajax 请求拿到图片的二进制数据
  • 将二进制数据转为 base64 格式
  • 将得到的 base64 数据作为图片元素的 src 设置并画到画布上
  • 正常调用 toDataURL

代码大致如下:

// 之前的代码
// ...
// 最后一行 imageElement.src = 'xxx' 替换:
getDataUrlBySrc('xxx').then(b64 => (imageElement.src = b64));

function getDataUrlBySrc(src: string) {
 return new Promise<string>((resolve, reject) => {
 if (Cache.localGet("isIE")) {
  const xmlHTTP = new XMLHttpRequest();
  xmlHTTP.open("GET", src, true);

  // 以 ArrayBuffer 的形式返回数据
  xmlHTTP.responseType = "arraybuffer";

  xmlHTTP.onload = function(e) {
  
  // 1. 将返回的数据存储在一个 8 位无符号整数值的类型化数组里面
  const arr = new Uint8Array(xmlHTTP.response);
  
  // 2. 转为 charCode 字符串
  const raw = Array.prototype.map
   .call(arr, charCode => String.fromCharCode(charCode))
   .join("");
   
  // 3. 将二进制字符串转为 base64 编码的字符串
  const b64 = btoa(raw);
  
  const dataURL = "data:image/jpeg;base64," + b64;
  resolve(dataURL);
  };
  xmlHTTP.onerror = function(err) {
  reject(err);
  };
  xmlHTTP.send();
 } else {
  resolve(src);
 }
 });
}

尝试了一下,成功达到了目的。

后来查阅资料得知,如果 canvas 污染了,那无论是 toDataURL 还是 toBlob,都是无法执行成功的。

缺陷

虽然这个方法可以达到目的,但是却牺牲了性能。要先请求一次图片数据不说,数据编码的转换也是相当耗时的。小图还好,如果图片比较大,例如超过 3M ,那整个流程需要花费的时间可以达到一两分钟,这是不可接受的。

canvas的toDataUrl是否会压缩图像?

使用canvas的drawImage方法将image对象draw到canvas画布上时,图片大小会显著增加,并且只能保存为PNG格式。

将canvas用toDataUrl转化为base64,即使encoderOptions设置为1,图片也会有较大幅度的减小,但是比起最初的image还是要大。如果encoderOptions使用默认的0.92,最终的图片大小和初始的是相差不多的

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
设为首页加入收藏兼容360/火狐/谷歌/IE等主流浏览器的代码
Mar 26 Javascript
JS日期和时间选择控件升级版(自写)
Aug 02 Javascript
node中socket.io的事件使用详解
Dec 15 Javascript
JQuery基础语法小结
Feb 27 Javascript
jquery过滤特殊字符',防sql注入的实现方法
Aug 17 Javascript
jQuery树形插件jquery.simpleTree.js用法分析
Sep 05 Javascript
简单实现js浮动框
Dec 13 Javascript
详解vue 路由跳转四种方式 (带参数)
Apr 28 Javascript
js图片无缝滚动插件使用详解
May 26 Javascript
weui中的picker使用js进行动态绑定数据问题
Nov 06 Javascript
jQuery操作元素追加内容示例
Jan 10 jQuery
Ajax常用封装库——Axios的使用
May 08 Javascript
使用DataTable插件实现异步加载数据
Nov 19 #Javascript
原生JavaScript实现Ajax异步请求
Nov 19 #Javascript
gulp安装以及打包合并的方法教程
Nov 19 #Javascript
js实现rem自动匹配计算font-size的示例
Nov 18 #Javascript
如何编写一个完整的Angular4 FormText 组件
Nov 18 #Javascript
Angular中支持SCSS的方法
Nov 18 #Javascript
VUE element-ui 写个复用Table组件的示例代码
Nov 18 #Javascript
You might like
CodeIgniter中使用Smarty3基本配置
2015/06/29 PHP
thinkPHP模型初始化实例分析
2015/12/03 PHP
php mysql PDO 查询操作的实例详解
2017/09/23 PHP
PHP 获取客户端 IP 地址的方法实例代码
2018/11/11 PHP
Thinkphp 框架扩展之Widget扩展实现方法分析
2020/04/23 PHP
解决FLASH需要点击激活的代码
2006/12/20 Javascript
[原创]js与自动伸缩图片 自动缩小图片的多浏览器兼容的方法总结
2007/03/12 Javascript
爱恋千雪-US-AscII加密解密工具(网页加密)下载
2007/06/06 Javascript
编写自己的jQuery提示框(Tip)插件
2015/02/05 Javascript
jQuery validate插件实现ajax验证重复的2种方法
2016/01/22 Javascript
Bootstrap下拉菜单效果实例代码分享
2016/06/30 Javascript
JavaScript实现倒计时跳转页面功能【实用】
2016/12/13 Javascript
深究AngularJS——ng-checked(回写:带真实案例代码)
2017/06/13 Javascript
开发Node CLI构建微信小程序脚手架的示例
2020/03/27 Javascript
js实现自定义右键菜单
2020/05/18 Javascript
jQuery 动画与停止动画效果实例详解
2020/05/19 jQuery
[25:45]2018DOTA2亚洲邀请赛4.5SOLO赛 Sylar vs Paparazi
2018/04/06 DOTA
[02:16]完美世界DOTA2联赛PWL S3 集锦第三期
2020/12/21 DOTA
Python学习笔记(一)(基础入门之环境搭建)
2014/06/05 Python
python实现的希尔排序算法实例
2015/07/01 Python
Python内建数据结构详解
2016/02/03 Python
详解Python实现多进程异步事件驱动引擎
2017/08/25 Python
Python turtle绘画象棋棋盘
2019/08/21 Python
在pycharm中配置Anaconda以及pip源配置详解
2019/09/09 Python
Python 面向对象静态方法、类方法、属性方法知识点小结
2020/03/09 Python
pycharm导入源码的具体步骤
2020/08/04 Python
python使用scapy模块实现ARP扫描的过程
2021/01/21 Python
使用HTML5的Canvas绘制曲线的简单方法
2015/09/08 HTML / CSS
html5视频常用API接口的实战示例
2020/03/20 HTML / CSS
猎人靴英国官网:Hunter Boots
2017/02/02 全球购物
英国珠宝钟表和家居礼品精品店:David Shuttle
2018/02/24 全球购物
美国花园雕像和家居装饰网上商店:Design Toscano
2019/03/09 全球购物
大学生职业生涯设计书
2014/01/02 职场文书
大学生实习鉴定评语
2014/04/25 职场文书
保研导师推荐信
2015/03/25 职场文书
导游词之峨眉山
2019/12/16 职场文书