001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.tools;
003
004import java.awt.Color;
005
006/**
007 * Helper to convert from color to HTML string and back.
008 */
009public final class ColorHelper {
010
011    private ColorHelper() {
012        // Hide default constructor for utils classes
013    }
014
015    /**
016     * Returns the {@code Color} for the given HTML code.
017     * @param html the color code
018     * @return the color
019     */
020    public static Color html2color(String html) {
021        if (!html.isEmpty() && html.charAt(0) == '#')
022            html = html.substring(1);
023        if (html.length() == 3) {
024            html = new String(new char[]{
025                    html.charAt(0), html.charAt(0),
026                    html.charAt(1), html.charAt(1),
027                    html.charAt(2), html.charAt(2)});
028        }
029        if (html.length() != 6 && html.length() != 8)
030            return null;
031        try {
032            return new Color(
033                    Integer.parseInt(html.substring(0, 2), 16),
034                    Integer.parseInt(html.substring(2, 4), 16),
035                    Integer.parseInt(html.substring(4, 6), 16),
036                    html.length() == 8 ? Integer.parseInt(html.substring(6, 8), 16) : 255);
037        } catch (NumberFormatException e) {
038            return null;
039        }
040    }
041
042    /**
043     * Returns the HTML color code (6 or 8 digit).
044     * @param col The color to convert
045     * @return the HTML color code (6 or 8 digit)
046     */
047    public static String color2html(Color col) {
048        return color2html(col, true);
049    }
050
051    /**
052     * Returns the HTML color code (6 or 8 digit).
053     * @param color The color to convert
054     * @param withAlpha if {@code true} and alpha value < 255, return 8-digit color code, else always 6-digit
055     * @return the HTML color code (6 or 8 digit)
056     * @since 6655
057     */
058    public static String color2html(Color color, boolean withAlpha) {
059        if (color == null)
060            return null;
061        int alpha = color.getAlpha();
062        return withAlpha && alpha != 255
063                ? String.format("#%06X%02X", color.getRGB() & 0x00ffffff, alpha)
064                : String.format("#%06X", color.getRGB() & 0x00ffffff);
065    }
066
067    /**
068     * Determines the correct foreground color (black or white) to use for the given background,
069     * so the text will be readable.
070     * @param bg background color
071     * @return {@code Color#BLACK} or {@code Color#WHITE}
072     * @since 9223
073     */
074    public static Color getForegroundColor(Color bg) {
075        // http://stackoverflow.com/a/3943023/2257172
076        return bg == null ? null :
077              (bg.getRed()*0.299 + bg.getGreen()*0.587 + bg.getBlue()*0.114) > 186 ?
078                  Color.BLACK : Color.WHITE;
079    }
080
081    /**
082     * convert float range 0 <= x <= 1 to integer range 0..255
083     * when dealing with colors and color alpha value
084     * @param val float value between 0 and 1
085     * @return null if val is null, the corresponding int if val is in the
086     *         range 0...1. If val is outside that range, return 255
087     */
088    public static Integer float2int(Float val) {
089        if (val == null)
090            return null;
091        if (val < 0 || val > 1)
092            return 255;
093        return (int) (255f * val + 0.5f);
094    }
095
096    /**
097     * convert integer range 0..255 to float range 0 &lt;= x &lt;= 1
098     * when dealing with colors and color alpha value
099     * @param val integer value
100     * @return corresponding float value in range 0 &lt;= x &lt;= 1
101     */
102    public static Float int2float(Integer val) {
103        if (val == null)
104            return null;
105        if (val < 0 || val > 255)
106            return 1f;
107        return ((float) val) / 255f;
108    }
109
110    /**
111     * Multiply the alpha value of the given color with the factor. The alpha value is clamped to 0..255
112     * @param color The color
113     * @param alphaFactor The factor to multiply alpha with.
114     * @return The new color.
115     * @since 11692
116     */
117    public static Color alphaMultiply(Color color, float alphaFactor) {
118        int alpha = float2int(int2float(color.getAlpha()) * alphaFactor);
119        alpha = Utils.clamp(alpha, 0, 255);
120        return new Color(color.getRed(), color.getGreen(), color.getBlue(), alpha);
121    }
122
123    /**
124     * Returns the complementary color of {@code clr}.
125     * @param clr the color to complement
126     * @return the complementary color of {@code clr}
127     */
128    public static Color complement(Color clr) {
129        return new Color(255 - clr.getRed(), 255 - clr.getGreen(), 255 - clr.getBlue(), clr.getAlpha());
130    }
131}