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