用 canvas 的 getImageData 作點有趣的事

說明

canvas元素標籤強大之處在於能夠直接在HTML上進行圖形操做,具備極大的應用價值。

canvas 能夠實現對圖像的像素操做,這就要說到 getImageData() 方法了。html

解釋

CanvasRenderingContext2D.getImageData() 返回一個 ImageData 對象,用來描述 canvas 區域隱含的像素數據,這個區域經過矩形表示,起始點爲(sx, sy)、寬爲sw、高爲sh。前端

語法

ctx.getImageData(sx, sy, sw, sh);git

參數

sx:將要被提取的圖像數據矩形區域的左上角 x 座標。github

sy:將要被提取的圖像數據矩形區域的左上角 y 座標。面試

sw:將要被提取的圖像數據矩形區域的寬度。算法

sh:將要被提取的圖像數據矩形區域的高度。canvas

返回值

一個 ImageData 對象,包含 canvas 給定的矩形圖像數據。segmentfault

ImageData 對象會有三個屬性,heightwidthdata跨域

ImageData.height
使用像素描述 ImageData 的實際高度,這個值其實等於 getImageData() 方法中的參數 sh數組

ImageData.width
使用像素描述 ImageData 的實際寬度。這個值其實等於 getImageData() 方法中的參數 sw

ImageData.data
一個一維數組,包含以 RGBA 順序的數據,數據使用 0 至 255(包含)的整數表示。

注意

若是高度(sh)或者寬度(sw)變量爲0,則會拋出錯誤。

示例

以上是須要知道的基本知識,下來看幾個例子吧!

顏色選擇器

效果圖

color—selector.gif

實現思路

一、先把圖片畫到 canvas 上,
二、獲取鼠標移動時的座標並經過 getImageData() 方法,獲取這一個點的像素,
三、獲得像素信息後,拼接出 rgba 的字符串,再設置下面的小正方形的背景是這個顏色。

代碼請點這裏

圖片灰度

效果圖

實現思路

一、先在 canvas 上畫出圖片,
二、經過 getImageData() 方法,獲取整個 canvas 上的像素信息,
三、點擊按鈕時,遍歷獲取到的像素信息的每一個像素的 紅色值、綠色值 和 藍色值,相加求出平均值,再把平均值賦值給紅色、綠色和藍色,這麼作是爲了求出每一個像素的灰度,
四、而後把改變後的像素信息,經過 putImageData() 方法從新添加到 canvas中,就實現了圖片灰度的效果。

代碼請點這裏

除了圖片能夠實現灰度的效果外,由於 canvas 中也能夠放視頻,對於視頻也能夠實現灰度的效果,原理都是同樣的,操做其實也同樣,其實視頻作灰度效果,能夠理解爲給不少張圖片作灰度效果。

效果圖

代碼請點這裏

文字粒子

效果圖

實現思路

咱們先不說,怎麼實現最後的動畫效果,咱們先來想怎麼獲取文字全部像素在 canvas 上的座標,

一、先獲取文字在canvas上的像素信息

  • 1.1 先在 canvas 上填充一個白色矩形
  • 1.2 用紅色,在 canvas 上寫文字
  • 1.3 獲取 canvas 的像素信息 ImageData
  • 1.4 清除整個 canvas
  • 1.5 在 ImageData 中找出是紅色的像素,記錄他們的 x 和 y 座標,找出的每一個像素的座標都保存在一個對象(Dot)中,全部的對象又都保存在一個數組(dotList)中,

計算機的速度是很快的,因此用戶是看不到紅色文字的,若是你以爲這種方式很差,也能夠在用一個 canvas 專門來獲取文字像素,這個canvas 不要讓用戶看到就行了。

咱們知道文字的像素信息,知道每一個像素的座標,就能實現各類效果,像示例中的效果,僅僅只是改變一個 x 座標的值而已。

二、遍歷保存文字像素的數組(dotList),每一個像素(Dot)對象還有一個 nowX 屬性,初始值是0,每次畫最後的圓點的時候,都是用這個屬性做爲圓的 x 座標,nowX 屬性不斷的增長,直到最後等於像素(Dot)對象的 x 屬性值就中止。

代碼請點這裏

這種效果我也是在 Canvas基礎-粒子動畫Part3 這篇文章中看到的,做者寫的很好,推薦看看。
在github上也有一個不錯的項目 shape-shifter,能夠了解一下。

計算圖片中的圖形個數和麪積

問題

平面上有若干個不特定的形狀,以下圖所示。請寫程序求出物體的個數,以及每一個不一樣物體的面積。

效果圖

實現思路

一、建立存儲圖片像素點的二維數組(coordinates ),圖中只有兩種顏色,空白區域一種顏色,形狀區域一種顏色,空白區域的像素標記爲0,形狀區域標記爲1,相似下面這樣

0,0,0,0,0,0,0,0,0,0,0,0
 0,0,1,1,1,0,0,0,0,0,0,0
 0,1,1,1,1,0,0,0,0,0,0,0
 0,1,1,1,0,0,0,1,1,1,1,0
 0,0,0,0,0,0,1,1,1,0,0,0
 0,0,0,0,0,0,1,1,1,0,0,0
 0,0,0,0,0,0,0,0,0,0,0,0

二、計算有多少個形狀,就是看二維數組中有多少個連續爲1的塊,計算形狀的面積,就是算一個連續爲1的塊,有多少個1。
這就要經過 遞歸回溯算法 來計算了。

回溯算法實際上一個相似枚舉的搜索嘗試過程,主要是在搜索嘗試過程當中尋找問題的解,當發現已不知足求解條件時,就「回溯」返回,嘗試別的路徑。
回溯法是一種選優搜索法,按選優條件向前搜索,以達到目標。但當探索到某一步時,發現原先選擇並不優或達不到目標,就退回一步從新選擇,這種走不通就退回再走的技術爲回溯法。

代碼請點這裏

這裏有一個示例,展現下用回溯法怎麼找到這些形狀的。

這個例子出自 前端面試的一道算法題(使用canvas解答)這篇文章,文章講的也很好,推薦看看

總結

getImageData() 方法 要考慮兩個問題

一、跨域問題
getImageData() 方法不容許操做非此域名外的圖片資源,因此若是想本地試試文章中的例子,直接寫圖片路徑就會報錯,

不過能夠將圖片轉換成base64編碼,直接把base64編碼賦值給圖片的src屬性就能夠簡單的解決這個問題了。這種方式僅僅適用於圖片,若是是視頻的話,仍是須要服務器端的配合。
具體能夠看看這篇文章 解決canvas圖片getImageData,toDataURL跨域問題

二、性能問題
getImageData() 方法通常獲取的像素信息是不少的,因此這就要考慮性能的問題,至於怎麼優化也是要看具體場景了,好比在文中的文字粒子效果的示例中,能夠先用 measureText() 方法計算文字寬度,結合 fontSize 就能知道 文字在哪塊區域,只經過這個塊區域獲取文字的像素就行了。

getImageData() 方法,一句話總結就是獲取 canvas 上的像素信息,文中實現的各類效果不論是簡單的仍是複雜的,都是在操做像素。
經過getImageData() 方法,能作的事情還有不少,遠不止文章中提到的這些,好比實現其餘的濾鏡效果,文中只是說了一個灰度,咱們還能夠去實現反相,模糊,浮雕等,文中實現了文字粒子效果,其實圖片也能夠實現粒子效果,除此以外還有不少好玩的事情,可是本人才疏學淺,好多我也不知道。
最後,若是文中有不足或者錯誤的地方,還請小夥伴們指出,萬分感謝。

參考

Canvas基礎-粒子動畫Part3
前端面試的一道算法題(使用canvas解答)
leetcode題解(遞歸和回溯法)

相關文章
相關標籤/搜索