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