001package jmri.util; 002 003import java.awt.Color; 004import javax.annotation.CheckForNull; 005import javax.annotation.CheckReturnValue; 006import javax.annotation.Nonnull; 007import org.slf4j.Logger; 008import org.slf4j.LoggerFactory; 009 010/** 011 * A collection of utilities related to colors. 012 * 013 * @author Dave Duchamp Copyright: (c) 2004-2007 014 */ 015public class ColorUtil { 016 017 /* 018 * Color lists for screen colors. 019 */ 020 public final static String ColorTrack = "track"; 021 public final static String ColorBlack = "black"; 022 public final static String ColorDarkGray = "darkGray"; 023 public final static String ColorGray = "gray"; 024 public final static String ColorLightGray = "lightGray"; 025 public final static String ColorWhite = "white"; 026 public final static String ColorRed = "red"; 027 public final static String ColorPink = "pink"; 028 public final static String ColorOrange = "orange"; 029 public final static String ColorYellow = "yellow"; 030 public final static String ColorGreen = "green"; 031 public final static String ColorBlue = "blue"; 032 public final static String ColorMagenta = "magenta"; 033 public final static String ColorCyan = "cyan"; 034 public final static String ColorClear = "clear"; 035 public final static String ColorBrown = "brown"; 036 037 public final static Color clear = setAlpha(Color.BLACK, 0); 038 public final static Color CLEAR = clear; 039 public final static Color BROWN = new Color(102, 51, 0); 040 041 /** 042 * Handles known colors plus special value for track. 043 * 044 * @param color the color or null 045 * @return the name of the color or "black" if a color was provided; "track" 046 * if color is null 047 */ 048 @Nonnull 049 public static String colorToString(@CheckForNull Color color) { 050 if (color == null) { 051 return ColorTrack; 052 } 053 String colorName = colorToName(color); 054 if (colorName != null) { 055 return colorName; 056 } 057 log.error("unknown color sent to colorToString"); 058 return ColorBlack; 059 } 060 061 /** 062 * Returns known color name or hex value in form #RRGGBB. 063 * 064 * @param color the color 065 * @return the name or hex value of color; returns null if color is null 066 */ 067 @CheckForNull 068 public static String colorToColorName(@CheckForNull Color color) { 069 if (color == null) { 070 return null; 071 } 072 String colorName = colorToName(color); 073 if (colorName != null) { 074 return colorName; 075 } 076 return colorToHexString(color); 077 } 078 079 /** 080 * Returns localized color name or hex value in form #RRGGBB. 081 * 082 * @since 4.13.1 083 * @param color the color object 084 * @return the localized name or hex value of color; returns null if color is null 085 */ 086 @CheckForNull 087 public static String colorToLocalizedName(@CheckForNull Color color) { 088 if (color == null) { 089 return null; 090 } 091 String colorName = colorToName(color); 092 if (colorName != null) { 093 colorName = Character.toUpperCase(colorName.charAt(0)) + colorName.substring(1); 094 return Bundle.getMessage(colorName); 095 } 096 return colorToHexString(color); 097 } 098 099 /** 100 * @param string Either a hexadecimal representation of the rgb value of a 101 * color or a color name defined as a constant. 102 * @return the color from the string or null if the string equals 103 * {@value #ColorTrack} or equals the localized value for "None" 104 * @throws IllegalArgumentException if string cannot be converted into a Color 105 */ 106 public static Color stringToColor(String string) { 107 try { 108 return Color.decode(string); 109 } catch (NumberFormatException nfe) { 110 switch (string) { 111 case ColorBlack: 112 return Color.black; 113 case ColorDarkGray: 114 return Color.darkGray; 115 case ColorGray: 116 return Color.gray; 117 case ColorLightGray: 118 return Color.lightGray; 119 case ColorWhite: 120 return Color.white; 121 case ColorRed: 122 return Color.red; 123 case ColorPink: 124 return Color.pink; 125 case ColorOrange: 126 return Color.orange; 127 case ColorYellow: 128 return Color.yellow; 129 case ColorGreen: 130 return Color.green; 131 case ColorBlue: 132 return Color.blue; 133 case ColorMagenta: 134 return Color.magenta; 135 case ColorCyan: 136 return Color.cyan; 137 case ColorBrown: 138 return BROWN; 139 case ColorTrack: 140 return null; 141 default: 142 // check translated strings, just in case there is one in a data file. 143 if (string.equals(Bundle.getMessage("Black"))) { 144 return Color.black; 145 } 146 if (string.equals(Bundle.getMessage("DarkGray"))) { 147 return Color.darkGray; 148 } 149 if (string.equals(Bundle.getMessage("Gray"))) { 150 return Color.gray; 151 } 152 if (string.equals(Bundle.getMessage("LightGray"))) { 153 return Color.lightGray; 154 } 155 if (string.equals(Bundle.getMessage("White"))) { 156 return Color.white; 157 } 158 if (string.equals(Bundle.getMessage("Red"))) { 159 return Color.red; 160 } 161 if (string.equals(Bundle.getMessage("Pink"))) { 162 return Color.pink; 163 } 164 if (string.equals(Bundle.getMessage("Yellow"))) { 165 return Color.yellow; 166 } 167 if (string.equals(Bundle.getMessage("Green"))) { 168 return Color.green; 169 } 170 if (string.equals(Bundle.getMessage("Orange"))) { 171 return Color.orange; 172 } 173 if (string.equals(Bundle.getMessage("Blue"))) { 174 return Color.blue; 175 } 176 if (string.equals(Bundle.getMessage("Magenta"))) { 177 return Color.magenta; 178 } 179 if (string.equals(Bundle.getMessage("Cyan"))) { 180 return Color.cyan; 181 } 182 if (string.equals(Bundle.getMessage("ColorClear"))) { 183 return clear; 184 } 185 if (string.equals(Bundle.getMessage("None"))) { 186 return null; 187 } else { 188 log.error("unknown color text '{}' sent to stringToColor", string); 189 throw new IllegalArgumentException("unknown color text '" + string + "'"); 190 } 191 } 192 } 193 } 194 195 /** 196 * Convert a color into hex value of form #RRGGBB. 197 * 198 * @param color the color or null 199 * @return the hex string or null if color is null 200 */ 201 @CheckForNull 202 public static String colorToHexString(@CheckForNull Color color) { 203 if (color == null) { 204 return null; 205 } 206 return String.format("#%02X%02X%02X", color.getRed(), color.getGreen(), color.getBlue()); 207 } 208 209 /** 210 * Internal method to return string name of several known colors. 211 * 212 * @param color the color 213 * @return the color name or null if not known/not in list 214 */ 215 @CheckForNull 216 private static String colorToName(@CheckForNull Color color) { 217 if (color == null) { 218 return null; 219 } 220 if (color.equals(Color.black)) { 221 return ColorBlack; 222 } else if (color.equals(Color.darkGray)) { 223 return ColorDarkGray; 224 } else if (color.equals(Color.gray)) { 225 return ColorGray; 226 } else if (color.equals(Color.lightGray)) { 227 return ColorLightGray; 228 } else if (color.equals(Color.white)) { 229 return ColorWhite; 230 } else if (color.equals(Color.red)) { 231 return ColorRed; 232 } else if (color.equals(Color.pink)) { 233 return ColorPink; 234 } else if (color.equals(Color.orange)) { 235 return ColorOrange; 236 } else if (color.equals(Color.yellow)) { 237 return ColorYellow; 238 } else if (color.equals(Color.green)) { 239 return ColorGreen; 240 } else if (color.equals(Color.blue)) { 241 return ColorBlue; 242 } else if (color.equals(Color.magenta)) { 243 return ColorMagenta; 244 } else if (color.equals(Color.cyan)) { 245 return ColorCyan; 246 } else if (color.equals(BROWN)) { 247 return ColorBrown; 248 } 249 return null; 250 } 251 252 /** 253 * Return the color (Black/White) that most contrasts with the specified 254 * color. 255 * 256 * @param color the source color 257 * @return the contrasting color 258 */ 259 public static Color contrast(@Nonnull Color color) { 260 int red = color.getRed(); 261 int green = color.getGreen(); 262 int blue = color.getBlue(); 263 int average = (red + green + blue) / 3; 264 265 return (average >= 128) ? Color.BLACK : Color.WHITE; 266 } 267 268 /** 269 * Calculate the linear interpolation between two colors. 270 * 271 * @param colorA the first color 272 * @param colorB the second color 273 * @param t the fraction (between 0 and 1) 274 * @return the linear interpolation between a and b for t 275 */ 276 @CheckReturnValue 277 public static Color lerp(@Nonnull Color colorA, @Nonnull Color colorB, double t) { 278 return new Color( 279 MathUtil.lerp(colorA.getRed(), colorB.getRed(), t), 280 MathUtil.lerp(colorA.getGreen(), colorB.getGreen(), t), 281 MathUtil.lerp(colorA.getBlue(), colorB.getBlue(), t), 282 MathUtil.lerp(colorA.getAlpha(), colorB.getAlpha(), t) 283 ); 284 } 285 286 /** 287 * Set the alpha component of a color. 288 * 289 * @param color the color 290 * @param alpha the alpha component (integer 0 - 255) 291 * @return the new color with the specified alpha 292 */ 293 @CheckReturnValue 294 public static Color setAlpha(@Nonnull Color color, int alpha) { 295 return new Color(color.getRed(), color.getGreen(), color.getBlue(), alpha); 296 } 297 298 /** 299 * Set the alpha component of a color. 300 * 301 * @param color the color 302 * @param alpha the alpha component (double 0.0 - 1.0) 303 * @return the new color with the specified alpha 304 */ 305 @CheckReturnValue 306 public static Color setAlpha(@Nonnull Color color, double alpha) { 307 return new Color(color.getRed(), color.getGreen(), color.getBlue(), 308 (int) (255.0 * alpha)); 309 } 310 311 // initialize logging 312 private final static Logger log = LoggerFactory.getLogger(ColorUtil.class); 313 314}