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