这篇文章由 Paul Rouget 撰写,他是 Mozilla 布道团队的成员。Paul 居住在法国巴黎,因其在 网络开放视频 等方面的一些出色工作而闻名。
从最简单的层面上讲,Canvas 是一种将位图数据绘制到 HTML 页面中的简单方法。它具有允许您绘制矩形、弧形、曲线和其他简单图元的方法。但是,对于某些类型的效果和绘图,您需要直接访问像素。
在 Firefox 3.5 中,我们向 canvas 元素添加了一种新方法 - createImageData。createImageData 调用是一种便捷方法,用于创建一组空白像素以进行操作,最终可以将其复制回画布。
由于我们正在讨论单个调用,因此我们认为值得遍历所有允许您直接读取、操作和更新画布中像素的调用,并将 createImageData 置于其完整上下文中。
检索像素数据
您无法直接操作画布中的像素。为了更改画布中的数据,您首先需要将数据复制出来,进行更改,然后将更改后的数据复制回目标画布。
The getImageData 调用允许您从画布中复制出一个矩形像素。获取画布中所有像素数据的调用如下所示
var canvas = document.getElementById('myCanvasElt');
var ctx = canvas.getContext('2d');
var canvasData = ctx.getImageData(0, 0, canvas.width, canvas.height);
canvasData 对象包含像素数据。它具有以下成员
canvasData {
width: unsigned long, // the width of the canvas
height: unsigned long, // the height of the canvas
data: CanvasPixelArray // the values of the pixels
}
数据是一个扁平的值数组,每个像素的每个分量都有一个值,从左到右、从上到下排列,每个像素都表示为 RGBA 顺序的四个值。
例如,在 2×2 画布中,将有 4 个像素表示为 16 个值,如下所示
0,0 0,1 1,0 1,1 RGBA RGBA RGBA RGBA
因此,您可以使用以下公式计算该数组的长度:width * height * 4。
在一个较大的画布中,如果您想知道 x = 10、y = 20 处像素的蓝色值,则可以使用以下代码
var x = 10; var y = 10; var blue = canvasData.data[(y * width + x) * 4 + 2];
请注意,每个 RGB 像素的值为 0..255,alpha 位的值为 0..255,其中 0 表示完全透明,255 表示完全不透明。
创建新的像素集
如果要从头开始创建新的矩阵,只需使用 createImageData 调用,它需要两个参数:矩阵的高度和宽度。
请注意,createImageData 调用不会从现有画布中复制像素,它会生成一个空白像素矩阵,其值设置为透明黑色 (255,255,255,0)。
以下是一个示例,您希望创建一个适合画布大小的像素集
var canvas = document.getElementById('myCanvasElt');
var ctx = canvas.getContext('2d');
var canvasData = ctx.createImageData(canvas.width, canvas.height);
请注意,这是您应该用于创建像素数据的方法。早期版本的 Firefox 允许您从一个简单的 JavaScript 对象中创建一个 canvasData 对象,并在后续调用中使用它来更新画布数据。添加此调用是为了与 WebKit 保持兼容性,WebKit 在底层使用专门的对象而不是通用 JavaScript 对象。
更新像素
获得 canvasData 对象后,您可以通过数组更新像素值。以下是如何遍历数组读取和更新值的示例。
for (var x = 0; x < canvasData.width; x++) {
for (var y = 0; y < canvasData.height; y++) {
// Index of the pixel in the array
var idx = (x + y * width) * 4;
// If you want to know the values of the pixel
var r = canvasData.data[idx + 0];
var g = canvasData.data[idx + 1];
var b = canvasData.data[idx + 2];
var a = canvasData.data[idx + 3];
//[...] do what you want with these values
// If you want to update the values of the pixel
canvasData.data[idx + 0] = ...; // Red channel
canvasData.data[idx + 1] = ...; // Green channel
canvasData.data[idx + 2] = ...; // Blue channel
canvasData.data[idx + 3] = ...; // Alpha channel
}
}
更新画布
现在您已经获得了一组更新的像素,您可以使用简单的 putImageData 调用。此调用接受 canvasData 对象以及您希望在画布中绘制像素数据矩形的 x,y 位置
var canvas = document.getElementById('myCanvasElt');
var ctx = canvas.getContext('2d');
var canvasData = ctx.putImageData(canvasData, 0, 0);
getImageData 的完整示例
以下代码将彩色图像转换为图像的灰度版本。您还可以查看 Paul 网站上的此演示的实时版本。
var canvas = document.getElementById('myCanvasElt');
var ctx = canvas.getContext('2d');
var canvasData = ctx.getImageData(0, 0, canvas.width, canvas.height);
for (var x = 0; x < canvasData.width; x++) {
for (var y = 0; y < canvasData.height; y++) {
// Index of the pixel in the array
var idx = (x + y * canvas.width) * 4;
// The RGB values
var r = canvasData.data[idx + 0];
var g = canvasData.data[idx + 1];
var b = canvasData.data[idx + 2];
// Update the values of the pixel;
var gray = (r + g + b) / 3;
canvasData.data[idx + 0] = gray;
canvasData.data[idx + 1] = gray;
canvasData.data[idx + 2] = gray;
}
}
ctx.putImageData(canvasData, 0, 0);
createImageData 的完整示例
此代码段将分形绘制到画布中。同样,您可以在 Paul 的网站上查看此代码的实时 演示。
var canvas = document.getElementById('myCanvasElt');
var ctx = canvas.getContext('2d');
var canvasData = ctx.createImageData(canvas.width, canvas.height);
// Mandelbrot
function computeColor(x, y) {
x = 2.5 * (x/canvas.width - 0.5);
y = 2 * (y/canvas.height - 0.5);
var x0 = x;
var y0 = y;
var iteration = 0;
var max_iteration = 100;
while (x * x + y * y <= 4 && iteration < max_iteration ) {
var xtemp = x*x - y*y + x0;
y = 2*x*y + y0;
x = xtemp;
iteration++;
}
return Math.round(255 * iteration / max_iteration);
}
for (var x = 0; x < canvasData.width; x++) {
for (var y = 0; y < canvasData.height; y++) {
var color = computeColor(x, y);
// Index of the pixel in the array
var idx = (x + y * canvas.width) * 4;
// Update the values of the pixel;
canvasData.data[idx + 0] = color;
canvasData.data[idx + 1] = color;
canvasData.data[idx + 2] = color;
canvasData.data[idx + 3] = 255;
}
}
ctx.putImageData(canvasData, 0, 0);
更多文档
如果您想了解有关 Canvas 的更多信息,我们强烈建议您浏览我们为 canvas 提供的 MDC 文档
我们希望这对每个人都有用,并将单个调用置于其完整上下文中。
关于 Christopher Blizzard
一次发布一个,让网络变得更好。
17 条评论