54

是否有关于如何将任意字符串散列为 RGB 颜色值的最佳实践?或者更笼统地说:到 3 个字节。

你在问:我什么时候需要这个?对我来说没关系,但想象一下任何 GitHub网络页面上的那些管图。在那里你可以看到这样的东西:

git 分支

每条彩色线都表示一个不同的 git 分支。为这些分支着色的低技术方法是 CLUT(颜色查找表)。更复杂的版本是:

$branchColor = hashStringToColor(concat($username,$branchname));

因为每次看到分支表示时都需要静态颜色。对于奖励积分:您如何确保该哈希函数的颜色分布均匀?

所以我的问题的答案归结为hashStringToColor().

4

7 回答 7

38

一个好的散列函数将在密钥空间上提供近乎均匀的分布。这减少了如何将随机 32 位数字转换为 3 字节 RGB 空间的问题。我认为只取低 3 个字节没有任何问题。

int hash = string.getHashCode();
int r = (hash & 0xFF0000) >> 16;
int g = (hash & 0x00FF00) >> 8;
int b = hash & 0x0000FF;
于 2012-06-20T13:46:23.797 回答
26

对于那里的任何 Javascript 用户,我将@jeff-foster 接受的答案与erlycoderdjb2的哈希函数结合起来。

每个问题的结果:

function djb2(str){
  var hash = 5381;
  for (var i = 0; i < str.length; i++) {
    hash = ((hash << 5) + hash) + str.charCodeAt(i); /* hash * 33 + c */
  }
  return hash;
}

function hashStringToColor(str) {
  var hash = djb2(str);
  var r = (hash & 0xFF0000) >> 16;
  var g = (hash & 0x00FF00) >> 8;
  var b = hash & 0x0000FF;
  return "#" + ("0" + r.toString(16)).substr(-2) + ("0" + g.toString(16)).substr(-2) + ("0" + b.toString(16)).substr(-2);
}

更新:修复了返回字符串以始终根据@alexc 的编辑返回一个#000000 格式的十六进制字符串(谢谢!)。

于 2013-05-14T01:06:09.857 回答
13

我只是构建了一个名为 color-hash 的 JavaScript 库,它可以根据给定的字符串生成颜色(使用 HSL 颜色空间和 BKDRHash)。

回购:https
://github.com/zenozeng/color-hash 演示:https ://zenozeng.github.io/color-hash/demo/

于 2015-02-12T15:03:12.750 回答
10

我尝试了其他人提供的所有解决方案,但发现相似的字符串(string1 vs string2)产生的颜色与我的喜好过于相似。因此,我在他人的输入和想法的影响下建立了自己的。

这将计算字符串的 MD5 校验和,并取前 6 个十六进制数字来定义 RGB 24 位代码。

MD5功能是一个开源的JQuery插件。JS功能如下:

function getRGB(str) {
    return '#' + $.md5(str).substring(0, 6);
}

此工作示例的链接位于jsFiddle上。只需在输入字段中输入一个字符串并按 Enter,然后一遍又一遍地执行此操作以比较您的发现。

于 2013-11-20T23:15:38.587 回答
2

例如,这是 Java 计算字符串哈希码的方式(第 1494 行及以下)。它返回一个int. 然后,您可以int用 16,777,216(2^24 = 3 个字节)计算它的模,以获得“RGB 兼容”数字。

这是一种确定性计算,因此相同的单词将始终具有相同的颜色。哈希冲突的可能性(2 个相同颜色的字符串)很小。不确定颜色分布,但可能相当随机。

于 2012-06-20T13:40:45.957 回答
0

如果您使用 C# 并想要 HSL 颜色

这是我根据Zeno Zeng 编写的库编写的课程,并在此答案中提到。

HSLColor 类是 Rich Newman 编写的,在这里定义


    public class ColorHash
    {        
        
        // you can pass in a string hashing function of you choice
        public ColorHash(Func<string, int> hashFunction)
        {
            this.hashFunction = hashFunction;
        }

        // or use the default string.GetHashCode()
        public ColorHash()
        {
            this.hashFunction = (string s) => { return s.GetHashCode(); };
        }
        
        Func<string, int> hashFunction = null;

        static float[] defaultValues = new float[] { 0.35F, 0.5F, 0.65F };

        // HSLColor class is defined at https://richnewman.wordpress.com/about/code-listings-and-diagrams/hslcolor-class/
        public HSLColor HSL(string s) {
            return HSL(s, defaultValues, defaultValues);
        }

        // HSL function ported from https://github.com/zenozeng/color-hash/       
        public HSLColor HSL(string s, float[] saturationValues, float[] lightnessValues)
        {
            
            double hue;
            double saturation;
            double luminosity;

            int hash = Math.Abs(this.hashFunction(s));

            hue = hash % 359;

            hash = (int)Math.Ceiling((double)hash / 360);
            saturation = saturationValues[hash % saturationValues.Length];

            hash = (int)Math.Ceiling((double)hash / saturationValues.Length);
            luminosity = lightnessValues[hash % lightnessValues.Length];

            return new HSLColor(hue, saturation, luminosity);
        }
        
    }

于 2022-02-11T16:19:41.117 回答
0

有趣的是,像 sha256 或 md5 这样的散列函数的常见表示形式是十六​​进制字符串。这是一个小提琴,它使用 10 个 6 字节的段来创建一个 sha256 哈希的彩色表示。它使用最后 4 字节段来确定颜色的角度。

https://jsfiddle.net/ypx4mtnr/4/

async function sha256(message) ... see fiddle ...

   async function sha256(message) {
    // encode as UTF-8
    const msgBuffer = new TextEncoder().encode(message);                    

    // hash the message
    const hashBuffer = await crypto.subtle.digest('SHA-256', msgBuffer);

    // convert ArrayBuffer to Array
    const hashArray = Array.from(new Uint8Array(hashBuffer));

    // convert bytes to hex string                  
    const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
    return hashHex;
   }  
   function sha256tohtml(x,b){
var y=chunkSubstr(x,6);
return '<div style="'+
    'display: inline-block;'+
    'margin:2em;'+
    'width:128px;'+
    'height:128px;'+
    'border-radius: 512px;'+
    'background: conic-gradient('+
    '   from '+((360/65536)*parseInt(y[10],16))+'deg at 50% 50%,'+
    '   #'+y[0]+' '+(0+b)+'%,'+
    '   #'+y[0]+' 10%,'+
    '   #'+y[1]+' '+(10+b)+'%,'+
    '   #'+y[1]+' 20%,'+
    '   #'+y[2]+' '+(20+b)+'%,'+
    '   #'+y[2]+' 30%,'+
    '   #'+y[3]+' '+(30+b)+'%,'+
    '   #'+y[3]+' 40%,'+
    '   #'+y[4]+' '+(40+b)+'%,'+
    '   #'+y[4]+' 50%,'+
    '   #'+y[5]+' '+(50+b)+'%,'+
    '   #'+y[5]+' 60%,'+
    '   #'+y[6]+' '+(60+b)+'%,'+
    '   #'+y[6]+' 70%,'+
    '   #'+y[7]+' '+(70+b)+'%,'+
    '   #'+y[7]+' 80%,'+
    '   #'+y[8]+' '+(80+b)+'%,'+
    '   #'+y[8]+' 90%,'+
    '   #'+y[9]+' '+(90+b)+'%,'+
    '   #'+y[9]+' 100%);"></div>';
  }
   function chunkSubstr(str, size) {
  const numChunks = Math.ceil(str.length / size)
  const chunks = new Array(numChunks)

  for (let i = 0, o = 0; i < numChunks; ++i, o += size) {
    chunks[i] = str.substr(o, size)
  }

  return chunks
}
   function draw(x){
    sha256(x).then((x)=>{
        var html=sha256tohtml(x,0);
            document.getElementById('addhere').innerHTML=html;
        });
   }
   window.onload=function(){
    document.getElementById('sha256string').oninput=function(){draw(this.value);}
        draw(document.getElementById('sha256string').value)
}
<html>
<input id="sha256string" value="Hello World">
 <div id="addhere"></div>
</html>

于 2021-12-20T20:13:39.757 回答