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