• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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