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