Canvas 多端實現生成圖片及儲存功能
在專案中需要實現生成圖片並儲存到本地的功能,其中包含網路圖片及後端介面返回資料。 而 canvas
作為 HTML5
中新增的標籤,主要用於在網頁實時生成影象,並且可以操作影象內容,故選取 canvas
畫圖方式進行實現是一個不錯的選擇,並且可以通過轉化為圖片格式,來實現圖片的下載儲存功能。
canvas的多端實現及對比
本文開篇為 canvas
多端實現的圖文對比及基本使用方式,比較適合 canvas
入門。對於已經熟悉 canvas
的同學,也可以直接閱讀後文關於 canvas
實現過程中遇到的一些問題,比如無法實現長按下載及 ios
中出現的圖片被旋轉的相容性總結,希望能夠對大家有所幫助~
canvas在H5中的實現
專案架構採用vue.js單頁面應用。主要實現過程是通過 <canvas>
進行繪圖,並轉換成 <img>
標籤展示,以此實現長按下載功能。
-
建立canvas標籤
由於要對圖片實現長按儲存, canvas
標籤無法直接實現,而後文將採用 img
標籤進行覆蓋以實現該功能。故此處將 canvas
樣式設定為 display:none
進行隱藏。
-
getContext() 方法獲得渲染上下文和它的繪畫功能
注意此處建立 canvas
繪圖上下文要在 mounted
函式中建立,即頁面完成掛載之後執行,否則會報無法讀取未定義屬性 getContext
的錯誤。 getContext()
只有一個引數:上下文的格式,此處為 2D
影象。
-
引入影象到 canvas
-
通過
newImage()
獲得一個指向HTMLImageElement
的物件 -
img.setAttribute('crossOrigin','anonymous')
解決跨域問題 -
img.src
設定圖片源地址 -
使用
drawImage()
函式將圖片繪製到canvas
畫布上
圖片載入是非同步的,若呼叫 drawImage()
時圖片沒載入完那畫布上就會是空的,用 onload
事件保證不會在載入完畢之前使用這個圖片。
-
將 canvas 轉換成圖片格式
此時可以得到以 base64
編碼的 base64Url
,引數 type
指定圖片型別,如果指定的型別不被支援則以預設值 image/png
替代; encoderOptions
可以設定圖片質量。
-
實現儲存圖片到本地
將返回的 base64Url
賦值給 <img>
標籤的 src
屬性,即可將繪製完成的影象以 <img>
標籤展示出來。
使用上述方式通常可以直接實現長按下載並儲存至本地。但在安卓系統中,卻可能存在app 中不支援直接長按儲存以 base64
格式展示的圖片的情況,故本文第二部分便針對該問題進行了實現。
canvas在小程式端的實現
canvas是小程式的原生元件,使用時需注意相關限制。其實現思路雖與H5中大致相同,但由於小程式封裝了自身的api,故本文對其進行了相應分析與總結。基本實現方式如下:
-
建立canvas標籤,此處需指定canvas-id作為canvas 元件的唯一識別符號
-
建立 canvas 繪圖上下文
使用 wx.createCanvasContext
方法建立 canvas
繪圖上下文,返回 CanvasContext
是小程式內建的一個物件,包含了一些繪圖的方法可供使用。
-
引入影象及文字到 canvas
由於小程式本身不支援在手機端用 canvas
繪製線上圖片,所以需要把圖片的線上地址換成本地路徑,然後再用本地路徑去進行 canvas
繪製。
-
使用
wx.getImageInfo()
獲取圖片資訊,返回圖片本地路徑(即下載一個網路圖片到本地,同時需先配置download
域名才能生效) -
使用
drawImage()
方法繪製圖像到畫布 -
必須使用
draw()
方法將繪圖上下文中的描述繪製上去,否則頁面將為空
-
將canvas 轉換成圖片格式
wx.canvasToTempFilePath()
方法把當前畫布指定區域的內容匯出生成指定大小的圖片,並返回檔案路徑。
-
儲存圖片到系統相簿
使用 wx.saveImageToPhotosAlbum()
儲存圖片到系統相簿,需要使用者授權 scope.writePhotosAlbum
。其中引數 filePath
是圖片檔案路徑,可以是臨時檔案路徑也可以是永久檔案路徑,注意不支援網路圖片路徑。
小結:無論是 H5 中的 toDataURL()
方法還是小程式中的 canvasToTempFilePath()
方法,都需要在圖片載入完成後執行,否則頁面將會呈現空白。由於我們無法精準得到圖片完成載入的時長,故此處最好添加回調或使用 promise
物件,以確保後續處理任務(比如傳遞到其他伺服器或儲存相簿)成功執行。
canvas 實現中遇到的問題
圖片無法長按儲存問題
在一般的開發中, canvas
標籤雖沒有像小程式這樣可直接實現儲存至相簿的方法,但卻可以通過轉換成 <img>
標籤進行展示,通過長按下載來儲存至相簿。但安卓手機在某些 app 中卻存在不支援直接長按儲存以 base64
格式展示的圖片的情況。故針對這種情況本文將 base64
資料適當處理,並通過後端返回圖片地址來實現長按儲存圖片至本地功能。
-
由於後端上傳介面又大多接收檔案格式的資料,此處首先將
base64
格式轉換成blob
格式:
-
然後新增至
FarmData
物件並傳輸後端,通過將返回的url
資料賦值給img
標籤的src
屬性機箱展示,即可實現長按下載儲存功能
ios拍攝的圖片被旋轉問題
當繪製的 canvas
圖片中包含本地拍照上傳的圖片時,那麼又會出現一個新的問題,如果使用本地拍照功能, ios
會針對橫豎屏拍照進行處理, ios
豎屏拍照上傳的照片,在安卓系統下顯示會被旋轉90度,故此時可以採用 canvas
對特定圖片進行旋轉解決方式。
-
首先獲取 ios 拍照資訊
判斷當前系統是否為 ios
,如果是的話此處可通過採用 exif-js
外掛來讀取影象的原始資料,以獲取拍照方向。
-
針對ios豎屏拍照,即拍攝方向屬性
Orientation=6
時,可應用canvas
的rotate()
方法將其旋轉90度,再後續對圖片進行儲存處理
總結
本文分別從 canvas
的多端實現及 canvas
使用過程中遇到的一些問題進行了總結,如果你還沒有入門 canvas
的話,也許能從本文對 canvas
有個初步瞭解,並希望可以獲得些許幫助。而 canvas
的深入使用還有很多地方值得探索,希望大家多多嘗試並提出寶貴意見。當然,我們的公眾號裡有更多小哥哥小姐姐帶來的前言技術文章,關注走起!~~