Hi all -
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.
Thanks in advance for any help -
b
Hi all -
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.
Thanks in advance for any help -
b
Hi there,
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);
}
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.
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
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;
Have you had a look at mx.utils.ColorUtil and the adjustBrightness methods?
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;
}
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.
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 };
}
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));
}