Home | History | Annotate | Download | only in graphics
      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 
     17 package android.graphics;
     18 
     19 import android.util.MathUtils;
     20 
     21 import java.util.HashMap;
     22 import 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  */
     36 public 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