【问题标题】:JS function to calculate complementary colour?JS函数计算补色?
【发布时间】:2010-12-12 10:58:42
【问题描述】:

有没有人知道,一个用于计算十六进制值的补色的 Javascript 解决方案?

网络上有许多颜色选择套件和调色板生成器,但我还没有看到任何实际使用 JS 动态计算颜色的工具。

非常感谢您提供详细的提示或 sn-p。

【问题讨论】:

    标签: javascript colors rgb


    【解决方案1】:

    通过http://design.geckotribe.com/colorwheel/解析

        // Complement
        temprgb={ r: 0, g: 0xff, b: 0xff }; // Cyan
        temphsv=RGB2HSV(temprgb);
        temphsv.hue=HueShift(temphsv.hue,180.0);
        temprgb=HSV2RGB(temphsv);
        console.log(temprgb); // Complement is red (0xff, 0, 0)
        
        function RGB2HSV(rgb) {
        	hsv = new Object();
        	max=max3(rgb.r,rgb.g,rgb.b);
        	dif=max-min3(rgb.r,rgb.g,rgb.b);
        	hsv.saturation=(max==0.0)?0:(100*dif/max);
        	if (hsv.saturation==0) hsv.hue=0;
         	else if (rgb.r==max) hsv.hue=60.0*(rgb.g-rgb.b)/dif;
        	else if (rgb.g==max) hsv.hue=120.0+60.0*(rgb.b-rgb.r)/dif;
        	else if (rgb.b==max) hsv.hue=240.0+60.0*(rgb.r-rgb.g)/dif;
        	if (hsv.hue<0.0) hsv.hue+=360.0;
        	hsv.value=Math.round(max*100/255);
        	hsv.hue=Math.round(hsv.hue);
        	hsv.saturation=Math.round(hsv.saturation);
        	return hsv;
        }
        
        // RGB2HSV and HSV2RGB are based on Color Match Remix [http://color.twysted.net/]
        // which is based on or copied from ColorMatch 5K [http://colormatch.dk/]
        function HSV2RGB(hsv) {
        	var rgb=new Object();
        	if (hsv.saturation==0) {
        		rgb.r=rgb.g=rgb.b=Math.round(hsv.value*2.55);
        	} else {
        		hsv.hue/=60;
        		hsv.saturation/=100;
        		hsv.value/=100;
        		i=Math.floor(hsv.hue);
        		f=hsv.hue-i;
        		p=hsv.value*(1-hsv.saturation);
        		q=hsv.value*(1-hsv.saturation*f);
        		t=hsv.value*(1-hsv.saturation*(1-f));
        		switch(i) {
        		case 0: rgb.r=hsv.value; rgb.g=t; rgb.b=p; break;
        		case 1: rgb.r=q; rgb.g=hsv.value; rgb.b=p; break;
        		case 2: rgb.r=p; rgb.g=hsv.value; rgb.b=t; break;
        		case 3: rgb.r=p; rgb.g=q; rgb.b=hsv.value; break;
        		case 4: rgb.r=t; rgb.g=p; rgb.b=hsv.value; break;
        		default: rgb.r=hsv.value; rgb.g=p; rgb.b=q;
        		}
        		rgb.r=Math.round(rgb.r*255);
        		rgb.g=Math.round(rgb.g*255);
        		rgb.b=Math.round(rgb.b*255);
        	}
        	return rgb;
        }
    
        //Adding HueShift via Jacob (see comments)
        function HueShift(h,s) { 
            h+=s; while (h>=360.0) h-=360.0; while (h<0.0) h+=360.0; return h; 
        }
        
        //min max via Hairgami_Master (see comments)
        function min3(a,b,c) { 
            return (a<b)?((a<c)?a:c):((b<c)?b:c); 
        } 
        function max3(a,b,c) { 
            return (a>b)?((a>c)?a:c):((b>c)?b:c); 
        }

    【讨论】:

    • 神奇的 HueShift(...) 函数是这样的: function HueShift(h,s) { h+=s;而 (h>=360.0) h-=360.0;而 (h
    • 你还需要 max3 和 min3 函数:
    • 函数 min3(a,b,c) { return (ab)?((a>c)?a:c):((b>c)?b:c); }
    • thisrgb 值应该是多少?
    • 虽然这确实做了一些很棒的事情,但还是有大量的代码丢失。 “色相”?你说“见 cmets”?什么cmets?缺乏整体性使得这个答案毫无用处。
    【解决方案2】:

    我发现采用按位补码效果很好,而且速度很快。

    var color = 0x320ae3;
    var complement = 0xffffff ^ color;
    

    我不确定它是否是“混合在一起形成 70% 的灰色”意义上的完美补充,但 70% 的灰色在电影色彩时序方面是“纯白色”。我突然想到,用纯白色对 RGB 十六进制进行异或运算可能是一个很好的初步近似值。您也可以尝试使用较深的灰色,看看效果如何。

    同样,这是一个快速的近似值,我不保证它会完全准确。

    请参阅 https://github.com/alfl/textful/blob/master/app.js#L38 了解我的实现。

    【讨论】:

    • 这很好用,除非您希望结果始终为 6 个字符长。我建议('000000' + (('0xffffff' ^ '0x320ae3').toString(16))).slice(-6);
    • Buzzzz:(错误)0x7F7F7F 的相反颜色是什么? 0x808080!这不是很“相反”。 XOR 与 0x808080 会更好(颜色距离总是一半)但仍然不是“最好的”。 HSL 方法给出了最好的结果。
    • 公平,如果你从灰色中异或灰色,你会得到不同的灰色。称其为方法的限制:D
    【解决方案3】:

    这里的其他功能都没有解决这个问题,所以我做了这个。

    它取一个十六进制值,将其转换为 HSL,将色调移动 180 度并转换回十六进制

    /* hexToComplimentary : Converts hex value to HSL, shifts
     * hue by 180 degrees and then converts hex, giving complimentary color
     * as a hex value
     * @param  [String] hex : hex value  
     * @return [String] : complimentary color as hex value
     */
    function hexToComplimentary(hex){
    
        // Convert hex to rgb
        // Credit to Denis http://stackoverflow.com/a/36253499/4939630
        var rgb = 'rgb(' + (hex = hex.replace('#', '')).match(new RegExp('(.{' + hex.length/3 + '})', 'g')).map(function(l) { return parseInt(hex.length%2 ? l+l : l, 16); }).join(',') + ')';
    
        // Get array of RGB values
        rgb = rgb.replace(/[^\d,]/g, '').split(',');
    
        var r = rgb[0], g = rgb[1], b = rgb[2];
    
        // Convert RGB to HSL
        // Adapted from answer by 0x000f http://stackoverflow.com/a/34946092/4939630
        r /= 255.0;
        g /= 255.0;
        b /= 255.0;
        var max = Math.max(r, g, b);
        var min = Math.min(r, g, b);
        var h, s, l = (max + min) / 2.0;
    
        if(max == min) {
            h = s = 0;  //achromatic
        } else {
            var d = max - min;
            s = (l > 0.5 ? d / (2.0 - max - min) : d / (max + min));
    
            if(max == r && g >= b) {
                h = 1.0472 * (g - b) / d ;
            } else if(max == r && g < b) {
                h = 1.0472 * (g - b) / d + 6.2832;
            } else if(max == g) {
                h = 1.0472 * (b - r) / d + 2.0944;
            } else if(max == b) {
                h = 1.0472 * (r - g) / d + 4.1888;
            }
        }
    
        h = h / 6.2832 * 360.0 + 0;
    
        // Shift hue to opposite side of wheel and convert to [0-1] value
        h+= 180;
        if (h > 360) { h -= 360; }
        h /= 360;
    
        // Convert h s and l values into r g and b values
        // Adapted from answer by Mohsen http://stackoverflow.com/a/9493060/4939630
        if(s === 0){
            r = g = b = l; // achromatic
        } else {
            var hue2rgb = function hue2rgb(p, q, t){
                if(t < 0) t += 1;
                if(t > 1) t -= 1;
                if(t < 1/6) return p + (q - p) * 6 * t;
                if(t < 1/2) return q;
                if(t < 2/3) return p + (q - p) * (2/3 - t) * 6;
                return p;
            };
    
            var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
            var p = 2 * l - q;
    
            r = hue2rgb(p, q, h + 1/3);
            g = hue2rgb(p, q, h);
            b = hue2rgb(p, q, h - 1/3);
        }
    
        r = Math.round(r * 255);
        g = Math.round(g * 255); 
        b = Math.round(b * 255);
    
        // Convert r b and g values to hex
        rgb = b | (g << 8) | (r << 16); 
        return "#" + (0x1000000 | rgb).toString(16).substring(1);
    }  
    

    【讨论】:

    • 这很好用。你花了多长时间写这个?我一直在寻找可以做到这一点的东西,但也遇到了几个不起作用的“开箱即用”解决方案。
    • 花了一个小时左右 - 我刚刚拼凑了一些 stackoverflow 答案(记入代码中)。
    • @Edd:嗨,我试过你的算法,用下面的颜色#00BCD4 它应该给我这个#d41900 作为补色,而不是给我这个#d41800。你能帮我一把吗?
    • 效果很好!对于任何想要较小差异的人,更改 h+= 180;到 h+= 40;
    【解决方案4】:

    我没有重新发明轮子,而是找到了一个处理颜色的库。

    Tiny Color

    这就是您将如何使用它来实现其他一些答案的方式。

    color1 = tinycolor2('#f00').spin(180).toHexString(); // Hue Shift
    color2 = tinycolor2("#f00").complement().toHexString(); // bitwise
    

    【讨论】:

      【解决方案5】:

      RGB 免费

      function componentToHex(c) {
          var hex = c.toString(16);
          return hex.length == 1 ? "0" + hex : hex;
      }
      
      
      function hexToRgb(hex) {
        var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
        return result ? {
          r: parseInt(result[1], 16),
          g: parseInt(result[2], 16),
          b: parseInt(result[3], 16)
        } : null;
      }
      
      function rgbComplimentary(r,g,b){
      
          var hex = "#" + componentToHex(r) + componentToHex(g) + componentToHex(b);
          var rgb = 'rgb(' + (hex = hex.replace('#', '')).match(new RegExp('(.{' + hex.length/3 + '})', 'g')).map(function(l) { return parseInt(hex.length%2 ? l+l : l, 16); }).join(',') + ')';
      
          // Get array of RGB values
          rgb = rgb.replace(/[^\d,]/g, '').split(',');
      
          var r = rgb[0]/255.0, g = rgb[1]/255.0, b = rgb[2]/255.0;
      
          var max = Math.max(r, g, b);
          var min = Math.min(r, g, b);
          var h, s, l = (max + min) / 2.0;
      
          if(max == min) {
              h = s = 0;  //achromatic
          } else {
              var d = max - min;
              s = (l > 0.5 ? d / (2.0 - max - min) : d / (max + min));
      
              if(max == r && g >= b) {
                  h = 1.0472 * (g - b) / d ;
              } else if(max == r && g < b) {
                  h = 1.0472 * (g - b) / d + 6.2832;
              } else if(max == g) {
                  h = 1.0472 * (b - r) / d + 2.0944;
              } else if(max == b) {
                  h = 1.0472 * (r - g) / d + 4.1888;
              }
          }
      
          h = h / 6.2832 * 360.0 + 0;
      
          // Shift hue to opposite side of wheel and convert to [0-1] value
          h+= 180;
          if (h > 360) { h -= 360; }
          h /= 360;
      
          // Convert h s and l values into r g and b values
          // Adapted from answer by Mohsen http://stackoverflow.com/a/9493060/4939630
          if(s === 0){
              r = g = b = l; // achromatic
          } else {
              var hue2rgb = function hue2rgb(p, q, t){
                  if(t < 0) t += 1;
                  if(t > 1) t -= 1;
                  if(t < 1/6) return p + (q - p) * 6 * t;
                  if(t < 1/2) return q;
                  if(t < 2/3) return p + (q - p) * (2/3 - t) * 6;
                  return p;
              };
      
              var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
              var p = 2 * l - q;
      
              r = hue2rgb(p, q, h + 1/3);
              g = hue2rgb(p, q, h);
              b = hue2rgb(p, q, h - 1/3);
          }
      
          r = Math.round(r * 255);
          g = Math.round(g * 255); 
          b = Math.round(b * 255);
      
          // Convert r b and g values to hex
          rgb = b | (g << 8) | (r << 16); 
          return hexToRgb("#" + (0x1000000 | rgb).toString(16).substring(1));
      
      }
      
      
      console.log(rgbComplimentary(242, 211, 215));

      十六进制免费

      function hexComplimentary(hex){
      
          var rgb = 'rgb(' + (hex = hex.replace('#', '')).match(new RegExp('(.{' + hex.length/3 + '})', 'g')).map(function(l) { return parseInt(hex.length%2 ? l+l : l, 16); }).join(',') + ')';
      
          // Get array of RGB values
          rgb = rgb.replace(/[^\d,]/g, '').split(',');
      
          var r = rgb[0]/255.0, g = rgb[1]/255.0, b = rgb[2]/255.0;
      
          var max = Math.max(r, g, b);
          var min = Math.min(r, g, b);
          var h, s, l = (max + min) / 2.0;
      
          if(max == min) {
              h = s = 0;  //achromatic
          } else {
              var d = max - min;
              s = (l > 0.5 ? d / (2.0 - max - min) : d / (max + min));
      
              if(max == r && g >= b) {
                  h = 1.0472 * (g - b) / d ;
              } else if(max == r && g < b) {
                  h = 1.0472 * (g - b) / d + 6.2832;
              } else if(max == g) {
                  h = 1.0472 * (b - r) / d + 2.0944;
              } else if(max == b) {
                  h = 1.0472 * (r - g) / d + 4.1888;
              }
          }
      
          h = h / 6.2832 * 360.0 + 0;
      
          // Shift hue to opposite side of wheel and convert to [0-1] value
          h+= 180;
          if (h > 360) { h -= 360; }
          h /= 360;
      
          if(s === 0){
              r = g = b = l; // achromatic
          } else {
              var hue2rgb = function hue2rgb(p, q, t){
                  if(t < 0) t += 1;
                  if(t > 1) t -= 1;
                  if(t < 1/6) return p + (q - p) * 6 * t;
                  if(t < 1/2) return q;
                  if(t < 2/3) return p + (q - p) * (2/3 - t) * 6;
                  return p;
              };
      
              var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
              var p = 2 * l - q;
      
              r = hue2rgb(p, q, h + 1/3);
              g = hue2rgb(p, q, h);
              b = hue2rgb(p, q, h - 1/3);
          }
      
          r = Math.round(r * 255);
          g = Math.round(g * 255); 
          b = Math.round(b * 255);
      
          // Convert r b and g values to hex
          rgb = b | (g << 8) | (r << 16); 
          return "#" + (0x1000000 | rgb).toString(16).substring(1);
      }
      
      
      console.log(hexComplimentary("#ff5a5a"));

      来源:更新https://stackoverflow.com/a/37657940/6569224答案

      【讨论】:

      • 嗨,我试过你的算法,用下面的颜色#00BCD4 它应该给我这个#d41900 作为补色而不是给我这个#d41800。你能帮我一把吗?
      【解决方案6】:

      十六进制和 RGB 互补 这是获得互补十六进制颜色值的最正确和最有效的方法

      function complementryHexColor(hex){
          let r = hex.length == 4 ? parseInt(hex[1] + hex[1], 16) : parseInt(hex.slice(1, 3), 16);
          let g = hex.length == 4 ? parseInt(hex[2] + hex[2], 16) : parseInt(hex.slice(3, 5), 16);
          let b = hex.length == 4 ? parseInt(hex[3] + hex[3], 16) : parseInt(hex.slice(5), 16);
        
          [r, g, b] = complementryRGBColor(r, g, b);
          return '#' + (r < 16 ? '0' + r.toString(16) : r.toString(16)) + (g < 16 ? '0' + g.toString(16) : g.toString(16)) + (b < 16 ? '0' + b.toString(16) : b.toString(16));
      }
      
      function complementryRGBColor(r, g, b) {
          if (Math.max(r, g, b) == Math.min(r, g, b)) {
              return [255 - r, 255 - g, 255 - b];
      
          } else {
              r /= 255, g /= 255, b /= 255;
              var max = Math.max(r, g, b), min = Math.min(r, g, b);
              var h, s, l = (max + min) / 2;
              var d = max - min;
              s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
          
              switch (max) {
                  case r: h = (g - b) / d + (g < b ? 6 : 0); break;
                  case g: h = (b - r) / d + 2; break;
                  case b: h = (r - g) / d + 4; break;
              }
          
              h = Math.round((h*60) + 180) % 360;
              h /= 360;
              
              function hue2rgb(p, q, t) {
                  if (t < 0) t += 1;
                  if (t > 1) t -= 1;
                  if (t < 1/6) return p + (q - p) * 6 * t;
                  if (t < 1/2) return q;
                  if (t < 2/3) return p + (q - p) * (2/3 - t) * 6;
                  return p;
              }
          
              var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
              var p = 2 * l - q;
          
              r = hue2rgb(p, q, h + 1/3);
              g = hue2rgb(p, q, h);
              b = hue2rgb(p, q, h - 1/3);
      
              return [Math.round(r*255), Math.round(g*255), Math.round(b*255)];
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2016-08-31
        • 2012-12-04
        • 2023-01-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-07-05
        • 2017-07-11
        相关资源
        最近更新 更多