8

Heading

Is there a way to map an arbitrary string to a HEX COLOR code. I tried to compute the HEX number for string using string hashcode. Now I need to convert this hex number to six digits which are in HEX color code range. Any suggestions ?

String [] programs = {"XYZ", "TEST1", "TEST2", "TEST3", "SDFSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS"};

for(int i = 0; i < programs.length; i++) {
  System.out.println( programs[i] + " -- " + Integer.toHexString(programs[i].hashCode()));
}
go2null
  • 2,080
  • 1
  • 21
  • 17
tech20nn
  • 729
  • 2
  • 6
  • 17

5 Answers5

15

If you don't really care about the "meaning" of the color you can just split up the bits of the int (remove the first for just RGB instead of ARGB)

String [] programs = {"XYZ", "TEST1", "TEST2", "TEST3", "SDFSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS"};

for(int i = 0; i < programs.length; i++) {
  System.out.println( programs[i] + " -- " + intToARGB(programs[i].hashCode()));
}
....
public static String intToARGB(int i){
    return Integer.toHexString(((i>>24)&0xFF))+
        Integer.toHexString(((i>>16)&0xFF))+
        Integer.toHexString(((i>>8)&0xFF))+
        Integer.toHexString((i&0xFF));
}
M. Jessup
  • 8,153
  • 1
  • 29
  • 29
  • Here's the same for C# `private string StringToARGB(string text) { int i = text.GetHashCode(); return "#" + (((i >> 24) & 0xFF)).ToString("X2") + (((i >> 16) & 0xFF)).ToString("X2") + (((i >> 8) & 0xFF)).ToString("X2") + ((i & 0xFF)).ToString("X2"); }` And you can create a **Color** object like so: `Color color = (Color)(new ColorConverter()).ConvertFromString(this.StringToARGB(source));` – Sal Mar 26 '19 at 16:33
5

How about anding the hashcode with 0x00FFFFFF (or 0xFFFFFF if you want to default the alpha channel)? For example:

private String getColorCode(String inputString)
{
    String colorCode = String.format("#%06x", 0xFFFFFF & inputString.hashCode());
}
simonalexander2005
  • 4,338
  • 4
  • 48
  • 92
codaddict
  • 445,704
  • 82
  • 492
  • 529
3

I ran into this question while looking for a Ruby solution, so I thought I would add an answer for Ruby in case someone follows the same path I did. I ended up using the following method, which creates the same six digit hex code from a string by using String.hash and the optional base-specifying parameter of Fixnum.to_s. It slices from 1 rather than 0 to skip negative signs.

def color_from_string(query)
  '#'+query.hash.to_s(16).slice(1,6)
end
go2null
  • 2,080
  • 1
  • 21
  • 17
NealJMD
  • 864
  • 8
  • 15
1

In case anyone else is looking for a solution for Flutter/Dart:

    Color _fromInt(int i) {
      final a = (i >> 24) & 0xFF;
      final r = (i >> 16) & 0xFF;
      final g = (i >> 8) & 0xFF;
      final b = i & 0xFF;
      return Color.fromARGB(a, r, g, b);
    }

It's also worth noting that with certain background colours e.g. black, it may be difficult to differentiate the colours.

To this end, I set the alpha channel to the max value of 255:

    Color _fromInt(int i) {
      const a = 255;
      final r = (i >> 16) & 0xFF;
      final g = (i >> 8) & 0xFF;
      final b = i & 0xFF;
      return Color.fromARGB(a, r, g, b);
    }
Cillian Myles
  • 696
  • 8
  • 16
1

The following class takes a String and converts it to a color. It is a simplified Java port of the Color-Hash TypeScript project (MIT license): https://github.com/zenozeng/color-hash. The original project contains some parameters to adjust the generated colours. These were not included.

The advantage of the Color-Hash algorithm, compared using a hash value directly, is that the generated colours are more perceptually uniform.

A lot of copy/paste was going on here:

Result:

XYZ: #bf40b3
TEST1: #86432d
TEST2: #3a2dd2
TEST3: #bf4073
SDFSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS: #53ac8b
public class ColorHash
{

  private static final double[] LigthnessArray  = new double[] { 0.35, 0.5, 0.65 };
  private static final double[] SaturationArray = new double[] { 0.35, 0.5, 0.65 };

  public Color generateColor(String input) throws NoSuchAlgorithmException
  {
    // Easiest way would be String.hashCode()
    // But "Test1" and "Test2" result in practically the same color
    // Therefore another hash algorithm should be used
    MessageDigest md = MessageDigest.getInstance("MD5");
    md.update(input.getBytes());
    byte[] digest = md.digest();
    int hash = Math.abs(ByteBuffer.wrap(digest).getInt());

    double hue, saturation, lightness;

    hue = hash % 359 / 359.; // note that 359 is a prime
    hash = (int) Math.ceil(hash / 360);
    saturation = SaturationArray[hash % SaturationArray.length];
    hash = (int) Math.ceil(hash / SaturationArray.length);
    lightness = LigthnessArray[hash % LigthnessArray.length];

    return hslColor((float) hue, (float) saturation, (float) lightness);
  }

  public String generateColorHash(String input) throws NoSuchAlgorithmException
  {
    return "#" + Integer.toHexString(generateColor(input).getRGB()).substring(2);
  }

  private static Color hslColor(float h, float s, float l)
  {
    float q, p, r, g, b;

    if (s == 0)
    {
      r = g = b = l; // achromatic
    } else
    {
      q = l < 0.5 ? (l * (1 + s)) : (l + s - l * s);
      p = 2 * l - q;
      r = hue2rgb(p, q, h + 1.0f / 3);
      g = hue2rgb(p, q, h);
      b = hue2rgb(p, q, h - 1.0f / 3);
    }
    return new Color(Math.round(r * 255), Math.round(g * 255), Math.round(b * 255));
  }

  private static float hue2rgb(float p, float q, float h)
  {
    if (h < 0)
    {
      h += 1;
    }

    if (h > 1)
    {
      h -= 1;
    }

    if (6 * h < 1) { return p + ((q - p) * 6 * h); }
    if (2 * h < 1) { return q; }
    if (3 * h < 2) { return p + ((q - p) * 6 * ((2.0f / 3.0f) - h)); }

    return p;
  }
  
  public static void main(String[] args) throws NoSuchAlgorithmException
  {
    String [] programs = {"XYZ", "TEST1", "TEST2", "TEST3", "SDFSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS"};
    ColorHash gen = new ColorHash();
    for(String p : programs) {
      System.out.println(p + ": " + gen.generateColorHash(p));
    }
  }

}
gillesB
  • 1,061
  • 1
  • 14
  • 30