本文發佈於個人我的網站: http://wintc.top/article/27,轉載請註明。
前兩天給我的網站添加了一個小功能,就是在文章編輯上傳圖片的時候自動給圖片加上水印。給網頁圖片添加水印是個常見的功能,也是互聯網內容做者保護本身版權的方法之一。本文簡單記錄一下藉助canvas在前端實現圖片添加水印的實現方法。
canvas元素其實就是一個畫布,咱們能夠很方便地繪製一些文字、線條、圖形等,它也能夠將一個img標籤裏渲染的圖片畫在畫布上。
在上傳文件到後端的時候,使用input標籤讀取用戶本地文件後獲得的實際上是一個Blob對象(更精確的說是File對象,特殊的Blob對象);而在頁面上展現一個圖片使用的是img標籤;繪製功能用canvas實現。添加水印的功能須要在img標籤、canvas畫布、Blob對象這三者之間相互轉換,經過一些API能夠完成這個工做:javascript
咱們能夠從本地讀取圖片Blob,而後渲染到img標籤,使用canvas繪製img內容而且繪製水印內容到畫布,再將canvas內容轉爲Blob對象上傳服務器,這樣就完整實現了圖片+水印的功能。前端
本地讀取圖片文件將會獲得一個Blob對象,咱們能夠藉助FileReader.readAsDataURL方法讀取Blob的內容,並獲得一個Base64編碼的文件內容,能夠將該內容賦值給img.src從而在瀏覽器上渲染出本地的圖像。固然,img並不是必須渲染到DOM樹。讀取操做是個異步操做,讀取完成會觸發load事件,爲了便於以後的調用,咱們能夠用一個Promise包裝這個操做,最後返回一個Promise對象。java
function blobToImg (blob) { return new Promise((resolve, reject) => { let reader = new FileReader() reader.addEventListener('load', () => { let img = new Image() img.src = reader.result img.addEventListener('load', () => resolve(img)) }) reader.readAsDataURL(blob) }) }
調用canvas元素畫布上下文對象的drawImage方法便可實現將img內容繪製到畫布。canvas
function imgToCanvas (img) { let canvas = document.createElement('canvas') canvas.width = img.width canvas.height = img.height let ctx = canvas.getContext('2d') ctx.drawImage(img, 0, 0) return canvas }
drawImage這個方法能夠傳入多個參數,以定義繪製的圖像的範圍,這裏傳入的0, 0定義從圖像左上角開始繪製,後面能夠繼續傳入兩個參數來定義圖像的繪製終點,不過這裏整個圖片都要繪製到canvas,因此採用默認值便可。後端
在圖片上傳的時候,咱們一般採用FormData,圖片文件以一個Blob對象的形式放到FormData中,因此咱們須要把canvas再轉爲Blob以便文件上傳等操做。利用HTMLCanvasElement.toBlob方法:瀏覽器
function watermark (canvas, text) { return new Promise((resolve, reject) => { let ctx = canvas.getContext('2d') // 設置填充字號和字體,樣式 ctx.font = "24px 宋體" ctx.fillStyle = "#FFC82C" // 設置右對齊 ctx.textAlign = 'right' // 在指定位置繪製文字,這裏指定距離右下角20座標的地方 ctx.fillText(text, canvas.width - 20, canvas.height - 20) canvas.toBlob(blob => resolve(blob)) }) }
將以上三個步驟結合起來,就完整地實現了從圖片添加水印,下面是一個簡單的使用示例:從本地選擇一個圖片文件,而後添加水印後,在傳入的dom元素下預覽添加水印後的圖片。服務器
function imgWatermark (dom, text) { let input = document.createElement('input') input.setAttribute('type', 'file') input.setAttribute('accept', 'image/*') input.onchange = async () => { let img = await blobToImg(input.files[0]) let canvas = imgToCanvas(img) let blob = await watermark(canvas, text) // 此處將Blob讀取到img標籤,並在dom內渲染出來;若是是上傳文件,能夠將blob添加到FormData中 let newImage = await blobToImg(blob) dom.appendChild(newImage) } input.click() }
給頁面加一個id爲container的div元素,而後以下調用:app
let dom = document.querySelector('#container') imgWatermark(dom, '水印文字')
這樣就完整地給圖片添加了水印效果,下面看一下實際效果,你也能夠在線體驗。dom
添加水印前:異步
添加水印後(水印內容:「騰衝·清涼山」):
本文僅僅介紹了圖像+水印文字的簡單實現,只是作了一些示例性的介紹,其實能夠實現更復雜的水印效果,好比圖像、半透明或漸變色文字等,可是原理都是同樣的。另外文中涉及的一些接口其實頗有用,好比一個常見功能是頭像上傳的預覽和剪裁,這時候你能夠利用FileReader來讀取文件內容預覽,利用CanvasRenderingContext2D.drawImage來實現剪裁功能。關於本文涉及接口的更多詳細用法,能夠參照MDN文檔,文章中的API都使用了連接的形式,你能夠快速查看它們的文檔。