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