Canvas 实现根据背景色更改前景色
最近有一个需求,大致是要根据图片的背景色来切换前景色,也就是根据 background-color 的色值切换 color。
虽然这么一说,那么就能抽象出以下几个问题:
- 如何取到图片某像素的 color 值,或者是某像素区域的平均 color 值
如何根据 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 搞得时间久的竟然是计算坐标和拖拽效果……不过最终大致是这样的,可以尝试点击画布以及拖拽「天」字:
植入部分
如果您觉得文章不错,可以通过赞助支持我。
如果您不希望打赏,也可以通过关闭广告屏蔽插件的形式帮助网站运作。
const [ red, green, blue, alpha ] = imgData.data;
写反了
谢谢老板
膜拜大佬
厉害了大佬竟然给我留言了 感人
hhh 你们前端互相吹捧互称大佬的恶劣风气
一天不捧浑身难受