Canvas ImageData 对象
终于快接近尾声了,要准备鲜花庆祝下了,之前的章节,我们都学习如何绘图,如何让图像动起来,如何响应用户的交互
是的,这没错,因为我们本来要的就是这些能力,但是我们还没有弄清楚 Canvas 真实的像素原理,我们只是绘了一些图形,然后展现出来,我们并没有深入的去操作或者获取图像背后的像素
我们可能需要导出当前画布上的绘制的东西,或者把绘制的东西赋给一个 <img>
元素让它显示出来
Canvas 能够提供这些操作,因为,它提供了一个 ImageData
对象来操作画布本身的像素能力
ImageData 对象
ImageData
对象中存储着 canvas
对象真实的像素数据
它提供了以下属性
属性 | 说明 |
---|---|
ImageData.data | 只读,Uint8ClampedArray 类型的一维数组,包含着 RGBA 格式的整型数据,范围在 0 至 255 之间( 包括 255 )顺序的数据, |
ImageData.height | 只读,无符号长整型(unsigned long),图片高度,单位是像素 |
ImageData.width | 只读,无符号长整型(unsigned long),图片宽度,单位是像素 |
Uint8ClampedArray
Uint8ClampedArray
是一个 高度 × 宽度 × 4 bytes
的一维数组
这是什么意思呢 ?
我们知道,图片是平面图形,有宽有高,因此我们可以把它看作是一个矩形
如果我们以 1 像素为单位给它绘制一个网格,下面这样
那么有多少个小格子呢 ?
不用去数啊,直接是 (width / 1 ) x ( height/1 ) = width x height
个
然后每一个像素格子都是一种颜色,那么总共就有 width x height
个颜色了
我们知道颜色的存储有 3 字节表示法 ( RGB
) 和 四字节表示法 ( RGBA
) ,Canvas 使用的是 RGBA 存储一个颜色值,也即是一个颜色需要 4 字节来存储
所以,那么 Canvas 中存储一个张 width x height
的图片就需要 高度 × 宽度 × 4 bytes
字节了
既然知道了 Uint8ClampedArray
是一个 高度 × 宽度 × 4 bytes
的一维数组
那么它的索引值就是从 0
到 (高度×宽度×4) -1
那么 Uint8ClampedArray
到底是是怎么存放每个像素的颜色呢?
很简单,首先创建一个长度为 (高度×宽度×4)
的字节数组,然后按照下面的公式存放第 m 行 n 列颜色(RGBA)
R = 4 * (m-1) * (n-1) + 0 G = 4 * (m-1) * (n-1) + 1 B = 4 * (m-1) * (n-1) + 2 A = 4 * (m-1) * (n-1) + 3
例如第一行第一列的颜色放在
R = 4 * 0 * 0 + 0 = 0 G = 4 * 0 * 0 + 1 = 1 B = 4 * 0 * 0 + 2 = 2 A = 4 * 0 * 0 + 3 = 3
第一行第二列的颜色放在
R = 4 * 1 * 1 + 0 = 4 G = 4 * 1 * 1 + 1 = 5 B = 4 * 1 * 1 + 2 = 6 A = 4 * 1 * 1 + 3 = 7
如果你看脑补不明白,那就看图吧
是不是很酷,是不是很有趣?
所以我们要取得第 m 行第 n 列颜色值的 B 值,就可以像下面这样使用
ImageData.data[(m-1)*(n-1)*4+3]
例如从行 50,列 30 的像素中读取图片的蓝色部份,就会这样写
blue = ImageData.data[(50-1)*(30-1)*4+3] = ImageData.data[7647]
获取 Uint8ClampedArray 的长度
既然 Uint8ClampedArray
是一个数组,我们就可以使用 length
属性来获得数组的长度
var len = imageData.data.length