问题描述
使用farbic.image生产图片的时候,需要将canvas导出成图片出现跨域问题
分析
这是由于canvas导出toDataURL
不允许引用跨域的图片,所以出现报错。
通过阅读源码,发现其实fabric加载图片的时候是通过创建img
标签来下载图片数据,所以只需要在img
标签设置允许跨域即可解决这个问题。
img.crossOrigin = 'anonymous'
解决方案
第一种:把图片转为base64
案例:
let base64 = ''// 服务器传输base64代替url路径
let arr = base64.split(',')
let mime = arr[0].match(/:(.*?);/)[1]
let bstr = atob(arr[1])
let n = bstr.length
let u8Arr=new Uint8Array(n)
while(n--){
u8Arr[n] = bstr.charCodeAt(n)
}
// 变成二进制格式
let blod = new Blod([u8Arr],[type:mime])
let url = ''
if (window.createObjectURL !== undefined) {
// basic
url = window.createObjectURL(blod)
} else if (window.URL !== undefined) {
// mozilla(firefox)
url = window.URL.createObjectURL(blod)
} else if (window.webkitURL !== undefined) {
// webkit or chrome
url = window.webkitURL.createObjectURL(blod)
}
// url保存的是本地临时路径,所以不会 出现跨域报错
// 由于不是加载的是本地文件,需要使用fabric提供的加载图片来加载,避免图片没有缓存时出现的不能正常刷新
fabric.Image.fromURL(url, (img) => {
let {width, height} = img
let proportion = 1
var oImg = img.set({ left: width / 2,
top: height/ 2,
originX: 'center',
originY: 'center'
}).scale(proportion)
canvas.add(oImg)
// 更新页面
this.canvas.renderAll()
})
第二种(推荐)使用fabric提供的参数允许跨域
let url = 'http://'
let img = new Image()
img.src = url
img.crossOrigin = 'anonymous'// 跨域
img.onload = () => {
let { width, height } = img
}
var imgInstance = new fabric.Image(url, {
left: width/ 2,
top: height / 2,
originX: 'center',
originY: 'center',
crossOrigin: 'anonymous'// 跨域
}).scale(proportion)
canvas.add(imgInstance)
this.canvas.renderAll()
这里出现了2次设置跨域,并不多余。
- 第一次设置跨域时,为了当前的图片可以进行跨域加载
- 第二次设置跨域时,为了使得
fabric
中的toObject
与toJSON
时能够保存到元素上的设置,这样使用loadCanvasFromObject
的时候可以自动给图片设置跨域。
在我遇到问题的时候,发现国内只考虑到了一次加载的问题,就是设置加载图片的允许跨域。
但是由于我的数据是允许多次重复加载的,不可能每次使用时需要把图片单独抽取出来进行加载,所以通过查找文档和源码发现了,fabric提供了跨域的设置。这样就可以解决多次加载的问题。