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