基于canvas粒子系统的构建详解

关于图像数据imageData共有3个方法,包括getImageData()、putImageData()、createImageData()

【getImageData()】

2D上下文可以通过getImageData()取得原始图像数据。这个方法接收4个参数:画面区域的x和y坐标以及该区域的像素宽度和高度

例如,要取得左上角坐标为(10,5)、大小为50*50像素的区域的图像数据,可以使用以下代码:

var imageData = context.getImageData(10,5,50,50);

返回的对象是ImageData的实例,每个ImageData对象有3个属性:width\height\data

1、width:表示imageData对角的宽度

2、height:表示imageData对象的高度

3、data是一个数组,保存着图像中每一个像素的数据。在data数组中,每一个像素用4个元素来保存,分别表示red、green、blue、透明度

[注意]图像中有多少像素,data的长度就等于像素个数乘以4

//第一个像素如下 var data = imageData.data; var red = data[0]; var green = data[1]; var blue = data[2]; var alpha = data[3];

数组中每个元素的值是在0-255之间,能够直接访问到原始图像数据,就能够以各种方式来操作这些数据

[注意]如果要使用getImageData()获取的canvas中包含drawImage()方法,则该方法中的URL不能跨域

【createImageData()】

createImageData(width,height)方法创建新的空白ImageData对象。新对象的默认像素值 transparent black,相当于rgba(0,0,0,0)

var imgData = context.createImageData(100,100);

【putImageData()】

putImageData()方法将图像数据从指定的ImageData对象放回画布上,该方法共有以下参数

imgData:要放回画布的ImageData对象(必须) x:imageData对象的左上角的x坐标(必须) y:imageData对象的左上角的y坐标(必须) dirtyX:在画布上放置图像的水平位置(可选) dirtyY:在画布上放置图像的垂直位置(可选) dirtyWidth:在画布上绘制图像所使用的宽度(可选) dirtyHeight:在画布上绘制图像所使用的高度(可选)

[注意]参数3到7要么都没有,要么都存在

context.putImageData(imgData,0,0);
context.putImageData(imgData,0,0,50,50,200,200);

粒子写入

粒子,指图像数据imageData中的每一个像素点。下面以一个简易实例来说明完全写入与粒子写入

【完全写入】

200*200的canvas1中存在文字'小火柴',并将canvas1整个作为图像数据写入同样尺寸的canvas2中

<canvas></canvas> <canvas></canvas> <script> var drawing1 = document.getElementById('drawing1'); var drawing2 = document.getElementById('drawing2'); if(drawing1.getContext){ var cxt = drawing1.getContext('2d'); var cxt2 = drawing2.getContext('2d'); var W = drawing1.width = drawing2.width = 200; var H = drawing1.height = drawing2.height = 200; var str = '小火柴'; cxt.textBaseline = 'top'; var sh = 60; cxt.font = sh + 'px 宋体' var sw = cxt.measureText(str).width; if(sw > W){ sw = W; } cxt.fillText(str,(W - sw)/2,(H - sh)/2,W); //获取imageData var imageData = cxt.getImageData(0,0,W,H); //写入drawing2中 cxt2.putImageData(imageData,0,0); </script>

【粒子写入】

对于完全写入而言,相当于只是简单的复制粘贴,如果要对每个像素点进行精细地控制,则需要使用粒子写入。canvas1中存在着大量的空白区域,只有'小火柴'这三个字的区域是有效的。于是,可以根据图像数据imageData中的透明度对粒子进行筛选,只筛选出透明度大于0的粒子

<canvas></canvas> <canvas></canvas> <script> var drawing1 = document.getElementById('drawing1'); var drawing2 = document.getElementById('drawing2'); if(drawing1.getContext){ var cxt = drawing1.getContext('2d'); var cxt2 = drawing2.getContext('2d'); var W = drawing1.width = drawing2.width = 200; var H = drawing1.height = drawing2.height = 200; var str = '小火柴'; cxt.textBaseline = 'top'; var sh = 60; cxt.font = sh + 'px 宋体' var sw = cxt.measureText(str).width; if(sw > W){ sw = W; } cxt.fillText(str,(W - sw)/2,(H - sh)/2,W); //获取imageData var imageData = cxt.getImageData(0,0,W,H); //写入drawing2中 cxt2.putImageData(setData(imageData),0,0); function setData(imageData){ //从imageData对象中取得粒子,并存储到dots数组中 var dots = []; for(var i = 0; i < W; i++){ for(var j = 0; j < H ;j++){ //data值中的红色值 var k = 4*(i + j*W); //data值中的透明度 if(imageData.data[k+3] > 0){ //将透明度大于0的data中的红色值保存到dots数组中 dots.push(k); } } } //40000 2336 console.log(i*j,dots.length); //新建一个imageData,并将筛选后的粒子信息保存到新建的imageData中 var oNewImage = cxt.createImageData(W,H); for(var i = 0; i < dots.length; i++){ oNewImage.data[dots[i]+0] = imageData.data[dots[i]+0]; oNewImage.data[dots[i]+1] = imageData.data[dots[i]+1]; oNewImage.data[dots[i]+2] = imageData.data[dots[i]+2]; oNewImage.data[dots[i]+3] = imageData.data[dots[i]+3]; } return oNewImage; } } </script>

虽然结果看上去相同,但canvas2只使用了canvas1中40000个粒子中的2336个

粒子筛选

当粒子完全写入时,与canvas复制粘贴的效果相同。而当粒子有所筛选时,则会出现一些奇妙的效果

【按序筛选】

由于取得粒子时,使用的是宽度值*高度值的双重循环,且都以加1的形式递增。如果不是加1,而是加n,则可以实现按序筛选的效果

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wygfpz.html