Color.java revision 7873b6da5afada5d962b233feb6cc613b526ffb1
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 RGB components to HSV.
240     *     hsv[0] is Hue [0 .. 360)
241     *     hsv[1] is Saturation [0...1]
242     *     hsv[2] is Value [0...1]
243     * @param red  red component value [0..255]
244     * @param green  green component value [0..255]
245     * @param blue  blue component value [0..255]
246     * @param hsv  3 element array which holds the resulting HSV components.
247     */
248    public static void RGBToHSV(int red, int green, int blue, @Size(3) float hsv[]) {
249        if (hsv.length < 3) {
250            throw new RuntimeException("3 components required for hsv");
251        }
252        nativeRGBToHSV(red, green, blue, hsv);
253    }
254
255    /**
256     * Convert the argb color to its HSV components.
257     *     hsv[0] is Hue [0 .. 360)
258     *     hsv[1] is Saturation [0...1]
259     *     hsv[2] is Value [0...1]
260     * @param color the argb color to convert. The alpha component is ignored.
261     * @param hsv  3 element array which holds the resulting HSV components.
262     */
263    public static void colorToHSV(@ColorInt int color, @Size(3) float hsv[]) {
264        RGBToHSV((color >> 16) & 0xFF, (color >> 8) & 0xFF, color & 0xFF, hsv);
265    }
266
267    /**
268     * Convert HSV components to an ARGB color. Alpha set to 0xFF.
269     *     hsv[0] is Hue [0 .. 360)
270     *     hsv[1] is Saturation [0...1]
271     *     hsv[2] is Value [0...1]
272     * If hsv values are out of range, they are pinned.
273     * @param hsv  3 element array which holds the input HSV components.
274     * @return the resulting argb color
275    */
276    public static int HSVToColor(@Size(3) float hsv[]) {
277        return HSVToColor(0xFF, hsv);
278    }
279
280    /**
281     * Convert HSV components to an ARGB color. The alpha component is passed
282     * through unchanged.
283     *     hsv[0] is Hue [0 .. 360)
284     *     hsv[1] is Saturation [0...1]
285     *     hsv[2] is Value [0...1]
286     * If hsv values are out of range, they are pinned.
287     * @param alpha the alpha component of the returned argb color.
288     * @param hsv  3 element array which holds the input HSV components.
289     * @return the resulting argb color
290    */
291    public static int HSVToColor(int alpha, @Size(3) float hsv[]) {
292        if (hsv.length < 3) {
293            throw new RuntimeException("3 components required for hsv");
294        }
295        return nativeHSVToColor(alpha, hsv);
296    }
297
298    private static native void nativeRGBToHSV(int red, int greed, int blue, float hsv[]);
299    private static native int nativeHSVToColor(int alpha, float hsv[]);
300
301    /**
302     * Converts an HTML color (named or numeric) to an integer RGB value.
303     *
304     * @param color Non-null color string.
305     *
306     * @return A color value, or {@code -1} if the color string could not be interpreted.
307     *
308     * @hide
309     */
310    @ColorInt
311    public static int getHtmlColor(String color) {
312        Integer i = sColorNameMap.get(color.toLowerCase(Locale.ROOT));
313        if (i != null) {
314            return i;
315        } else {
316            try {
317                return XmlUtils.convertValueToInt(color, -1);
318            } catch (NumberFormatException nfe) {
319                return -1;
320            }
321        }
322    }
323
324    private static final HashMap<String, Integer> sColorNameMap;
325
326    static {
327        sColorNameMap = new HashMap<String, Integer>();
328        sColorNameMap.put("black", BLACK);
329        sColorNameMap.put("darkgray", DKGRAY);
330        sColorNameMap.put("gray", GRAY);
331        sColorNameMap.put("lightgray", LTGRAY);
332        sColorNameMap.put("white", WHITE);
333        sColorNameMap.put("red", RED);
334        sColorNameMap.put("green", GREEN);
335        sColorNameMap.put("blue", BLUE);
336        sColorNameMap.put("yellow", YELLOW);
337        sColorNameMap.put("cyan", CYAN);
338        sColorNameMap.put("magenta", MAGENTA);
339        sColorNameMap.put("aqua", 0xFF00FFFF);
340        sColorNameMap.put("fuchsia", 0xFFFF00FF);
341        sColorNameMap.put("darkgrey", DKGRAY);
342        sColorNameMap.put("grey", GRAY);
343        sColorNameMap.put("lightgrey", LTGRAY);
344        sColorNameMap.put("lime", 0xFF00FF00);
345        sColorNameMap.put("maroon", 0xFF800000);
346        sColorNameMap.put("navy", 0xFF000080);
347        sColorNameMap.put("olive", 0xFF808000);
348        sColorNameMap.put("purple", 0xFF800080);
349        sColorNameMap.put("silver", 0xFFC0C0C0);
350        sColorNameMap.put("teal", 0xFF008080);
351
352    }
353}
354