『不要再问我头像如何变灰了,试试这几种滤镜吧!』

Canvas-Filter

在实际的工做中,有时候会有一些需求,让你作一些图片的滤镜效果,好比将图片变成黑白,调整图片亮度等。本文手把手教你如何实现五种滤镜效果,核心代码总共不到 70 行。html

笔者所在的公司就有一个需求须要用到图片处理的知识,大概场景我来描述一下:git

用户能够手动上传印章,而且支持给印章设置不一样的显示效果,这里的效果具体指的是“线条的清晰程度”,以下图所示:github

这里咱们使用 Canvas 来实现。若是你对 Canvas 不熟悉,建议看下以前我写的一篇文章100 * 100 Canvas 占用内存多大,花上几分钟看完,基本上够看懂这篇文章了。web

准备工做

首先咱们先将图片绘制到 Canvas 画布上,为了简单起见,图片大小固定为 300 x 300。canvas

<canvas id="canvas" width="300px" height="300px"></canvas>
复制代码

(html)数组

//获取canvas元素
ctx = document.getElementById("canvas").getContext("2d");
//建立image对象
var img = new Image();
img.src = require("./seal.png");
//待图片加载完后,将其显示在canvas上
img.onload = () => {
  ctx.drawImage(img, 00);
  this.imgData = ctx.getImageData(00300300);
};
复制代码

(js)dom

效果是这样的:编辑器

操做像素

熟悉 Canvas 的应该知道上面的 this.imgData 实际上就是ImageData类的实例,其中 imgData.data 是一个 Uint8ClampedArray, 其描述了一个一维数组,包含以 RGBA 顺序的数据,数据使用 0 至 255(包含)的整数表示。 简单来讲,就是图片像素信息,每四位表示一个像素单元。其中每四位的信息分别是 RGBA。即第一个 Bit 标记 R,第二个 Bit 表示 G,第三个 Bit 表示 B,第四个 Bit 表示 A,第五个 Bit 又是 R...,依次类推。flex

接下来,咱们就要操做 imgData,来实现滤镜的效果。简单起见,我这里对超过 200 的值进行了一次提升亮度的操做。实际上这个值是 200,仍是别的数字,须要咱们化身"调参工程师",不断实验才行。 而且粗暴地对 RGB 执行一样的逻辑是不合理的。更为合理的作法是对 RGB 的阀值分别进行度量,因为比较麻烦,我这里没有实现。可是若是你对效果要求比较高,那么最好能够分开度量。ui

const data = this.imgData.data;
for (let i = 0; i < data.length; i += 4) {
  if (data[i] < 200) {
    data[i] = data[i] + brightness > 255 ? 255 : data[i] + brightness;
  }

  if (data[i + 1] < 200) {
    data[i + 1] =
      data[i + 1] + brightness > 255 ? 255 : data[i + 1] + brightness;
  }
  if (data[i + 2] < 200) {
    data[i + 2] =
      data[i + 2] + brightness > 255 ? 255 : data[i + 2] + brightness;
  }
}
复制代码

如上,咱们对图片的像素进行了处理,以达到咱们的目的,这样从用户感官上来看,显示效果发生了变化,大概效果如图:

(清晰版)

(模糊版)

若是你愿意的话,你也能够将处理好的图片进行导出,也很简单,直接调用 Canvas 实例的 toDataURL 方法便可,图片保存的格式也能够在这个方法中进行指定。

平常开发中,咱们还可能碰到不少其余的滤镜效果。下面介绍几个比较现常见的效果。 若是你正好用到了不妨做为参考。若是遇到了新的滤镜效果, 不妨在文末向我留言,看到后会及时回答,提早感谢你的参与。

下面介绍其余四种滤镜效果。这里只贴出核心代码,完整代码能够访问个人 Github Repo 进行查看。若是你嫌下载到本地麻烦,也能够在这里在线安装并访问,打开这个连接,分别执行yarnyarn start便可。

如下效果均如下图为原图制做:

如何实现黑白效果

for (let i = 0; i < data.length; i += 4) {
  // 将红黄蓝按照必定比例混合,具体比例为0.299 : 0.587 : 0.114, 这个比例须要慢慢调制。
  const avg = 0.299 * data[i] + 0.587 * data[i + 1] + 0.114 * data[i + 2];
  data[i] = data[i + 1] = data[i + 2] = avg;
}
复制代码

如何实现反色效果

for (let i = 0; i < data.length; i += 4) {
  data[i] = 255 - data[i]; //r
  data[i + 1] = 255 - data[i + 1]; //g
  data[i + 2] = 255 - data[i + 2]; //b
}
复制代码

如何给图片增长噪音

const random = ((Math.random() * 70) >>> 0) - 35;
for (let i = 0; i < data.length; i += 4) {
  data[i] = data[i] + random;
  data[i + 1] = data[i + 1] + random;
  data[i + 2] = data[i + 2] + random;
}
复制代码

如何提升图片亮度

const brightness = +e.target.value;
for (let i = 0; i < data.length; i += 4) {
  data[i] = data[i] + brightness > 255 ? 255 : data[i] + brightness;
  data[i + 1] = data[i + 1] + brightness > 255 ? 255 : data[i + 1] + brightness;
  data[i + 2] = data[i + 2] + brightness > 255 ? 255 : data[i + 2] + brightness;
}
复制代码

总结

本文经过不到 70 行代码实现了五种滤镜效果,对于其余滤镜效果也能够参考这种方式来实现。还不赶忙拿上小姐姐的照片来秀一手么?

相关文章
相关标签/搜索