8

Is there any way to generate a color from any String in Java / Android like an Encrypt / Hash function?

Example: The String "Home" generates a color like "#FF1234".
The String "Sky" generates a color like "#00CC33" ...

Without randomize. So, the system will always calculate the same colors for that strings

Thanks

EDIT: The Strings are freely defined by the user

5
  • You could probably define a hashmap somewhere that maps strings to colors, though you'd have to populate it yourself. java's default color class already has some default colors defined, though nothing crazy like "Sky". It's stuff like "Red" and "LightGray" Commented Jun 8, 2012 at 17:33
  • 1
    Sure, you can define any math function you want to combine the characters into a 24bit (without alpha) or 32 bits (if you wanted alpha) value, then apply that as the color for the word. A hash function could work as well, and will most likely get you better color disperssion throughout the full color range (capable on todays computers). A hash like ANY mathematical function that does NOT use a random input will result you with the same color for that input string always. Only thing could be capitalization to look at. Commented Jun 8, 2012 at 17:34
  • @Hans - a HASH map would be extremely large if his input was any arbitraty word. Better to calculated the hash and apply any static portion (digest will be larger than 32 or 24 bits) of the digest's output bits to a color value. I could see potentially using a more simplistic CRC or something, but the hamming distance between values wouldnt be as good as for a HASH. Commented Jun 8, 2012 at 17:37
  • I thought the point was to create a dictionary of predefined colors. Looks like I was wrong. Commented Jun 8, 2012 at 17:42
  • @Hans If I understand what you mean, I guess I can't do this, because the Strings are defined by the user and not by me. Commented Jun 8, 2012 at 17:43

5 Answers 5

9

the String.hashCode() will return an int value, so then it's just a matter of turning that into into a hex value.

String s = "Home";
String color = String.format("#%X", s.hashCode());
Sign up to request clarification or add additional context in comments.

6 Comments

This is again a simplistic answer, if you look up the Java hashCode routine for a string, it is a simple multiply add. This will result in situations where "Home" would get the same hash code as "moeH". This might be fine if his requirements are as such.
Actually java's String hashCode() is a litte more efficent than that. Same characters will not actually generate the same code. Check it out for yourself... just do a println on "Home".hashCode() and "emoH".hashCode()... they will be different.
Ah yes, this is due to i in the summation being incorporated into the exponent of the SUM(i = 0, i < strlen - 1, string[i] * 31^(n-1-i)) equation. This may be a pretty decent solution. While i wont prove it (LOL) my gut tells me that a SHA based solution will give a BETTER 1-to-1 mapping of string to color, but depending on his requirements, your solution may be just what he needs :-)
Thanks for the help! I made some changes to meet my needs: String s = word; String hexColor = String.format("FF%06X", (0xFFFFFF & s.hashCode())); Thanks to all who helped
There's no guarantee you'll get a 6-digit hex code, e.g. construction will result in #810D1. You can manually add leading zeroes with something like this: while (s.length() < 7) s = "#" + s.replace('#', '0');
|
5

With consistent opacity:

String opacity = "#99"; //opacity between 00-ff
String hexColor = String.format(
        opacity + "%06X", (0xFFFFFF & anyString.hashCode()));

Or using the new material design android Palette:
https://gist.github.com/odedhb/79d9ea471c10c040245e

Comments

3

Try looking here for how to create a message digest of your string.

http://www.mkyong.com/java/java-sha-hashing-example/

After you have created a message digest, use how many every of the bytes generated to create your color value. You could use least significant, most significant, anywhere in the middle.

2 Comments

Same issue that you pointed out in my answer,don't you think? Sorry just in case,because I feel I might be mistaken here.
Not sure as I haven't really analyzed the true properties of the hash code function for a string (provided by java). I do know that if a SHA-384 or 512 has the property that for a given input stream if a single bit in the stream changes, approximately 50% of the output digest will change (somewhat) randomly dispersed throughout. If then taken to the lowest 32 bits, this property would still be true. For this reason it can be deduced that this would give quite a good separation in values for the given input strings. An not too many repeats until past 2^24 or 2^32 input strings processed.
1

I am guessing you are not trying to change the resource file.

Depends on how you want to do it to be honest. THere are millions of ways to accomplish it

For me, I would take the Ascii value of each character, add them all up, then convert it to hex. With that Said, to cover the case of too many characters, would mod it to the max size of a hex string. IE. FFFFFF so that way it wraps around and starts over.

//pseudocode
counter = 0;
foreach(char in string){
    counter+=(int)char;

}
counter = convertToHex(counter)%0xffffff;
string x = "#"+counter.toString();

AFter that i would store it into a string

string x = "#"+hexVal.toString();

them you could do with it what you wanted.

4 Comments

This might be overly simplistic if he is trying to get a BETTER one-to-one matching of word to color. A simple addition could result more easily in many words holding the same color. On the other hand, this is a great example of a very simplistic math routine as I stated in my note above.
so then he would want a dictionary of words and associated colors I would think, though it would still repeat if there were enough words on the page
@ Fallenreaper - It really depends on what he is trying to do. If he is trying to get as close as he can to a 1 to 1 mapping, then a HASH would probably be the CLOSEST answer as a HASH would not only take into consideration the value of each letter, but also the ordering (which matters in a 1-to-1 mapping). If he is mapping any arbitrary word, then a dictionary could get TOO TOO large. Live calc would be the way to go. Even HASH has its problems when applied here as only 24 to 32 bits of (much larger) hash would be used. With an infinite amount of words, repeats are bound to happen.
The repeats Im speaking of would happen after 2^24 or 2^32 unique words' HASHs had been exausted.
0

You can try something like:

String s = "Home";
byte[] b = s.getBytes("US-ASCII");
StringBuffer hexString = new StringBuffer();
for (int i=0;i<b.length;i++) {
    hexString.append(Integer.toHexString(0xFF & b[i]));
    }
String finalHex = "#" + hexString.substring(0,6);
System.out.println(finalHex);

Generates a hex : #486f6d

Similarly generate hex for all the Strings you want and keep adding them up to a HashMap as a key-value pair.

5 Comments

This takes care of ordering, but really only will calculated if the word is the same or different for the first 6 characters. In this case "homer123456" would get the same color as "homer178902".
Oops. Yeah right. But if I don't do the substring, the hex won't turn out to be a valid Color hex,it'll just cross the valid length.
for every iteration in your loop, all you are doing is appending a math function based upon the current character. This means that you are essentially making another string of the same size as s (which you have put into b). Afterwards you are simply taking the substring of the first 6 characters of the string you generated. You have created a character based 1-to-1 mapping and leaving behind all character you have generated past character 6).
That is very correct. But, as I've already told, I need to reduce the length to 6 to make it a valid color hex for the purpose required.
THIS IS WHY I KEEP SUGGESTING A SHA BASED MESSAGE DIGEST. SHA will take into account the full string, as well as ordering. At that point you can use a subset of the message digest bytes as your color value.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.