0

I have got color names such as White, Red, Blue, etc., and I'm trying to get its corresponding hexadecimal representation. For example, if I pass an argument such as White it should return #FFFFFF.

Although it seems simple, there's no straight solution in Java. Following is the code I have tried.

private String getHexaColor (String basicColor /* White */) {
    java.awt.Color color;
    try {
        java.lang.reflect.Field field = Class.forName("java.awt.Color").getField(basicColor.toLowerCase());
        color = (Color) field.get(null);
    } catch (Exception e) {
        color = null; 
    }

    return (color != null) ? String.format("%06x#", color.getRGB() & 0x00FFFFFF).toUpperCase() : ""; //return #FFFFFF
}

Above code is working fine, but I'm looking for a clean and elegant solution if at all available at least in the latest version of Java.

Vijin Paulraj
  • 4,469
  • 5
  • 39
  • 54
  • 1
    This looks like a question for https://codereview.stackexchange.com/ – Cardinal System Apr 21 '19 at 00:05
  • I googled some. The best I could find is a S.O. question with the answer being to do just this: https://stackoverflow.com/questions/2854043/converting-a-string-to-color-in-java - there some other options there involving 3rd party solutions. - I would think there would be a list of colors with hex values online somewhere that you could grab and use. – CryptoFool Apr 21 '19 at 01:06
  • What is your universe of possible color names? – CryptoFool Apr 21 '19 at 01:09
  • I found a really exhaustive list of colors and hex values. If it were me, I'd probably wrap some code around that. - https://www.rapidtables.com/web/color/RGB_Color.html – CryptoFool Apr 21 '19 at 01:17

2 Answers2

2

You should use the format string "#%06X" rather than "%06x#". First, it places the # character at the position you actually want, second, it generates an upper case hexadecimal string, removing the need to call toUpperCase() on the result.

But how much does your reflective operation save, compared to an explicit map of values? When I run over all fields of Color, e.g. via

final int constant = Modifier.STATIC | Modifier.FINAL;
Map<String,Integer> m = new HashMap<>();
for(Field f: Color.class.getFields()) try {
    if((f.getModifiers() & constant) == constant && f.getType() == Color.class)
        m.put(f.getName().toLowerCase().replace('_', ' '),
            ((Color)f.get(null)).getRGB() & 0x00FFFFFF);
} catch(ReflectiveOperationException ex) {
    throw new AssertionError(ex);
}
m.forEach((name,rgb) -> System.out.printf("map.put(\"%s\", \"#%06X\");%n", name, rgb));

I get

map.put("magenta", "#FF00FF");
map.put("pink", "#FFAFAF");
map.put("green", "#00FF00");
map.put("black", "#000000");
map.put("yellow", "#FFFF00");
map.put("cyan", "#00FFFF");
map.put("dark gray", "#404040");
map.put("red", "#FF0000");
map.put("orange", "#FFC800");
map.put("gray", "#808080");
map.put("white", "#FFFFFF");
map.put("blue", "#0000FF");
map.put("darkgray", "#404040");
map.put("light gray", "#C0C0C0");
map.put("lightgray", "#C0C0C0");

which is not that big. So, when I copy that output into a new code like

static final Map<String,String> COLOR_CODES;
static {
    Map<String,String> map = new HashMap<>();
    map.put("magenta", "#FF00FF");
    map.put("pink", "#FFAFAF");
    map.put("green", "#00FF00");
    map.put("black", "#000000");
    map.put("yellow", "#FFFF00");
    map.put("cyan", "#00FFFF");
    map.put("dark gray", "#404040");
    map.put("red", "#FF0000");
    map.put("orange", "#FFC800");
    map.put("gray", "#808080");
    map.put("white", "#FFFFFF");
    map.put("blue", "#0000FF");
    map.put("darkgray", "#404040");
    map.put("light gray", "#C0C0C0");
    map.put("lightgray", "#C0C0C0");
    COLOR_CODES = Collections.unmodifiableMap(map);
}
static String getHexaColor(String colorName) {
    return COLOR_CODES.getOrDefault(colorName.toLowerCase(), "");
}

the result is simple and reflection free. Maintenance would be independent of the reflective code that produced this version, as it is simpler to add a new constant to the map than to add a new constant to the java.awt.Color class (to re-run the reflective code).

The only alternative with more flexibility would be to use a properties file, which allows to update the map without recompiling the application. It’s easy to adapt the code above to generate a properties file instead, but on the other hand, there are enough ready-to-use files on the internet with even more colors. E.g., you can copy the VGA based web colors directly from w3.org, whereas this extended list would require an advanced search-and-replace to be brought into the properties format.

Holger
  • 285,553
  • 42
  • 434
  • 765
0

Using Color from OpenFX, one disposes over a method for all web colors.

import javafx.scene.paint.Color;
Color color = Color.web("skyblue");

Result:

0x87cdebff

These exist also as constant fields, so one might use autocompletion. But I like the autocompletion in a CSS/HTML editor.


This is a separate dependency, library. But as of java 9 a modular infrastructure is to be expected, and OpenFX, formerly JavaFX, is unproblematic.

Joop Eggen
  • 107,315
  • 7
  • 83
  • 138