报错详尽信息

Uncaught DOMException: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.

关键词

canvas.toDataURL()

crossOrigin

Access-Control-Allow-Origin

前言

最近在做一个创意类的图片合成工具,大概齐就是通过拼接自定义的文字和图片信息生成一张商品图片类似的功能,项目中用到了fabric.js这个画板库,最后一步在保存图片的时候报上面的一长串错误,墙内墙外搜了一遍,给出的解决方案都不全面,为避免同学们再次踩坑,于是有了此文

正文

我们在convertDOM2Image时,如果DOM内存在图片资源,该资源所在的web-server是不支持跨域的,保存图片是不会成功的。

因此在排查问题时,首先要确定

  1. web-server是否允许跨域,我们以nginx为例,response-header内要存在Access-Control-Allow-Orgin:xxxx(可以是*,安全性要求比较高的可以根据主域名自定义)

  2. 如果是img标签, 是否添加了crossorigin="anonymous", 如果是Image对象,同样是否添加了改属性obj.crossOrigin='anonymous'

  3. 如果还不行,这里先不把答案放出来,我们先看看栗子


在接下来的栗子中我们会用到将Image转换为canvas对象的方法

  function convertImageToCanvas(image) {
// 创建canvas DOM元素,并设置其宽高和图片一样
let canvas = document.createElement("canvas");
canvas.width = image.width;
canvas.height = image.height;
canvas.getContext("2d").drawImage(image, 0, 0);
// 我们在实际的开发中,需要将抓换后的base64图片编码传输到后台图片服务器,由server直接存储或者生成一张图片;
// 所以会用到 toDataURL
console.log(canvas.toDataURL('image/jpeg'))
return canvas;
}

栗子1

本地未设置跨域允许选项crossorigin=anonymous,web-server未设置跨域允许选项

  <div id="d1">
<img style="width: 300px;height: 240px;" src="http://es6.ruanyifeng.com/images/cover_thumbnail_3rd.jpg" alt="">
<p>本地未设置跨域允许选项crossorigin=anonymous,web-server未设置跨域允许选项</p>
</div>
<button onclick="setCanvas('d1')">canvas保存</button>
    function setCanvas(DOMID) {
let img = document.getElementById(DOMID).querySelector('img')
document.body.appendChild(convertImageToCanvas(img))
}

很显然,报错

栗子2

本地标签内设置跨域允许选项, web-server未设置跨域允许选项

这次连图片都出不来,直接报错

这个好理解,浏览器同源策略限制嘛

Access to image at 'xxxx' (redirected from 'xxxx') from origin 'null' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

栗子3

本地未设置跨域允许选项crossorigin=anonymous, web-server设置跨域允许选项

报错,妥妥的。

栗子4

本地标签内设置跨域允许选项crossorigin=anonymous, web-server设置跨域允许选项

  <div id="d4">
<img style="width: 300px;height: 240px;" src="https://img.alicdn.com/tfs/TB1_uT8a5ERMeJjSspiXXbZLFXa-143-59.png" alt="" crossorigin="anonymous">
<p>本地设置跨域允许选项`crossorigin=anonymous`,`web-server`设置跨域允许选项</p>
</div>
<button onclick="setCanvas('d4')">canvas保存</button>

居然可以了,但是~如果在代码内设置跨域呢?

栗子5

  function setCanvas(DOMID) {
let img = document.getElementById(DOMID).querySelector('img') img.crossOrigin= 'anonymous' document.body.appendChild(convertImageToCanvas(img))
}

报错

我看官方文档的意思是必须同步设置crossOrigin=anonymous,该图片凭证才会被信任

This means that CORS is enabled and credentials are sent if the image is fetched from the same origin from which the document was loaded.

否则缓存的图像数据仍然会被画布视为有污染的跨源内容.

怎么办?重新取一遍图片呗,加个随机数,图片还是那个图片,不过加了个马甲,浏览器就不认识了

栗子6

  function setCanvas(DOMID) {
let img = document.getElementById(DOMID).querySelector('img') img.src =img.src+'?v='+Math.random()
img.crossOrigin= 'anonymous' img.onload=()=>{
document.body.appendChild(convertImageToCanvas(img))
}
}

binggo, 完美解决

所以我们在开发过程中,新建图片,更换图片,还原图片等功能代码内,最好每一次都加个随机数,以保证源都是最新的,不走缓存


多说一点吧,关于fabric.js的相关跨域配置见下方

    let _fabricConfig = {
// ....
crossOrigin:'anonymous'
};
/* fabric对象 */
let _fabricObj = new fabric.Canvas(id, _fabricConfig); // 新建图片对象时
let imgInstance = new fabric.Image.fromURL(url + '?v='+ Math.random(), img => {}, {crossOrigin: 'anonymous'}) // 动态更新图片时
let currentActive = _fabricInstance.getActiveObj();
currentActive.setSrc(randomURL, img =>{}, {crossOrigin: 'anonymous'})

canvas.toDataURL()报错的解决方案全都在这了的更多相关文章

  1. Canvas引入跨域的图片导致toDataURL()报错的问题的解决

    本文介绍了Canvas引入跨域的图片导致toDataURL()报错的问题的解决,分享给大家,具体如下: [场景] 用户打开网页,则请求腾讯COS(图片服务器)上的图片js代码.使用canvas绘图. ...

  2. 关于Entity Framework中的Attached报错相关解决方案的总结

    关于Entity Framework中的Attached报错的问题,我这里分为以下几种类型,每种类型我都给出相应的解决方案,希望能给大家带来一些的帮助,当然作为读者的您如果觉得有不同的意见或更好的方法 ...

  3. 新手常见的python报错及解决方案

    此篇文章整理新手编写代码常见的一些错误,有些错误是粗心的错误,但对于新手而已,会折腾很长时间才搞定,所以在此总结下我遇到的一些问题.希望帮助到刚入门的朋友们.后续会不断补充. 目录 1.NameErr ...

  4. Mysql only_full_group_by以及其他关于sql_mode原因报错详细解决方案

    Mysql only_full_group_by以及其他关于sql_mode原因报错详细解决方案 网上太多相关资料,但是抄袭严重,有的讲的也是之言片语的,根本不连贯(可能知道的人确实不想多说) 我总共 ...

  5. Win7下nginx默认80端口被System占用,造成nginx启动报错的解决方案

    Win7下nginx默认80端口被System占用,造成nginx启动报错的解决方案   在win7 32位旗舰版下,启动1.0.8版本nginx,显示如下错误:  [plain] 2012/04/0 ...

  6. Mac上PyCharm运行多进程报错的解决方案

    Mac上PyCharm运行多进程报错的解决方案 运行时报错 may have been in progress in another thread when fork() was called. We ...

  7. 安装Redis-cluster-gem install redis报错的解决方案

    错误描述: [root@eshop-cache01 local]# gem install redis ERROR: Loading command: install (LoadError) cann ...

  8. ELK报错及解决方案

    ELK报错及解决方案 1.jdk版本问题 报错如下: future versions of Elasticsearch will require Java 11; your Java version ...

  9. web.xml配置文件中<async-supported>true</async-supported>报错的解决方案

    为什么用到这个: ssh集成了cxf,当登录系统后,发现系统报错,控制台不断输出下面信息: 2016-05-05 11:05:06 - [http-bio-8080-exec-4] - WARN - ...

随机推荐

  1. 杂记:VMware中为mac虚拟机扩容

    之前在VMware中安装Mac虚拟机时,硬盘选的是默认的40G,后来用的过程中随着软件的安装,特别是安装完Xcode和QT5.9之后,可用空间只剩不到3G,每次开机之后都会提醒空间不足,需要清理空间, ...

  2. 11. 无数人难办事? - 迪米特法则(LoD)

    11.1 第一天上班 时间: 4月2日19点   地点: 小菜大鸟住所的客厅   任务: 小菜, 大鸟      "回来啦! 怎么样? 第一天上班感受多吧." 大鸟关关心的问道.  ...

  3. OPPO招聘-互联网测试

    邮       箱:ljy@oppo.com 工作地点:深圳

  4. 每日一译系列-模块化css怎么玩(译文)

    原文链接:How Css Modules Work 原文作者是Preact的作者 这是一篇关于如何使用Css Modules的快速介绍,使用到的工具是Webpack吊炸的css-loader 首先,我 ...

  5. USB描述符(转)

    //============================================================================// 文件名: USBDESC.C// 用 ...

  6. diary20180428

    17:05:59 今天早晨去了图书馆.学习了一把vscode.试图在河边看电脑,总有小虫不让我专心. 23:27:34 看纯黑直播打战神,有点感触. 动漫或游戏,角色觉醒,实力大增,小时候(甚至现在) ...

  7. 《HelloGitHub》第 47 期

    兴趣是最好的老师,HelloGitHub 就是帮你找到兴趣! 简介 分享 GitHub 上有趣.入门级的开源项目. 这是一个面向编程新手.热爱编程.对开源社区感兴趣 人群的月刊,月刊的内容包括:各种编 ...

  8. c++背包问题

    又鸽了好久…… 前言 博主刚刚学会背包问题不久,然后有一段时间没练习了 今天就来重新温习一下,顺手就写了这一篇博客. 好了,下面进入正题! 算法简介 背包问题是动态规划的一个分支 主要是分成了01背包 ...

  9. 01.JS块级作用域与let

    1.块级作用域   什么是:         在一个代码块(括在一对花括号中的一组语句)中定义的所需变量(与let配合使用)并在代码块的外部是不可见的.   为什么:         在ES6之前,函 ...

  10. 如何通过学校系统漏洞注册到 @edu.cn 邮箱账号?

    此文章仅针对我自己学校的系统进行分析,并不代表所有学校的系统都是如此. 我们学校比较"抠",可能是为了节省学校的带宽资源然后禁止学生注册教育邮箱账号.不过像一部电影所说的那样&qu ...