基於canvas實現波浪式繪製圖片

Annn發表於2017-08-04

寫在最前

本次的分享是一個基於canvas的更新圖片特效實現。其中主要涉及canvas中getImageData()、putImageData()、toDataURL()方法的使用。效果請看下面。
歡迎關注我的部落格,不定期更新中——

PS:請在本地伺服器中開啟頁面,因谷歌瀏覽器中會有跨域問題,如需node靜態伺服器可以參照這個地址

效果預覽

點我檢視原始碼倉庫

實現流程

  • 點選換膚按鍵,在目標圖片的相應位置按照同等比例繪製一張空canvas畫布
  • 在畫布中以波浪的形式渲染圖片
  • 將畫布轉換為圖片

繪製canvas覆蓋層

1.獲取底圖即目標圖的尺寸

//當點選按鈕時傳遞底圖的寬高
var img = new Image()
img.src = 'xxx'
img.onload = function() {
    $('.btn').click(function() {
        ...
        var that = this
        var imgSize = {
            realHeight: that.height,
            realWidth: that.width
        }
        changeImg(imgSize, img)
    })
}複製程式碼

2.繪製畫布到相同位置

var changeImg = function(imgSize, oldImg) {
  var img = $(oldImg),
      offset = img.offset(),
      imgLeft = offset.left,
      imgTop = offset.top,
      canvasId = 'canvas'
  $('body').append('<canvas id='+ canvasId +' width='+ imgSize.realWidth+' height='+ imgSize.realHeight +'></canvas>')
  $('#'+ canvasId).css({
    'position': 'absolute',
    'left': imgLeft,
    'top': imgTop,
    'z-index': 1
  })
  ...
}複製程式碼

以波浪的形式渲染圖片

首先來介紹下getImageData()、putImageData()這兩個方法

CanvasRenderingContext2D.getImageData() 返回一個ImageData物件,用來描述canvas區域隱含的畫素資料,這個區域通過矩形表示,起始點為(sx, sy)、寬為sw、高為sh。

CanvasRenderingContext2D.putImageData() 是 Canvas 2D API 將資料從已有的 ImageData 物件繪製到點陣圖的方法。

這其中的重點則是ImageData物件是什麼。不妨我們列印一下看看:


可以看出一個2乘2的畫布佔4個畫素,其中列印了一個長度為16的一維陣列,結合文件中的講解我們可以知道,其中每一個畫素均有4位分別為rgba,故通過getImageData()我們可以得到一個拍平了的rgba陣列,那麼當我們動態的去改變一些東西的時候整個影象的色值透明度就會引起相應的變化,想想還有些小激動呢。同時putImageData()就很好理解了。當我們改變完畫素數值後通過這個方法再反饋到畫布上。

//核心程式碼
//通過sin函式畫出曲線
var imgData = content.getImageData(0, 0, width, height)
for(var i = 0; i < width / 10; i+=0.1 ) {
    x=Math.round(i*10)
    y=Math.round(Math.sin(i - t) * scale + initY) 
    //scale為曲線幅度,initY為初始位置
    for(var k = 0; k < y; k++) { 
        var sym = x * 4 + k * width * 4 
        //每個畫素4位,sym表示當前為第幾個畫素的第一位
        imgData.data[sym + 3] = 0 //令該畫素點變透明
        //imgData.data[sym + 3]會到達該畫素點的透明度位即第四位
    }
}
content.putImageData(imgData, 0, 0, 0, 0, width, height)複製程式碼

其中initY為sin曲線的縱座標位置,那麼當動態減小這個iniY時影象渲染的曲線會一點點向上,同時透明的區域便一點點變小,同時改變t值會另曲線橫向移動,以此來形成最後的波浪形並緩緩向上的效果。

將畫布轉換為圖片

oldImg.src = oCanvas.toDataURL('image/png')
$(oCanvas).remove()複製程式碼

通過toDataURL()方法,可以使畫布轉換成base64形式的img圖片,將其替換到舊圖片的url中便可以實現圖片的更新特效。

最後

慣例po作者的部落格,不定時更新中——
有問題歡迎在issues下交流,捂臉求star=。=

相關文章