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