背景是這樣的,母親節的時候,我們有個需求就是用戶可以長按或者點擊一個按鈕進行截圖后去分享我們的活動,然而我們的圖片例如頭像,采用又拍云做 cdn 優化,所以意味著圖片的鏈接跟主頁面所在域名不一樣,當需要需要對 canvas 圖片進行 getImageData() 或 toDataURL() 操作的時候,跨域問題就出來了,

對于跨域的圖片,只要能夠在網頁中正常顯示出來,就可以使用 canvas 的 drawImage() API 繪制出來,但是如果你想更進一步,通過 getImageData() 方法獲取圖片的完整的像素資訊,則多半會出錯,
舉例來說,使用下面代碼獲取 github 上的自己頭像圖片資訊:
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
var img = new Image();
img.onload = function () {
context.drawImage(this, 0, 0);
context.getImageData(0, 0, this.width, this.height);
};
img.src = 'https://avatars3.githubusercontent.com/u/496048?s=120&v=4';';
結果在 Chrome 瀏覽器下顯示如下錯誤:
Uncaught DOMException: Failed to execute ‘getImageData’ on ‘CanvasRenderingContext2D’: The canvas has been tainted by cross-origin data.

Firefox 瀏覽器錯誤為:
SecurityError: The operation is insecure.
如果使用的是 canvas.toDataURL()方法,則會報:
Failed to execute ‘toDataURL’ on ’HTMLCanvasElement’: Tainted canvased may not be exported
原因其實都是一樣的,跨域導致,
那有沒有什么辦法可以解決這個問題呢?
可以試試 crossOrigin 屬性,
HTML crossOrigin 屬性解決資源跨域問題
在 HTML5 中,有些元素提供了支持 CORS(Cross-Origin Resource Sharing)(跨域資源共享)的屬性,這些元素包括 ,,`` 等,而提供的屬性名就是 crossOrigin 屬性,
因此,上面的跨域問題可以這么處理:
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
var img = new Image();
img.crossOrigin = '';
img.onload = function () {
context.drawImage(this, 0, 0);
context.getImageData(0, 0, this.width, this.height);
};
img.src = 'https://avatars3.githubusercontent.com/u/496048?s=120&v=4';';
增加一個 img.crossOrigin = '' 即可,雖然 JS 代碼這里設定的是空字串,實際上起作用的屬性值是 anonymous,
crossOrigin 可以有下面兩個值:
| 關鍵字 | 釋義 |
|---|---|
| anonymous | 元素的跨域資源請求不需要憑證標志設定, |
| use-credentials | 元素的跨域資源請求需要憑證標志設定,意味著該請求需要提供憑證, |
其中,只要 crossOrigin 的屬性值不是 use-credentials,全部都會決議為 anonymous,包括空字串,包括類似 'abc' 這樣的字符,
例如:
img.crossOrigin = 'abc';
console.log(img.crossOrigin); // 結果是'anonymous'

另外還有一點需要注意,那就是雖然沒有 crossOrigin 屬性,和設定 crossOrigin="use-credentials" 在默認情況下都會報跨域出錯,但是性質上卻不一樣,兩者有較大區別,
crossOrigin 兼容性
IE11+(IE Edge),Safari,Chrome,Firefox 瀏覽器均支持,IE9 和 IE10 會報 SecurityError 安全錯誤,如下截圖:

crossOrigin 屬性為什么可以解決資源跨域問題?
crossOrigin=anonymous 相對于告訴對方服務器,你不需要帶任何非匿名資訊過來,例如 cookie,因此,當前瀏覽器肯定是安全的,
就好比你要去別人家里拿一件衣服,crossOrigin=anonymous 相對于告訴對方,我只要衣服,其他都不要,如果不說,可能對方在衣服里放個竊聽的工具什么的,就不安全了,瀏覽器就會阻止,
下載到本地
IE10 瀏覽器不支持 crossOrigin 怎么辦?
我們請求圖片的時候,不是直接通過 new Image(),而是借助 ajax 和 URL.createObjectURL() 方法曲線救國,
代碼如下:
var xhr = new XMLHttpRequest();
xhr.onload = function () {
var url = URL.createObjectURL(this.response);
var img = new Image();
img.onload = function () {
// 此時你就可以使用canvas對img為所欲為了
// ... code ...
// 圖片用完后記得釋放記憶體
URL.revokeObjectURL(url);
};
img.src = https://www.cnblogs.com/Jomsou/p/url;
};
xhr.open('GET', url, true);
xhr.responseType = 'blob';
xhr.send();
此方法不僅 IE10 瀏覽器 OK,原本支持 crossOrigin 的諸位瀏覽器也是支持的,
也就多走一個 ajax 請求,還可以!
根據,根據實踐發現,在 IE 瀏覽器下,如果請求的圖片過大,幾千像素那種,圖片會加載失敗,我猜是超過了 blob 尺寸限制,
后來采用的解決方案是:把圖片下載到本地(前端或者是后端都可以,最后采用我前端來做)
getAvator(user, func) {
window.URL = window.URL || window.webkitURL; // Take care of vendor prefixes.
var xhr = new XMLHttpRequest();
xhr.open('GET', user.avatar, true);
xhr.responseType = 'blob';
xhr.send()
xhr.onload = function(e) {
const {target} = e
const {status, response, readyState} = target
if (readyState == 4 && status == 200) {
var blob = response;
var img = document.createElement('img');
img.classList.add("avatar")
var reader = new window.FileReader();
reader.readAsDataURL(blob);
reader.onloadend = function() {
var base64data = https://www.cnblogs.com/Jomsou/p/reader.result;
img.src = base64data;
};
func && func(img)
}
};
},
設定 nginx 代理
如 PHP 添加回應頭資訊,* 通配符表示允許任意域名:
header("Access-Control-Allow-Origin: *");
或者指定域名:
header("Access-Control-Allow-Origin: www.zhangxinxu.com");
html2canvas 真實采坑記和建議
- 如果使用 vue 做資料渲染,不要在生成頁做太多資料處理的操作,提前把動態資料處理好,否則即便用 $nextTick 也會有在生成圖片時資料不完整的情況
- 參考 CDN 上的圖片,需要設定 useCORS 為 true,同時要保證所有圖片加載完成后再生成,可使用 new Imaage 做預加載和判斷是否全部 load
- 用背景 background,生成的圖片清晰度不夠,會模糊;用 img 引入的方式可避免這個問題
- 在 iOS 系統的 13.4.1,無法生成圖片,需要退回到 1.0.0-rc.4 版本,不要使用 1.0.0-rc.5 版本,issues 地址:https://github.com/niklasvh/html2canvas/issues/2205
- 可把生成的圖片設定透明度 opacity 為 0,蓋在原有元素之上,便于在微信保存,不會因為生成的圖和原有元素略微有差距,而抖動,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/34152.html
標籤:JavaScript
