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

最近有一个需求,大致是要根据图片的背景色来切换前景色,也就是根据 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 时传入图片宽高为画布大小,需要注意,待图片载入完成才能渲染该图:

canvas.width  = document.querySelector('body').clientWidth;
canvas.height = document.querySelector('body').clientHeight;

// ...image 初始化配置省略

img.addEventListener('load', () => {
  ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
});

Step2: 获取颜色

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

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

[
  r, g, b, a,
  r, g, b, a,
  r, g, b, a
  // ...
]

于是我们就取到了颜色。

Step3: 计算灰度

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

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

Demo

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

植入部分

如果您觉得文章不错,可以通过赞助支持我。

如果您不希望打赏,也可以通过关闭广告屏蔽插件的形式帮助网站运作。

标签: 成品, 源码, 知识, 代码段, canvas

已有 6 条评论

  1. const [ red, green, blue, alpha ] = imgData.data;

    写反了

  2. 膜拜大佬

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

      1. hhh 你们前端互相吹捧互称大佬的恶劣风气

        1. 一天不捧浑身难受

添加新评论