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