canvas.toDataURL()报错的解决方案全都在这了

软件发布|下载排行|最新软件

当前位置:首页IT学院IT技术

canvas.toDataURL()报错的解决方案全都在这了

小云菜   2020-03-29 我要评论
**报错详尽信息**

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='anonymouse'` 3. 如果还不行,这里先不把答案放出来,我们先看看栗子 ---- 在接下来的栗子中我们会用到将`Image`转换为`canvas`对象的方法 ```js 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`未设置跨域允许选项 ```html

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

``` ```js function setCanvas(DOMID) { let img = document.getElementById(DOMID).querySelector('img') document.body.appendChild(convertImageToCanvas(img)) } ``` 很显然,报错 #### 栗子2 本地标签内设置跨域允许选项, `web-server`未设置跨域允许选项 这次连图片都出不来,直接报错 这个好理解,浏览器[同源策略](https:/https://img.qb5200.com/download-x/developer.mozilla.org/zh-CNhttps://img.qb5200.com/download-x/docs/Web/Security/Same-origin_policy)限制嘛

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`设置跨域允许选项 ```html

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

``` **居然可以了**,但是~如果在代码内设置跨域呢? ### 栗子5 ```js function setCanvas(DOMID) { let img = document.getElementById(DOMID).querySelector('img') img.crossOrigin= 'anonymous' document.body.appendChild(convertImageToCanvas(img)) } ``` **报错** 我看[官方文档](https:/https://img.qb5200.com/download-x/developer.mozilla.org/zh-CNhttps://img.qb5200.com/download-x/docs/Web/API/HTMLImageElement/crossOrigin)的意思是必须同步设置`crossOrigin=anonymouse`,该图片凭证才会被信任 *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 ```js 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`的相关跨域配置见下方 ```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'}) ```

Copyright 2022 版权所有 软件发布 访问手机版

声明:所有软件和文章来自软件开发商或者作者 如有异议 请与本站联系 联系我们