html 像素操作

一.简介

Canvas相对于SVG来说的一大优势就是像素级别的操作,而SVG相对于Canvas来说的一大优势就是方便添加事件,当然这个Canvas可以用第三方库来弥补。

在理论上:SVG能做到的,Canvas都能做到;Canvas能做到的,SVG不一定能做到(或者复杂度相当之高)。

二.两种像素操作

我们首先画两个圆形:

var c = document.getElementById("myCanvas");

  var cxt = c.getContext("2d");

  cxt.strokeStyle = "#fff";

  cxt.beginPath();

  cxt.arc(70, 18, 15, 0, Math.PI * 2, true);

  cxt.closePath();

  cxt.stroke();

  cxt.beginPath();

  cxt.arc(70, 38, 15, 0, Math.PI * 2, true);

  cxt.closePath();

  cxt.stroke();

效果如下:

然后我们把白色的两个球改成别的颜色:

for (var i = 0; i < c.width; i++) {

  for (var j = 0; j < c.height; j++) {

  currentimageData = cxt.getImageData(i, j, 1, 1);

  if (currentimageData.data[0] === 255) {

  currentimageData.data[0] = 130;

  cxt.putImageData(currentimageData, i, j);

  }

  }

  }

效果如下:

这就是传说中的像素级别操作,但是这种方式有一种优势:他可以获取当前像素的坐标,但是频繁的调用了API,性能不是一般的差,所以有了下面这种方式:

var imageData;

  imageData = cxt.getImageData(0, 0, c.width, c.height);

  var pix = imageData.data;

  for (var i = 0, n = pix.length; i < n; i += 4) {

  if (pix[i] === 255) {

  pix[i] = 130;

  }

  }

  cxt.putImageData(imageData, 0, 0);

这种方式的优势是性能好,但是有一个不好的地方就是不能直观的得到改像素的坐标位置。

在一些BT场景下,我们既要性能好,又要坐标和像素值,怎么获取该像素的坐标呢?什么场景下需要?


Canvas API最有用的特性之一是允许开发人员直接访问canvas底层像素数据。这种数据访问是双向的:一方面,可以以数值数组形式获取像素数据;另一方面,可以修改数组的值以将其应用于canvas。这要归功于context API内置的三个函数。

其中最重要的一个是context.getImageData(sx, sy, sw, sh)。这个函数返回当前canvas状态并以数值数组的方式显示。具体来说,返回的对象包括三个属性。

width:每行有多少个像素。

height:每列有多少个像素。

data:一维数组,存有从canvas获取的每个像素的RGBA值。该数组为每个像素保存了四个值--红、绿、蓝和alpha透明度。每个值都在0到255之间。因此,canvas上的每个像素在这个数组中就变成了四个整数值。数组的填充顺序是从左到右,从上到下(也就是先第一行再第二行,依此类推),如图所示。

纠错

在《HTML5高级程序设计》中的2.2.16 像素数据中是这样写的:

getImageData函数有四个参数,该函数只返回这四个参数所限定的区域内的数据。只有被x、y、width和height四个参数框定的矩形区域内的canvas上的像素才会被取到,因此要想获取所有像素数据,就需要这样传入参数:getImageData(0, 0, canvas.width, canvas.height)。

因为每个像素由四个图像数据表示,所以要计算指定的像素点对应的值是什么就有点头疼。不要紧,下面有公式。

在给定了width和height的canvas上,在坐标(x ,y)上的像素的构成如下。

红色部分:((width * y) + x) * 4

绿色部分:((width * y) + x) * 4 + 1

蓝色部分:((width * y) + x) * 4 + 2

透明度部分:((width * y) + x) * 4 + 3

一旦可以通过像素数据的方式访问对象,就可以通过数学方式轻松修改数组中的像素值,因为这些值都是从0到255的简单数字。修改了任何像素的红、绿、蓝和alpha值之后,可以通过第二个函数来更新canvas上的显示,那就是context.putImageData(imagedata, dx, dy)。

其中标红的地方会让读者一头雾水。而准确的描述应该如下:

在给定了width和height的canvas上,在坐标(x ,y)上的像素的index构成如下。

var data=getImageData(0, 0, canvas.width, canvas.height);

红色index:((width * y) + x) * 4 像素值:data[((width * y) + x) * 4]

绿色index:((width * y) + x) * 4 + 1 像素值:data[((width * y) + x) * 4+1]

蓝色index:((width * y) + x) * 4 + 2 像素值:data[((width * y) + x) * 4+2]

透明度index:((width * y) + x) * 4 + 3像素值:data[((width * y) + x) * 4+3]

逆推呢?

上面,我们是根据x,y坐标得到对应的索引的像素值,如果我们不知道x,y坐标,只知道getImageData返回的data怎么得到相应的(x,y)坐标呢?

因为像素是从左到右从上到下依次排列过去的,所以我们可以轻松得到对应的X,Y坐标:

  var w = canvas.width;

  var h = canvas.height;

  var imageData = cxt.getImageData(0, 0, w, h);

  var pix = imageData.data;

  for (var i = 0, n = pix.length; i < n; i += 4) {

  var x = (i / 4) % w;

  var y = parseInt((i / 4) / w);

  }

在线演示

我们继续昨天的例子,利用像素级别操作把重叠的部分隐藏掉:

  Vector2 = function (x, y) {

  this.x = x || 0;

  this.y = y || 0;

  };

  Vector2.prototype = {

  constructor: Vector2,

  distanceTo: function (v) {

  return Math.sqrt(this.distanceToSquared(v));

  },

  distanceToSquared: function (v) {

  var dx = this.x - v.x, dy = this.y - v.y;

  return dx * dx + dy * dy;

  }

  };

像素操作:

  var imageData;

  imageData = cxt.getImageData(0, 0, canvas.width, canvas.height);

  var pix = imageData.data;

  for (var i = 0, n = pix.length; i < n; i += 4) {

  if (pix[i] === 255) {

  var distance = round1Position.distanceTo(new Vector2((i / 4) % w, parseInt((i / 4) / w)));

  var distance2 = round2Position.distanceTo(new Vector2((i / 4) % w, parseInt((i / 4) / w)))

  if (distance < 13.5 || distance2 <r-1.5) {

  pix[i] = 0;

  pix[i+1] = 0;

  pix[i+2] = 0;

  }

  }

  }

  cxt.putImageData(imageData, 0, 0);

效果如下:

展望

是否不够过瘾,不够绚?不够震撼?不要急,震撼作品在后头,只要你思想够活跃,像素级别绝对是你挥洒艺术细胞的天堂。

原文链接:http://www.cnblogs.com/iamzhanglei/archive/2011/12/02/2272567.html


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值