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