取反色值过程的一些想法与分析

3,049 阅读2分钟

RGB色彩模式下反色比较简单,我针对此模式中的RGB颜色表示法进行反色计算,分享一些计算上的技巧 (HEX颜色表示法理论上也是相通的)。

取反色值非常简便,使用255减去三色即可,操作一步到位,如下所示:

rgb(a,b,c); //原值
rgb(255-a,255-b,255-c) //反色

但是在页面的实际应用中,我们通常拿不到rgb三值,而是获取到"rgb(a,b,c)"整体的字符串,那么需要三个步骤

  • 拆解 拆解出rgb值
  • 反色 计算出反色值
  • 合并 组装计算结果

首先给出拆解的思路,按照常规的想法,以截取的方式拆解出rgb值:

let rgb = 'rgb(25,100,72)'

//查找颜色值的起始点
const redPoint = rgb.indexOf(',')
const greenPoint = rgb.indexOf(',', redPoint + 1);
const bluePoint = rgb.indexOf(',', redPoint + 1);

//截取出颜色值
let r = rgb.substring('4', redPoint)
let g = rgb.substring(redPoint + 1, greenPoint)
let b = rgb.substring(bluePoint + 1, rgb.indexOf(')'))

//反色
r = 255 - Number(r);
g = 255 - Number(g);
b = 255 - Number(b);

//组装结果
rgb = 'rgb(' + r + ',' + g + ',' + b + ')'

思路非常清晰,但是我们发现,拆解过程较长,需要逐个使用indexOf查找颜色值的起始点,然后用substring截取出颜色值,较为不便,其实这一过程可以用split函数进行优化:

let rgb = 'rgb(25,100,72)'

//拆分颜色值
rgb = rgb.substring(4, rgb.lastIndexOf(')')).split(',')

//分解出颜色值
let r = rgb[0]
let g = rgb[1]
let b = rgb[2]

此时,既然拿到拆分后的数组,有必要怀疑分解出颜色值这一过程的必要性,因为我们可以直接对数组使用map函数进行循环,在过程中反转颜色值,最后使用join提取出结果

let rgb = 'rgb(25,100,72)'

//拆分颜色值
rgb = rgb.substring(4, rgb.lastIndexOf(')')).split(',')

//循环计算并合并结果
rgb = rgb.map((item) => 255 - Number(item)).join(',')

rgb = 'rgb(' + rgb + ')'

此时只需要两个步骤了,那么我们便逐个分析,拆分颜色值是否还有更简便的方法,截取出有效的颜色值其实不如过滤掉的无效字符,我认为可以用replace的正则替换代替substring

rgb = rgb.replace(/[rgb\(\)]/g, '').split(',')

显然这一过程更加简洁,那么循环并合并结果能否简便呢,其实reduce便可总结mapjoin的操作,总结如下

let rgb = 'rgb(25,100,72)'.replace(/[rgb\(\)]/g, ',').split(',').reduce((e, c) =>
    c.length ? e + "," + (255 - Number(c)) : e).replace(',', 'rgb(') + ')'