是否有关于如何将任意字符串哈希为 RGB 颜色值的最佳实践?或者更一般地说:3 个字节。
您在问:我什么时候需要这个?这对我来说并不重要,但想象一下任何 GitHub 网络页面上的那些管图。在那里你可以看到这样的东西:
每条彩色线都代表一个不同的 git 分支。为这些分支着色的低技术方法是 CLUT(颜色查找表)。更复杂的版本是:
$branchColor = hashStringToColor(concat($username,$branchname));
因为每次看到分支表示时您都需要静态颜色。还有加分点:如何确保哈希函数的颜色分布均匀?
所以我的问题的答案归结为
hashStringToColor()
的实施。
一个好的哈希函数将在密钥空间上提供近乎均匀的分布。这将问题简化为如何将随机 32 位数字转换为 3 字节 RGB 空间。我认为只取低 3 个字节没有什么问题。
int hash = string.getHashCode();
int r = (hash & 0xFF0000) >> 16;
int g = (hash & 0x00FF00) >> 8;
int b = hash & 0x0000FF;
对于任何 Javascript 用户,我将 @jeff-foster 接受的答案与
djb2
哈希函数从 erlycoder 结合起来。
每个问题的结果:
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 格式的十六进制字符串(谢谢!)。
我刚刚构建了一个名为 color-hash 的 JavaScript 库,它可以根据给定的字符串生成颜色(使用 HSL 颜色空间和 BKDRHash)。
回购:https://github.com/zenozeng/color-hash
演示:https://zenozeng.github.io/color-hash/demo/
我尝试了其他人提供的所有解决方案,但发现相似的字符串(string1 与 string2)产生的颜色对于我的喜好来说太相似了。因此,我受到他人的意见和想法的影响而建立了自己的。
这个将计算字符串的 MD5 校验和,并采用前 6 个十六进制数字来定义 RGB 24 位代码。
MD5 功能是一个开源 JQuery 插件。 JS函数如下:
function getRGB(str) {
return '#' + $.md5(str).substring(0, 6);
}
此工作示例的链接位于 jsFiddle。只需在输入字段中输入一个字符串并按 Enter 键,然后一遍又一遍地执行此操作以比较您的发现。
哈希码返回一个
int
,该值是使用 javadoc 中定义的公式计算得出的。然后,您可以计算该 int
与 16,777,216(2^24 = 3 字节)的模以获得“RGB 兼容”数字。
这是一种确定性计算,因此相同的单词将始终具有相同的颜色。哈希冲突(2 个字符串具有相同颜色)的可能性很小。不确定颜色分布,但可能相当随机。
有趣的是,像 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>
这是我根据Zeno Zeng编写的library编写的一个类,并在这个answer中提到。
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);
}
}