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 30 import java.util.Arrays; 31 import java.util.HashMap; 32 import java.util.Locale; 33 import 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) << 8 | (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 291 @SuppressAutoDoc 292 public class Color { 293 @ColorInt public static final int BLACK = 0xFF000000; 294 @ColorInt public static final int DKGRAY = 0xFF444444; 295 @ColorInt public static final int GRAY = 0xFF888888; 296 @ColorInt public static final int LTGRAY = 0xFFCCCCCC; 297 @ColorInt public static final int WHITE = 0xFFFFFFFF; 298 @ColorInt public static final int RED = 0xFFFF0000; 299 @ColorInt public static final int GREEN = 0xFF00FF00; 300 @ColorInt public static final int BLUE = 0xFF0000FF; 301 @ColorInt public static final int YELLOW = 0xFFFFFF00; 302 @ColorInt public static final int CYAN = 0xFF00FFFF; 303 @ColorInt public static final int MAGENTA = 0xFFFF00FF; 304 @ColorInt public static final int TRANSPARENT = 0; 305 306 @NonNull 307 @Size(min = 4, max = 5) 308 private final float[] mComponents; 309 310 @NonNull 311 private final ColorSpace mColorSpace; 312 313 /** 314 * Creates a new color instance set to opaque black in the 315 * {@link ColorSpace.Named#SRGB sRGB} color space. 316 * 317 * @see #valueOf(float, float, float) 318 * @see #valueOf(float, float, float, float) 319 * @see #valueOf(float, float, float, float, ColorSpace) 320 * @see #valueOf(float[], ColorSpace) 321 * @see #valueOf(int) 322 * @see #valueOf(long) 323 */ Color()324 public Color() { 325 // This constructor is required for compatibility with previous APIs 326 mComponents = new float[] { 0.0f, 0.0f, 0.0f, 1.0f }; 327 mColorSpace = ColorSpace.get(ColorSpace.Named.SRGB); 328 } 329 330 /** 331 * Creates a new color instance in the {@link ColorSpace.Named#SRGB sRGB} 332 * color space. 333 * 334 * @param r The value of the red channel, must be in [0..1] range 335 * @param g The value of the green channel, must be in [0..1] range 336 * @param b The value of the blue channel, must be in [0..1] range 337 * @param a The value of the alpha channel, must be in [0..1] range 338 */ Color(float r, float g, float b, float a)339 private Color(float r, float g, float b, float a) { 340 this(r, g, b, a, ColorSpace.get(ColorSpace.Named.SRGB)); 341 } 342 343 /** 344 * Creates a new color instance in the specified color space. The color space 345 * must have a 3 components model. 346 * 347 * @param r The value of the red channel, must be in the color space defined range 348 * @param g The value of the green channel, must be in the color space defined range 349 * @param b The value of the blue channel, must be in the color space defined range 350 * @param a The value of the alpha channel, must be in [0..1] range 351 * @param colorSpace This color's color space, cannot be null 352 */ Color(float r, float g, float b, float a, @NonNull ColorSpace colorSpace)353 private Color(float r, float g, float b, float a, @NonNull ColorSpace colorSpace) { 354 mComponents = new float[] { r, g, b, a }; 355 mColorSpace = colorSpace; 356 } 357 358 /** 359 * Creates a new color instance in the specified color space. 360 * 361 * @param components An array of color components, plus alpha 362 * @param colorSpace This color's color space, cannot be null 363 */ Color(@izemin = 4, max = 5) float[] components, @NonNull ColorSpace colorSpace)364 private Color(@Size(min = 4, max = 5) float[] components, @NonNull ColorSpace colorSpace) { 365 mComponents = components; 366 mColorSpace = colorSpace; 367 } 368 369 /** 370 * Returns this color's color space. 371 * 372 * @return A non-null instance of {@link ColorSpace} 373 */ 374 @NonNull getColorSpace()375 public ColorSpace getColorSpace() { 376 return mColorSpace; 377 } 378 379 /** 380 * Returns the color model of this color. 381 * 382 * @return A non-null {@link ColorSpace.Model} 383 */ getModel()384 public ColorSpace.Model getModel() { 385 return mColorSpace.getModel(); 386 } 387 388 /** 389 * Indicates whether this color color is in a wide-gamut color space. 390 * See {@link ColorSpace#isWideGamut()} for a definition of a wide-gamut 391 * color space. 392 * 393 * @return True if this color is in a wide-gamut color space, false otherwise 394 * 395 * @see #isSrgb() 396 * @see ColorSpace#isWideGamut() 397 */ isWideGamut()398 public boolean isWideGamut() { 399 return getColorSpace().isWideGamut(); 400 } 401 402 /** 403 * Indicates whether this color is in the {@link ColorSpace.Named#SRGB sRGB} 404 * color space. 405 * 406 * @return True if this color is in the sRGB color space, false otherwise 407 * 408 * @see #isWideGamut() 409 */ isSrgb()410 public boolean isSrgb() { 411 return getColorSpace().isSrgb(); 412 } 413 414 /** 415 * Returns the number of components that form a color value according 416 * to this color space's color model, plus one extra component for 417 * alpha. 418 * 419 * @return The integer 4 or 5 420 */ 421 @IntRange(from = 4, to = 5) getComponentCount()422 public int getComponentCount() { 423 return mColorSpace.getComponentCount() + 1; 424 } 425 426 /** 427 * Packs this color into a color long. See the documentation of this class 428 * for a description of the color long format. 429 * 430 * @return A color long 431 * 432 * @throws IllegalArgumentException If this color's color space has the id 433 * {@link ColorSpace#MIN_ID} or if this color has more than 4 components 434 */ 435 @ColorLong pack()436 public long pack() { 437 return pack(mComponents[0], mComponents[1], mComponents[2], mComponents[3], mColorSpace); 438 } 439 440 /** 441 * Converts this color from its color space to the specified color space. 442 * The conversion is done using the default rendering intent as specified 443 * by {@link ColorSpace#connect(ColorSpace, ColorSpace)}. 444 * 445 * @param colorSpace The destination color space, cannot be null 446 * 447 * @return A non-null color instance in the specified color space 448 */ 449 @NonNull convert(@onNull ColorSpace colorSpace)450 public Color convert(@NonNull ColorSpace colorSpace) { 451 ColorSpace.Connector connector = ColorSpace.connect(mColorSpace, colorSpace); 452 float[] color = new float[] { 453 mComponents[0], mComponents[1], mComponents[2], mComponents[3] 454 }; 455 connector.transform(color); 456 return new Color(color, colorSpace); 457 } 458 459 /** 460 * Converts this color to an ARGB color int. A color int is always in 461 * the {@link ColorSpace.Named#SRGB sRGB} color space. This implies 462 * a color space conversion is applied if needed. 463 * 464 * @return An ARGB color in the sRGB color space 465 */ 466 @ColorInt toArgb()467 public int toArgb() { 468 if (mColorSpace.isSrgb()) { 469 return ((int) (mComponents[3] * 255.0f + 0.5f) << 24) | 470 ((int) (mComponents[0] * 255.0f + 0.5f) << 16) | 471 ((int) (mComponents[1] * 255.0f + 0.5f) << 8) | 472 (int) (mComponents[2] * 255.0f + 0.5f); 473 } 474 475 float[] color = new float[] { 476 mComponents[0], mComponents[1], mComponents[2], mComponents[3] 477 }; 478 // The transformation saturates the output 479 ColorSpace.connect(mColorSpace).transform(color); 480 481 return ((int) (color[3] * 255.0f + 0.5f) << 24) | 482 ((int) (color[0] * 255.0f + 0.5f) << 16) | 483 ((int) (color[1] * 255.0f + 0.5f) << 8) | 484 (int) (color[2] * 255.0f + 0.5f); 485 } 486 487 /** 488 * <p>Returns the value of the red component in the range defined by this 489 * color's color space (see {@link ColorSpace#getMinValue(int)} and 490 * {@link ColorSpace#getMaxValue(int)}).</p> 491 * 492 * <p>If this color's color model is not {@link ColorSpace.Model#RGB RGB}, 493 * calling this method is equivalent to <code>getComponent(0)</code>.</p> 494 * 495 * @see #alpha() 496 * @see #red() 497 * @see #green 498 * @see #getComponents() 499 */ red()500 public float red() { 501 return mComponents[0]; 502 } 503 504 /** 505 * <p>Returns the value of the green component in the range defined by this 506 * color's color space (see {@link ColorSpace#getMinValue(int)} and 507 * {@link ColorSpace#getMaxValue(int)}).</p> 508 * 509 * <p>If this color's color model is not {@link ColorSpace.Model#RGB RGB}, 510 * calling this method is equivalent to <code>getComponent(1)</code>.</p> 511 * 512 * @see #alpha() 513 * @see #red() 514 * @see #green 515 * @see #getComponents() 516 */ green()517 public float green() { 518 return mComponents[1]; 519 } 520 521 /** 522 * <p>Returns the value of the blue component in the range defined by this 523 * color's color space (see {@link ColorSpace#getMinValue(int)} and 524 * {@link ColorSpace#getMaxValue(int)}).</p> 525 * 526 * <p>If this color's color model is not {@link ColorSpace.Model#RGB RGB}, 527 * calling this method is equivalent to <code>getComponent(2)</code>.</p> 528 * 529 * @see #alpha() 530 * @see #red() 531 * @see #green 532 * @see #getComponents() 533 */ blue()534 public float blue() { 535 return mComponents[2]; 536 } 537 538 /** 539 * Returns the value of the alpha component in the range \([0..1]\). 540 * Calling this method is equivalent to 541 * <code>getComponent(getComponentCount() - 1)</code>. 542 * 543 * @see #red() 544 * @see #green() 545 * @see #blue() 546 * @see #getComponents() 547 * @see #getComponent(int) 548 */ alpha()549 public float alpha() { 550 return mComponents[mComponents.length - 1]; 551 } 552 553 /** 554 * Returns this color's components as a new array. The last element of the 555 * array is always the alpha component. 556 * 557 * @return A new, non-null array whose size is equal to {@link #getComponentCount()} 558 * 559 * @see #getComponent(int) 560 */ 561 @NonNull 562 @Size(min = 4, max = 5) getComponents()563 public float[] getComponents() { 564 return Arrays.copyOf(mComponents, mComponents.length); 565 } 566 567 /** 568 * Copies this color's components in the supplied array. The last element of the 569 * array is always the alpha component. 570 * 571 * @param components An array of floats whose size must be at least 572 * {@link #getComponentCount()}, can be null 573 * @return The array passed as a parameter if not null, or a new array of length 574 * {@link #getComponentCount()} 575 * 576 * @see #getComponent(int) 577 * 578 * @throws IllegalArgumentException If the specified array's length is less than 579 * {@link #getComponentCount()} 580 */ 581 @NonNull 582 @Size(min = 4) getComponents(@ullable @izemin = 4) float[] components)583 public float[] getComponents(@Nullable @Size(min = 4) float[] components) { 584 if (components == null) { 585 return Arrays.copyOf(mComponents, mComponents.length); 586 } 587 588 if (components.length < mComponents.length) { 589 throw new IllegalArgumentException("The specified array's length must be at " 590 + "least " + mComponents.length); 591 } 592 593 System.arraycopy(mComponents, 0, components, 0, mComponents.length); 594 return components; 595 } 596 597 /** 598 * <p>Returns the value of the specified component in the range defined by 599 * this color's color space (see {@link ColorSpace#getMinValue(int)} and 600 * {@link ColorSpace#getMaxValue(int)}).</p> 601 * 602 * <p>If the requested component index is {@link #getComponentCount()}, 603 * this method returns the alpha component, always in the range 604 * \([0..1]\).</p> 605 * 606 * @see #getComponents() 607 * 608 * @throws ArrayIndexOutOfBoundsException If the specified component index 609 * is < 0 or >= {@link #getComponentCount()} 610 */ getComponent(@ntRangefrom = 0, to = 4) int component)611 public float getComponent(@IntRange(from = 0, to = 4) int component) { 612 return mComponents[component]; 613 } 614 615 /** 616 * <p>Returns the relative luminance of this color.</p> 617 * 618 * <p>Based on the formula for relative luminance defined in WCAG 2.0, 619 * W3C Recommendation 11 December 2008.</p> 620 * 621 * @return A value between 0 (darkest black) and 1 (lightest white) 622 * 623 * @throws IllegalArgumentException If the this color's color space 624 * does not use the {@link ColorSpace.Model#RGB RGB} color model 625 */ luminance()626 public float luminance() { 627 if (mColorSpace.getModel() != ColorSpace.Model.RGB) { 628 throw new IllegalArgumentException("The specified color must be encoded in an RGB " + 629 "color space. The supplied color space is " + mColorSpace.getModel()); 630 } 631 632 DoubleUnaryOperator eotf = ((ColorSpace.Rgb) mColorSpace).getEotf(); 633 double r = eotf.applyAsDouble(mComponents[0]); 634 double g = eotf.applyAsDouble(mComponents[1]); 635 double b = eotf.applyAsDouble(mComponents[2]); 636 637 return saturate((float) ((0.2126 * r) + (0.7152 * g) + (0.0722 * b))); 638 } 639 640 @Override equals(Object o)641 public boolean equals(Object o) { 642 if (this == o) return true; 643 if (o == null || getClass() != o.getClass()) return false; 644 645 Color color = (Color) o; 646 647 //noinspection SimplifiableIfStatement 648 if (!Arrays.equals(mComponents, color.mComponents)) return false; 649 return mColorSpace.equals(color.mColorSpace); 650 } 651 652 @Override hashCode()653 public int hashCode() { 654 int result = Arrays.hashCode(mComponents); 655 result = 31 * result + mColorSpace.hashCode(); 656 return result; 657 } 658 659 /** 660 * <p>Returns a string representation of the object. This method returns 661 * a string equal to the value of:</p> 662 * 663 * <pre class="prettyprint"> 664 * "Color(" + r + ", " + g + ", " + b + ", " + a + 665 * ", " + getColorSpace().getName + ')' 666 * </pre> 667 * 668 * <p>For instance, the string representation of opaque black in the sRGB 669 * color space is equal to the following value:</p> 670 * 671 * <pre> 672 * Color(0.0, 0.0, 0.0, 1.0, sRGB IEC61966-2.1) 673 * </pre> 674 * 675 * @return A non-null string representation of the object 676 */ 677 @Override 678 @NonNull toString()679 public String toString() { 680 StringBuilder b = new StringBuilder("Color("); 681 for (float c : mComponents) { 682 b.append(c).append(", "); 683 } 684 b.append(mColorSpace.getName()); 685 b.append(')'); 686 return b.toString(); 687 } 688 689 /** 690 * Returns the color space encoded in the specified color long. 691 * 692 * @param color The color long whose color space to extract 693 * @return A non-null color space instance 694 * @throws IllegalArgumentException If the encoded color space is invalid or unknown 695 * 696 * @see #red(long) 697 * @see #green(long) 698 * @see #blue(long) 699 * @see #alpha(long) 700 */ 701 @NonNull colorSpace(@olorLong long color)702 public static ColorSpace colorSpace(@ColorLong long color) { 703 return ColorSpace.get((int) (color & 0x3fL)); 704 } 705 706 /** 707 * Returns the red component encoded in the specified color long. 708 * The range of the returned value depends on the color space 709 * associated with the specified color. The color space can be 710 * queried by calling {@link #colorSpace(long)}. 711 * 712 * @param color The color long whose red channel to extract 713 * @return A float value with a range defined by the specified color's 714 * color space 715 * 716 * @see #colorSpace(long) 717 * @see #green(long) 718 * @see #blue(long) 719 * @see #alpha(long) 720 */ red(@olorLong long color)721 public static float red(@ColorLong long color) { 722 if ((color & 0x3fL) == 0L) return ((color >> 48) & 0xff) / 255.0f; 723 return Half.toFloat((short) ((color >> 48) & 0xffff)); 724 } 725 726 /** 727 * Returns the green component encoded in the specified color long. 728 * The range of the returned value depends on the color space 729 * associated with the specified color. The color space can be 730 * queried by calling {@link #colorSpace(long)}. 731 * 732 * @param color The color long whose green channel to extract 733 * @return A float value with a range defined by the specified color's 734 * color space 735 * 736 * @see #colorSpace(long) 737 * @see #red(long) 738 * @see #blue(long) 739 * @see #alpha(long) 740 */ green(@olorLong long color)741 public static float green(@ColorLong long color) { 742 if ((color & 0x3fL) == 0L) return ((color >> 40) & 0xff) / 255.0f; 743 return Half.toFloat((short) ((color >> 32) & 0xffff)); 744 } 745 746 /** 747 * Returns the blue component encoded in the specified color long. 748 * The range of the returned value depends on the color space 749 * associated with the specified color. The color space can be 750 * queried by calling {@link #colorSpace(long)}. 751 * 752 * @param color The color long whose blue channel to extract 753 * @return A float value with a range defined by the specified color's 754 * color space 755 * 756 * @see #colorSpace(long) 757 * @see #red(long) 758 * @see #green(long) 759 * @see #alpha(long) 760 */ blue(@olorLong long color)761 public static float blue(@ColorLong long color) { 762 if ((color & 0x3fL) == 0L) return ((color >> 32) & 0xff) / 255.0f; 763 return Half.toFloat((short) ((color >> 16) & 0xffff)); 764 } 765 766 /** 767 * Returns the alpha component encoded in the specified color long. 768 * The returned value is always in the range \([0..1]\). 769 * 770 * @param color The color long whose blue channel to extract 771 * @return A float value in the range \([0..1]\) 772 * 773 * @see #colorSpace(long) 774 * @see #red(long) 775 * @see #green(long) 776 * @see #blue(long) 777 */ alpha(@olorLong long color)778 public static float alpha(@ColorLong long color) { 779 if ((color & 0x3fL) == 0L) return ((color >> 56) & 0xff) / 255.0f; 780 return ((color >> 6) & 0x3ff) / 1023.0f; 781 } 782 783 /** 784 * Indicates whether the specified color is in the 785 * {@link ColorSpace.Named#SRGB sRGB} color space. 786 * 787 * @param color The color to test 788 * @return True if the color is in the sRGB color space, false otherwise 789 * @throws IllegalArgumentException If the encoded color space is invalid or unknown 790 * 791 * @see #isInColorSpace(long, ColorSpace) 792 * @see #isWideGamut(long) 793 */ isSrgb(@olorLong long color)794 public static boolean isSrgb(@ColorLong long color) { 795 return colorSpace(color).isSrgb(); 796 } 797 798 /** 799 * Indicates whether the specified color is in a wide-gamut color space. 800 * See {@link ColorSpace#isWideGamut()} for a definition of a wide-gamut 801 * color space. 802 * 803 * @param color The color to test 804 * @return True if the color is in a wide-gamut color space, false otherwise 805 * @throws IllegalArgumentException If the encoded color space is invalid or unknown 806 * 807 * @see #isInColorSpace(long, ColorSpace) 808 * @see #isSrgb(long) 809 * @see ColorSpace#isWideGamut() 810 */ isWideGamut(@olorLong long color)811 public static boolean isWideGamut(@ColorLong long color) { 812 return colorSpace(color).isWideGamut(); 813 } 814 815 /** 816 * Indicates whether the specified color is in the specified color space. 817 * 818 * @param color The color to test 819 * @param colorSpace The color space to test against 820 * @return True if the color is in the specified color space, false otherwise 821 * 822 * @see #isSrgb(long) 823 * @see #isWideGamut(long) 824 */ isInColorSpace(@olorLong long color, @NonNull ColorSpace colorSpace)825 public static boolean isInColorSpace(@ColorLong long color, @NonNull ColorSpace colorSpace) { 826 return (int) (color & 0x3fL) == colorSpace.getId(); 827 } 828 829 /** 830 * Converts the specified color long to an ARGB color int. A color int is 831 * always in the {@link ColorSpace.Named#SRGB sRGB} color space. This implies 832 * a color space conversion is applied if needed. 833 * 834 * @return An ARGB color in the sRGB color space 835 * @throws IllegalArgumentException If the encoded color space is invalid or unknown 836 */ 837 @ColorInt toArgb(@olorLong long color)838 public static int toArgb(@ColorLong long color) { 839 if ((color & 0x3fL) == 0L) return (int) (color >> 32); 840 841 float r = red(color); 842 float g = green(color); 843 float b = blue(color); 844 float a = alpha(color); 845 846 // The transformation saturates the output 847 float[] c = ColorSpace.connect(colorSpace(color)).transform(r, g, b); 848 849 return ((int) (a * 255.0f + 0.5f) << 24) | 850 ((int) (c[0] * 255.0f + 0.5f) << 16) | 851 ((int) (c[1] * 255.0f + 0.5f) << 8) | 852 (int) (c[2] * 255.0f + 0.5f); 853 } 854 855 /** 856 * Creates a new <code>Color</code> instance from an ARGB color int. 857 * The resulting color is in the {@link ColorSpace.Named#SRGB sRGB} 858 * color space. 859 * 860 * @param color The ARGB color int to create a <code>Color</code> from 861 * @return A non-null instance of {@link Color} 862 */ 863 @NonNull valueOf(@olorInt int color)864 public static Color valueOf(@ColorInt int color) { 865 float r = ((color >> 16) & 0xff) / 255.0f; 866 float g = ((color >> 8) & 0xff) / 255.0f; 867 float b = ((color ) & 0xff) / 255.0f; 868 float a = ((color >> 24) & 0xff) / 255.0f; 869 return new Color(r, g, b, a, ColorSpace.get(ColorSpace.Named.SRGB)); 870 } 871 872 /** 873 * Creates a new <code>Color</code> instance from a color long. 874 * The resulting color is in the same color space as the specified color long. 875 * 876 * @param color The color long to create a <code>Color</code> from 877 * @return A non-null instance of {@link Color} 878 * @throws IllegalArgumentException If the encoded color space is invalid or unknown 879 */ 880 @NonNull valueOf(@olorLong long color)881 public static Color valueOf(@ColorLong long color) { 882 return new Color(red(color), green(color), blue(color), alpha(color), colorSpace(color)); 883 } 884 885 /** 886 * Creates a new opaque <code>Color</code> in the {@link ColorSpace.Named#SRGB sRGB} 887 * color space with the specified red, green and blue component values. The component 888 * values must be in the range \([0..1]\). 889 * 890 * @param r The red component of the opaque sRGB color to create, in \([0..1]\) 891 * @param g The green component of the opaque sRGB color to create, in \([0..1]\) 892 * @param b The blue component of the opaque sRGB color to create, in \([0..1]\) 893 * @return A non-null instance of {@link Color} 894 */ 895 @NonNull valueOf(float r, float g, float b)896 public static Color valueOf(float r, float g, float b) { 897 return new Color(r, g, b, 1.0f); 898 } 899 900 /** 901 * Creates a new <code>Color</code> in the {@link ColorSpace.Named#SRGB sRGB} 902 * color space with the specified red, green, blue and alpha component values. 903 * The component values must be in the range \([0..1]\). 904 * 905 * @param r The red component of the sRGB color to create, in \([0..1]\) 906 * @param g The green component of the sRGB color to create, in \([0..1]\) 907 * @param b The blue component of the sRGB color to create, in \([0..1]\) 908 * @param a The alpha component of the sRGB color to create, in \([0..1]\) 909 * @return A non-null instance of {@link Color} 910 */ 911 @NonNull valueOf(float r, float g, float b, float a)912 public static Color valueOf(float r, float g, float b, float a) { 913 return new Color(saturate(r), saturate(g), saturate(b), saturate(a)); 914 } 915 916 /** 917 * Creates a new <code>Color</code> in the specified color space with the 918 * specified red, green, blue and alpha component values. The range of the 919 * components is defined by {@link ColorSpace#getMinValue(int)} and 920 * {@link ColorSpace#getMaxValue(int)}. The values passed to this method 921 * must be in the proper range. 922 * 923 * @param r The red component of the color to create 924 * @param g The green component of the color to create 925 * @param b The blue component of the color to create 926 * @param a The alpha component of the color to create, in \([0..1]\) 927 * @param colorSpace The color space of the color to create 928 * @return A non-null instance of {@link Color} 929 * 930 * @throws IllegalArgumentException If the specified color space uses a 931 * color model with more than 3 components 932 */ 933 @NonNull valueOf(float r, float g, float b, float a, @NonNull ColorSpace colorSpace)934 public static Color valueOf(float r, float g, float b, float a, @NonNull ColorSpace colorSpace) { 935 if (colorSpace.getComponentCount() > 3) { 936 throw new IllegalArgumentException("The specified color space must use a color model " + 937 "with at most 3 color components"); 938 } 939 return new Color(r, g, b, a, colorSpace); 940 } 941 942 /** 943 * <p>Creates a new <code>Color</code> in the specified color space with the 944 * specified component values. The range of the components is defined by 945 * {@link ColorSpace#getMinValue(int)} and {@link ColorSpace#getMaxValue(int)}. 946 * The values passed to this method must be in the proper range. The alpha 947 * component is always in the range \([0..1]\).</p> 948 * 949 * <p>The length of the array of components must be at least 950 * <code>{@link ColorSpace#getComponentCount()} + 1</code>. The component at index 951 * {@link ColorSpace#getComponentCount()} is always alpha.</p> 952 * 953 * @param components The components of the color to create, with alpha as the last component 954 * @param colorSpace The color space of the color to create 955 * @return A non-null instance of {@link Color} 956 * 957 * @throws IllegalArgumentException If the array of components is smaller than 958 * required by the color space 959 */ 960 @NonNull valueOf(@onNull @izemin = 4, max = 5) float[] components, @NonNull ColorSpace colorSpace)961 public static Color valueOf(@NonNull @Size(min = 4, max = 5) float[] components, 962 @NonNull ColorSpace colorSpace) { 963 if (components.length < colorSpace.getComponentCount() + 1) { 964 throw new IllegalArgumentException("Received a component array of length " + 965 components.length + " but the color model requires " + 966 (colorSpace.getComponentCount() + 1) + " (including alpha)"); 967 } 968 return new Color(Arrays.copyOf(components, colorSpace.getComponentCount() + 1), colorSpace); 969 } 970 971 /** 972 * Converts the specified ARGB color int to an RGBA color long in the sRGB 973 * color space. See the documentation of this class for a description of 974 * the color long format. 975 * 976 * @param color The ARGB color int to convert to an RGBA color long in sRGB 977 * 978 * @return A color long 979 */ 980 @ColorLong pack(@olorInt int color)981 public static long pack(@ColorInt int color) { 982 return (color & 0xffffffffL) << 32; 983 } 984 985 /** 986 * Packs the sRGB color defined by the specified red, green and blue component 987 * values into an RGBA color long in the sRGB color space. The alpha component 988 * is set to 1.0. See the documentation of this class for a description of the 989 * color long format. 990 * 991 * @param red The red component of the sRGB color to create, in \([0..1]\) 992 * @param green The green component of the sRGB color to create, in \([0..1]\) 993 * @param blue The blue component of the sRGB color to create, in \([0..1]\) 994 * 995 * @return A color long 996 */ 997 @ColorLong pack(float red, float green, float blue)998 public static long pack(float red, float green, float blue) { 999 return pack(red, green, blue, 1.0f, ColorSpace.get(ColorSpace.Named.SRGB)); 1000 } 1001 1002 /** 1003 * Packs the sRGB color defined by the specified red, green, blue and alpha 1004 * component values into an RGBA color long in the sRGB color space. See the 1005 * documentation of this class for a description of the color long format. 1006 * 1007 * @param red The red component of the sRGB color to create, in \([0..1]\) 1008 * @param green The green component of the sRGB color to create, in \([0..1]\) 1009 * @param blue The blue component of the sRGB color to create, in \([0..1]\) 1010 * @param alpha The alpha component of the sRGB color to create, in \([0..1]\) 1011 * 1012 * @return A color long 1013 */ 1014 @ColorLong pack(float red, float green, float blue, float alpha)1015 public static long pack(float red, float green, float blue, float alpha) { 1016 return pack(red, green, blue, alpha, ColorSpace.get(ColorSpace.Named.SRGB)); 1017 } 1018 1019 /** 1020 * <p>Packs the 3 component color defined by the specified red, green, blue and 1021 * alpha component values into a color long in the specified color space. See the 1022 * documentation of this class for a description of the color long format.</p> 1023 * 1024 * <p>The red, green and blue components must be in the range defined by the 1025 * specified color space. See {@link ColorSpace#getMinValue(int)} and 1026 * {@link ColorSpace#getMaxValue(int)}.</p> 1027 * 1028 * @param red The red component of the color to create 1029 * @param green The green component of the color to create 1030 * @param blue The blue component of the color to create 1031 * @param alpha The alpha component of the color to create, in \([0..1]\) 1032 * 1033 * @return A color long 1034 * 1035 * @throws IllegalArgumentException If the color space's id is {@link ColorSpace#MIN_ID} 1036 * or if the color space's color model has more than 3 components 1037 */ 1038 @ColorLong pack(float red, float green, float blue, float alpha, @NonNull ColorSpace colorSpace)1039 public static long pack(float red, float green, float blue, float alpha, 1040 @NonNull ColorSpace colorSpace) { 1041 if (colorSpace.isSrgb()) { 1042 int argb = 1043 ((int) (alpha * 255.0f + 0.5f) << 24) | 1044 ((int) (red * 255.0f + 0.5f) << 16) | 1045 ((int) (green * 255.0f + 0.5f) << 8) | 1046 (int) (blue * 255.0f + 0.5f); 1047 return (argb & 0xffffffffL) << 32; 1048 } 1049 1050 int id = colorSpace.getId(); 1051 if (id == ColorSpace.MIN_ID) { 1052 throw new IllegalArgumentException( 1053 "Unknown color space, please use a color space returned by ColorSpace.get()"); 1054 } 1055 if (colorSpace.getComponentCount() > 3) { 1056 throw new IllegalArgumentException( 1057 "The color space must use a color model with at most 3 components"); 1058 } 1059 1060 @HalfFloat short r = Half.toHalf(red); 1061 @HalfFloat short g = Half.toHalf(green); 1062 @HalfFloat short b = Half.toHalf(blue); 1063 1064 int a = (int) (Math.max(0.0f, Math.min(alpha, 1.0f)) * 1023.0f + 0.5f); 1065 1066 // Suppress sign extension 1067 return (r & 0xffffL) << 48 | 1068 (g & 0xffffL) << 32 | 1069 (b & 0xffffL) << 16 | 1070 (a & 0x3ffL ) << 6 | 1071 id & 0x3fL; 1072 } 1073 1074 /** 1075 * Converts the specified ARGB color int from the {@link ColorSpace.Named#SRGB sRGB} 1076 * color space into the specified destination color space. The resulting color is 1077 * returned as a color long. See the documentation of this class for a description 1078 * of the color long format. 1079 * 1080 * @param color The sRGB color int to convert 1081 * @param colorSpace The destination color space 1082 * @return A color long in the destination color space 1083 */ 1084 @ColorLong convert(@olorInt int color, @NonNull ColorSpace colorSpace)1085 public static long convert(@ColorInt int color, @NonNull ColorSpace colorSpace) { 1086 float r = ((color >> 16) & 0xff) / 255.0f; 1087 float g = ((color >> 8) & 0xff) / 255.0f; 1088 float b = ((color ) & 0xff) / 255.0f; 1089 float a = ((color >> 24) & 0xff) / 255.0f; 1090 ColorSpace source = ColorSpace.get(ColorSpace.Named.SRGB); 1091 return convert(r, g, b, a, source, colorSpace); 1092 } 1093 1094 /** 1095 * <p>Converts the specified color long from its color space into the specified 1096 * destination color space. The resulting color is returned as a color long. See 1097 * the documentation of this class for a description of the color long format.</p> 1098 * 1099 * <p>When converting several colors in a row, it is recommended to use 1100 * {@link #convert(long, ColorSpace.Connector)} instead to 1101 * avoid the creation of a {@link ColorSpace.Connector} on every invocation.</p> 1102 * 1103 * @param color The color long to convert 1104 * @param colorSpace The destination color space 1105 * @return A color long in the destination color space 1106 * @throws IllegalArgumentException If the encoded color space is invalid or unknown 1107 */ 1108 @ColorLong convert(@olorLong long color, @NonNull ColorSpace colorSpace)1109 public static long convert(@ColorLong long color, @NonNull ColorSpace colorSpace) { 1110 float r = red(color); 1111 float g = green(color); 1112 float b = blue(color); 1113 float a = alpha(color); 1114 ColorSpace source = colorSpace(color); 1115 return convert(r, g, b, a, source, colorSpace); 1116 } 1117 1118 /** 1119 * <p>Converts the specified 3 component color from the source color space to the 1120 * destination color space. The resulting color is returned as a color long. See 1121 * the documentation of this class for a description of the color long format.</p> 1122 * 1123 * <p>When converting multiple colors in a row, it is recommended to use 1124 * {@link #convert(float, float, float, float, ColorSpace.Connector)} instead to 1125 * avoid the creation of a {@link ColorSpace.Connector} on every invocation.</p> 1126 * 1127 * <p>The red, green and blue components must be in the range defined by the 1128 * specified color space. See {@link ColorSpace#getMinValue(int)} and 1129 * {@link ColorSpace#getMaxValue(int)}.</p> 1130 * 1131 * @param r The red component of the color to convert 1132 * @param g The green component of the color to convert 1133 * @param b The blue component of the color to convert 1134 * @param a The alpha component of the color to convert, in \([0..1]\) 1135 * @param source The source color space, cannot be null 1136 * @param destination The destination color space, cannot be null 1137 * @return A color long in the destination color space 1138 * 1139 * @see #convert(float, float, float, float, ColorSpace.Connector) 1140 */ 1141 @ColorLong convert(float r, float g, float b, float a, @NonNull ColorSpace source, @NonNull ColorSpace destination)1142 public static long convert(float r, float g, float b, float a, 1143 @NonNull ColorSpace source, @NonNull ColorSpace destination) { 1144 float[] c = ColorSpace.connect(source, destination).transform(r, g, b); 1145 return pack(c[0], c[1], c[2], a, destination); 1146 } 1147 1148 /** 1149 * <p>Converts the specified color long from a color space to another using the 1150 * specified color space {@link ColorSpace.Connector connector}. The resulting 1151 * color is returned as a color long. See the documentation of this class for a 1152 * description of the color long format.</p> 1153 * 1154 * <p>When converting several colors in a row, this method is preferable to 1155 * {@link #convert(long, ColorSpace)} as it prevents a new connector from being 1156 * created on every invocation.</p> 1157 * 1158 * <p class="note">The connector's source color space should match the color long's 1159 * color space.</p> 1160 * 1161 * @param color The color long to convert 1162 * @param connector A color space connector, cannot be null 1163 * @return A color long in the destination color space of the connector 1164 */ 1165 @ColorLong convert(@olorLong long color, @NonNull ColorSpace.Connector connector)1166 public static long convert(@ColorLong long color, @NonNull ColorSpace.Connector connector) { 1167 float r = red(color); 1168 float g = green(color); 1169 float b = blue(color); 1170 float a = alpha(color); 1171 return convert(r, g, b, a, connector); 1172 } 1173 1174 /** 1175 * <p>Converts the specified 3 component color from a color space to another using 1176 * the specified color space {@link ColorSpace.Connector connector}. The resulting 1177 * color is returned as a color long. See the documentation of this class for a 1178 * description of the color long format.</p> 1179 * 1180 * <p>When converting several colors in a row, this method is preferable to 1181 * {@link #convert(float, float, float, float, ColorSpace, ColorSpace)} as 1182 * it prevents a new connector from being created on every invocation.</p> 1183 * 1184 * <p>The red, green and blue components must be in the range defined by the 1185 * source color space of the connector. See {@link ColorSpace#getMinValue(int)} 1186 * and {@link ColorSpace#getMaxValue(int)}.</p> 1187 * 1188 * @param r The red component of the color to convert 1189 * @param g The green component of the color to convert 1190 * @param b The blue component of the color to convert 1191 * @param a The alpha component of the color to convert, in \([0..1]\) 1192 * @param connector A color space connector, cannot be null 1193 * @return A color long in the destination color space of the connector 1194 * 1195 * @see #convert(float, float, float, float, ColorSpace, ColorSpace) 1196 */ 1197 @ColorLong convert(float r, float g, float b, float a, @NonNull ColorSpace.Connector connector)1198 public static long convert(float r, float g, float b, float a, 1199 @NonNull ColorSpace.Connector connector) { 1200 float[] c = connector.transform(r, g, b); 1201 return pack(c[0], c[1], c[2], a, connector.getDestination()); 1202 } 1203 1204 /** 1205 * <p>Returns the relative luminance of a color.</p> 1206 * 1207 * <p>Based on the formula for relative luminance defined in WCAG 2.0, 1208 * W3C Recommendation 11 December 2008.</p> 1209 * 1210 * @return A value between 0 (darkest black) and 1 (lightest white) 1211 * 1212 * @throws IllegalArgumentException If the specified color's color space 1213 * is unknown or does not use the {@link ColorSpace.Model#RGB RGB} color model 1214 */ luminance(@olorLong long color)1215 public static float luminance(@ColorLong long color) { 1216 ColorSpace colorSpace = colorSpace(color); 1217 if (colorSpace.getModel() != ColorSpace.Model.RGB) { 1218 throw new IllegalArgumentException("The specified color must be encoded in an RGB " + 1219 "color space. The supplied color space is " + colorSpace.getModel()); 1220 } 1221 1222 DoubleUnaryOperator eotf = ((ColorSpace.Rgb) colorSpace).getEotf(); 1223 double r = eotf.applyAsDouble(red(color)); 1224 double g = eotf.applyAsDouble(green(color)); 1225 double b = eotf.applyAsDouble(blue(color)); 1226 1227 return saturate((float) ((0.2126 * r) + (0.7152 * g) + (0.0722 * b))); 1228 } 1229 saturate(float v)1230 private static float saturate(float v) { 1231 return v <= 0.0f ? 0.0f : (v >= 1.0f ? 1.0f : v); 1232 } 1233 1234 /** 1235 * Return the alpha component of a color int. This is the same as saying 1236 * color >>> 24 1237 */ 1238 @IntRange(from = 0, to = 255) alpha(int color)1239 public static int alpha(int color) { 1240 return color >>> 24; 1241 } 1242 1243 /** 1244 * Return the red component of a color int. This is the same as saying 1245 * (color >> 16) & 0xFF 1246 */ 1247 @IntRange(from = 0, to = 255) red(int color)1248 public static int red(int color) { 1249 return (color >> 16) & 0xFF; 1250 } 1251 1252 /** 1253 * Return the green component of a color int. This is the same as saying 1254 * (color >> 8) & 0xFF 1255 */ 1256 @IntRange(from = 0, to = 255) green(int color)1257 public static int green(int color) { 1258 return (color >> 8) & 0xFF; 1259 } 1260 1261 /** 1262 * Return the blue component of a color int. This is the same as saying 1263 * color & 0xFF 1264 */ 1265 @IntRange(from = 0, to = 255) blue(int color)1266 public static int blue(int color) { 1267 return color & 0xFF; 1268 } 1269 1270 /** 1271 * Return a color-int from red, green, blue components. 1272 * The alpha component is implicitly 255 (fully opaque). 1273 * These component values should be \([0..255]\), but there is no 1274 * range check performed, so if they are out of range, the 1275 * returned color is undefined. 1276 * 1277 * @param red Red component \([0..255]\) of the color 1278 * @param green Green component \([0..255]\) of the color 1279 * @param blue Blue component \([0..255]\) of the color 1280 */ 1281 @ColorInt rgb( @ntRangefrom = 0, to = 255) int red, @IntRange(from = 0, to = 255) int green, @IntRange(from = 0, to = 255) int blue)1282 public static int rgb( 1283 @IntRange(from = 0, to = 255) int red, 1284 @IntRange(from = 0, to = 255) int green, 1285 @IntRange(from = 0, to = 255) int blue) { 1286 return 0xff000000 | (red << 16) | (green << 8) | blue; 1287 } 1288 1289 /** 1290 * Return a color-int from red, green, blue float components 1291 * in the range \([0..1]\). The alpha component is implicitly 1292 * 1.0 (fully opaque). If the components are out of range, the 1293 * returned color is undefined. 1294 * 1295 * @param red Red component \([0..1]\) of the color 1296 * @param green Green component \([0..1]\) of the color 1297 * @param blue Blue component \([0..1]\) of the color 1298 */ 1299 @ColorInt rgb(float red, float green, float blue)1300 public static int rgb(float red, float green, float blue) { 1301 return 0xff000000 | 1302 ((int) (red * 255.0f + 0.5f) << 16) | 1303 ((int) (green * 255.0f + 0.5f) << 8) | 1304 (int) (blue * 255.0f + 0.5f); 1305 } 1306 1307 /** 1308 * Return a color-int from alpha, red, green, blue components. 1309 * These component values should be \([0..255]\), but there is no 1310 * range check performed, so if they are out of range, the 1311 * returned color is undefined. 1312 * @param alpha Alpha component \([0..255]\) of the color 1313 * @param red Red component \([0..255]\) of the color 1314 * @param green Green component \([0..255]\) of the color 1315 * @param blue Blue component \([0..255]\) of the color 1316 */ 1317 @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)1318 public static int argb( 1319 @IntRange(from = 0, to = 255) int alpha, 1320 @IntRange(from = 0, to = 255) int red, 1321 @IntRange(from = 0, to = 255) int green, 1322 @IntRange(from = 0, to = 255) int blue) { 1323 return (alpha << 24) | (red << 16) | (green << 8) | blue; 1324 } 1325 1326 /** 1327 * Return a color-int from alpha, red, green, blue float components 1328 * in the range \([0..1]\). If the components are out of range, the 1329 * returned color is undefined. 1330 * 1331 * @param alpha Alpha component \([0..1]\) of the color 1332 * @param red Red component \([0..1]\) of the color 1333 * @param green Green component \([0..1]\) of the color 1334 * @param blue Blue component \([0..1]\) of the color 1335 */ 1336 @ColorInt argb(float alpha, float red, float green, float blue)1337 public static int argb(float alpha, float red, float green, float blue) { 1338 return ((int) (alpha * 255.0f + 0.5f) << 24) | 1339 ((int) (red * 255.0f + 0.5f) << 16) | 1340 ((int) (green * 255.0f + 0.5f) << 8) | 1341 (int) (blue * 255.0f + 0.5f); 1342 } 1343 1344 /** 1345 * Returns the relative luminance of a color. 1346 * <p> 1347 * Assumes sRGB encoding. Based on the formula for relative luminance 1348 * defined in WCAG 2.0, W3C Recommendation 11 December 2008. 1349 * 1350 * @return a value between 0 (darkest black) and 1 (lightest white) 1351 */ luminance(@olorInt int color)1352 public static float luminance(@ColorInt int color) { 1353 ColorSpace.Rgb cs = (ColorSpace.Rgb) ColorSpace.get(ColorSpace.Named.SRGB); 1354 DoubleUnaryOperator eotf = cs.getEotf(); 1355 1356 double r = eotf.applyAsDouble(red(color) / 255.0); 1357 double g = eotf.applyAsDouble(green(color) / 255.0); 1358 double b = eotf.applyAsDouble(blue(color) / 255.0); 1359 1360 return (float) ((0.2126 * r) + (0.7152 * g) + (0.0722 * b)); 1361 } 1362 1363 /** 1364 * </p>Parse the color string, and return the corresponding color-int. 1365 * If the string cannot be parsed, throws an IllegalArgumentException 1366 * exception. Supported formats are:</p> 1367 * 1368 * <ul> 1369 * <li><code>#RRGGBB</code></li> 1370 * <li><code>#AARRGGBB</code></li> 1371 * </ul> 1372 * 1373 * <p>The following names are also accepted: <code>red</code>, <code>blue</code>, 1374 * <code>green</code>, <code>black</code>, <code>white</code>, <code>gray</code>, 1375 * <code>cyan</code>, <code>magenta</code>, <code>yellow</code>, <code>lightgray</code>, 1376 * <code>darkgray</code>, <code>grey</code>, <code>lightgrey</code>, <code>darkgrey</code>, 1377 * <code>aqua</code>, <code>fuchsia</code>, <code>lime</code>, <code>maroon</code>, 1378 * <code>navy</code>, <code>olive</code>, <code>purple</code>, <code>silver</code>, 1379 * and <code>teal</code>.</p> 1380 */ 1381 @ColorInt parseColor(@izemin=1) String colorString)1382 public static int parseColor(@Size(min=1) String colorString) { 1383 if (colorString.charAt(0) == '#') { 1384 // Use a long to avoid rollovers on #ffXXXXXX 1385 long color = Long.parseLong(colorString.substring(1), 16); 1386 if (colorString.length() == 7) { 1387 // Set the alpha value 1388 color |= 0x00000000ff000000; 1389 } else if (colorString.length() != 9) { 1390 throw new IllegalArgumentException("Unknown color"); 1391 } 1392 return (int)color; 1393 } else { 1394 Integer color = sColorNameMap.get(colorString.toLowerCase(Locale.ROOT)); 1395 if (color != null) { 1396 return color; 1397 } 1398 } 1399 throw new IllegalArgumentException("Unknown color"); 1400 } 1401 1402 /** 1403 * Convert RGB components to HSV. 1404 * <ul> 1405 * <li><code>hsv[0]</code> is Hue \([0..360[\)</li> 1406 * <li><code>hsv[1]</code> is Saturation \([0...1]\)</li> 1407 * <li><code>hsv[2]</code> is Value \([0...1]\)</li> 1408 * </ul> 1409 * @param red red component value \([0..255]\) 1410 * @param green green component value \([0..255]\) 1411 * @param blue blue component value \([0..255]\) 1412 * @param hsv 3 element array which holds the resulting HSV components. 1413 */ 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[])1414 public static void RGBToHSV( 1415 @IntRange(from = 0, to = 255) int red, 1416 @IntRange(from = 0, to = 255) int green, 1417 @IntRange(from = 0, to = 255) int blue, @Size(3) float hsv[]) { 1418 if (hsv.length < 3) { 1419 throw new RuntimeException("3 components required for hsv"); 1420 } 1421 nativeRGBToHSV(red, green, blue, hsv); 1422 } 1423 1424 /** 1425 * Convert the ARGB color to its HSV components. 1426 * <ul> 1427 * <li><code>hsv[0]</code> is Hue \([0..360[\)</li> 1428 * <li><code>hsv[1]</code> is Saturation \([0...1]\)</li> 1429 * <li><code>hsv[2]</code> is Value \([0...1]\)</li> 1430 * </ul> 1431 * @param color the argb color to convert. The alpha component is ignored. 1432 * @param hsv 3 element array which holds the resulting HSV components. 1433 */ colorToHSV(@olorInt int color, @Size(3) float hsv[])1434 public static void colorToHSV(@ColorInt int color, @Size(3) float hsv[]) { 1435 RGBToHSV((color >> 16) & 0xFF, (color >> 8) & 0xFF, color & 0xFF, hsv); 1436 } 1437 1438 /** 1439 * Convert HSV components to an ARGB color. Alpha set to 0xFF. 1440 * <ul> 1441 * <li><code>hsv[0]</code> is Hue \([0..360[\)</li> 1442 * <li><code>hsv[1]</code> is Saturation \([0...1]\)</li> 1443 * <li><code>hsv[2]</code> is Value \([0...1]\)</li> 1444 * </ul> 1445 * If hsv values are out of range, they are pinned. 1446 * @param hsv 3 element array which holds the input HSV components. 1447 * @return the resulting argb color 1448 */ 1449 @ColorInt HSVToColor(@ize3) float hsv[])1450 public static int HSVToColor(@Size(3) float hsv[]) { 1451 return HSVToColor(0xFF, hsv); 1452 } 1453 1454 /** 1455 * Convert HSV components to an ARGB color. The alpha component is passed 1456 * through unchanged. 1457 * <ul> 1458 * <li><code>hsv[0]</code> is Hue \([0..360[\)</li> 1459 * <li><code>hsv[1]</code> is Saturation \([0...1]\)</li> 1460 * <li><code>hsv[2]</code> is Value \([0...1]\)</li> 1461 * </ul> 1462 * If hsv values are out of range, they are pinned. 1463 * @param alpha the alpha component of the returned argb color. 1464 * @param hsv 3 element array which holds the input HSV components. 1465 * @return the resulting argb color 1466 */ 1467 @ColorInt HSVToColor(@ntRangefrom = 0, to = 255) int alpha, @Size(3) float hsv[])1468 public static int HSVToColor(@IntRange(from = 0, to = 255) int alpha, @Size(3) float hsv[]) { 1469 if (hsv.length < 3) { 1470 throw new RuntimeException("3 components required for hsv"); 1471 } 1472 return nativeHSVToColor(alpha, hsv); 1473 } 1474 nativeRGBToHSV(int red, int greed, int blue, float hsv[])1475 private static native void nativeRGBToHSV(int red, int greed, int blue, float hsv[]); nativeHSVToColor(int alpha, float hsv[])1476 private static native int nativeHSVToColor(int alpha, float hsv[]); 1477 1478 private static final HashMap<String, Integer> sColorNameMap; 1479 static { 1480 sColorNameMap = new HashMap<>(); 1481 sColorNameMap.put("black", BLACK); 1482 sColorNameMap.put("darkgray", DKGRAY); 1483 sColorNameMap.put("gray", GRAY); 1484 sColorNameMap.put("lightgray", LTGRAY); 1485 sColorNameMap.put("white", WHITE); 1486 sColorNameMap.put("red", RED); 1487 sColorNameMap.put("green", GREEN); 1488 sColorNameMap.put("blue", BLUE); 1489 sColorNameMap.put("yellow", YELLOW); 1490 sColorNameMap.put("cyan", CYAN); 1491 sColorNameMap.put("magenta", MAGENTA); 1492 sColorNameMap.put("aqua", 0xFF00FFFF); 1493 sColorNameMap.put("fuchsia", 0xFFFF00FF); 1494 sColorNameMap.put("darkgrey", DKGRAY); 1495 sColorNameMap.put("grey", GRAY); 1496 sColorNameMap.put("lightgrey", LTGRAY); 1497 sColorNameMap.put("lime", 0xFF00FF00); 1498 sColorNameMap.put("maroon", 0xFF800000); 1499 sColorNameMap.put("navy", 0xFF000080); 1500 sColorNameMap.put("olive", 0xFF808000); 1501 sColorNameMap.put("purple", 0xFF800080); 1502 sColorNameMap.put("silver", 0xFFC0C0C0); 1503 sColorNameMap.put("teal", 0xFF008080); 1504 1505 } 1506 } 1507