Average 2 hex colors together in javascript

后端 未结 8 2011
天命终不由人
天命终不由人 2021-01-31 20:13

Alright thought I would throw this one out there for the crowd to think over.

Given a function (written in javascript) that expects two strings

相关标签:
8条回答
  • 2021-01-31 20:20

    Only requires a few lines of POJS if you don't want to bother with lots of unnecessary stuff:

    // 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('');
      }
    }());
    
    0 讨论(0)
  • 2021-01-31 20:24

    Here is the function

    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"
    

    To check you can use this link and midpoint 1 then blend https://meyerweb.com/eric/tools/color-blend/#CC0D73:0000FF:1:hex

    0 讨论(0)
  • 2021-01-31 20:29

    Here's a compact set of relevant (interdependent) functions:

    Hex ⟷ RGB Color 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);}
    

    Calculate Average of 2 Hex Colors: Requires conversion functions (above)

    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));}
    

    Generate Random Hex Color:

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

    Run snippet for demo:

    // 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>

    0 讨论(0)
  • 2021-01-31 20:30

    I hate sounding like the oh-so-broken jQuery record, but there is a jQuery plugin for this already.

    $.xcolor.average(color, color)

    0 讨论(0)
  • 2021-01-31 20:32

    Very late to this party, but I was personally looking for a way to average an undefined amount of HEX values. Based on the answer @RobG, I came up with this. Granted, the more colors you add the more brown/greyish they get, but, perhaps it helps!

    /**
     * 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"

    0 讨论(0)
  • 2021-01-31 20:38

    Smells like homework to me, but here's my clue.

    Take each hex value for R, G, and B, and average each of them. If necessary convert to Decimal to do the math.

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

    function h2d(h) {return parseInt(h,16);}

    Then return a string containing the concatenated values of the three elements.

    0 讨论(0)
提交回复
热议问题