基於canvas生成圖片

連城發表於2019-03-04

隨著APP的獲客成本越來越高,很多產品開始從wap頁引流,而最常見的方式便是分享,尤其是在微信中。因此誕生了一些新玩法,比如生成一張海報圖片,使用者可以儲存或分享到其他平臺。

本文將介紹如何生成一張海報圖片,以及可能會碰到的問題和解決方案。

canvas轉圖片

目前移動端瀏覽器對於canvas的支援非常好,而canvas可以通過toDataURL來轉換成base64圖片。

市場上的一些js庫,如:html2canvasdom-to-image,其本質也是通過toDataURL來轉換成圖片。但我個人不太建議使用這類js庫,因為你可能需要填很多坑,結果也並不一定能達到你的期望,所以還是老老實實用canvas畫出來吧。

外鏈圖片

最重要也是最複雜的便是對外鏈圖片的處理,canvas繪圖時不會有任何問題,但是呼叫toDataURL這個方法時,瀏覽器會報錯。

跨域

你請求的外域圖片,可能會暴露你的隱私,所以瀏覽器為了保護你的隱私限制了這樣的請求。

我們可以設定crossOriginanonymous來允許跨域,瀏覽器會為這張圖片的請求頭附帶Origin資訊,告訴靜態資源伺服器,請在響應頭中附帶Access-Control-Allow-MethodsAccess-Control-Allow-Origin,以便瀏覽器放行。

但是有些時候,設定了crossOrigin依然會報錯,其實不是設定了沒有作用,而是cdn快取了伺服器響應結果,這個結果往往是沒有上述兩個欄位的。這個時候可以考慮給圖片連結後追加時間戳,對於cdn來說,這是一個沒有請求過的資源,因此它會從源伺服器去拿資料。

程式碼示例如下:

var img = new Image()
img.crossOrigin = `anonymous`
img.onload = function () {
  // 在圖片載入完成後繪圖,避免空白和斷斷續續載入
  ctx.drawImage(img, 0, 0)
}
img.src = `https://xxxx` + `?` + (+new Date())
複製程式碼

儲存圖片

a標籤有一個download屬性,可以將指定的資源下載下來,但該方法只適用於pc端,移動端基本不支援(Safari會開啟一個base64的網頁,而在微信中甚至不會有任何響應,更不用提眾多的安卓機)。

既然不能在瀏覽器主動儲存圖片,我們只好另闢蹊徑,經調研發現:現在絕大多數的移動端瀏覽器都支援長按圖片喚起下拉選單來儲存,因此我們可以通過文案提示使用者進行操作,但它的弊端是沒有API來呼叫,也就是說只能提示使用者自發地進行長按儲存操作,而我們對於使用者是否儲存了圖片是無感知的。

文末總結

對於目前的產品需求,長按圖片儲存基本能夠滿足要求。所以,目前的做法是:通過canvas繪製一張海報圖片,將其轉換為base64圖片,建立img標籤並渲染到檢視上,文字提示使用者長按可以儲存(只有在圖片上長按才有效)。

示例程式碼:

var canvas = document.getElementById(`canvas`)
var ctx = canvas.getContext(`2d`)

canvas.width = 300
canvas.height = 300

// 畫圓
ctx.fillStyle = `yellow`
ctx.fillRect(0, 0, 50, 100)

ctx.strokeStyle = `blue`
ctx.strokeRect(0, 120, 50, 100)

var img = new Image()
img.onload = () => {
  // 畫圖片
  ctx.drawImage(img, 60, 0)
  // toImage
  var dataImg = new Image()
  dataImg.src = canvas.toDataURL(`image/png`)
  document.body.appendChild(dataImg) // 長按圖片儲存
}
img.crossOrigin = `anonymous`
img.src = `https://nos.netease.com/easyread/fle/a0df1d4009c7a2ec5fee/1524215500140/avatar.png?` + (+new Date())
複製程式碼

相關文章