Color.java revision 80756e38882720860db52f1fcc21fa1505a02abf
1/* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.graphics; 18 19import android.annotation.ColorInt; 20import android.util.MathUtils; 21import com.android.internal.util.XmlUtils; 22 23import java.util.HashMap; 24import java.util.Locale; 25 26/** 27 * The Color class defines methods for creating and converting color ints. 28 * Colors are represented as packed ints, made up of 4 bytes: alpha, red, 29 * green, blue. The values are unpremultiplied, meaning any transparency is 30 * stored solely in the alpha component, and not in the color components. The 31 * components are stored as follows (alpha << 24) | (red << 16) | 32 * (green << 8) | blue. Each component ranges between 0..255 with 0 33 * meaning no contribution for that component, and 255 meaning 100% 34 * contribution. Thus opaque-black would be 0xFF000000 (100% opaque but 35 * no contributions from red, green, or blue), and opaque-white would be 36 * 0xFFFFFFFF 37 */ 38public class Color { 39 @ColorInt public static final int BLACK = 0xFF000000; 40 @ColorInt public static final int DKGRAY = 0xFF444444; 41 @ColorInt public static final int GRAY = 0xFF888888; 42 @ColorInt public static final int LTGRAY = 0xFFCCCCCC; 43 @ColorInt public static final int WHITE = 0xFFFFFFFF; 44 @ColorInt public static final int RED = 0xFFFF0000; 45 @ColorInt public static final int GREEN = 0xFF00FF00; 46 @ColorInt public static final int BLUE = 0xFF0000FF; 47 @ColorInt public static final int YELLOW = 0xFFFFFF00; 48 @ColorInt public static final int CYAN = 0xFF00FFFF; 49 @ColorInt public static final int MAGENTA = 0xFFFF00FF; 50 @ColorInt public static final int TRANSPARENT = 0; 51 52 /** 53 * Return the alpha component of a color int. This is the same as saying 54 * color >>> 24 55 */ 56 @ColorInt 57 public static int alpha(int color) { 58 return color >>> 24; 59 } 60 61 /** 62 * Return the red component of a color int. This is the same as saying 63 * (color >> 16) & 0xFF 64 */ 65 @ColorInt 66 public static int red(int color) { 67 return (color >> 16) & 0xFF; 68 } 69 70 /** 71 * Return the green component of a color int. This is the same as saying 72 * (color >> 8) & 0xFF 73 */ 74 @ColorInt 75 public static int green(int color) { 76 return (color >> 8) & 0xFF; 77 } 78 79 /** 80 * Return the blue component of a color int. This is the same as saying 81 * color & 0xFF 82 */ 83 @ColorInt 84 public static int blue(int color) { 85 return color & 0xFF; 86 } 87 88 /** 89 * Return a color-int from red, green, blue components. 90 * The alpha component is implicity 255 (fully opaque). 91 * These component values should be [0..255], but there is no 92 * range check performed, so if they are out of range, the 93 * returned color is undefined. 94 * @param red Red component [0..255] of the color 95 * @param green Green component [0..255] of the color 96 * @param blue Blue component [0..255] of the color 97 */ 98 @ColorInt 99 public static int rgb(int red, int green, int blue) { 100 return (0xFF << 24) | (red << 16) | (green << 8) | blue; 101 } 102 103 /** 104 * Return a color-int from alpha, red, green, blue components. 105 * These component values should be [0..255], but there is no 106 * range check performed, so if they are out of range, the 107 * returned color is undefined. 108 * @param alpha Alpha component [0..255] of the color 109 * @param red Red component [0..255] of the color 110 * @param green Green component [0..255] of the color 111 * @param blue Blue component [0..255] of the color 112 */ 113 @ColorInt 114 public static int argb(int alpha, int red, int green, int blue) { 115 return (alpha << 24) | (red << 16) | (green << 8) | blue; 116 } 117 118 /** 119 * Returns the hue component of a color int. 120 * 121 * @return A value between 0.0f and 1.0f 122 * 123 * @hide Pending API council 124 */ 125 public static float hue(@ColorInt int color) { 126 int r = (color >> 16) & 0xFF; 127 int g = (color >> 8) & 0xFF; 128 int b = color & 0xFF; 129 130 int V = Math.max(b, Math.max(r, g)); 131 int temp = Math.min(b, Math.min(r, g)); 132 133 float H; 134 135 if (V == temp) { 136 H = 0; 137 } else { 138 final float vtemp = (float) (V - temp); 139 final float cr = (V - r) / vtemp; 140 final float cg = (V - g) / vtemp; 141 final float cb = (V - b) / vtemp; 142 143 if (r == V) { 144 H = cb - cg; 145 } else if (g == V) { 146 H = 2 + cr - cb; 147 } else { 148 H = 4 + cg - cr; 149 } 150 151 H /= 6.f; 152 if (H < 0) { 153 H++; 154 } 155 } 156 157 return H; 158 } 159 160 /** 161 * Returns the saturation component of a color int. 162 * 163 * @return A value between 0.0f and 1.0f 164 * 165 * @hide Pending API council 166 */ 167 public static float saturation(@ColorInt int color) { 168 int r = (color >> 16) & 0xFF; 169 int g = (color >> 8) & 0xFF; 170 int b = color & 0xFF; 171 172 173 int V = Math.max(b, Math.max(r, g)); 174 int temp = Math.min(b, Math.min(r, g)); 175 176 float S; 177 178 if (V == temp) { 179 S = 0; 180 } else { 181 S = (V - temp) / (float) V; 182 } 183 184 return S; 185 } 186 187 /** 188 * Returns the brightness component of a color int. 189 * 190 * @return A value between 0.0f and 1.0f 191 * 192 * @hide Pending API council 193 */ 194 public static float brightness(@ColorInt int color) { 195 int r = (color >> 16) & 0xFF; 196 int g = (color >> 8) & 0xFF; 197 int b = color & 0xFF; 198 199 int V = Math.max(b, Math.max(r, g)); 200 201 return (V / 255.f); 202 } 203 204 /** 205 * Parse the color string, and return the corresponding color-int. 206 * If the string cannot be parsed, throws an IllegalArgumentException 207 * exception. Supported formats are: 208 * #RRGGBB 209 * #AARRGGBB 210 * or one of the following names: 211 * 'red', 'blue', 'green', 'black', 'white', 'gray', 'cyan', 'magenta', 212 * 'yellow', 'lightgray', 'darkgray', 'grey', 'lightgrey', 'darkgrey', 213 * 'aqua', 'fuchsia', 'lime', 'maroon', 'navy', 'olive', 'purple', 214 * 'silver', 'teal'. 215 */ 216 @ColorInt 217 public static int parseColor(String colorString) { 218 if (colorString.charAt(0) == '#') { 219 // Use a long to avoid rollovers on #ffXXXXXX 220 long color = Long.parseLong(colorString.substring(1), 16); 221 if (colorString.length() == 7) { 222 // Set the alpha value 223 color |= 0x00000000ff000000; 224 } else if (colorString.length() != 9) { 225 throw new IllegalArgumentException("Unknown color"); 226 } 227 return (int)color; 228 } else { 229 Integer color = sColorNameMap.get(colorString.toLowerCase(Locale.ROOT)); 230 if (color != null) { 231 return color; 232 } 233 } 234 throw new IllegalArgumentException("Unknown color"); 235 } 236 237 /** 238 * Convert HSB components to an ARGB color. Alpha set to 0xFF. 239 * hsv[0] is Hue [0 .. 1) 240 * hsv[1] is Saturation [0...1] 241 * hsv[2] is Value [0...1] 242 * If hsv values are out of range, they are pinned. 243 * @param hsb 3 element array which holds the input HSB components. 244 * @return the resulting argb color 245 * 246 * @hide Pending API council 247 */ 248 @ColorInt 249 public static int HSBtoColor(float[] hsb) { 250 return HSBtoColor(hsb[0], hsb[1], hsb[2]); 251 } 252 253 /** 254 * Convert HSB components to an ARGB color. Alpha set to 0xFF. 255 * hsv[0] is Hue [0 .. 1) 256 * hsv[1] is Saturation [0...1] 257 * hsv[2] is Value [0...1] 258 * If hsv values are out of range, they are pinned. 259 * @param h Hue component 260 * @param s Saturation component 261 * @param b Brightness component 262 * @return the resulting argb color 263 * 264 * @hide Pending API council 265 */ 266 @ColorInt 267 public static int HSBtoColor(float h, float s, float b) { 268 h = MathUtils.constrain(h, 0.0f, 1.0f); 269 s = MathUtils.constrain(s, 0.0f, 1.0f); 270 b = MathUtils.constrain(b, 0.0f, 1.0f); 271 272 float red = 0.0f; 273 float green = 0.0f; 274 float blue = 0.0f; 275 276 final float hf = (h - (int) h) * 6.0f; 277 final int ihf = (int) hf; 278 final float f = hf - ihf; 279 final float pv = b * (1.0f - s); 280 final float qv = b * (1.0f - s * f); 281 final float tv = b * (1.0f - s * (1.0f - f)); 282 283 switch (ihf) { 284 case 0: // Red is the dominant color 285 red = b; 286 green = tv; 287 blue = pv; 288 break; 289 case 1: // Green is the dominant color 290 red = qv; 291 green = b; 292 blue = pv; 293 break; 294 case 2: 295 red = pv; 296 green = b; 297 blue = tv; 298 break; 299 case 3: // Blue is the dominant color 300 red = pv; 301 green = qv; 302 blue = b; 303 break; 304 case 4: 305 red = tv; 306 green = pv; 307 blue = b; 308 break; 309 case 5: // Red is the dominant color 310 red = b; 311 green = pv; 312 blue = qv; 313 break; 314 } 315 316 return 0xFF000000 | (((int) (red * 255.0f)) << 16) | 317 (((int) (green * 255.0f)) << 8) | ((int) (blue * 255.0f)); 318 } 319 320 /** 321 * Convert RGB components to HSV. 322 * hsv[0] is Hue [0 .. 360) 323 * hsv[1] is Saturation [0...1] 324 * hsv[2] is Value [0...1] 325 * @param red red component value [0..255] 326 * @param green green component value [0..255] 327 * @param blue blue component value [0..255] 328 * @param hsv 3 element array which holds the resulting HSV components. 329 */ 330 public static void RGBToHSV(int red, int green, int blue, float hsv[]) { 331 if (hsv.length < 3) { 332 throw new RuntimeException("3 components required for hsv"); 333 } 334 nativeRGBToHSV(red, green, blue, hsv); 335 } 336 337 /** 338 * Convert the argb color to its HSV components. 339 * hsv[0] is Hue [0 .. 360) 340 * hsv[1] is Saturation [0...1] 341 * hsv[2] is Value [0...1] 342 * @param color the argb color to convert. The alpha component is ignored. 343 * @param hsv 3 element array which holds the resulting HSV components. 344 */ 345 public static void colorToHSV(@ColorInt int color, float hsv[]) { 346 RGBToHSV((color >> 16) & 0xFF, (color >> 8) & 0xFF, color & 0xFF, hsv); 347 } 348 349 /** 350 * Convert HSV components to an ARGB color. Alpha set to 0xFF. 351 * hsv[0] is Hue [0 .. 360) 352 * hsv[1] is Saturation [0...1] 353 * hsv[2] is Value [0...1] 354 * If hsv values are out of range, they are pinned. 355 * @param hsv 3 element array which holds the input HSV components. 356 * @return the resulting argb color 357 */ 358 public static int HSVToColor(float hsv[]) { 359 return HSVToColor(0xFF, hsv); 360 } 361 362 /** 363 * Convert HSV components to an ARGB color. The alpha component is passed 364 * through unchanged. 365 * hsv[0] is Hue [0 .. 360) 366 * hsv[1] is Saturation [0...1] 367 * hsv[2] is Value [0...1] 368 * If hsv values are out of range, they are pinned. 369 * @param alpha the alpha component of the returned argb color. 370 * @param hsv 3 element array which holds the input HSV components. 371 * @return the resulting argb color 372 */ 373 public static int HSVToColor(int alpha, float hsv[]) { 374 if (hsv.length < 3) { 375 throw new RuntimeException("3 components required for hsv"); 376 } 377 return nativeHSVToColor(alpha, hsv); 378 } 379 380 private static native void nativeRGBToHSV(int red, int greed, int blue, float hsv[]); 381 private static native int nativeHSVToColor(int alpha, float hsv[]); 382 383 /** 384 * Converts an HTML color (named or numeric) to an integer RGB value. 385 * 386 * @param color Non-null color string. 387 * 388 * @return A color value, or {@code -1} if the color string could not be interpreted. 389 * 390 * @hide 391 */ 392 @ColorInt 393 public static int getHtmlColor(String color) { 394 Integer i = sColorNameMap.get(color.toLowerCase(Locale.ROOT)); 395 if (i != null) { 396 return i; 397 } else { 398 try { 399 return XmlUtils.convertValueToInt(color, -1); 400 } catch (NumberFormatException nfe) { 401 return -1; 402 } 403 } 404 } 405 406 private static final HashMap<String, Integer> sColorNameMap; 407 408 static { 409 sColorNameMap = new HashMap<String, Integer>(); 410 sColorNameMap.put("black", BLACK); 411 sColorNameMap.put("darkgray", DKGRAY); 412 sColorNameMap.put("gray", GRAY); 413 sColorNameMap.put("lightgray", LTGRAY); 414 sColorNameMap.put("white", WHITE); 415 sColorNameMap.put("red", RED); 416 sColorNameMap.put("green", GREEN); 417 sColorNameMap.put("blue", BLUE); 418 sColorNameMap.put("yellow", YELLOW); 419 sColorNameMap.put("cyan", CYAN); 420 sColorNameMap.put("magenta", MAGENTA); 421 sColorNameMap.put("aqua", 0xFF00FFFF); 422 sColorNameMap.put("fuchsia", 0xFFFF00FF); 423 sColorNameMap.put("darkgrey", DKGRAY); 424 sColorNameMap.put("grey", GRAY); 425 sColorNameMap.put("lightgrey", LTGRAY); 426 sColorNameMap.put("lime", 0xFF00FF00); 427 sColorNameMap.put("maroon", 0xFF800000); 428 sColorNameMap.put("navy", 0xFF000080); 429 sColorNameMap.put("olive", 0xFF808000); 430 sColorNameMap.put("purple", 0xFF800080); 431 sColorNameMap.put("silver", 0xFFC0C0C0); 432 sColorNameMap.put("teal", 0xFF008080); 433 434 } 435} 436