【问题标题】:Mixing two colors using their hexcodes使用它们的十六进制代码混合两种颜色
【发布时间】:2020-10-03 13:28:32
【问题描述】:

我正在制作一个反应本机应用程序,并尝试使用它们的十六进制代码将两种或多种颜色混合在一起,然后得到结果颜色及其十六进制代码。

例如,当每种颜色具有相同的比例时,混合颜色: #4285F4 + #EA4335 + #FBBC05 = #SomeColorHexcode。有没有一种算法可以用来获取结果颜色的十六进制代码?

我浏览了一些旧帖子,这里似乎有一个解决方案:Mixing two colors "naturally" in javascript。但是这篇文章的主要解决方案似乎使用了 jquery,react native 不支持。另外,这个问题是大约 7 年前提出的,我想知道现在是否有更好的算法可用于混合颜色。

谢谢!

【问题讨论】:

    标签: javascript react-native math colors


    【解决方案1】:

    原则

    1. 您获取颜色值
    2. 您将 CSS 颜色值转换为整数
    3. 你取每个 RGB 值的中间

    let color1 = document.getElementById('color1')
    let color2 = document.getElementById('color2')
    let colormixed = document.getElementById('colormixed')
    let button = document.getElementById('mix')
    
    // this function takes an integer and converts it in a 2 digit hexadecimal number
    function componentToHex(c) {
      var hex = c.toString(16);
      return hex.length == 1 ? "0" + hex : hex;
    }
    
    // this function takes an array of 3 RGB integer values and converts this array into a CSS color, like this: #AAAAA
    function rgbToHex([r, g, b]) {
      return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b);
    }
    
    // the regex is separating the value into groups of 2 characters, these characters being letters from 'a' to 'f' and digits, that is to say hexadecimal numbers. 
    function convert(color) {
      return /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(color.value).map(x=>parseInt('0x'+x)).slice(1, 4)
    }
    
    button.addEventListener("click", function() {
      // we get the two colors and convert them in integer arrays
      let [c1,c2]= [color1,color2].map(x=>convert(x))
    
      // this variable will be the array of the mixed color
      let cm = []
    
      // we take the middle of each RGB value between the two colors
      c1.forEach((c,i) => cm.push(parseInt((c1[i]+c2[i])/2)))
    
      // we convert the value into a CSS value
      colormixed.value = rgbToHex(cm)
    });
    <input type="color" id="color1" />
    <input type="color" id="color2" />
    <input type="button" id="mix" value="Mix" /><br />
    <input type="color" id="colormixed"/>

    exec 在这里解释:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/exec

    短代码,多种颜色

    document.getElementById('add').addEventListener("click", function() {
      let newColor = document.createElement("input")
      newColor.type = 'color'
      newColor.className = 'color'
      document.getElementById('colors').appendChild(newColor)
    })
    
    document.getElementById('mix').addEventListener("click", function() {
      document.getElementById('colormixed').value = '#'+Array.from(document.getElementsByClassName('color')).map(x=>/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(x.value).map(y=>parseInt('0x'+y)).slice(1, 4)).reduce((a,b)=>a.map( (num, i) => (num + b[i]))).map(x=>parseInt(x/Array.from(document.getElementsByClassName('color')).length).toString(16).padStart(2, '0')).join('')
    });
    <div id="colors">
      <header>
        <input type="button" id="mix" value="Mix" />
        <input type="button" id="add" value="Add" />
      </header>
      <input type="color" class="color" value="#ffffff" />
      <input type="color" class="color" value="#000000" />
    </div>
    
    <label for"colormixed">Result:</label> <input type="color" id="colormixed"/>

    单线解释

    它需要所有颜色:

    Array.from(document.getElementsByClassName('color'))
    

    对于每个元素,我们采用 CSS 颜色代码并分隔 RGB 值:

    .map(x=>/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(x.value)
    

    对于其中的每个元素,我们将每个十六进制数转换为整数:

    .map(y=>parseInt('0x'+y))
    

    我们只取 RGB 三元组:

    .slice(1, 4)
    

    然后我们对所有 RGB 数组求和:

    .reduce((a,b)=>a.map( (num, i) => (num + b[i])))
    

    我们将每个 RGB 总和值除以颜色总数:

    .map(x=>parseInt(x/Array.from(document.getElementsByClassName('color')).length)
    

    我们将每个值转换回十六进制:

    .toString(16)
    

    只有一位数字时不要忘记添加“0”:

    .padStart(2, '0')
    

    我们将 RGB 数组转换成字符串:

    .join('')
    

    我们把'#'放在前面:

    '#' + 
    

    你有你的混色器。

    【讨论】:

    • 感谢您的回复!有什么办法可以澄清正则表达式在做什么?另外,.exec 是什么意思
    • 我解释过了 :)
    【解决方案2】:

    我相信这段代码产生的结果与前面的答案相同,但希望它的工作原理更清楚。

    console.log(mix_hexes('#3890b9', '#f6ff00')); // #8cc46f
    
    function hex2dec(hex) {
      return hex.replace('#', '').match(/.{2}/g).map(n => parseInt(n, 16));
    }
    
    function rgb2hex(r, g, b) {
      r = Math.round(r);
      g = Math.round(g);
      b = Math.round(b);
      r = Math.min(r, 255);
      g = Math.min(g, 255);
      b = Math.min(b, 255);
      return '#' + [r, g, b].map(c => c.toString(16).padStart(2, '0')).join('');
    }
    
    function rgb2cmyk(r, g, b) {
      let c = 1 - (r / 255);
      let m = 1 - (g / 255);
      let y = 1 - (b / 255);
      let k = Math.min(c, m, y);
      c = (c - k) / (1 - k);
      m = (m - k) / (1 - k);
      y = (y - k) / (1 - k);
      return [c, m, y, k];
    }
    
    function cmyk2rgb(c, m, y, k) {
      let r = c * (1 - k) + k;
      let g = m * (1 - k) + k;
      let b = y * (1 - k) + k;
      r = (1 - r) * 255 + .5;
      g = (1 - g) * 255 + .5;
      b = (1 - b) * 255 + .5;
      return [r, g, b];
    }
    
    
    function mix_cmyks(...cmyks) {
      let c = cmyks.map(cmyk => cmyk[0]).reduce((a, b) => a + b, 0) / cmyks.length;
      let m = cmyks.map(cmyk => cmyk[1]).reduce((a, b) => a + b, 0) / cmyks.length;
      let y = cmyks.map(cmyk => cmyk[2]).reduce((a, b) => a + b, 0) / cmyks.length;
      let k = cmyks.map(cmyk => cmyk[3]).reduce((a, b) => a + b, 0) / cmyks.length;
      return [c, m, y, k];
    }
    
    function mix_hexes(...hexes) {
      let rgbs = hexes.map(hex => hex2dec(hex)); 
      let cmyks = rgbs.map(rgb => rgb2cmyk(...rgb));
      let mixture_cmyk = mix_cmyks(...cmyks);
      let mixture_rgb = cmyk2rgb(...mixture_cmyk);
      let mixture_hex = rgb2hex(...mixture_rgb);
      return mixture_hex;
    }
    

    【讨论】:

    • 谢谢!如果我需要混合 3 种颜色,这是否也有效?我怀疑也许我可以混合两种颜色,然后将得到的颜色与第三种颜色混合。这会产生与同时混合三种颜色相同的结果吗?
    • 是的,你的猜测是正确的。将 2 种颜色与第 3 种颜色混合将产生您期望的结果。
    • 谢谢!这个实现和上面的一样。
    • 我正在使用这种方法进行更多测试,但我遇到了一个问题,如果我继续将颜色“#FFC6E3”添加回自身,它似乎最终会变暗紫色的阴影。发生这种情况有原因吗?另外,如果我自己加上颜色“F8712E”,它就会变成“F9722F”。
    • 另外,如果我想混合三种颜色,它们的比例都相同,目前我的方法是将其中两种混合在一起,然后混合得到的颜色,称之为'colorX ',用我最后的颜色,称之为'colorY',我还没有混合(正如我们上面谈到的)。但是当我这样做时,一个缺陷可能是算法会假设 colorX 与 colorY 的比例相同(它们的大小都是 1/2),这是错误的,因为 colorX 是 2/3 而 colorY 是 1/3 .这将导致不准确的混合。让我知道我的逻辑是否有缺陷:)
    猜你喜欢
    • 2011-10-25
    • 2011-09-20
    • 2017-11-07
    • 2017-10-01
    • 2014-05-02
    • 2019-11-28
    • 1970-01-01
    • 1970-01-01
    • 2017-12-13
    相关资源
    最近更新 更多