問題描述
使用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提供了跨域的設置。這樣就可以解決多次加載的問題。