【问题标题】:Average 2 hex colors together in javascript在javascript中平均2个十六进制颜色
【发布时间】:2011-09-16 01:22:39
【问题描述】:

好吧,我想我会把这个扔出去让大家思考。

给定一个 函数 (用 javascript 编写),它期望两个字符串的格式类似于十六进制颜色(ex #FF0000

返回一个十六进制颜色,它是所传递的两种颜色的平均值。

function averageColors(firstColor,secondColor)
{
  ...
  return avgColor;
}

--编辑--

平均值将被定义为

如果传递的颜色是黄色而第二个是浅紫色,则返回的颜色将是中等橙色

【问题讨论】:

  • 您将什么定义为“平均”?这有多种可能的含义,具体取决于您使用的色彩空间等等。
  • @Amber,我更新了问题以澄清
  • 关于这个的作业的明显气味......
  • 不抱歉@Marc B 没有作业,只是个人项目。我希望我的 CS 课程能教 JS:/

标签: javascript colors hex


【解决方案1】:

以下是一组紧凑的相关(相互依赖)函数:

Hex ⟷ RGB 颜色转换:

function hexToRgb(h){return['0x'+h[1]+h[2]|0,'0x'+h[3]+h[4]|0,'0x'+h[5]+h[6]|0]}
function rgbToHex(r,g,b){return"#"+((1<<24)+(r<<16)+(g<<8)+ b).toString(16).slice(1);}

计算 2 种十六进制颜色的平均值:需要转换函数(上)

function avgHex(h1,h2){a=hexToRgb(h1);b=hexToRgb(h2); return rgbToHex(~~((a[0]+b[0])/2),~~((a[1]+b[1])/2),~~((a[2]+b[2])/2));}

生成随机十六进制颜色:

function rndHex(){return'#'+('00000'+(Math.random()*(1<<24)|0).toString(16)).slice(-6);}

运行 sn-p 进行演示:

// color functions (average/random/conversion)
function hexToRgb(h){return['0x'+h[1]+h[2]|0,'0x'+h[3]+h[4]|0,'0x'+h[5]+h[6]|0]}
function rgbToHex(r,g,b){return"#"+((1<<24)+(r<<16)+(g<<8)+ b).toString(16).slice(1);}
function rndHex(){return'#'+('00000'+(Math.random()*(1<<24)|0).toString(16)).slice(-6);}
function avgHex(h1,h2){a=hexToRgb(h1);b=hexToRgb(h2);return rgbToHex(~~((a[0]+b[0])/2),~~((a[1]+b[1])/2),~~((a[2]+b[2])/2));}

//code below is just for the demo
function auto(){if(chk.checked){tmr=setInterval(rnd,1000)}else{clearTimeout(tmr)}}auto();
function rnd(go){for(h of[h1,h2]){h.value=rndHex();}avgInput();}
addEventListener('input',avgInput); 
function avgInput(){ // get avg & colorize
 ha.value=avgHex(h1.value,h2.value);
 for(h of [h1,h2,ha])h.style.background=h.value;
}
*{font-family:monospace;font-size:5vw; }
<label>Color 1 → <input id='h1'></label><br>
<label>Average → <input id='ha'></label><br>
<label>Color 2 → <input id='h2'></label><br>
<label>Type hex colors or <input type='checkbox' id='chk' onclick='auto()' style=' transform: scale(1.5)'checked>Autorandom</label>

【讨论】:

    【解决方案2】:

    一种按指定百分比混合两种十六进制颜色的快速/脏/方便/ES6 方法:

    // blend two hex colors together by an amount
    function blendColors(colorA, colorB, amount) {
      const [rA, gA, bA] = colorA.match(/\w\w/g).map((c) => parseInt(c, 16));
      const [rB, gB, bB] = colorB.match(/\w\w/g).map((c) => parseInt(c, 16));
      const r = Math.round(rA + (rB - rA) * amount).toString(16).padStart(2, '0');
      const g = Math.round(gA + (gB - gA) * amount).toString(16).padStart(2, '0');
      const b = Math.round(bA + (bB - bA) * amount).toString(16).padStart(2, '0');
      return '#' + r + g + b;
    }
    
    console.log(blendColors('#00FF66', '#443456', 0.5));

    amount 应该是 010 正好是 colorA1 正好是 colorB0.5 是“中点”。

    【讨论】:

    • 警告,此代码不做任何输入有效性检查。它假定它将始终接收格式良好的 6 位十六进制颜色。仅在您确定它始终会收到该信息时才使用。
    【解决方案3】:

    参加这个聚会很晚,但我个人一直在寻找一种方法来平均未定义数量的 HEX 值。基于答案@RobG,我想出了这个。当然,您添加的颜色越多,它们得到的棕色/灰色就越多,但是,也许它会有所帮助!

    /**
     * Averages an array of hex colors. Returns one hex value (with leading #)
     *
     * @param {Array} colors - An array of hex strings, e.g. ["#001122", "#001133", ...]
     */
    function averageHex(colors) {
    
      // transform all hex codes to integer arrays, e.g. [[R, G, B], [R,G,B], ...]
      let numbers = colors.map(function(hex) {
        // split in seperate R, G and B
        let split = hex.match(/[\da-z]{2}/gi);
    
        // transform to integer values
        return split.map(function(toInt) {
          return parseInt(toInt, 16);
        });
      });
    
      // reduce the array by averaging all values, resulting in an average [R, G, B]
      let averages = numbers.reduce(function(total, amount, index, array) {
        return total.map(function(subtotal, subindex) {
    
          // if we reached the last color, average it out and return the hex value
          if (index == array.length - 1) {
    
            let result = Math.round((subtotal + amount[subindex]) / array.length).toString(16);
    
            // add a leading 0 if it is only one character
            return result.length == 2 ? '' + result : '0' + result;
    
          } else {
            return subtotal + amount[subindex];
          }
        });
      });
    
      // return them as a single hex string
      return "#" + averages.join('');
    }
    
    console.log(averageHex(["#FF110C", "#0000AA", "#55063d", "#06551e"]));
    // expected: #571b44, see also https://www.colorhexa.com/ and enter "#FF110C+#0000AA+#55063d+#06551e"

    【讨论】:

    • 嗯,现在我看到 @Endorox 之前的回答正是这样做的......
    【解决方案4】:

    这里是函数

    function avgColor(color1, color2) {
      //separate each color alone (red, green, blue) from the first parameter (color1) 
      //then convert to decimal
      let color1Decimal = {
        red: parseInt(color1.slice(0, 2), 16),
        green: parseInt(color1.slice(2, 4), 16),
        blue: parseInt(color1.slice(4, 6), 16)
      }
      //separate each color alone (red, green, blue) from the second parameter (color2) 
      //then convert to decimal
      let color2Decimal = {
        red: parseInt(color2.slice(0, 2), 16),
        green: parseInt(color2.slice(2, 4), 16),
        blue: parseInt(color2.slice(4, 6), 16),
      }
      // calculate the average of each color (red, green, blue) from each parameter (color1,color2) 
      let color3Decimal = {
        red: Math.ceil((color1Decimal.red + color2Decimal.red) / 2),
        green: Math.ceil((color1Decimal.green + color2Decimal.green) / 2),
        blue: Math.ceil((color1Decimal.blue + color2Decimal.blue) / 2)
      }
      //convert the result to hexadecimal and don't forget if the result is one character
      //then convert it to uppercase
      let color3Hex = {
        red: color3Decimal.red.toString(16).padStart(2, '0').toUpperCase(),
        green: color3Decimal.green.toString(16).padStart(2, '0').toUpperCase(),
        blue: color3Decimal.blue.toString(16).padStart(2, '0').toUpperCase()
      }
      //put the colors (red, green, blue) together to have the output
      let color3 = color3Hex.red + color3Hex.green + color3Hex.blue
      return color3
    }
    console.log(avgColor("FF33CC", "3300FF"))
    // avgColor("FF33CC", "3300FF") => "991AE6"
    
    console.log(avgColor("991AE6", "FF0000"))
    // avgColor("991AE6", "FF0000") => "CC0D73"
    
    console.log(avgColor("CC0D73", "0000FF"))
    // avgColor("CC0D73", "0000FF") => "6607B9"
    

    要检查您可以使用此链接和中点 1,然后混合 https://meyerweb.com/eric/tools/color-blend/#CC0D73:0000FF:1:hex

    【讨论】:

      【解决方案5】:

      我闻起来像家庭作业,但这是我的线索。

      取 R、G 和 B 的每个十六进制值,并对它们进行平均。如有必要,转换为十进制以进行数学运算。

      function d2h(d) {return d.toString(16).padStart(2,'0');}

      函数 h2d(h) {return parseInt(h,16);}

      然后返回一个包含三个元素的连接值的字符串。

      【讨论】:

      • 很好的电话@Deleplace。我更新了添加 .padStart() 的函数。
      【解决方案6】:

      这是我的功能,希望对你有帮助。

      function averageColors( colorArray ){
          var red = 0, green = 0, blue = 0;
      
          for ( var i = 0; i < colorArray.length; i++ ){
              red += hexToR( "" + colorArray[ i ] + "" );
              green += hexToG( "" + colorArray[ i ] + "" );
              blue += hexToB( "" + colorArray[ i ] + "" );
          }
      
          //Average RGB
          red = (red/colorArray.length);
          green = (green/colorArray.length);
          blue = (blue/colorArray.length);
      
          console.log(red + ", " + green + ", " + blue);
          return new THREE.Color( "rgb("+ red +","+ green +","+ blue +")" );
      }
      
      //get the red of RGB from a hex value
      function hexToR(h) {return parseInt((cutHex( h )).substring( 0, 2 ), 16 )}
      
      //get the green of RGB from a hex value
      function hexToG(h) {return parseInt((cutHex( h )).substring( 2, 4 ), 16 )}
      
      //get the blue of RGB from a hex value
      function hexToB(h) {return parseInt((cutHex( h )).substring( 4, 6 ), 16 )}
      
      //cut the hex into pieces
      function cutHex(h) {if(h.charAt(1) == "x"){return h.substring( 2, 8 );} else {return h.substring(1,7);}}
      

      【讨论】:

        【解决方案7】:

        我讨厌听起来像是破烂的 jQuery 记录,但有 jQuery plugin for this already

        【讨论】:

          【解决方案8】:

          如果您不想打扰很多不必要的东西,只需要几行 POJS:

          // Expects input as 'nnnnnn' where each nn is a 
          // 2 character hex number for an RGB color value
          // e.g. #3f33c6
          // Returns the average as a hex number without leading #
          var averageRGB = (function () {
          
            // Keep helper stuff in closures
            var reSegment = /[\da-z]{2}/gi;
          
            // If speed matters, put these in for loop below
            function dec2hex(v) {return v.toString(16);}
            function hex2dec(v) {return parseInt(v,16);}
          
            return function (c1, c2) {
          
              // Split into parts
              var b1 = c1.match(reSegment);
              var b2 = c2.match(reSegment);
              var t, c = [];
          
              // Average each set of hex numbers going via dec
              // always rounds down
              for (var i=b1.length; i;) {
                t = dec2hex( (hex2dec(b1[--i]) + hex2dec(b2[i])) >> 1 );
          
                // Add leading zero if only one character
                c[i] = t.length == 2? '' + t : '0' + t; 
              }
              return  c.join('');
            }
          }());
          

          【讨论】:

          • 谢谢你,我向你致敬,RobG
          猜你喜欢
          • 2013-10-28
          • 1970-01-01
          • 2016-12-27
          • 2014-07-03
          • 2019-06-16
          • 2021-03-08
          • 2019-10-29
          • 2013-07-25
          • 1970-01-01
          相关资源
          最近更新 更多