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