New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Canvas 操作图像像素 #12

Open
YIXUNFE opened this Issue Sep 8, 2015 · 1 comment

Comments

Projects
None yet
2 participants
@YIXUNFE
Owner

YIXUNFE commented Sep 8, 2015

Canvas 操作图像像素

HTML5 中最吸引我的新标签就是 canvas,canvas 元素为我们操作图像带来了更多的可能。


## ImageData 对象

canvas 元素给我们提供了一系列绘制 2d 图像的 API,比如绘制一个正方形或者一个椭圆等,同时我们也可以利用 getImageData() 方法返回的 ImageData 对象,获取一个图像的像素点。

var ctx = canvas.getContext('2d')
// 获取 ImageData 对象
var imageData = ctx.getImageData(x, y, width, height)

getImageData() 方法的参数说明

参数 说明
x 选区横坐标起始点,默认 0
y 选区纵坐标起始点,默认 0
width 选区宽度,默认整幅图像宽度
height 选区高度,默认整幅图像高度

getImageData() 方法返回的 ImageData 对象包含下列三个属性:

  • width: 设备像素为单位的图像数据宽度;
  • height: 设备像素为单位的图像数据高度;
  • data: 包含各个设备像素数值的数组。

ImageData 对象的 width 与 height 属性是只读的。

ImageData 对象的 data 属性是一个数组,具有 4 * width * height 的整数值。因为每个像素点包含 4 个整数值,即 RGBA 值。

拿到了像素点的值,我们就能够对图像进行操作了。

getImageData() 方法只能获取同源图片的像素信息哦


## 遍历像素点

我们从 ImageData 的 data 属性中遍历图像的像素点:

var imageData =  ctx.getImageData(x, y, width, height)
var i = 0,  l = imageData.data.length, r, g, b, a

//循环像素点
for (i; i < l; i += 4) {
    r = imageData.data[i]    //
    g = imageData.data[i + 1] //绿
    b = imageData.data[i + 2] //
    a = imageData.data[i + 3] //透明
}

由于每个像素点的 RGBA 四个数值都依次存放在 data 属性中,所以我们需要将4个数值一组放在循环体中,以明确当前像素点的 RGBA 值。

这种方法的好处在于可以明确的知道某个像素点的 RGBA 值,缺点也很明显,无法直观的获取像素点所在的行和列。更加重要的是在只需要对行或列进行相关计算的时候,每个像素的遍历会造成很多重复计算,按行与列遍历像素点的方法可以弥补这些缺点:

var imageData =  ctx.getImageData(x, y, width, height)
var x = 0, y = 0,  l = imageData.data.length, r, g, b, a, w = imageData.width, h = imageData.height

//循环行
for (y; y < h; y++) {
    //循环列
    for (x = 0; x < w; x++) {
        r = imageData.data[(x + y * w) * 4]    //
        g = imageData.data[(x + y * w) * 4 + 1] //绿
        b = imageData.data[(x + y * w) * 4 + 2] //
        a = imageData.data[(x + y * w) * 4 + 3] //透明
    }
}

## 简易效果实现

学会了遍历像素点,我们可以对其修改,达到一些出乎意料的效果。这里我们使用 YIXUNFE 的 LOGO 图做一些效果介绍。

原图:
原图


#### 反相

反相效果就是用 255 减去每个像素点的 RGB 值。

data[i] = 255 - data[i]
data[i + 1] = 255 - data[i + 1]
data[i + 2] = 255 - data[i + 2]

实现的效果如图:

反相


#### 黑白

黑白效果的特征就是像素点的 RGB 三个值相同。

var a = Math.ceil((data[i] + data[i + 1] + data[i + 2]) / 3)
data[i] = a
data[i + 1] = a
data[i + 2] = a

实现的效果如图:

黑白


#### 模糊

模糊效果是通过获取当前像素点周围的点的 RGB 各平均值实现。这里我们仅通过当前像素点的周围8格实现该效果。

//像素点副本,用来获取原图的像素值
var copy = data.slice(0)

//循环行
for (y; y < h; y++) {
    //循环列
    for (x = 0; x < w; x++) {
        index = (x + y * w) * 4
        l = (x - 1 + y * w) * 4
        r = (x + 1 + y * w) * 4
        t = (x + (y - 1) * w) * 4
        b = (x + (y + 1) * w) * 4
        lt = (x - 1 + (y - 1) * w) * 4
        rt = (x + 1 + (y - 1) * w) * 4
        lb = (x - 1 + (y + 1) * w) * 4
        rb = (x + 1 + (y + 1) * w) * 4

        //获取R平均值
        data[index] = (copy[index] + copy[l] + copy[r] + copy[t] + copy[b] + copy[lt] + copy[rt] + copy[lb] + copy[rb]) / 9

        //获取G平均值
        data[index + 1] = (copy[index + 1] + copy[l + 1] + copy[r + 1] + copy[t + 1] + copy[b + 1] + copy[lt + 1] + copy[rt + 1] + copy[lb + 1] + copy[rb + 1]) / 9

        //获取B平均值
        data[index + 2] = (copy[index + 2] + copy[l + 2] + copy[r + 2] + copy[t + 2] + copy[b + 2] + copy[lt + 2] + copy[rt + 2] + copy[lb + 2] + copy[rb + 2]) / 9
    }
}

模糊


### [查看更多效果](http://yixunfe.github.io/blog/demo/12.html)

对角线反相
噪点
扭曲


## Thanks

@YIXUNFE YIXUNFE changed the title from Canvas 操作图像像素(待续) to Canvas 操作图像像素 Sep 9, 2015

@peakcool

This comment has been minimized.

peakcool commented Apr 20, 2018

很赞,学习了!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment