先說下canvas繪圖的基本方法,如下:
const myCanvas = document.createElement('canvas'); myCanvas.width = 400; myCanvas.height = 400;const ctx = myCanvas.getContext('2d');const img = new Image();img.src = 1.jpg;//當圖片載入完畢的時候在drawImage,否則可能圖片還沒載入完畢img.onload=()=>{ ctx.drawImage(img, 0, 0, 100, 50);}文法:
drawImage(image, x, y)
以canvas上指定的座標點開始,依照影像的原始尺寸大小繪製整個影像。
drawImage(image, x, y, width, height)
以canvas上指定的座標點開始,以指定的大小(width和height)繪製整個影像,影像會自動縮放。
drawImage(image, imageX, imageY, imageWidth, imageHeight, x, y, width, height)
將指定影像的局部影像(以(imageX, imageY)為左上角、寬度為imageWidth、高度為imageHeight的矩形部分)繪製到canvas中以( x, y)為左上角座標、寬度為width、高度為height的矩形區域中
這次多圖拼合的業務場景是做不同內容的客製化分享圖片,用到的圖片元素有,背景圖片、外鏈圖片、網站logo、客製化生產的二維碼圖,需要解決的問題,都是在畫布轉圖片輸出時產出的。主要有3點:
1、圖片的跨域問題;
2、繪製多圖,造成的畫布污染;
3、圖片的大小;
首先圖片的跨域問題,這個問題在網路上已經有很多相關訊息,解決方法如下:
img.setAttribute('crossOrigin', 'anonymous');
當解決跨域問題後,在多圖拼合導出後,出現了新的報錯資訊:
Uncaught DOMException: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted Canvases may not be exported.
我發現這個問題時,查看網路上的資料,大多也是用上面的跨域方法解決的,可是我明顯在我的業務場景裡是不管用的。
透過程式碼的排查,我發現,背景圖+二維碼圖時,並不會報這個錯誤,如外鏈圖片做了跨域處理,單獨使用時,也不會報錯。而logo圖片都是本地的文件,顯然不應該是跨域問題。
那麼二維碼圖和背景圖能夠不出錯的原因,應該在於二維碼圖片來源是base64格式的。
於是,我試著將logo圖使用畫布匯出base64格式,然後跟背景圖+二維碼圖拼合,匯出時果然沒再報錯。
所有解決多圖拼合導出時,Tainted Canvases的問題,應該是將圖片元素做成base64的格式,就能夠避免了。
因為我的業務場景中有外鏈圖片,而且不是所有的外鏈都對我網站域名做了跨域允許的處理,所以,在生成外鏈圖片的base64數據時,可是使用img.onerror事件的處理,用缺省圖替換。
因為有在畫總圖之前,有對多圖的分別處理,因此,使用Promise處理可能會更好一些。
在圖片匯出的大小問題上,匯出時盡量使用
myCanvas.toDataURL('image/jpeg', encoderOptions)
encoderOptions:可以從0到1的區間內選擇圖片的品質。如果超出取值範圍,將會使用預設值0.92。其他參數會被忽略。
以上個人對canvas拼合多圖並匯出圖片的經驗總結。 希望對大家的學習有幫助,也希望大家多多支持VeVb武林網。