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