Color.java revision 95b52fd187564cabceb3309daa4ee6ddf697de58
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.AnyThread; 20import android.annotation.ColorInt; 21import android.annotation.ColorLong; 22import android.annotation.HalfFloat; 23import android.annotation.IntRange; 24import android.annotation.NonNull; 25import android.annotation.Size; 26 27import android.util.Half; 28import com.android.internal.util.XmlUtils; 29 30import java.util.Arrays; 31import java.util.HashMap; 32import java.util.Locale; 33import java.util.function.DoubleUnaryOperator; 34 35/** 36 * {@usesMathJax} 37 * 38 * <p>The <code>Color</code> class provides methods for creating, converting and 39 * manipulating colors. Colors have three different representations:</p> 40 * <ul> 41 * <li>Color ints, the most common representation</li> 42 * <li>Color longs</li> 43 * <li><code>Color</code> instances</li> 44 * </ul> 45 * <p>The section below describe each representation in detail.</p> 46 * 47 * <h3>Color ints</h3> 48 * <p>Color ints are the most common representation of colors on Android and 49 * have been used since {@link android.os.Build.VERSION_CODES#BASE API level 1}.</p> 50 * 51 * <p>A color int always defines a color in the {@link ColorSpace.Named#SRGB sRGB} 52 * color space using 4 components packed in a single 32 bit integer value:</p> 53 * 54 * <table summary="Color int definition"> 55 * <tr> 56 * <th>Component</th><th>Name</th><th>Size</th><th>Range</th> 57 * </tr> 58 * <tr><td>A</td><td>Alpha</td><td>8 bits</td><td>\([0..255]\)</td></tr> 59 * <tr><td>R</td><td>Red</td><td>8 bits</td><td>\([0..255]\)</td></tr> 60 * <tr><td>G</td><td>Green</td><td>8 bits</td><td>\([0..255]\)</td></tr> 61 * <tr><td>B</td><td>Blue</td><td>8 bits</td><td>\([0..255]\)</td></tr> 62 * </table> 63 * 64 * <p>The components in this table are listed in encoding order (see below), 65 * which is why color ints are called ARGB colors.</p> 66 * 67 * <h4>Usage in code</h4> 68 * <p>To avoid confusing color ints with arbitrary integer values, it is a 69 * good practice to annotate them with the <code>@ColorInt</code> annotation 70 * found in the Android Support Library.</p> 71 * 72 * <h4>Encoding</h4> 73 * <p>The four components of a color int are encoded in the following way:</p> 74 * <pre class="prettyprint"> 75 * int color = (A & 0xff) << 24 | (R & 0xff) << 16 | (G & 0xff) << 16 | (B & 0xff); 76 * </pre> 77 * 78 * <p>Because of this encoding, color ints can easily be described as an integer 79 * constant in source. For instance, opaque blue is <code>0xff0000ff</code> 80 * and yellow is <code>0xffffff00</code>.</p> 81 * 82 * <p>To easily encode color ints, it is recommended to use the static methods 83 * {@link #argb(int, int, int, int)} and {@link #rgb(int, int, int)}. The second 84 * method omits the alpha component and assumes the color is opaque (alpha is 255). 85 * As a convenience this class also offers methods to encode color ints from components 86 * defined in the \([0..1]\) range: {@link #argb(float, float, float, float)} and 87 * {@link #rgb(float, float, float)}.</p> 88 * 89 * <p>Color longs (defined below) can be easily converted to color ints by invoking 90 * the {@link #toArgb(long)} method. This method performs a color space conversion 91 * if needed.</p> 92 * 93 * <p>It is also possible to create a color int by invoking the method {@link #toArgb()} 94 * on a color instance.</p> 95 * 96 * <h4>Decoding</h4> 97 * <p>The four ARGB components can be individually extracted from a color int 98 * using the following expressions:</p> 99 * <pre class="prettyprint"> 100 * int A = (color >> 24) & 0xff; // or color >>> 24 101 * int R = (color >> 16) & 0xff; 102 * int G = (color >> 8) & 0xff; 103 * int B = (color ) & 0xff; 104 * </pre> 105 * 106 * <p>This class offers convenience methods to easily extract these components:</p> 107 * <ul> 108 * <li>{@link #alpha(int)} to extract the alpha component</li> 109 * <li>{@link #red(int)} to extract the red component</li> 110 * <li>{@link #green(int)} to extract the green component</li> 111 * <li>{@link #blue(int)} to extract the blue component</li> 112 * </ul> 113 * 114 * <h3>Color longs</h3> 115 * <p>Color longs are a representation introduced in 116 * {@link android.os.Build.VERSION_CODES#O Android O} to store colors in different 117 * {@link ColorSpace color spaces}, with more precision than color ints.</p> 118 * 119 * <p>A color long always defines a color using 4 components packed in a single 120 * 64 bit long value. One of these components is always alpha while the other 121 * three components depend on the color space's {@link ColorSpace.Model color model}. 122 * The most common color model is the {@link ColorSpace.Model#RGB RGB} model in 123 * which the components represent red, green and blue values.</p> 124 * 125 * <p class="note"><b>Component ranges:</b> the ranges defined in the tables 126 * below indicate the ranges that can be encoded in a color long. They do not 127 * represent the actual ranges as they may differ per color space. For instance, 128 * the RGB components of a color in the {@link ColorSpace.Named#DISPLAY_P3 Display P3} 129 * color space use the \([0..1]\) range. Please refer to the documentation of the 130 * various {@link ColorSpace.Named color spaces} to find their respective ranges.</p> 131 * 132 * <p class="note"><b>Alpha range:</b> while alpha is encoded in a color long using 133 * a 10 bit integer (thus using a range of \([0..1023]\)), it is converted to and 134 * from \([0..1]\) float values when decoding and encoding color longs.</p> 135 * 136 * <p class="note"><b>sRGB color space:</b> for compatibility reasons and ease of 137 * use, color longs encoding {@link ColorSpace.Named#SRGB sRGB} colors do not 138 * use the same encoding as other color longs.</p> 139 * 140 * <table summary="Color long definition"> 141 * <tr> 142 * <th>Component</th><th>Name</th><th>Size</th><th>Range</th> 143 * </tr> 144 * <tr><td colspan="4">{@link ColorSpace.Model#RGB RGB} color model</td></tr> 145 * <tr><td>R</td><td>Red</td><td>16 bits</td><td>\([-65504.0, 65504.0]\)</td></tr> 146 * <tr><td>G</td><td>Green</td><td>16 bits</td><td>\([-65504.0, 65504.0]\)</td></tr> 147 * <tr><td>B</td><td>Blue</td><td>16 bits</td><td>\([-65504.0, 65504.0]\)</td></tr> 148 * <tr><td>A</td><td>Alpha</td><td>10 bits</td><td>\([0..1023]\)</td></tr> 149 * <tr><td></td><td>Color space</td><td>6 bits</td><td>\([0..63]\)</td></tr> 150 * <tr><td colspan="4">{@link ColorSpace.Named#SRGB sRGB} color space</td></tr> 151 * <tr><td>A</td><td>Alpha</td><td>8 bits</td><td>\([0..255]\)</td></tr> 152 * <tr><td>R</td><td>Red</td><td>8 bits</td><td>\([0..255]\)</td></tr> 153 * <tr><td>G</td><td>Green</td><td>8 bits</td><td>\([0..255]\)</td></tr> 154 * <tr><td>B</td><td>Blue</td><td>8 bits</td><td>\([0..255]\)</td></tr> 155 * <tr><td>X</td><td>Unused</td><td>32 bits</td><td>\(0\)</td></tr> 156 * <tr><td colspan="4">{@link ColorSpace.Model#XYZ XYZ} color model</td></tr> 157 * <tr><td>X</td><td>X</td><td>16 bits</td><td>\([-65504.0, 65504.0]\)</td></tr> 158 * <tr><td>Y</td><td>Y</td><td>16 bits</td><td>\([-65504.0, 65504.0]\)</td></tr> 159 * <tr><td>Z</td><td>Z</td><td>16 bits</td><td>\([-65504.0, 65504.0]\)</td></tr> 160 * <tr><td>A</td><td>Alpha</td><td>10 bits</td><td>\([0..1023]\)</td></tr> 161 * <tr><td></td><td>Color space</td><td>6 bits</td><td>\([0..63]\)</td></tr> 162 * <tr><td colspan="4">{@link ColorSpace.Model#XYZ Lab} color model</td></tr> 163 * <tr><td>L</td><td>L</td><td>16 bits</td><td>\([-65504.0, 65504.0]\)</td></tr> 164 * <tr><td>a</td><td>a</td><td>16 bits</td><td>\([-65504.0, 65504.0]\)</td></tr> 165 * <tr><td>b</td><td>b</td><td>16 bits</td><td>\([-65504.0, 65504.0]\)</td></tr> 166 * <tr><td>A</td><td>Alpha</td><td>10 bits</td><td>\([0..1023]\)</td></tr> 167 * <tr><td></td><td>Color space</td><td>6 bits</td><td>\([0..63]\)</td></tr> 168 * <tr><td colspan="4">{@link ColorSpace.Model#CMYK CMYK} color model</td></tr> 169 * <tr><td colspan="4">Unsupported</td></tr> 170 * </table> 171 * 172 * <p>The components in this table are listed in encoding order (see below), 173 * which is why color longs in the RGB model are called RGBA colors (even if 174 * this doesn't quite hold for the special case of sRGB colors).</p> 175 * 176 * <p>The color long encoding relies on half-precision float values (fp16). If you 177 * wish to know more about the limitations of half-precision float values, please 178 * refer to the documentation of the {@link Half} class.</p> 179 * 180 * <h4>Usage in code</h4> 181 * <p>To avoid confusing color longs with arbitrary long values, it is a 182 * good practice to annotate them with the <code>@ColorLong</code> annotation 183 * found in the Android Support Library.</p> 184 * 185 * <h4>Encoding</h4> 186 * 187 * <p>Given the complex nature of color longs, it is strongly encouraged to use 188 * the various methods provided by this class to encode them.</p> 189 * 190 * <p>The most flexible way to encode a color long is to use the method 191 * {@link #pack(float, float, float, float, ColorSpace)}. This method allows you 192 * to specify three color components (typically RGB), an alpha component and a 193 * color space. To encode sRGB colors, use {@link #pack(float, float, float)} 194 * and {@link #pack(float, float, float, float)} which are the 195 * equivalent of {@link #rgb(int, int, int)} and {@link #argb(int, int, int, int)} 196 * for color ints. If you simply need to convert a color int into a color long, 197 * use {@link #pack(int)}.</p> 198 * 199 * <p>It is also possible to create a color long value by invoking the method 200 * {@link #pack()} on a color instance.</p> 201 * 202 * <h4>Decoding</h4> 203 * 204 * <p>This class offers convenience methods to easily extract the components 205 * of a color long:</p> 206 * <ul> 207 * <li>{@link #alpha(long)} to extract the alpha component</li> 208 * <li>{@link #red(long)} to extract the red/X/L component</li> 209 * <li>{@link #green(long)} to extract the green/Y/a component</li> 210 * <li>{@link #blue(long)} to extract the blue/Z/b component</li> 211 * </ul> 212 * 213 * <p>The values returned by these methods depend on the color space encoded 214 * in the color long. The values are however typically in the \([0..1]\) range 215 * for RGB colors. Please refer to the documentation of the various 216 * {@link ColorSpace.Named color spaces} for the exact ranges.</p> 217 * 218 * <h3>Color instances</h3> 219 * <p>Color instances are a representation introduced in 220 * {@link android.os.Build.VERSION_CODES#O Android O} to store colors in different 221 * {@link ColorSpace color spaces}, with more precision than both color ints and 222 * color longs. Color instances also offer the ability to store more than 4 223 * components if necessary.</p> 224 * 225 * <p>Colors instances are immutable and can be created using one of the various 226 * <code>valueOf</code> methods. For instance:</p> 227 * <pre class="prettyprint"> 228 * // sRGB 229 * Color opaqueRed = Color.valueOf(0xffff0000); // from a color int 230 * Color translucentRed = Color.valueOf(1.0f, 0.0f, 0.0f, 0.5f); 231 * 232 * // Wide gamut color 233 * {@literal @}ColorLong long p3 = pack(1.0f, 1.0f, 0.0f, 1.0f, colorSpaceP3); 234 * Color opaqueYellow = Color.valueOf(p3); // from a color long 235 * 236 * // CIE L*a*b* color space 237 * ColorSpace lab = ColorSpace.get(ColorSpace.Named.LAB); 238 * Color green = Color.valueOf(100.0f, -128.0f, 128.0f, 1.0f, lab); 239 * </pre> 240 * 241 * <p>Color instances can be converted to color ints ({@link #toArgb()}) or 242 * color longs ({@link #pack()}). They also offer easy access to their various 243 * components using the following methods:</p> 244 * <ul> 245 * <li>{@link #alpha()}, returns the alpha component value</li> 246 * <li>{@link #red()}, returns the red component value (or first 247 * component value in non-RGB models)</li> 248 * <li>{@link #green()}, returns the green component value (or second 249 * component value in non-RGB models)</li> 250 * <li>{@link #blue()}, returns the blue component value (or third 251 * component value in non-RGB models)</li> 252 * <li>{@link #getComponent(int)}, returns a specific component value</li> 253 * <li>{@link #getComponents()}, returns all component values as an array</li> 254 * </ul> 255 * 256 * <h3>Color space conversions</h3> 257 * <p>You can convert colors from one color space to another using 258 * {@link ColorSpace#connect(ColorSpace, ColorSpace)} and its variants. However, 259 * the <code>Color</code> class provides a few convenience methods to simplify 260 * the process. Here is a brief description of some of them:</p> 261 * <ul> 262 * <li>{@link #convert(ColorSpace)} to convert a color instance in a color 263 * space to a new color instance in a different color space</li> 264 * <li>{@link #convert(float, float, float, float, ColorSpace, ColorSpace)} to 265 * convert a color from a source color space to a destination color space</li> 266 * <li>{@link #convert(long, ColorSpace)} to convert a color long from its 267 * built-in color space to a destination color space</li> 268 * <li>{@link #convert(int, ColorSpace)} to convert a color int from sRGB 269 * to a destination color space</li> 270 * </ul> 271 * 272 * <p>Please refere to the {@link ColorSpace} documentation for more 273 * information.</p> 274 * 275 * <h3>Alpha and transparency</h3> 276 * <p>The alpha component of a color defines the level of transparency of a 277 * color. When the alpha component is 0, the color is completely transparent. 278 * When the alpha is component is 1 (in the \([0..1]\) range) or 255 (in the 279 * \([0..255]\) range), the color is completely opaque.</p> 280 * 281 * <p>The color representations described above do not use pre-multiplied 282 * color components (a pre-multiplied color component is a color component 283 * that has been multiplied by the value of the alpha component). 284 * For instance, the color int representation of opaque red is 285 * <code>0xffff0000</code>. For semi-transparent (50%) red, the 286 * representation becomes <code>0x80ff0000</code>. The equivalent color 287 * instance representations would be <code>(1.0, 0.0, 0.0, 1.0)</code> 288 * and <code>(1.0, 0.0, 0.0, 0.5)</code>.</p> 289 */ 290@AnyThread 291public class Color { 292 @ColorInt public static final int BLACK = 0xFF000000; 293 @ColorInt public static final int DKGRAY = 0xFF444444; 294 @ColorInt public static final int GRAY = 0xFF888888; 295 @ColorInt public static final int LTGRAY = 0xFFCCCCCC; 296 @ColorInt public static final int WHITE = 0xFFFFFFFF; 297 @ColorInt public static final int RED = 0xFFFF0000; 298 @ColorInt public static final int GREEN = 0xFF00FF00; 299 @ColorInt public static final int BLUE = 0xFF0000FF; 300 @ColorInt public static final int YELLOW = 0xFFFFFF00; 301 @ColorInt public static final int CYAN = 0xFF00FFFF; 302 @ColorInt public static final int MAGENTA = 0xFFFF00FF; 303 @ColorInt public static final int TRANSPARENT = 0; 304 305 @NonNull 306 @Size(min = 4, max = 5) 307 private final float[] mComponents; 308 309 @NonNull 310 private final ColorSpace mColorSpace; 311 312 /** 313 * Creates a new color instance set to opaque black in the 314 * {@link ColorSpace.Named#SRGB sRGB} color space. 315 * 316 * @see #valueOf(float, float, float) 317 * @see #valueOf(float, float, float, float) 318 * @see #valueOf(float, float, float, float, ColorSpace) 319 * @see #valueOf(float[], ColorSpace) 320 * @see #valueOf(int) 321 * @see #valueOf(long) 322 */ 323 public Color() { 324 // This constructor is required for compatibility with previous APIs 325 mComponents = new float[] { 0.0f, 0.0f, 0.0f, 1.0f }; 326 mColorSpace = ColorSpace.get(ColorSpace.Named.SRGB); 327 } 328 329 /** 330 * Creates a new color instance in the {@link ColorSpace.Named#SRGB sRGB} 331 * color space. 332 * 333 * @param r The value of the red channel, must be in [0..1] range 334 * @param g The value of the green channel, must be in [0..1] range 335 * @param b The value of the blue channel, must be in [0..1] range 336 * @param a The value of the alpha channel, must be in [0..1] range 337 */ 338 private Color(float r, float g, float b, float a) { 339 this(r, g, b, a, ColorSpace.get(ColorSpace.Named.SRGB)); 340 } 341 342 /** 343 * Creates a new color instance in the specified color space. The color space 344 * must have a 3 components model. 345 * 346 * @param r The value of the red channel, must be in the color space defined range 347 * @param g The value of the green channel, must be in the color space defined range 348 * @param b The value of the blue channel, must be in the color space defined range 349 * @param a The value of the alpha channel, must be in [0..1] range 350 * @param colorSpace This color's color space, cannot be null 351 */ 352 private Color(float r, float g, float b, float a, @NonNull ColorSpace colorSpace) { 353 mComponents = new float[] { r, g, b, a }; 354 mColorSpace = colorSpace; 355 } 356 357 /** 358 * Creates a new color instance in the specified color space. 359 * 360 * @param components An array of color components, plus alpha 361 * @param colorSpace This color's color space, cannot be null 362 */ 363 private Color(@Size(min = 4, max = 5) float[] components, @NonNull ColorSpace colorSpace) { 364 mComponents = components; 365 mColorSpace = colorSpace; 366 } 367 368 /** 369 * Returns this color's color space. 370 * 371 * @return A non-null instance of {@link ColorSpace} 372 */ 373 @NonNull 374 public ColorSpace getColorSpace() { 375 return mColorSpace; 376 } 377 378 /** 379 * Returns the color model of this color. 380 * 381 * @return A non-null {@link ColorSpace.Model} 382 */ 383 public ColorSpace.Model getModel() { 384 return mColorSpace.getModel(); 385 } 386 387 /** 388 * Indicates whether this color color is in a wide-gamut color space. 389 * See {@link ColorSpace#isWideGamut()} for a definition of a wide-gamut 390 * color space. 391 * 392 * @return True if this color is in a wide-gamut color space, false otherwise 393 * 394 * @see #isSrgb() 395 * @see ColorSpace#isWideGamut() 396 */ 397 public boolean isWideGamut() { 398 return getColorSpace().isWideGamut(); 399 } 400 401 /** 402 * Indicates whether this color is in the {@link ColorSpace.Named#SRGB sRGB} 403 * color space. 404 * 405 * @return True if this color is in the sRGB color space, false otherwise 406 * 407 * @see #isWideGamut() 408 */ 409 public boolean isSrgb() { 410 return getColorSpace().isSrgb(); 411 } 412 413 /** 414 * Returns the number of components that form a color value according 415 * to this color space's color model, plus one extra component for 416 * alpha. 417 * 418 * @return An integer between 4 and 5 419 */ 420 @IntRange(from = 4, to = 5) 421 public int getComponentCount() { 422 return mColorSpace.getComponentCount() + 1; 423 } 424 425 /** 426 * Packs this color into a color long. See the documentation of this class 427 * for a description of the color long format. 428 * 429 * @return A color long 430 * 431 * @throws IllegalArgumentException If this color's color space has the id 432 * {@link ColorSpace#MIN_ID} or if this color has more than 4 components 433 */ 434 @ColorLong 435 public long pack() { 436 return pack(mComponents[0], mComponents[1], mComponents[2], mComponents[3], mColorSpace); 437 } 438 439 /** 440 * Converts this color from its color space to the specified color space. 441 * The conversion is done using the default rendering intent as specified 442 * by {@link ColorSpace#connect(ColorSpace, ColorSpace)}. 443 * 444 * @param colorSpace The destination color space, cannot be null 445 * 446 * @return A non-null color instance in the specified color space 447 */ 448 @NonNull 449 public Color convert(@NonNull ColorSpace colorSpace) { 450 ColorSpace.Connector connector = ColorSpace.connect(mColorSpace, colorSpace); 451 float[] color = new float[] { 452 mComponents[0], mComponents[1], mComponents[2], mComponents[3] 453 }; 454 connector.transform(color); 455 return new Color(color, colorSpace); 456 } 457 458 /** 459 * Converts this color to an ARGB color int. A color int is always in 460 * the {@link ColorSpace.Named#SRGB sRGB} color space. This implies 461 * a color space conversion is applied if needed. 462 * 463 * @return An ARGB color in the sRGB color space 464 */ 465 @ColorInt 466 public int toArgb() { 467 if (mColorSpace.isSrgb()) { 468 return ((int) (mComponents[3] * 255.0f + 0.5f) << 24) | 469 ((int) (mComponents[0] * 255.0f + 0.5f) << 16) | 470 ((int) (mComponents[1] * 255.0f + 0.5f) << 8) | 471 (int) (mComponents[2] * 255.0f + 0.5f); 472 } 473 474 float[] color = new float[] { 475 mComponents[0], mComponents[1], mComponents[2], mComponents[3] 476 }; 477 // The transformation saturates the output 478 ColorSpace.connect(mColorSpace).transform(color); 479 480 return ((int) (color[3] * 255.0f + 0.5f) << 24) | 481 ((int) (color[0] * 255.0f + 0.5f) << 16) | 482 ((int) (color[1] * 255.0f + 0.5f) << 8) | 483 (int) (color[2] * 255.0f + 0.5f); 484 } 485 486 /** 487 * <p>Returns the value of the red component in the range defined by this 488 * color's color space (see {@link ColorSpace#getMinValue(int)} and 489 * {@link ColorSpace#getMaxValue(int)}).</p> 490 * 491 * <p>If this color's color model is not {@link ColorSpace.Model#RGB RGB}, 492 * calling this method is equivalent to <code>getComponent(0)</code>.</p> 493 * 494 * @see #alpha() 495 * @see #red() 496 * @see #green 497 * @see #getComponents() 498 */ 499 public float red() { 500 return mComponents[0]; 501 } 502 503 /** 504 * <p>Returns the value of the green component in the range defined by this 505 * color's color space (see {@link ColorSpace#getMinValue(int)} and 506 * {@link ColorSpace#getMaxValue(int)}).</p> 507 * 508 * <p>If this color's color model is not {@link ColorSpace.Model#RGB RGB}, 509 * calling this method is equivalent to <code>getComponent(1)</code>.</p> 510 * 511 * @see #alpha() 512 * @see #red() 513 * @see #green 514 * @see #getComponents() 515 */ 516 public float green() { 517 return mComponents[1]; 518 } 519 520 /** 521 * <p>Returns the value of the blue component in the range defined by this 522 * color's color space (see {@link ColorSpace#getMinValue(int)} and 523 * {@link ColorSpace#getMaxValue(int)}).</p> 524 * 525 * <p>If this color's color model is not {@link ColorSpace.Model#RGB RGB}, 526 * calling this method is equivalent to <code>getComponent(2)</code>.</p> 527 * 528 * @see #alpha() 529 * @see #red() 530 * @see #green 531 * @see #getComponents() 532 */ 533 public float blue() { 534 return mComponents[2]; 535 } 536 537 /** 538 * Returns the value of the alpha component in the range \([0..1]\). 539 * Calling this method is equivalent to 540 * <code>getComponent(getComponentCount())</code>. 541 * 542 * @see #red() 543 * @see #green() 544 * @see #blue() 545 * @see #getComponents() 546 * @see #getComponent(int) 547 */ 548 public float alpha() { 549 return mComponents[mComponents.length - 1]; 550 } 551 552 /** 553 * Returns this color's components as a new array. The last element of the 554 * array is always the alpha component. 555 * 556 * @return A new, non-null array whose size is equal to {@link #getComponentCount()} 557 * 558 * @see #getComponent(int) 559 */ 560 @NonNull 561 @Size(min = 4, max = 5) 562 public float[] getComponents() { 563 return Arrays.copyOf(mComponents, mColorSpace.getComponentCount() + 1); 564 } 565 566 /** 567 * <p>Returns the value of the specified component in the range defined by 568 * this color's color space (see {@link ColorSpace#getMinValue(int)} and 569 * {@link ColorSpace#getMaxValue(int)}).</p> 570 * 571 * <p>If the requested component index is {@link #getComponentCount()}, 572 * this method returns the alpha component, always in the range 573 * \([0..1\).</p> 574 * 575 * @see #getComponents() 576 * 577 * @throws ArrayIndexOutOfBoundsException If the specified component index 578 * is < 0 or >= {@link #getComponentCount()} 579 */ 580 public float getComponent(@IntRange(from = 0, to = 4) int component) { 581 return mComponents[component]; 582 } 583 584 /** 585 * <p>Returns the relative luminance of this color.</p> 586 * 587 * <p>Based on the formula for relative luminance defined in WCAG 2.0, 588 * W3C Recommendation 11 December 2008.</p> 589 * 590 * @return A value between 0 (darkest black) and 1 (lightest white) 591 * 592 * @throws IllegalArgumentException If the this color's color space 593 * does not use the {@link ColorSpace.Model#RGB RGB} color model 594 */ 595 public float luminance() { 596 if (mColorSpace.getModel() != ColorSpace.Model.RGB) { 597 throw new IllegalArgumentException("The specified color must be encoded in an RGB " + 598 "color space. The supplied color space is " + mColorSpace.getModel()); 599 } 600 601 DoubleUnaryOperator eotf = ((ColorSpace.Rgb) mColorSpace).getEotf(); 602 double r = eotf.applyAsDouble(mComponents[0]); 603 double g = eotf.applyAsDouble(mComponents[1]); 604 double b = eotf.applyAsDouble(mComponents[2]); 605 606 return saturate((float) ((0.2126 * r) + (0.7152 * g) + (0.0722 * b))); 607 } 608 609 @Override 610 public boolean equals(Object o) { 611 if (this == o) return true; 612 if (o == null || getClass() != o.getClass()) return false; 613 614 Color color = (Color) o; 615 616 //noinspection SimplifiableIfStatement 617 if (!Arrays.equals(mComponents, color.mComponents)) return false; 618 return mColorSpace.equals(color.mColorSpace); 619 } 620 621 @Override 622 public int hashCode() { 623 int result = Arrays.hashCode(mComponents); 624 result = 31 * result + mColorSpace.hashCode(); 625 return result; 626 } 627 628 /** 629 * <p>Returns a string representation of the object. This method returns 630 * a string equal to the value of:</p> 631 * 632 * <pre class="prettyprint"> 633 * "Color(" + r + ", " + g + ", " + b + ", " + a + 634 * ", " + getColorSpace().getName + ')' 635 * </pre> 636 * 637 * <p>For instance, the string representation of opaque black in the sRGB 638 * color space is equal to the following value:</p> 639 * 640 * <pre> 641 * Color(0.0, 0.0, 0.0, 1.0, sRGB IEC61966-2.1) 642 * </pre> 643 * 644 * @return A non-null string representation of the object 645 */ 646 @Override 647 @NonNull 648 public String toString() { 649 StringBuilder b = new StringBuilder("Color("); 650 for (float c : mComponents) { 651 b.append(c).append(", "); 652 } 653 b.append(mColorSpace.getName()); 654 b.append(')'); 655 return b.toString(); 656 } 657 658 /** 659 * Returns the color space encoded in the specified color long. 660 * 661 * @param color The color long whose color space to extract 662 * @return A non-null color space instance. If the color long encodes 663 * an unknown or invalid color space, the {@link ColorSpace.Named#SRGB sRGB} 664 * color space is returned 665 * 666 * @see #red(long) 667 * @see #green(long) 668 * @see #blue(long) 669 * @see #alpha(long) 670 */ 671 @NonNull 672 public static ColorSpace colorSpace(@ColorLong long color) { 673 return ColorSpace.get((int) (color & 0x3fL)); 674 } 675 676 /** 677 * Returns the red component encoded in the specified color long. 678 * The range of the returned value depends on the color space 679 * associated with the specified color. The color space can be 680 * queried by calling {@link #colorSpace(long)}. 681 * 682 * @param color The color long whose red channel to extract 683 * @return A float value with a range defined by the specified color's 684 * color space 685 * 686 * @see #colorSpace(long) 687 * @see #green(long) 688 * @see #blue(long) 689 * @see #alpha(long) 690 */ 691 public static float red(@ColorLong long color) { 692 if ((color & 0x3fL) == 0L) return ((color >> 48) & 0xff) / 255.0f; 693 return Half.toFloat((short) ((color >> 48) & 0xffff)); 694 } 695 696 /** 697 * Returns the green component encoded in the specified color long. 698 * The range of the returned value depends on the color space 699 * associated with the specified color. The color space can be 700 * queried by calling {@link #colorSpace(long)}. 701 * 702 * @param color The color long whose green channel to extract 703 * @return A float value with a range defined by the specified color's 704 * color space 705 * 706 * @see #colorSpace(long) 707 * @see #red(long) 708 * @see #blue(long) 709 * @see #alpha(long) 710 */ 711 public static float green(@ColorLong long color) { 712 if ((color & 0x3fL) == 0L) return ((color >> 40) & 0xff) / 255.0f; 713 return Half.toFloat((short) ((color >> 32) & 0xffff)); 714 } 715 716 /** 717 * Returns the blue component encoded in the specified color long. 718 * The range of the returned value depends on the color space 719 * associated with the specified color. The color space can be 720 * queried by calling {@link #colorSpace(long)}. 721 * 722 * @param color The color long whose blue channel to extract 723 * @return A float value with a range defined by the specified color's 724 * color space 725 * 726 * @see #colorSpace(long) 727 * @see #red(long) 728 * @see #green(long) 729 * @see #alpha(long) 730 */ 731 public static float blue(@ColorLong long color) { 732 if ((color & 0x3fL) == 0L) return ((color >> 32) & 0xff) / 255.0f; 733 return Half.toFloat((short) ((color >> 16) & 0xffff)); 734 } 735 736 /** 737 * Returns the alpha component encoded in the specified color long. 738 * The returned value is always in the range \([0..1]\). 739 * 740 * @param color The color long whose blue channel to extract 741 * @return A float value in the range \([0..1]\) 742 * 743 * @see #colorSpace(long) 744 * @see #red(long) 745 * @see #green(long) 746 * @see #blue(long) 747 */ 748 public static float alpha(@ColorLong long color) { 749 if ((color & 0x3fL) == 0L) return ((color >> 56) & 0xff) / 255.0f; 750 return ((color >> 6) & 0x3ff) / 1023.0f; 751 } 752 753 /** 754 * Indicates whether the specified color is in the 755 * {@link ColorSpace.Named#SRGB sRGB} color space. 756 * 757 * @param color The color to test 758 * @return True if the color is in the sRGB color space, false otherwise 759 * 760 * @see #isInColorSpace(long, ColorSpace) 761 * @see #isWideGamut(long) 762 */ 763 public static boolean isSrgb(@ColorLong long color) { 764 return colorSpace(color).isSrgb(); 765 } 766 767 /** 768 * Indicates whether the specified color is in a wide-gamut color space. 769 * See {@link ColorSpace#isWideGamut()} for a definition of a wide-gamut 770 * color space. 771 * 772 * @param color The color to test 773 * @return True if the color is in a wide-gamut color space, false otherwise 774 * 775 * @see #isInColorSpace(long, ColorSpace) 776 * @see #isSrgb(long) 777 * @see ColorSpace#isWideGamut() 778 */ 779 public static boolean isWideGamut(@ColorLong long color) { 780 return colorSpace(color).isWideGamut(); 781 } 782 783 /** 784 * Indicates whether the specified color is in the specified color space. 785 * 786 * @param color The color to test 787 * @param colorSpace The color space to test against 788 * @return True if the color is in the specified color space, false otherwise 789 * 790 * @see #isSrgb(long) 791 * @see #isWideGamut(long) 792 */ 793 public static boolean isInColorSpace(@ColorLong long color, @NonNull ColorSpace colorSpace) { 794 return (int) (color & 0x3fL) == colorSpace.getId(); 795 } 796 797 /** 798 * Converts the specified color long to an ARGB color int. A color int is 799 * always in the {@link ColorSpace.Named#SRGB sRGB} color space. This implies 800 * a color space conversion is applied if needed. 801 * 802 * @return An ARGB color in the sRGB color space 803 */ 804 @ColorInt 805 public static int toArgb(@ColorLong long color) { 806 if ((color & 0x3fL) == 0L) return (int) (color >> 32); 807 808 float r = red(color); 809 float g = green(color); 810 float b = blue(color); 811 float a = alpha(color); 812 813 // The transformation saturates the output 814 float[] c = ColorSpace.connect(colorSpace(color)).transform(r, g, b); 815 816 return ((int) (a * 255.0f + 0.5f) << 24) | 817 ((int) (c[0] * 255.0f + 0.5f) << 16) | 818 ((int) (c[1] * 255.0f + 0.5f) << 8) | 819 (int) (c[2] * 255.0f + 0.5f); 820 } 821 822 /** 823 * Creates a new <code>Color</code> instance from an ARGB color int. 824 * The resulting color is in the {@link ColorSpace.Named#SRGB sRGB} 825 * color space. 826 * 827 * @param color The ARGB color int to create a <code>Color</code> from 828 * @return A non-null instance of {@link Color} 829 */ 830 @NonNull 831 public static Color valueOf(@ColorInt int color) { 832 float r = ((color >> 16) & 0xff) / 255.0f; 833 float g = ((color >> 8) & 0xff) / 255.0f; 834 float b = ((color ) & 0xff) / 255.0f; 835 float a = ((color >> 24) & 0xff) / 255.0f; 836 return new Color(r, g, b, a, ColorSpace.get(ColorSpace.Named.SRGB)); 837 } 838 839 /** 840 * Creates a new <code>Color</code> instance from a color long. 841 * The resulting color is in the same color space as the specified color long. 842 * 843 * @param color The color long to create a <code>Color</code> from 844 * @return A non-null instance of {@link Color} 845 */ 846 @NonNull 847 public static Color valueOf(@ColorLong long color) { 848 return new Color(red(color), green(color), blue(color), alpha(color), colorSpace(color)); 849 } 850 851 /** 852 * Creates a new opaque <code>Color</code> in the {@link ColorSpace.Named#SRGB sRGB} 853 * color space with the specified red, green and blue component values. The component 854 * values must be in the range \([0..1]\). 855 * 856 * @param r The red component of the opaque sRGB color to create, in \([0..1]\) 857 * @param g The green component of the opaque sRGB color to create, in \([0..1]\) 858 * @param b The blue component of the opaque sRGB color to create, in \([0..1]\) 859 * @return A non-null instance of {@link Color} 860 */ 861 @NonNull 862 public static Color valueOf(float r, float g, float b) { 863 return new Color(r, g, b, 1.0f); 864 } 865 866 /** 867 * Creates a new <code>Color</code> in the {@link ColorSpace.Named#SRGB sRGB} 868 * color space with the specified red, green, blue and alpha component values. 869 * The component values must be in the range \([0..1]\). 870 * 871 * @param r The red component of the sRGB color to create, in \([0..1]\) 872 * @param g The green component of the sRGB color to create, in \([0..1]\) 873 * @param b The blue component of the sRGB color to create, in \([0..1]\) 874 * @param a The alpha component of the sRGB color to create, in \([0..1]\) 875 * @return A non-null instance of {@link Color} 876 */ 877 @NonNull 878 public static Color valueOf(float r, float g, float b, float a) { 879 return new Color(saturate(r), saturate(g), saturate(b), saturate(a)); 880 } 881 882 /** 883 * Creates a new <code>Color</code> in the specified color space with the 884 * specified red, green, blue and alpha component values. The range of the 885 * components is defined by {@link ColorSpace#getMinValue(int)} and 886 * {@link ColorSpace#getMaxValue(int)}. The values passed to this method 887 * must be in the proper range. 888 * 889 * @param r The red component of the color to create 890 * @param g The green component of the color to create 891 * @param b The blue component of the color to create 892 * @param a The alpha component of the color to create, in \([0..1]\) 893 * @param colorSpace The color space of the color to create 894 * @return A non-null instance of {@link Color} 895 * 896 * @throws IllegalArgumentException If the specified color space uses a 897 * color model with more than 3 components 898 */ 899 @NonNull 900 public static Color valueOf(float r, float g, float b, float a, @NonNull ColorSpace colorSpace) { 901 if (colorSpace.getComponentCount() > 3) { 902 throw new IllegalArgumentException("The specified color space must use a color model " + 903 "with at most 3 color components"); 904 } 905 return new Color(r, g, b, a, colorSpace); 906 } 907 908 /** 909 * <p>Creates a new <code>Color</code> in the specified color space with the 910 * specified component values. The range of the components is defined by 911 * {@link ColorSpace#getMinValue(int)} and {@link ColorSpace#getMaxValue(int)}. 912 * The values passed to this method must be in the proper range. The alpha 913 * component is always in the range \([0..1]\).</p> 914 * 915 * <p>The length of the array of components must be at least 916 * <code>{@link ColorSpace#getComponentCount()} + 1</code>. The component at index 917 * {@link ColorSpace#getComponentCount()} is always alpha.</p> 918 * 919 * @param components The components of the color to create, with alpha as the last component 920 * @param colorSpace The color space of the color to create 921 * @return A non-null instance of {@link Color} 922 * 923 * @throws IllegalArgumentException If the array of components is smaller than 924 * required by the color space 925 */ 926 @NonNull 927 public static Color valueOf(@NonNull @Size(min = 4, max = 5) float[] components, 928 @NonNull ColorSpace colorSpace) { 929 if (components.length < colorSpace.getComponentCount() + 1) { 930 throw new IllegalArgumentException("Received a component array of length " + 931 components.length + " but the color model requires " + 932 (colorSpace.getComponentCount() + 1) + " (including alpha)"); 933 } 934 return new Color(Arrays.copyOf(components, colorSpace.getComponentCount() + 1), colorSpace); 935 } 936 937 /** 938 * Converts the specified ARGB color int to an RGBA color long in the sRGB 939 * color space. See the documentation of this class for a description of 940 * the color long format. 941 * 942 * @param color The ARGB color int to convert to an RGBA color long in sRGB 943 * 944 * @return A color long 945 */ 946 @ColorLong 947 public static long pack(@ColorInt int color) { 948 return (color & 0xffffffffL) << 32; 949 } 950 951 /** 952 * Packs the sRGB color defined by the specified red, green and blue component 953 * values into an RGBA color long in the sRGB color space. The alpha component 954 * is set to 1.0. See the documentation of this class for a description of the 955 * color long format. 956 * 957 * @param red The red component of the sRGB color to create, in \([0..1]\) 958 * @param green The green component of the sRGB color to create, in \([0..1]\) 959 * @param blue The blue component of the sRGB color to create, in \([0..1]\) 960 * 961 * @return A color long 962 */ 963 @ColorLong 964 public static long pack(float red, float green, float blue) { 965 return pack(red, green, blue, 1.0f, ColorSpace.get(ColorSpace.Named.SRGB)); 966 } 967 968 /** 969 * Packs the sRGB color defined by the specified red, green, blue and alpha 970 * component values into an RGBA color long in the sRGB color space. See the 971 * documentation of this class for a description of the color long format. 972 * 973 * @param red The red component of the sRGB color to create, in \([0..1]\) 974 * @param green The green component of the sRGB color to create, in \([0..1]\) 975 * @param blue The blue component of the sRGB color to create, in \([0..1]\) 976 * @param alpha The alpha component of the sRGB color to create, in \([0..1]\) 977 * 978 * @return A color long 979 */ 980 @ColorLong 981 public static long pack(float red, float green, float blue, float alpha) { 982 return pack(red, green, blue, alpha, ColorSpace.get(ColorSpace.Named.SRGB)); 983 } 984 985 /** 986 * <p>Packs the 3 component color defined by the specified red, green, blue and 987 * alpha component values into a color long in the specified color space. See the 988 * documentation of this class for a description of the color long format.</p> 989 * 990 * <p>The red, green and blue components must be in the range defined by the 991 * specified color space. See {@link ColorSpace#getMinValue(int)} and 992 * {@link ColorSpace#getMaxValue(int)}.</p> 993 * 994 * @param red The red component of the color to create 995 * @param green The green component of the color to create 996 * @param blue The blue component of the color to create 997 * @param alpha The alpha component of the color to create, in \([0..1]\) 998 * 999 * @return A color long 1000 * 1001 * @throws IllegalArgumentException If the color space's id is {@link ColorSpace#MIN_ID} 1002 * or if the color space's color model has more than 3 components 1003 */ 1004 @ColorLong 1005 public static long pack(float red, float green, float blue, float alpha, 1006 @NonNull ColorSpace colorSpace) { 1007 if (colorSpace.isSrgb()) { 1008 int argb = 1009 ((int) (alpha * 255.0f + 0.5f) << 24) | 1010 ((int) (red * 255.0f + 0.5f) << 16) | 1011 ((int) (green * 255.0f + 0.5f) << 8) | 1012 (int) (blue * 255.0f + 0.5f); 1013 return (argb & 0xffffffffL) << 32; 1014 } 1015 1016 int id = colorSpace.getId(); 1017 if (id == ColorSpace.MIN_ID) { 1018 throw new IllegalArgumentException( 1019 "Unknown color space, please use a color space returned by ColorSpace.get()"); 1020 } 1021 if (colorSpace.getComponentCount() > 3) { 1022 throw new IllegalArgumentException( 1023 "The color space must use a color model with at most 3 components"); 1024 } 1025 1026 @HalfFloat short r = Half.toHalf(red); 1027 @HalfFloat short g = Half.toHalf(green); 1028 @HalfFloat short b = Half.toHalf(blue); 1029 1030 int a = (int) (Math.max(0.0f, Math.min(alpha, 1.0f)) * 1023.0f + 0.5f); 1031 1032 // Suppress sign extension 1033 return (r & 0xffffL) << 48 | 1034 (g & 0xffffL) << 32 | 1035 (b & 0xffffL) << 16 | 1036 (a & 0x3ffL ) << 6 | 1037 id & 0x3fL; 1038 } 1039 1040 /** 1041 * Converts the specified ARGB color int from the {@link ColorSpace.Named#SRGB sRGB} 1042 * color space into the specified destination color space. The resulting color is 1043 * returned as a color long. See the documentation of this class for a description 1044 * of the color long format. 1045 * 1046 * @param color The sRGB color int to convert 1047 * @param colorSpace The destination color space 1048 * @return A color long in the destination color space 1049 */ 1050 @ColorLong 1051 public static long convert(@ColorInt int color, @NonNull ColorSpace colorSpace) { 1052 float r = ((color >> 16) & 0xff) / 255.0f; 1053 float g = ((color >> 8) & 0xff) / 255.0f; 1054 float b = ((color ) & 0xff) / 255.0f; 1055 float a = ((color >> 24) & 0xff) / 255.0f; 1056 ColorSpace source = ColorSpace.get(ColorSpace.Named.SRGB); 1057 return convert(r, g, b, a, source, colorSpace); 1058 } 1059 1060 /** 1061 * <p>Converts the specified color long from its color space into the specified 1062 * destination color space. The resulting color is returned as a color long. See 1063 * the documentation of this class for a description of the color long format.</p> 1064 * 1065 * <p>When converting several colors in a row, it is recommended to use 1066 * {@link #convert(long, ColorSpace.Connector)} instead to 1067 * avoid the creation of a {@link ColorSpace.Connector} on every invocation.</p> 1068 * 1069 * @param color The color long to convert 1070 * @param colorSpace The destination color space 1071 * @return A color long in the destination color space 1072 */ 1073 @ColorLong 1074 public static long convert(@ColorLong long color, @NonNull ColorSpace colorSpace) { 1075 float r = red(color); 1076 float g = green(color); 1077 float b = blue(color); 1078 float a = alpha(color); 1079 ColorSpace source = colorSpace(color); 1080 return convert(r, g, b, a, source, colorSpace); 1081 } 1082 1083 /** 1084 * <p>Converts the specified 3 component color from the source color space to the 1085 * destination color space. The resulting color is returned as a color long. See 1086 * the documentation of this class for a description of the color long format.</p> 1087 * 1088 * <p>When converting multiple colors in a row, it is recommended to use 1089 * {@link #convert(float, float, float, float, ColorSpace.Connector)} instead to 1090 * avoid the creation of a {@link ColorSpace.Connector} on every invocation.</p> 1091 * 1092 * <p>The red, green and blue components must be in the range defined by the 1093 * specified color space. See {@link ColorSpace#getMinValue(int)} and 1094 * {@link ColorSpace#getMaxValue(int)}.</p> 1095 * 1096 * @param r The red component of the color to convert 1097 * @param g The green component of the color to convert 1098 * @param b The blue component of the color to convert 1099 * @param a The alpha component of the color to convert, in \([0..1]\) 1100 * @param source The source color space, cannot be null 1101 * @param destination The destination color space, cannot be null 1102 * @return A color long in the destination color space 1103 * 1104 * @see #convert(float, float, float, float, ColorSpace.Connector) 1105 */ 1106 @ColorLong 1107 public static long convert(float r, float g, float b, float a, 1108 @NonNull ColorSpace source, @NonNull ColorSpace destination) { 1109 float[] c = ColorSpace.connect(source, destination).transform(r, g, b); 1110 return pack(c[0], c[1], c[2], a, destination); 1111 } 1112 1113 /** 1114 * <p>Converts the specified color long from a color space to another using the 1115 * specified color space {@link ColorSpace.Connector connector}. The resulting 1116 * color is returned as a color long. See the documentation of this class for a 1117 * description of the color long format.</p> 1118 * 1119 * <p>When converting several colors in a row, this method is preferable to 1120 * {@link #convert(long, ColorSpace)} as it prevents a new connector from being 1121 * created on every invocation.</p> 1122 * 1123 * <p class="note">The connector's source color space should match the color long's 1124 * color space.</p> 1125 * 1126 * @param color The color long to convert 1127 * @param connector A color space connector, cannot be null 1128 * @return A color long in the destination color space of the connector 1129 */ 1130 @ColorLong 1131 public static long convert(@ColorLong long color, @NonNull ColorSpace.Connector connector) { 1132 float r = red(color); 1133 float g = green(color); 1134 float b = blue(color); 1135 float a = alpha(color); 1136 return convert(r, g, b, a, connector); 1137 } 1138 1139 /** 1140 * <p>Converts the specified 3 component color from a color space to another using 1141 * the specified color space {@link ColorSpace.Connector connector}. The resulting 1142 * color is returned as a color long. See the documentation of this class for a 1143 * description of the color long format.</p> 1144 * 1145 * <p>When converting several colors in a row, this method is preferable to 1146 * {@link #convert(float, float, float, float, ColorSpace, ColorSpace)} as 1147 * it prevents a new connector from being created on every invocation.</p> 1148 * 1149 * <p>The red, green and blue components must be in the range defined by the 1150 * source color space of the connector. See {@link ColorSpace#getMinValue(int)} 1151 * and {@link ColorSpace#getMaxValue(int)}.</p> 1152 * 1153 * @param r The red component of the color to convert 1154 * @param g The green component of the color to convert 1155 * @param b The blue component of the color to convert 1156 * @param a The alpha component of the color to convert, in \([0..1]\) 1157 * @param connector A color space connector, cannot be null 1158 * @return A color long in the destination color space of the connector 1159 * 1160 * @see #convert(float, float, float, float, ColorSpace, ColorSpace) 1161 */ 1162 @ColorLong 1163 public static long convert(float r, float g, float b, float a, 1164 @NonNull ColorSpace.Connector connector) { 1165 float[] c = connector.transform(r, g, b); 1166 return pack(c[0], c[1], c[2], a, connector.getDestination()); 1167 } 1168 1169 /** 1170 * <p>Returns the relative luminance of a color.</p> 1171 * 1172 * <p>Based on the formula for relative luminance defined in WCAG 2.0, 1173 * W3C Recommendation 11 December 2008.</p> 1174 * 1175 * @return A value between 0 (darkest black) and 1 (lightest white) 1176 * 1177 * @throws IllegalArgumentException If the specified color's color space 1178 * does not use the {@link ColorSpace.Model#RGB RGB} color model 1179 */ 1180 public static float luminance(@ColorLong long color) { 1181 ColorSpace colorSpace = colorSpace(color); 1182 if (colorSpace.getModel() != ColorSpace.Model.RGB) { 1183 throw new IllegalArgumentException("The specified color must be encoded in an RGB " + 1184 "color space. The supplied color space is " + colorSpace.getModel()); 1185 } 1186 1187 DoubleUnaryOperator eotf = ((ColorSpace.Rgb) colorSpace).getEotf(); 1188 double r = eotf.applyAsDouble(red(color)); 1189 double g = eotf.applyAsDouble(green(color)); 1190 double b = eotf.applyAsDouble(blue(color)); 1191 1192 return saturate((float) ((0.2126 * r) + (0.7152 * g) + (0.0722 * b))); 1193 } 1194 1195 private static float saturate(float v) { 1196 return v <= 0.0f ? 0.0f : (v >= 1.0f ? 1.0f : v); 1197 } 1198 1199 /** 1200 * Return the alpha component of a color int. This is the same as saying 1201 * color >>> 24 1202 */ 1203 @IntRange(from = 0, to = 255) 1204 public static int alpha(int color) { 1205 return color >>> 24; 1206 } 1207 1208 /** 1209 * Return the red component of a color int. This is the same as saying 1210 * (color >> 16) & 0xFF 1211 */ 1212 @IntRange(from = 0, to = 255) 1213 public static int red(int color) { 1214 return (color >> 16) & 0xFF; 1215 } 1216 1217 /** 1218 * Return the green component of a color int. This is the same as saying 1219 * (color >> 8) & 0xFF 1220 */ 1221 @IntRange(from = 0, to = 255) 1222 public static int green(int color) { 1223 return (color >> 8) & 0xFF; 1224 } 1225 1226 /** 1227 * Return the blue component of a color int. This is the same as saying 1228 * color & 0xFF 1229 */ 1230 @IntRange(from = 0, to = 255) 1231 public static int blue(int color) { 1232 return color & 0xFF; 1233 } 1234 1235 /** 1236 * Return a color-int from red, green, blue components. 1237 * The alpha component is implicitly 255 (fully opaque). 1238 * These component values should be \([0..255]\), but there is no 1239 * range check performed, so if they are out of range, the 1240 * returned color is undefined. 1241 * 1242 * @param red Red component \([0..255]\) of the color 1243 * @param green Green component \([0..255]\) of the color 1244 * @param blue Blue component \([0..255]\) of the color 1245 */ 1246 @ColorInt 1247 public static int rgb( 1248 @IntRange(from = 0, to = 255) int red, 1249 @IntRange(from = 0, to = 255) int green, 1250 @IntRange(from = 0, to = 255) int blue) { 1251 return 0xff000000 | (red << 16) | (green << 8) | blue; 1252 } 1253 1254 /** 1255 * Return a color-int from red, green, blue float components 1256 * in the range \([0..1]\). The alpha component is implicitly 1257 * 1.0 (fully opaque). If the components are out of range, the 1258 * returned color is undefined. 1259 * 1260 * @param red Red component \([0..1]\) of the color 1261 * @param green Green component \([0..1]\) of the color 1262 * @param blue Blue component \([0..1]\) of the color 1263 */ 1264 @ColorInt 1265 public static int rgb(float red, float green, float blue) { 1266 return 0xff000000 | 1267 ((int) (red * 255.0f + 0.5f) << 16) | 1268 ((int) (green * 255.0f + 0.5f) << 8) | 1269 (int) (blue * 255.0f + 0.5f); 1270 } 1271 1272 /** 1273 * Return a color-int from alpha, red, green, blue components. 1274 * These component values should be \([0..255]\), but there is no 1275 * range check performed, so if they are out of range, the 1276 * returned color is undefined. 1277 * @param alpha Alpha component \([0..255]\) of the color 1278 * @param red Red component \([0..255]\) of the color 1279 * @param green Green component \([0..255]\) of the color 1280 * @param blue Blue component \([0..255]\) of the color 1281 */ 1282 @ColorInt 1283 public static int argb( 1284 @IntRange(from = 0, to = 255) int alpha, 1285 @IntRange(from = 0, to = 255) int red, 1286 @IntRange(from = 0, to = 255) int green, 1287 @IntRange(from = 0, to = 255) int blue) { 1288 return (alpha << 24) | (red << 16) | (green << 8) | blue; 1289 } 1290 1291 /** 1292 * Return a color-int from alpha, red, green, blue float components 1293 * in the range \([0..1]\). If the components are out of range, the 1294 * returned color is undefined. 1295 * 1296 * @param alpha Alpha component \([0..1]\) of the color 1297 * @param red Red component \([0..1]\) of the color 1298 * @param green Green component \([0..1]\) of the color 1299 * @param blue Blue component \([0..1]\) of the color 1300 */ 1301 @ColorInt 1302 public static int argb(float alpha, float red, float green, float blue) { 1303 return ((int) (alpha * 255.0f + 0.5f) << 24) | 1304 ((int) (red * 255.0f + 0.5f) << 16) | 1305 ((int) (green * 255.0f + 0.5f) << 8) | 1306 (int) (blue * 255.0f + 0.5f); 1307 } 1308 1309 /** 1310 * Returns the relative luminance of a color. 1311 * <p> 1312 * Assumes sRGB encoding. Based on the formula for relative luminance 1313 * defined in WCAG 2.0, W3C Recommendation 11 December 2008. 1314 * 1315 * @return a value between 0 (darkest black) and 1 (lightest white) 1316 */ 1317 public static float luminance(@ColorInt int color) { 1318 ColorSpace.Rgb cs = (ColorSpace.Rgb) ColorSpace.get(ColorSpace.Named.SRGB); 1319 DoubleUnaryOperator eotf = cs.getEotf(); 1320 1321 double r = eotf.applyAsDouble(red(color) / 255.0); 1322 double g = eotf.applyAsDouble(green(color) / 255.0); 1323 double b = eotf.applyAsDouble(blue(color) / 255.0); 1324 1325 return (float) ((0.2126 * r) + (0.7152 * g) + (0.0722 * b)); 1326 } 1327 1328 /** 1329 * </p>Parse the color string, and return the corresponding color-int. 1330 * If the string cannot be parsed, throws an IllegalArgumentException 1331 * exception. Supported formats are:</p> 1332 * 1333 * <ul> 1334 * <li><code>#RRGGBB</code></li> 1335 * <li><code>#AARRGGBB</code></li> 1336 * </ul> 1337 * 1338 * <p>The following names are also accepted: <code>red</code>, <code>blue</code>, 1339 * <code>green</code>, <code>black</code>, <code>white</code>, <code>gray</code>, 1340 * <code>cyan</code>, <code>magenta</code>, <code>yellow</code>, <code>lightgray</code>, 1341 * <code>darkgray</code>, <code>grey</code>, <code>lightgrey</code>, <code>darkgrey</code>, 1342 * <code>aqua</code>, <code>fuchsia</code>, <code>lime</code>, <code>maroon</code>, 1343 * <code>navy</code>, <code>olive</code>, <code>purple</code>, <code>silver</code>, 1344 * and <code>teal</code>.</p> 1345 */ 1346 @ColorInt 1347 public static int parseColor(@Size(min=1) String colorString) { 1348 if (colorString.charAt(0) == '#') { 1349 // Use a long to avoid rollovers on #ffXXXXXX 1350 long color = Long.parseLong(colorString.substring(1), 16); 1351 if (colorString.length() == 7) { 1352 // Set the alpha value 1353 color |= 0x00000000ff000000; 1354 } else if (colorString.length() != 9) { 1355 throw new IllegalArgumentException("Unknown color"); 1356 } 1357 return (int)color; 1358 } else { 1359 Integer color = sColorNameMap.get(colorString.toLowerCase(Locale.ROOT)); 1360 if (color != null) { 1361 return color; 1362 } 1363 } 1364 throw new IllegalArgumentException("Unknown color"); 1365 } 1366 1367 /** 1368 * Convert RGB components to HSV. 1369 * <ul> 1370 * <li><code>hsv[0]</code> is Hue \([0..360[\)</li> 1371 * <li><code>hsv[1]</code> is Saturation \([0...1]\)</li> 1372 * <li><code>hsv[2]</code> is Value \([0...1]\)</li> 1373 * </ul> 1374 * @param red red component value \([0..255]\) 1375 * @param green green component value \([0..255]\) 1376 * @param blue blue component value \([0..255]\) 1377 * @param hsv 3 element array which holds the resulting HSV components. 1378 */ 1379 public static void RGBToHSV( 1380 @IntRange(from = 0, to = 255) int red, 1381 @IntRange(from = 0, to = 255) int green, 1382 @IntRange(from = 0, to = 255) int blue, @Size(3) float hsv[]) { 1383 if (hsv.length < 3) { 1384 throw new RuntimeException("3 components required for hsv"); 1385 } 1386 nativeRGBToHSV(red, green, blue, hsv); 1387 } 1388 1389 /** 1390 * Convert the ARGB color to its HSV components. 1391 * <ul> 1392 * <li><code>hsv[0]</code> is Hue \([0..360[\)</li> 1393 * <li><code>hsv[1]</code> is Saturation \([0...1]\)</li> 1394 * <li><code>hsv[2]</code> is Value \([0...1]\)</li> 1395 * </ul> 1396 * @param color the argb color to convert. The alpha component is ignored. 1397 * @param hsv 3 element array which holds the resulting HSV components. 1398 */ 1399 public static void colorToHSV(@ColorInt int color, @Size(3) float hsv[]) { 1400 RGBToHSV((color >> 16) & 0xFF, (color >> 8) & 0xFF, color & 0xFF, hsv); 1401 } 1402 1403 /** 1404 * Convert HSV components to an ARGB color. Alpha set to 0xFF. 1405 * <ul> 1406 * <li><code>hsv[0]</code> is Hue \([0..360[\)</li> 1407 * <li><code>hsv[1]</code> is Saturation \([0...1]\)</li> 1408 * <li><code>hsv[2]</code> is Value \([0...1]\)</li> 1409 * </ul> 1410 * If hsv values are out of range, they are pinned. 1411 * @param hsv 3 element array which holds the input HSV components. 1412 * @return the resulting argb color 1413 */ 1414 @ColorInt 1415 public static int HSVToColor(@Size(3) float hsv[]) { 1416 return HSVToColor(0xFF, hsv); 1417 } 1418 1419 /** 1420 * Convert HSV components to an ARGB color. The alpha component is passed 1421 * through unchanged. 1422 * <ul> 1423 * <li><code>hsv[0]</code> is Hue \([0..360[\)</li> 1424 * <li><code>hsv[1]</code> is Saturation \([0...1]\)</li> 1425 * <li><code>hsv[2]</code> is Value \([0...1]\)</li> 1426 * </ul> 1427 * If hsv values are out of range, they are pinned. 1428 * @param alpha the alpha component of the returned argb color. 1429 * @param hsv 3 element array which holds the input HSV components. 1430 * @return the resulting argb color 1431 */ 1432 @ColorInt 1433 public static int HSVToColor(@IntRange(from = 0, to = 255) int alpha, @Size(3) float hsv[]) { 1434 if (hsv.length < 3) { 1435 throw new RuntimeException("3 components required for hsv"); 1436 } 1437 return nativeHSVToColor(alpha, hsv); 1438 } 1439 1440 private static native void nativeRGBToHSV(int red, int greed, int blue, float hsv[]); 1441 private static native int nativeHSVToColor(int alpha, float hsv[]); 1442 1443 /** 1444 * Converts an HTML color (named or numeric) to an integer RGB value. 1445 * 1446 * @param color Non-null color string. 1447 * 1448 * @return A color value, or {@code -1} if the color string could not be interpreted. 1449 * 1450 * @hide 1451 */ 1452 @ColorInt 1453 public static int getHtmlColor(@NonNull String color) { 1454 Integer i = sColorNameMap.get(color.toLowerCase(Locale.ROOT)); 1455 if (i != null) { 1456 return i; 1457 } else { 1458 try { 1459 return XmlUtils.convertValueToInt(color, -1); 1460 } catch (NumberFormatException nfe) { 1461 return -1; 1462 } 1463 } 1464 } 1465 1466 private static final HashMap<String, Integer> sColorNameMap; 1467 static { 1468 sColorNameMap = new HashMap<>(); 1469 sColorNameMap.put("black", BLACK); 1470 sColorNameMap.put("darkgray", DKGRAY); 1471 sColorNameMap.put("gray", GRAY); 1472 sColorNameMap.put("lightgray", LTGRAY); 1473 sColorNameMap.put("white", WHITE); 1474 sColorNameMap.put("red", RED); 1475 sColorNameMap.put("green", GREEN); 1476 sColorNameMap.put("blue", BLUE); 1477 sColorNameMap.put("yellow", YELLOW); 1478 sColorNameMap.put("cyan", CYAN); 1479 sColorNameMap.put("magenta", MAGENTA); 1480 sColorNameMap.put("aqua", 0xFF00FFFF); 1481 sColorNameMap.put("fuchsia", 0xFFFF00FF); 1482 sColorNameMap.put("darkgrey", DKGRAY); 1483 sColorNameMap.put("grey", GRAY); 1484 sColorNameMap.put("lightgrey", LTGRAY); 1485 sColorNameMap.put("lime", 0xFF00FF00); 1486 sColorNameMap.put("maroon", 0xFF800000); 1487 sColorNameMap.put("navy", 0xFF000080); 1488 sColorNameMap.put("olive", 0xFF808000); 1489 sColorNameMap.put("purple", 0xFF800080); 1490 sColorNameMap.put("silver", 0xFFC0C0C0); 1491 sColorNameMap.put("teal", 0xFF008080); 1492 1493 } 1494} 1495