1. 程式人生 > >canvas.toDataURL()報錯的解決方案全都在這了

canvas.toDataURL()報錯的解決方案全都在這了

**報錯詳盡資訊**

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://developer.mozilla.org/zh-CN/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://developer.mozilla.org/zh-CN/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: 'anonymou