ColorUtils.java Source code

Java tutorial

Introduction

Here is the source code for ColorUtils.java

Source

import java.awt.*;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;

/**
 * Utility for checking colors given either hexa or "natural language" string descriptions.
 * <p>For all assertEquals/equals methods, the "expected" parameter can be either:
 * <ul>
 * <li>A <code>Color</code> object specifying the exact color</li>
 * <li>A <code>String</code> object containing the hexadecimal description of the exact color</li>
 * <li>A <code>String</code> object containing the name of a color for an approximate comparison.
 * The authorized names are those of the predefined Color objects defined in the Java
 * <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/awt/Color.html">Color</a> class.</li>
 * </ul>
 * </p>
 *
 * @see <a href="http://www.uispec4j.org/usingcolors.html">Using colors</a>
 */
public final class ColorUtils {
    private static final Map<String, Color> nameToColorMap = buildNameToColorMap();
    static final String UNEXPECTED_COLOR_CLASS = "Expected color should be an instance of Color or String";

    public static boolean equals(Object expectedColor, Color actual) {
        if (expectedColor instanceof Color) {
            return expectedColor.equals(actual);
        } else if (expectedColor instanceof String) {
            return equals((String) expectedColor, actual);
        }
        throw new IllegalArgumentException(UNEXPECTED_COLOR_CLASS);
    }

    public static boolean equals(String expectedColor, Color actual) {
        Color foundColor = nameToColorMap.get(expectedColor.toUpperCase());
        if (foundColor != null) {
            return equals(foundColor, actual, true);
        }

        try {
            foundColor = getColor(expectedColor);
            return equals(foundColor, actual, false);
        } catch (NumberFormatException e) {
            throw new IllegalArgumentException("'" + expectedColor + "' does not seem to be a color");
        }
    }

    public static Color getColor(String hexaString) {
        return new Color(Integer.parseInt(hexaString, 16));
    }

    /**
     * Returns a normalized string description given a Color or another String description
     */
    public static String getColorDescription(Object color) {
        if (color instanceof Color) {
            return getColorDescription((Color) color);
        } else if (color instanceof String) {
            return getColorDescription((String) color);
        }
        throw new IllegalArgumentException(UNEXPECTED_COLOR_CLASS);
    }

    /**
     * Returns a description string for a given Color object
     */
    public static String getColorDescription(Color color) {
        return toHexString(color).toUpperCase();
    }

    /**
     * Normalizes a given color description string
     */
    public static String getColorDescription(String color) {
        return color.toUpperCase();
    }

    private static boolean equals(Color expected, Color actual, boolean matchBySimilarity) {
        if (matchBySimilarity) {
            return computeHSBDistance(expected, actual) < 0.9;
        } else {
            return expected.equals(actual);
        }
    }

    private static Color getColor(Object input) {
        if (input instanceof Color) {
            return (Color) input;
        } else if (input instanceof String) {
            Color namedColor = nameToColorMap.get(((String) input).toUpperCase());
            if (namedColor != null) {
                return namedColor;
            }
            return getColor((String) input);
        }
        throw new IllegalArgumentException(UNEXPECTED_COLOR_CLASS);

    }

    private static double computeHSBDistance(Color expected, Color actual) {
        float[] expectedHSB = toHSB(expected);
        float[] actualHSB = toHSB(actual);

        return Math.sqrt(Math.pow((expectedHSB[0] - actualHSB[0]) * 20, 2)
                + Math.pow(expectedHSB[1] - actualHSB[1], 2) + Math.pow((expectedHSB[2] - actualHSB[2]) * 2, 2));
    }

    private static float[] toHSB(Color aColor) {
        return Color.RGBtoHSB(aColor.getRed(), aColor.getGreen(), aColor.getBlue(), null);
    }

    private static Map<String, Color> buildNameToColorMap() {
        Map<String, Color> colorMap = new HashMap<String, Color>();
        for (Field field : Color.class.getDeclaredFields()) {
            if (isConstantColorField(field)) {
                try {
                    Color color = (Color) field.get(null);
                    colorMap.put(field.getName().toUpperCase(), color);
                } catch (IllegalAccessException e) {
                    // Should not occur because the field is public and static
                }
            }
        }

        colorMap.put("DARKGREY", getColor("555555"));
        colorMap.put("DARKBLUE", getColor("000055"));
        colorMap.put("DARKRED", getColor("550000"));
        colorMap.put("DARKGREEN", getColor("005500"));

        colorMap.put("DARK_GREY", getColor("555555"));
        colorMap.put("DARK_BLUE", getColor("000055"));
        colorMap.put("DARK_RED", getColor("550000"));
        colorMap.put("DARK_GREEN", getColor("005500"));

        return colorMap;
    }

    private static boolean isConstantColorField(Field field) {
        return Modifier.isPublic(field.getModifiers()) && Modifier.isStatic(field.getModifiers())
                && Color.class == field.getType();
    }

    private static String toHexString(Color color) {
        return Integer.toHexString(color.getRGB()).substring(2);
    }
}