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