canvas 的 getImageData 和 toDataUrl 跨域問題

来源:https://www.cnblogs.com/Jomsou/archive/2020/07/18/13334741.html
-Advertisement-
Play Games

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


背景是這樣的,母親節的時候,我們有個需求就是用戶可以長按或者點擊一個按鈕進行截圖後去分享我們的活動,然而我們的圖片例如頭像,採用又拍雲做 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 解析為 anonymous

另外還有一點需要註意,那就是雖然沒有 crossOrigin 屬性,和設置 crossOrigin="use-credentials" 在預設情況下都會報跨域出錯,但是性質上卻不一樣,兩者有較大區別。

crossOrigin 相容性

IE11+(IE Edge),Safari,Chrome,Firefox 瀏覽器均支持,IE9 和 IE10 會報 SecurityError 安全錯誤,如下截圖:

img

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 = 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 = reader.result;
            img.src = base64data;
          };
          func && func(img)
        }
      };
    },

設置 nginx 代理

如 PHP 添加響應頭信息,* 通配符表示允許任意功能變數名稱:

header("Access-Control-Allow-Origin: *");

或者指定功能變數名稱:

header("Access-Control-Allow-Origin: www.zhangxinxu.com");

html2canvas 真實採坑記和建議

  1. 如果使用 vue 做數據渲染,不要在生成頁做太多數據處理的操作,提前把動態數據處理好,否則即便用 $nextTick 也會有在生成圖片時數據不完整的情況
  2. 引用 CDN 上的圖片,需要設置 useCORS 為 true,同時要保證所有圖片載入完成後再生成,可使用 new Imaage 做預載入和判斷是否全部 load
  3. 用背景 background,生成的圖片清晰度不夠,會模糊;用 img 引入的方式可避免這個問題
  4. 在 iOS 系統的 13.4.1,無法生成圖片,需要退回到 1.0.0-rc.4 版本,不要使用 1.0.0-rc.5 版本,issues 地址:https://github.com/niklasvh/html2canvas/issues/2205
  5. 可把生成的圖片設置透明度 opacity 為 0,蓋在原有元素之上,便於在微信保存,不會因為生成的圖和原有元素略微有差距,而抖動。

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • #安裝Node環境 在node.js01中我大概瞭解了什麼是node.js,這次進入起步階段,首先要安裝下Node環境。 ###開始安裝 查看當前Node環境的版本號 win+r輸入cmd進入命令行,輸入node --version 我這裡並沒有安裝!!! 下載:https://nodejs.org ...
  • 主要是用到了after偽類和字體符號。 1 input{ 2 -webkit-appearance: none; 3 -moz-appearance: none; 4 appearance: none; 5 display: inline-block; 6 } 7 input:after{ 8 co ...
  • 1.<video></video> 用於定義視頻,如影視片段 語法<video src="XXXmovie.mp4" controls></video> 支持視頻格式:mp4、ogg移動端、webM高清 常用屬性: src,視頻的地址url autoplay,視頻就緒後自動播放 controls,向 ...
  • 五角星形線的笛卡爾坐標方程式可設為: r=10+(3*sin(θ*2.5))^2 x=r*cos(θ) y=r*sin(θ) (0≤θ≤2π) 根據這個曲線方程,在[0,2π]區間取一系列角度值,根據給定角度值計算對應的各點坐標,然後在計算出的坐標位置繪製一個填充色交替變換的小圓,從而得到沿五角星形 ...
  • 1.新增類型 電子郵件類型,語法<input type="email"/>,input中輸入的內容必須包含“@”,並且“@”後面必須有內容 搜索類型,語法<input type="search"/>,輸入搜索關鍵字的文本框 URL類型,語法<input type="url"/>,輸入web站點的文本 ...
  • 一、安裝node.js(https://nodejs.org/en/) 下載完畢後,可以安裝node,建議不要安裝在系統盤(如C:)。 二、設置nodejs prefix(全局)和cache(緩存)路徑 1、在nodejs安裝路徑下,新建node_global和node_cache兩個文件夾 2、設 ...
  • 1.粒子文本的實現原理 粒子文本的實現原理是:使用兩張 canvas,一張是用戶看不到的canvas1,用來繪製文本;另一張是用戶看到的canvas2,用來根據canvas1中繪製的文本數據來生成粒子。 先在canvas1中用如下的語句繪製待顯示的文本。 ctx1.font = '100px Pin ...
  • 定位 定位:通過定位可以將元素擺放在頁面中任意位置 語法:position屬性設置元素的定位 可選值:static:預設值,開啟定位 relative開啟相對定位 absolute開啟絕對定位 fixed開啟固定定位 相對定位:當元素設置position:relative;開啟元素的相對定位 1 開 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...