天天看點

《HTML5遊戲程式設計核心技術與實戰》——2.3 圖像API

本節書摘來自異步社群《html5遊戲程式設計核心技術與實戰》一書中的第2章,第2.3節,作者: 向峰 更多章節内容可以通路雲栖社群“異步社群”公衆号檢視。

除了繪制常用的圖形以外,canvas提供了一系列的api能夠對圖像進行操作,常見的圖像api有以下3個方法。

drawimage (image, dx, dy):把image圖像繪制到畫布上(dx, dy)坐标位置。

drawimage (image, dx, dy, w, h):把image圖像繪制到畫布上(dx, dy)坐标位置,圖像的寬度是w,高度是h。

drawimage (image, sx, sy, sw, sh, dx, dy, dw, dh):截取image圖像以(sx, sy)為左上角坐标,寬度為sw,高度為sh的一塊矩形區域繪制到畫布上(dx, dy)坐标位置,圖像寬度是dw,高度是dh。

其中image可以是htmlimageelement元素、htmlcanvaselement元素、htmlvideoelement元素,htmlvideoelement元素是html5中新增加的video視訊播放元素。

《HTML5遊戲程式設計核心技術與實戰》——2.3 圖像API

https://yqfile.alicdn.com/72e8aa99f7730abe9609f15c55afa6a503f12e7f.png" >

圖2-14顯示了drawimage中源圖像和目标canvas之間的關系。

采用後面兩種方式進行繪制的時候可以實作圖像的放大和縮小。

**

2.3.1 使用canvas繪制圖像**

先看一個簡單的例子,我們把< image />标簽中的圖像顯示到一個canvas中。

代碼中有一個圖檔元素、一個按鈕和一個canvas元素,當點選按鈕的時候首先擷取了id為img1的圖檔的寬度和高度,然後改變canvas的大小,最後使用drawimage方法把img的圖檔繪制到canvas元素中,使用drawimage把img1繪制到canvas坐标(0, 0)的位置,大小和原圖像一樣大。

2.3.2 案例:放大鏡

現在,我們可以借助drawimage方法實作一個簡單的放大鏡效果,效果如圖2-15所示。

在這個放大鏡效果中,我們可以在任意一張圖檔上點選,在該位置就會出現一個圓形的放大鏡。實作原理也比較簡單,首先,需要擷取滑鼠目前的位置,然後根據放大鏡的尺寸,截取圖檔中相應大小的圖檔,最後通過drawimage方法把圖檔中的部分繪制到canvas上面。

這裡涉及一個問題,放大鏡是圓形的,但實際上如果直接通過canvas繪制,将最終以矩形的方式顯示。這裡,我們可以使用剪裁的方式進行繪制,所謂剪裁,就是在canvas中指定一塊區域,在這個區域之内的都會顯示,之外的一律不顯示,是以如果我們把剪裁區域設定成圓形就可以了。canvas中使用context.clip()方法定義一個畫布的剪裁路徑,方法沒有任何參數,它會使用目前的路徑作為一個剪裁的區域,預設情況下,整個canvas本身就是一個剪裁路徑。如 圖2-16所示,圖中定義了一個圓形的剪裁區域,在圓形之外的區域将不會顯示。

《HTML5遊戲程式設計核心技術與實戰》——2.3 圖像API

https://yqfile.alicdn.com/35d27e7f6c5a83d54d35ecf5cc2619fa90c25ad1.png" >

好了,有了以上的基本知識,現在可以開始制作一個放大鏡了,具體代碼如下:

除了實作靜态的效果外,還可以通過drawimage實作動畫效果。

2.3.3 案例:幀動畫實作

來看一個比較複雜的例子,該例子中實作了一個簡單的人物動畫,先簡單了解一下動畫的原理。通常我們看到的動畫稱為逐幀動畫,它是利用人眼睛視覺暫留的原理,即物體被移動後其形象在人眼視網膜上還可有約1秒的停留。利用這個原理,我們在一秒鐘内如果連續放映20張靜态的圖檔,這樣就形成了動畫的效果,當然20是最基本的要求,如果流暢的話至少要30幀/秒,也就是說每秒鐘放30張靜态圖檔,每一幀圖檔稱為一幀,在第4章的制作遊戲引擎中會詳細介紹動畫機制。

本例子中我們有3張人物行走的圖檔,這3張圖檔構成了人物行走的過程,為了提高效率通常情況下制作動畫的時候,會把人物的動作放在一張圖檔中,如圖2-17所示(該圖截取自遊戲《超級瑪麗》)。

《HTML5遊戲程式設計核心技術與實戰》——2.3 圖像API

這張圖檔包含了瑪麗行走的動畫,一共由3幀組成,我們在canvas上循環繪制這三張圖檔就形成了瑪麗行走的動畫,代碼如下:

來看看代碼功能,首先定義了幾個變量,isanimstart标記是否已經開始播放動畫标記,用來切換播放和停止動畫。animhandle儲存定時器的句柄,可以通過它關閉定時器,定義frames數組變量記錄圖檔中3個動作幀左上角的起始坐标,在繪制動畫的時候,需要根據這個坐标來截取圖檔中的每幀圖像。fwidth和fheight分别表示每幀圖檔的寬度和高度,本例中使用的瑪麗圖像幀是32×32大小。然後定義init初始化方法,在該方法中綁定了開始按鈕的事件,為了實作動畫的播放,使用了serinterval方法,該方法每100毫秒執行一次,每次讀取frames中的一幀圖像,并把它顯示在畫布上,其核心代碼是:

這段代碼首先使用ctx.clearrect方法清空整個畫布,因為在定時器動畫中需要每100毫秒更新畫布中的内容,那麼每次更新時,需要先把上個畫面清除掉,然後再進行繪制,否則會把幾張動畫重疊起來。然後使用了ctx.drawimage方法,把img1圖檔中的内容複制到canvas上面,複制的時候第1個參數是選取的圖檔,第2~5的參數分别對應着img1圖檔上的一塊矩形區域,最後4個參數對應着canvas上面的一塊矩形區域,實際上就是把圖檔上的某一矩形區域部分繪制到canvas上面,由于畫到canvas上面的寬度和高度分别是fwidth×4和fheight×4,實際上也就是把原圖像放大了4倍。

除了直接對圖檔元素操作外,canvas還提供了直接對像素元素進行處理的api。

2.3.4 像素操作

canvas另外一個非常強大的功能就是可以對圖像中的任一個像素進行處理。我們知道圖像實際上是由很多像素點組成,一幅寬度為320,高度200的圖檔是由320×200=64 000個像素點構成,每個像素由red、green、blue三種顔色組成。

canvas提供了以下api讓我們可以進行像素操作。

getimagedata (sx, sy, sw, sh):擷取canvas上以(sx, sy)為左上角,寬度為sw,高度為sh的一塊矩形區域的像素資料。通過getimagedata擷取到了imagedata對象,該對象有以下3個屬性。

width:每行的像素數量。

height:每列的像素數量。

data:存有從canvas中擷取的每個像素的rgba的值,該數組為每個像素儲存了四個值,分别是紅色、綠色、藍色和alpha透明度,每個值在0~255之間,數組填充的資料是從上到下,從左到右,比如imgdata.data[0]~imgdata.data[3]就儲存了canvas圖像中左上角第一個像素點的rgba的資料,imgdata.data[4]~imgdata.data[7]儲存了canvas圖像中左上角第二個像素點的rgba的資料,依次類推,從左到右,從上到下。

createimagedata (sw, sh):建立一個寬度為sw,高度為sh的imagedata對象,該對象中所有的像素都是黑色的。

createimagedata (imagedata):建立一個imagedata對象的副本,像素值和imagedata的一緻。

putimagedata (imagedata, dx, dy, [dirtyx, dirtyy, dirtywidth, dirtyheight]):在繪圖畫布上繪制給定的imagedata對象。假如髒矩形被提供,則隻有在髒矩形上面的像素被繪制。本方法對全局透明、陰影和全局組合等屬性均忽略。

data數組中的資料可以擷取也可以設定,我們可以把data中的資料進行修改後重新繪制達到修改圖像的目的。

利用可以對像素操作的特性,我們可以完成一些簡單的圖像處理效果,類似于photoshop中的濾鏡效果,如轉成灰階圖、浮雕效果等,接下來看看相關的例子。

2.3.5 案例:轉換灰階圖

現在來看一個簡單的像素操作的例子,該例子中會把任意一張彩色圖檔轉換成灰階圖檔,如圖2-18所示。

《HTML5遊戲程式設計核心技術與實戰》——2.3 圖像API

彩色圖像要轉換成灰階圖,需要對圖中的每一個像素點進行處理,我們可以通過getimage data()方法擷取每個點的像素值,然後把該點的色彩轉成灰階。彩色轉灰階的算法很多,這裡,我們采用以下算法:

灰階值=(r×30 + g×59 + b×11 + 50) / 100

具體實作代碼如下:

代碼先通過contex.drawimage把圖像繪制到canvas上,需要注意的是,隻有canvas上有圖像了才能通過getimagedata擷取canvas的圖像資料,然後定義imgdata變量得到canvas的圖像資料,接着通過循環imgdata資料,修改canvas圖像中的每個像素資料。因為每個圖像資料由4個值構成,是以循環data資料每次加4,然後接着擷取每個像素的rgb值,然後通過公式轉成灰階。

把彩色資訊轉成灰階資訊後,最後重新設定每個像素的顔色值,就完成了彩色圖到灰階圖的轉變。我們雖然改變了圖像的像素值,但是還不能讓圖像立刻變成我們想要的樣子,還需要重新把像素的資料繪制到canvas中,是以我們使用了putimagedata方法。

這樣就完成了整個的圖像轉變過程。

2.3.6 案例:浮雕效果

接下來,來實作一個浮雕效果,浮雕效果如圖2-19所示。

《HTML5遊戲程式設計核心技術與實戰》——2.3 圖像API

https://yqfile.alicdn.com/c730b1328421c27c2b165b5fb6e416eef0c84ca9.png" >

浮雕效果的實作原理也有很多種,常用的算法是把每個點周圍的8個點和一個轉換矩陣進行卷積操作,得到的值作為該點的新色彩。但計算量過大,這裡采用一種相對簡單的算法,該算法是這樣的,對于任一點的像素來說,新的色彩值等于該點的色彩和右邊像素的色彩值相減,然後加上128。

具體實作如下:

需要注意的是,在得到新的像素點色彩值之後,需要進行越界處理,并轉成灰階色彩,否則,該像素點還有可能是彩色點。

接下來,來看看坐标變換相關的一些知識。

繼續閱讀