Color.java revision 80756e38882720860db52f1fcc21fa1505a02abf
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.ColorInt;
20import android.util.MathUtils;
21import com.android.internal.util.XmlUtils;
22
23import java.util.HashMap;
24import java.util.Locale;
25
26/**
27 * The Color class defines methods for creating and converting color ints.
28 * Colors are represented as packed ints, made up of 4 bytes: alpha, red,
29 * green, blue. The values are unpremultiplied, meaning any transparency is
30 * stored solely in the alpha component, and not in the color components. The
31 * components are stored as follows (alpha << 24) | (red << 16) |
32 * (green << 8) | blue. Each component ranges between 0..255 with 0
33 * meaning no contribution for that component, and 255 meaning 100%
34 * contribution. Thus opaque-black would be 0xFF000000 (100% opaque but
35 * no contributions from red, green, or blue), and opaque-white would be
36 * 0xFFFFFFFF
37 */
38public class Color {
39    @ColorInt public static final int BLACK       = 0xFF000000;
40    @ColorInt public static final int DKGRAY      = 0xFF444444;
41    @ColorInt public static final int GRAY        = 0xFF888888;
42    @ColorInt public static final int LTGRAY      = 0xFFCCCCCC;
43    @ColorInt public static final int WHITE       = 0xFFFFFFFF;
44    @ColorInt public static final int RED         = 0xFFFF0000;
45    @ColorInt public static final int GREEN       = 0xFF00FF00;
46    @ColorInt public static final int BLUE        = 0xFF0000FF;
47    @ColorInt public static final int YELLOW      = 0xFFFFFF00;
48    @ColorInt public static final int CYAN        = 0xFF00FFFF;
49    @ColorInt public static final int MAGENTA     = 0xFFFF00FF;
50    @ColorInt public static final int TRANSPARENT = 0;
51
52    /**
53     * Return the alpha component of a color int. This is the same as saying
54     * color >>> 24
55     */
56    @ColorInt
57    public static int alpha(int color) {
58        return color >>> 24;
59    }
60
61    /**
62     * Return the red component of a color int. This is the same as saying
63     * (color >> 16) & 0xFF
64     */
65    @ColorInt
66    public static int red(int color) {
67        return (color >> 16) & 0xFF;
68    }
69
70    /**
71     * Return the green component of a color int. This is the same as saying
72     * (color >> 8) & 0xFF
73     */
74    @ColorInt
75    public static int green(int color) {
76        return (color >> 8) & 0xFF;
77    }
78
79    /**
80     * Return the blue component of a color int. This is the same as saying
81     * color & 0xFF
82     */
83    @ColorInt
84    public static int blue(int color) {
85        return color & 0xFF;
86    }
87
88    /**
89     * Return a color-int from red, green, blue components.
90     * The alpha component is implicity 255 (fully opaque).
91     * These component values should be [0..255], but there is no
92     * range check performed, so if they are out of range, the
93     * returned color is undefined.
94     * @param red  Red component [0..255] of the color
95     * @param green Green component [0..255] of the color
96     * @param blue  Blue component [0..255] of the color
97     */
98    @ColorInt
99    public static int rgb(int red, int green, int blue) {
100        return (0xFF << 24) | (red << 16) | (green << 8) | blue;
101    }
102
103    /**
104     * Return a color-int from alpha, red, green, blue components.
105     * These component values should be [0..255], but there is no
106     * range check performed, so if they are out of range, the
107     * returned color is undefined.
108     * @param alpha Alpha component [0..255] of the color
109     * @param red   Red component [0..255] of the color
110     * @param green Green component [0..255] of the color
111     * @param blue  Blue component [0..255] of the color
112     */
113    @ColorInt
114    public static int argb(int alpha, int red, int green, int blue) {
115        return (alpha << 24) | (red << 16) | (green << 8) | blue;
116    }
117
118    /**
119     * Returns the hue component of a color int.
120     *
121     * @return A value between 0.0f and 1.0f
122     *
123     * @hide Pending API council
124     */
125    public static float hue(@ColorInt int color) {
126        int r = (color >> 16) & 0xFF;
127        int g = (color >> 8) & 0xFF;
128        int b = color & 0xFF;
129
130        int V = Math.max(b, Math.max(r, g));
131        int temp = Math.min(b, Math.min(r, g));
132
133        float H;
134
135        if (V == temp) {
136            H = 0;
137        } else {
138            final float vtemp = (float) (V - temp);
139            final float cr = (V - r) / vtemp;
140            final float cg = (V - g) / vtemp;
141            final float cb = (V - b) / vtemp;
142
143            if (r == V) {
144                H = cb - cg;
145            } else if (g == V) {
146                H = 2 + cr - cb;
147            } else {
148                H = 4 + cg - cr;
149            }
150
151            H /= 6.f;
152            if (H < 0) {
153                H++;
154            }
155        }
156
157        return H;
158    }
159
160    /**
161     * Returns the saturation component of a color int.
162     *
163     * @return A value between 0.0f and 1.0f
164     *
165     * @hide Pending API council
166     */
167    public static float saturation(@ColorInt int color) {
168        int r = (color >> 16) & 0xFF;
169        int g = (color >> 8) & 0xFF;
170        int b = color & 0xFF;
171
172
173        int V = Math.max(b, Math.max(r, g));
174        int temp = Math.min(b, Math.min(r, g));
175
176        float S;
177
178        if (V == temp) {
179            S = 0;
180        } else {
181            S = (V - temp) / (float) V;
182        }
183
184        return S;
185    }
186
187    /**
188     * Returns the brightness component of a color int.
189     *
190     * @return A value between 0.0f and 1.0f
191     *
192     * @hide Pending API council
193     */
194    public static float brightness(@ColorInt int color) {
195        int r = (color >> 16) & 0xFF;
196        int g = (color >> 8) & 0xFF;
197        int b = color & 0xFF;
198
199        int V = Math.max(b, Math.max(r, g));
200
201        return (V / 255.f);
202    }
203
204    /**
205     * Parse the color string, and return the corresponding color-int.
206     * If the string cannot be parsed, throws an IllegalArgumentException
207     * exception. Supported formats are:
208     * #RRGGBB
209     * #AARRGGBB
210     * or one of the following names:
211     * 'red', 'blue', 'green', 'black', 'white', 'gray', 'cyan', 'magenta',
212     * 'yellow', 'lightgray', 'darkgray', 'grey', 'lightgrey', 'darkgrey',
213     * 'aqua', 'fuchsia', 'lime', 'maroon', 'navy', 'olive', 'purple',
214     * 'silver', 'teal'.
215     */
216    @ColorInt
217    public static int parseColor(String colorString) {
218        if (colorString.charAt(0) == '#') {
219            // Use a long to avoid rollovers on #ffXXXXXX
220            long color = Long.parseLong(colorString.substring(1), 16);
221            if (colorString.length() == 7) {
222                // Set the alpha value
223                color |= 0x00000000ff000000;
224            } else if (colorString.length() != 9) {
225                throw new IllegalArgumentException("Unknown color");
226            }
227            return (int)color;
228        } else {
229            Integer color = sColorNameMap.get(colorString.toLowerCase(Locale.ROOT));
230            if (color != null) {
231                return color;
232            }
233        }
234        throw new IllegalArgumentException("Unknown color");
235    }
236
237    /**
238     * Convert HSB components to an ARGB color. Alpha set to 0xFF.
239     *     hsv[0] is Hue [0 .. 1)
240     *     hsv[1] is Saturation [0...1]
241     *     hsv[2] is Value [0...1]
242     * If hsv values are out of range, they are pinned.
243     * @param hsb  3 element array which holds the input HSB components.
244     * @return the resulting argb color
245     *
246     * @hide Pending API council
247     */
248    @ColorInt
249    public static int HSBtoColor(float[] hsb) {
250        return HSBtoColor(hsb[0], hsb[1], hsb[2]);
251    }
252
253    /**
254     * Convert HSB components to an ARGB color. Alpha set to 0xFF.
255     *     hsv[0] is Hue [0 .. 1)
256     *     hsv[1] is Saturation [0...1]
257     *     hsv[2] is Value [0...1]
258     * If hsv values are out of range, they are pinned.
259     * @param h Hue component
260     * @param s Saturation component
261     * @param b Brightness component
262     * @return the resulting argb color
263     *
264     * @hide Pending API council
265     */
266    @ColorInt
267    public static int HSBtoColor(float h, float s, float b) {
268        h = MathUtils.constrain(h, 0.0f, 1.0f);
269        s = MathUtils.constrain(s, 0.0f, 1.0f);
270        b = MathUtils.constrain(b, 0.0f, 1.0f);
271
272        float red = 0.0f;
273        float green = 0.0f;
274        float blue = 0.0f;
275
276        final float hf = (h - (int) h) * 6.0f;
277        final int ihf = (int) hf;
278        final float f = hf - ihf;
279        final float pv = b * (1.0f - s);
280        final float qv = b * (1.0f - s * f);
281        final float tv = b * (1.0f - s * (1.0f - f));
282
283        switch (ihf) {
284            case 0:         // Red is the dominant color
285                red = b;
286                green = tv;
287                blue = pv;
288                break;
289            case 1:         // Green is the dominant color
290                red = qv;
291                green = b;
292                blue = pv;
293                break;
294            case 2:
295                red = pv;
296                green = b;
297                blue = tv;
298                break;
299            case 3:         // Blue is the dominant color
300                red = pv;
301                green = qv;
302                blue = b;
303                break;
304            case 4:
305                red = tv;
306                green = pv;
307                blue = b;
308                break;
309            case 5:         // Red is the dominant color
310                red = b;
311                green = pv;
312                blue = qv;
313                break;
314        }
315
316        return 0xFF000000 | (((int) (red * 255.0f)) << 16) |
317                (((int) (green * 255.0f)) << 8) | ((int) (blue * 255.0f));
318    }
319
320    /**
321     * Convert RGB components to HSV.
322     *     hsv[0] is Hue [0 .. 360)
323     *     hsv[1] is Saturation [0...1]
324     *     hsv[2] is Value [0...1]
325     * @param red  red component value [0..255]
326     * @param green  green component value [0..255]
327     * @param blue  blue component value [0..255]
328     * @param hsv  3 element array which holds the resulting HSV components.
329     */
330    public static void RGBToHSV(int red, int green, int blue, float hsv[]) {
331        if (hsv.length < 3) {
332            throw new RuntimeException("3 components required for hsv");
333        }
334        nativeRGBToHSV(red, green, blue, hsv);
335    }
336
337    /**
338     * Convert the argb color to its HSV components.
339     *     hsv[0] is Hue [0 .. 360)
340     *     hsv[1] is Saturation [0...1]
341     *     hsv[2] is Value [0...1]
342     * @param color the argb color to convert. The alpha component is ignored.
343     * @param hsv  3 element array which holds the resulting HSV components.
344     */
345    public static void colorToHSV(@ColorInt int color, float hsv[]) {
346        RGBToHSV((color >> 16) & 0xFF, (color >> 8) & 0xFF, color & 0xFF, hsv);
347    }
348
349    /**
350     * Convert HSV components to an ARGB color. Alpha set to 0xFF.
351     *     hsv[0] is Hue [0 .. 360)
352     *     hsv[1] is Saturation [0...1]
353     *     hsv[2] is Value [0...1]
354     * If hsv values are out of range, they are pinned.
355     * @param hsv  3 element array which holds the input HSV components.
356     * @return the resulting argb color
357    */
358    public static int HSVToColor(float hsv[]) {
359        return HSVToColor(0xFF, hsv);
360    }
361
362    /**
363     * Convert HSV components to an ARGB color. The alpha component is passed
364     * through unchanged.
365     *     hsv[0] is Hue [0 .. 360)
366     *     hsv[1] is Saturation [0...1]
367     *     hsv[2] is Value [0...1]
368     * If hsv values are out of range, they are pinned.
369     * @param alpha the alpha component of the returned argb color.
370     * @param hsv  3 element array which holds the input HSV components.
371     * @return the resulting argb color
372    */
373    public static int HSVToColor(int alpha, float hsv[]) {
374        if (hsv.length < 3) {
375            throw new RuntimeException("3 components required for hsv");
376        }
377        return nativeHSVToColor(alpha, hsv);
378    }
379
380    private static native void nativeRGBToHSV(int red, int greed, int blue, float hsv[]);
381    private static native int nativeHSVToColor(int alpha, float hsv[]);
382
383    /**
384     * Converts an HTML color (named or numeric) to an integer RGB value.
385     *
386     * @param color Non-null color string.
387     *
388     * @return A color value, or {@code -1} if the color string could not be interpreted.
389     *
390     * @hide
391     */
392    @ColorInt
393    public static int getHtmlColor(String color) {
394        Integer i = sColorNameMap.get(color.toLowerCase(Locale.ROOT));
395        if (i != null) {
396            return i;
397        } else {
398            try {
399                return XmlUtils.convertValueToInt(color, -1);
400            } catch (NumberFormatException nfe) {
401                return -1;
402            }
403        }
404    }
405
406    private static final HashMap<String, Integer> sColorNameMap;
407
408    static {
409        sColorNameMap = new HashMap<String, Integer>();
410        sColorNameMap.put("black", BLACK);
411        sColorNameMap.put("darkgray", DKGRAY);
412        sColorNameMap.put("gray", GRAY);
413        sColorNameMap.put("lightgray", LTGRAY);
414        sColorNameMap.put("white", WHITE);
415        sColorNameMap.put("red", RED);
416        sColorNameMap.put("green", GREEN);
417        sColorNameMap.put("blue", BLUE);
418        sColorNameMap.put("yellow", YELLOW);
419        sColorNameMap.put("cyan", CYAN);
420        sColorNameMap.put("magenta", MAGENTA);
421        sColorNameMap.put("aqua", 0xFF00FFFF);
422        sColorNameMap.put("fuchsia", 0xFFFF00FF);
423        sColorNameMap.put("darkgrey", DKGRAY);
424        sColorNameMap.put("grey", GRAY);
425        sColorNameMap.put("lightgrey", LTGRAY);
426        sColorNameMap.put("lime", 0xFF00FF00);
427        sColorNameMap.put("maroon", 0xFF800000);
428        sColorNameMap.put("navy", 0xFF000080);
429        sColorNameMap.put("olive", 0xFF808000);
430        sColorNameMap.put("purple", 0xFF800080);
431        sColorNameMap.put("silver", 0xFFC0C0C0);
432        sColorNameMap.put("teal", 0xFF008080);
433
434    }
435}
436