Canvas 跨域脫坑實踐

Canvas 跨域如何解決?這裏記錄下使用 Canvas 繪圖過程中所遇到的跨域問題和解決方案。

先來看下實現方法。

實現方法

目標圖片一般是由 圖片 + 文本 構成。無論是千奇百怪的大小圖片,還是變幻莫測的各式文本,都能用 canvas api drawImagefillText 方法來完成。

基本流程如下:

  1. 獲取 canvas 上下文 -- ctx

    const canvas = document.querySelector(selector)
    const ctx = canvas.getContext('2d')
  2. 繪圖

    忽略圖片上的內容,直接用 drawImage 將其畫到 canvas 畫布上即可。

    const image = new Image()
    image.src = src
    image.onload = () => {
        ctx.save()
        // 這裏我們採用以下參數調用
        this.ctx.drawImage(image, dx, dy, dWidth, dHeight)
        this.ctx.restore()
    }

    drawImage 有3種參數使用方式,具體用法可以查看 MDN 文檔

  3. 獲取圖像數據

    調用 HTMLCanvasElement DOM 對象提供的 toBlob(), toDataURL()getImageData() 方法,即可。

    canvas.toBlob(blob => {
        // 你要的 blob
    }, mimeType, encoderOptions)

    這裏的 mimeType 默認值爲 image/pngencoderOptions 指定了圖片質量,可用於壓縮,不過需要 mimeType 格式爲 image/jpeg 或者 image/webp

Canvas 跨域

正常情況下,如果需要將繪製好的圖像輸出,我們可以調用 canvastoBlob(), toDataURL()getImageData() 方法來獲取到圖像數據。然而,遇到圖片跨域的情況就有些尷尬了。可能回報如下錯誤:

Failed to execute 'toBlob' on 'HTMLCanvasElement': Tainted canvases may not be exported.

或者

Access to image at 'https://your.image.src' from origin 'https://your.website' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

先來看看第2種情況。

  • Access-Control-Allow-Origin
    如果你跨域使用某些圖片資源,並且該服務未正確響應 Access-Control-Allow-Origin 頭信息, 則會報出如下錯誤信息:

    Access to image at 'https://your.image.src' from origin 'https://your.website' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

    說明不允許跨域訪問,那麼你可以試着讓後臺修改 Access-Control-Allow-Origin 的值爲 *your.website, 或者改用同域資源(考慮下?)。

接下來,我們來解決第1種情況。

  • img.crossOrigin = 'Anonymous'
    爲避免未經許可拉取遠程網站信息而導致的用戶隱私泄露(如 GPS 等信息,具體可搜索 Exif),在調用 canvastoBlob(), toDataURL()getImageData() 會拋出安全錯誤:

    Failed to execute 'toBlob' on 'HTMLCanvasElement': Tainted canvases may not be exported.

    如果你的圖片服務允許跨域使用(如果不允許,見上條),那麼你該考慮下給 img 元素加上 crossOrigin 屬性,即:

    const image = new Image()
    image.crossOrigin = 'Anonymous'
    image.src = src

如此,你便可以拿到圖片數據了。如果沒招,換同域資源吧~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章