CodeSky 代码之空

随手记录自己的学习过程

Canvas 实现根据背景色更改前景色

2017-05-09 00:25分类: JavaScript评论: 6

最近有一个需求,大致是要根据图片的背景色来切换前景色,也就是根据 background-color 的色值切换 color。

虽然这么一说,那么就能抽象出以下几个问题:

  1. 如何取到图片某像素的 color 值,或者是某像素区域的平均 color 值
  2. 如何根据 color 划分、如何改变前景的(如 icon、font)color。

同时也把问题分为了两步,问题 1 可以用 canvas 解决,通过 canvas 获取画布上某个像素的颜色。而问题 2,我们则转换为一个灰度问题,通过灰度大小来决定选择黑或白色:

Step1: Canvas 绘制图片

MDN 中 使用图像 Using images 一节说得非常清楚,通过 drawImage 即可绘制,非常方便。

当然,在这里需要注意一点,对于之后的操作,我们需要图片资源服务器可以跨域,否则这个图片会污染 canvas。无法再对这个画布进行一些获取信息的操作,会抛出安全问题——对于 Chrome 插件,不存在跨域问题,我们可以用的比较放心,如果在其他地方使用,请务必注意。

在文末的 demo 中,为了解决这个问题,我们转换为 Base64 引入。

这里为了绘制完整图片,我们把画布大小定义为全屏,在 drawImage 时传入图片宽高为画布大小,需要注意,待图片载入完成才能渲染该图:

1canvas.width  = document.querySelector('body').clientWidth;
2canvas.height = document.querySelector('body').clientHeight;
3
4// ...image 初始化配置省略
5
6img.addEventListener('load', () => {
7  ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
8});
9

Step2: 获取颜色

在 MDN 中的 像素操作 中有完整的颜色选择器的例子,非常靠谱。

我们通过 ctx.getImageData(x, y, 1, 1) 来取画布中某一像素点的大小,返回值可以看做这样的矩阵(但是是一维数组)

1[
2  r, g, b, a,
3  r, g, b, a,
4  r, g, b, a
5  // ...
6]
7

于是我们就取到了颜色。

Step3: 计算灰度

灰度计算可以表现出图片的明度情况,由此我们可以大致得出一个像素点是深色或者是浅色,那么由我们的直觉定义:深色的背景取白色的前景色,而浅色的背景取深色的前景色。

它主要用到一个非常简单的公式:0.299 * r + 0.587 * g + 0.114 * b,灰度的范围是(0 - 255),我们取中间值进行比较区分即可,值高,则取黑。

Demo

这个 Demo 搞得时间久的竟然是计算坐标和拖拽效果……不过最终大致是这样的,可以尝试点击画布以及拖拽「天」字:

评论 (2)

jiananshi2017年5月11日 10:10

膜拜大佬

敖天羽2017年5月11日 10:13

厉害了大佬竟然给我留言了 感人

lujjjh2017年5月9日 22:19

const [ red, green, blue, alpha ] = imgData.data; 写反了

敖天羽2017年5月9日 23:05

谢谢老板