天天看点

《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。

具体实现如下:

需要注意的是,在得到新的像素点色彩值之后,需要进行越界处理,并转成灰度色彩,否则,该像素点还有可能是彩色点。

接下来,来看看坐标变换相关的一些知识。

继续阅读