Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I calculate shades of a given hex color in actionscript 3?

I need a way to calculate lighter hex color(s) based on a provided one. I realize I could use a color transform, but I need the actual value in order to generate a gradient.

like image 979
WillyCornbread Avatar asked Feb 13 '10 19:02

WillyCornbread


4 Answers

Here is a function that I wrote for a recent project that allows you to find a colour value between two others based on a range of 0-1. I think it will meet your needs

private function getBetweenColourByPercent(value:Number = 0.5 /* 0-1 */, highColor:uint = 0xFFFFFF, lowColor:uint = 0x000000):uint {
    var r:uint = highColor >> 16;
    var g:uint = highColor >> 8 & 0xFF;
    var b:uint = highColor & 0xFF;

    r += ((lowColor >> 16) - r) * value;
    g += ((lowColor >> 8 & 0xFF) - g) * value;
    b += ((lowColor & 0xFF) - b) * value;

    return (r << 16 | g << 8 | b);
}
like image 141
Tyler Egeto Avatar answered Oct 16 '22 00:10

Tyler Egeto


The most accurate way to do this is to convert the RGB value to HSL or HSV (Hue, Saturation, Luminance/Brightness) and then adjust the saturation and or luminance/brightness values (leaving the hue alone). Then convert back to RGB.

When you try to do math on RGB values directly, you tend to get hue changes.

Saturation is how pure the color is, a value of 0.0 is grey, while a value of 1.0 is pure color.

Luminance/Brightness aren't the same thing, but they are similar. They both are used to move a value towards black or white.

So when you say lighter, you probably mean more towards white, but you may also mean more towards grey (desaturated). Or possibly both.

Once you have your RGB value converted into Hue, Saturation and Brightness, then you just multiply brightness by some number > 1 to make it brighter, or Saturation by some value < 1 to make it greyer. then convert back to RGB.

I don't know action script, but here is C style pseudocode for RGB->HSB and HSB->RGB.

RGB to HSB

unsigned int RGB;
double   red   = ((RGB >> 16) & 0xFF) / 255.0; // red value between 0.0 and 1.0
double   green = ((RGB >> 8) & 0xFF) / 255.0;
double   blue  = ((RGB) & 0xFF) / 255.0);

double   dmax = max(max(red, green) blue);
double   dmin = min(min(red, green) blue);
double   range = dmax - dmin;

double   brite = dmax;
double   sat   = 0.0;
double   hue   = 0.0;  // hue is always 0 when sat is 0

if (dmax != 0.0)  sat = range / dmax;

if (sat != 0.0) 
{
   if (red == dmax)
      hue = (green - blue) / range;
   else if (green = dmax)
      hue = 2.0 + (blue - red) / range;
   else if (blue == dmax)
      hue = 4.0 + (green - red) / range;

   // it is conventional to convert hue to a value between 0 and 360.0 (a color circle)
   hue = hue * 60;
   if (hue < 0.0)
      hue = hue + 360.0;
}

// result is now in hue, sat, & brite variables

HSB to RGB

double hue, sat, brite; // these are inputs

double red, green, blue;

if (sat == 0.0)
{
   red   = brite;
   green = brite;        
   blue  = brite;
}       
else
{
   if (hue == 360.0)
      hue = 0;

   int slice = (int)(hue / 60.0);
   double hue_frac = (hue / 60.0) - slice;

   double aa = brite * (1.0 - sat);
   double bb = brite * (1.0 - sat * hue_frac);
   double cc = brite * (1.0 - sat * (1.0 - hue_frac));

   switch (slice)
   {
       case 0: red = brite; green = cc;     blue = aa;    break;
       case 1: red = bb;    green = brite;  blue = aa;    break;
       case 2: red = aa;    green = brite;  blue = cc;    break;
       case 3: red = aa;    green = bb;     blue = brite; break;
       case 4: red = cc;    green = aa;     blue = brite; break;
       case 5: red = brite; green = aa;     blue = bb;    break;
      default: red = 0.0;   green = 0.0;    blue = 0.0;   break;
   }

}

int ir = (int)(red * 255);
int ig = (int)(green * 255);
int ib = (int)(blue * 255);

// this is the result.
unsigned int RGB = (ir << 16) | (ig << 8) | ib;
like image 25
John Knoeller Avatar answered Oct 16 '22 02:10

John Knoeller


Here's some stuff pulled out of my Color utils. Sounds like makeGradient might be useful to you.

    /**
     * Return a gradient given a color.
     *
     * @param color      Base color of the gradient.
     * @param intensity  Amount to shift secondary color.
     * @return An array with a length of two colors.
     */
    public static function makeGradient(color:uint, intensity:int = 20):Array
    {
        var c:Object = hexToRGB(color);
        for (var key:String in c)
        {
            c[key] += intensity;
            c[key] = Math.min(c[key], 255); // -- make sure below 255
            c[key] = Math.max(c[key], 0);   // -- make sure above 0
        }
        return [color, RGBToHex(c)];
    }

    /**
     * Convert a uint (0x000000) to a color object.
     *
     * @param hex  Color.
     * @return Converted object {r:, g:, b:}
     */
    public static function hexToRGB(hex:uint):Object
    {
        var c:Object = {};

        c.a = hex >> 24 & 0xFF;
        c.r = hex >> 16 & 0xFF;
        c.g = hex >> 8 & 0xFF;
        c.b = hex & 0xFF;

        return c;
    }

    /**
     * Convert a color object to uint octal (0x000000).
     *
     * @param c  Color object {r:, g:, b:}.
     * @return Converted color uint (0x000000).
     */
    public static function RGBToHex(c:Object):uint
    {
        var ct:ColorTransform = new ColorTransform(0, 0, 0, 0, c.r, c.g, c.b, 100);
        return ct.color as uint
    }

Also, can't recall where I got this from but these static function will generate a harmony list given a color:

    /**
     * Convert RGB bits to a hexcode
     *
     * @param r  Red bits
     * @param g  Green bits
     * @param b  Blue bits
     * @return A color as a uint
     */
    public static function convertToHex(r:uint, g:uint, b:uint):uint
    {
        var colorHexString:uint = (r << 16) | (g << 8) | b;
        return colorHexString;
    }

    /**
     * Get a series of complements of a given color.
     *
     * @param color   Color to get harmonies for
     * @param weight  Threshold to apply to color harmonies, 0 - 255
     */
    public static function getHarmonies(color:uint, weight:Number):Array
    {
        var red:uint = color >> 16;
        var green:uint = (color ^ (red << 16)) >> 8;
        var blue:uint = (color ^ (red << 16)) ^ (green << 8);

        var colorHarmonyArray:Array = new Array();
        //weight = red+green+blue/3;

        colorHarmonyArray.push(convertToHex(red, green, weight));
        colorHarmonyArray.push(convertToHex(red, weight, blue));
        colorHarmonyArray.push(convertToHex(weight, green, blue));
        colorHarmonyArray.push(convertToHex(red, weight, weight));
        colorHarmonyArray.push(convertToHex(weight, green, weight));
        colorHarmonyArray.push(convertToHex(weight, weight, blue));

        return colorHarmonyArray;
    }
like image 6
typeoneerror Avatar answered Oct 16 '22 00:10

typeoneerror


I have translated the c code to AS3 and fixed the few errors in the code as well. dmin was calculating the max in the rgb to hsb function as well as when calculating the hue when blue is the max it should be red - green else cyan and magenta get turned backwards.

RGB to HSB

    private function RGBtoHSB(_rgb:uint):Object {
        var red:Number = ((_rgb >> 16) & 0xFF) / 255.0;
        var green:Number = ((_rgb >> 8) & 0xFF) / 255.0;
        var blue:Number = ((_rgb) & 0xFF) / 255.0;

        var dmax:Number = Math.max(Math.max(red, green), blue);
        var dmin:Number = Math.min(Math.min(red, green), blue);
        var range:Number = dmax - dmin;

        var bright:Number = dmax;
        var sat:Number = 0.0;
        var hue:Number = 0.0;

        if (dmax != 0.0) {
            sat = range / dmax;
        }

        if (sat != 0.0) {
            if (red == dmax) {
                hue = (green - blue) / range;
            }else if (green == dmax) {
                hue = 2.0 + (blue - red) / range;
            }else if (blue == dmax) {
                hue = 4.0 + (red - green) / range;
            }

            hue = hue * 60;
            if (hue < 0.0) {
                hue = hue + 360.0;
            }
        }

        return { "v":bright, "s":sat, "h":hue };
    }

HSB to RGB

    private function HSBtoRGB(_hue:Number, _sat:Number, _value:Number):uint {
        var red:Number = 0.0;
        var green:Number = 0.0;
        var blue:Number = 0.0;

        if (_sat == 0.0) {
            red = _value;
            green = _value;
            blue = _value;
        }else {
            if (_hue == 360.0) {
                _hue = 0;
            }

            var slice:int = _hue / 60.0;
            var hue_frac:Number = (_hue / 60.0) - slice;

            var aa:Number = _value * (1.0 - _sat);
            var bb:Number = _value * (1.0 - _sat * hue_frac);
            var cc:Number = _value * (1.0 - _sat * (1.0 - hue_frac));

            switch(slice) {
                case 0:
                    red = _value;
                    green = cc;
                    blue = aa;
                    break;
                case 1:
                    red = bb;
                    green = _value;
                    blue = aa;
                    break;
                case 2:
                    red = aa;
                    green = _value;
                    blue = cc;
                    break;
                case 3:
                    red = aa;
                    green = bb;
                    blue = _value;
                    break;
                case 4:
                    red = cc;
                    green = aa;
                    blue = _value;
                    break;
                case 5:
                    red = _value;
                    green = aa;
                    blue = bb;
                    break;
                default:
                    red = 0.0;
                    green = 0.0;
                    blue = 0.0;
                    break;
            }
        }

        var ired:Number = red * 255.0;
        var igreen:Number = green * 255.0;
        var iblue:Number = blue * 255.0;


        return ((ired << 16) | (igreen << 8) | (iblue));
    }
like image 3
Orin Avatar answered Oct 16 '22 02:10

Orin